blob: f5e50bf7ace06f3ecd732194d214e6cf116a041d [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
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. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
73 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030074static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030075static void l2cap_send_disconn_req(struct l2cap_conn *conn,
76 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030078static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
79
Marcel Holtmann01394182006-07-03 10:02:46 +020080/* ---- L2CAP channels ---- */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030081static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020082{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030083 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030084
85 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030086 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030087 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020088 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030089 return NULL;
90
Marcel Holtmann01394182006-07-03 10:02:46 +020091}
92
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030093static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020094{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030095 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030096
97 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030098 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030099 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200100 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200102}
103
104/* Find channel with given SCID.
105 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200107{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300108 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109
110 read_lock(&conn->chan_lock);
111 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300112 if (c)
113 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300115 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200116}
117
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300118static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200119{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300120 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300121
122 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300123 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200125 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200127}
128
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200130{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300131 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300132
133 read_lock(&conn->chan_lock);
134 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300135 if (c)
136 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300138 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200139}
140
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300141static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300142{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300143 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300144
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300145 list_for_each_entry(c, &chan_list, global_l) {
146 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300147 goto found;
148 }
149
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300150 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300151found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300152 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300153}
154
155int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
156{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300157 int err;
158
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300159 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300161 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300162 err = -EADDRINUSE;
163 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300164 }
165
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300166 if (psm) {
167 chan->psm = psm;
168 chan->sport = psm;
169 err = 0;
170 } else {
171 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300172
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300173 err = -EINVAL;
174 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300175 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 chan->psm = cpu_to_le16(p);
177 chan->sport = cpu_to_le16(p);
178 err = 0;
179 break;
180 }
181 }
182
183done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300184 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300185 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300186}
187
188int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
189{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300190 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300191
192 chan->scid = scid;
193
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300194 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300195
196 return 0;
197}
198
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300199static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200200{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300201 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200202
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300203 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300204 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200205 return cid;
206 }
207
208 return 0;
209}
210
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300211struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200212{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300213 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200214
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300215 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
216 if (!chan)
217 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200218
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300219 chan->sk = sk;
220
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300221 write_lock_bh(&chan_list_lock);
222 list_add(&chan->global_l, &chan_list);
223 write_unlock_bh(&chan_list_lock);
224
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300225 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200226}
227
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300228void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300229{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300230 write_lock_bh(&chan_list_lock);
231 list_del(&chan->global_l);
232 write_unlock_bh(&chan_list_lock);
233
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300234 kfree(chan);
235}
236
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300237static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200238{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300239 struct sock *sk = chan->sk;
Marcel Holtmann01394182006-07-03 10:02:46 +0200240
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300241 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300242 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200243
Marcel Holtmann2950f212009-02-12 14:02:50 +0100244 conn->disc_reason = 0x13;
245
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300246 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200247
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300248 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300249 if (conn->hcon->type == LE_LINK) {
250 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300251 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300252 chan->scid = L2CAP_CID_LE_DATA;
253 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300254 } else {
255 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300256 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300257 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300258 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300259 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200260 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300261 chan->scid = L2CAP_CID_CONN_LESS;
262 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300263 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200264 } else {
265 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300266 chan->scid = L2CAP_CID_SIGNALING;
267 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300268 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200269 }
270
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300271 sock_hold(sk);
272
273 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200274}
275
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900276/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200277 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300278static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200279{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300280 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300281 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200282 struct sock *parent = bt_sk(sk)->parent;
283
284 l2cap_sock_clear_timer(sk);
285
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300286 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200287
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900288 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300289 /* Delete from channel list */
290 write_lock_bh(&conn->chan_lock);
291 list_del(&chan->list);
292 write_unlock_bh(&conn->chan_lock);
293 __sock_put(sk);
294
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300295 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200296 hci_conn_put(conn->hcon);
297 }
298
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200299 sk->sk_state = BT_CLOSED;
Marcel Holtmann01394182006-07-03 10:02:46 +0200300 sock_set_flag(sk, SOCK_ZAPPED);
301
302 if (err)
303 sk->sk_err = err;
304
305 if (parent) {
306 bt_accept_unlink(sk);
307 parent->sk_data_ready(parent, 0);
308 } else
309 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300310
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300311 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
312 chan->conf_state & L2CAP_CONF_INPUT_DONE))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300313 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300314
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300315 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300316
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300317 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300318 struct srej_list *l, *tmp;
319
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300320 del_timer(&chan->retrans_timer);
321 del_timer(&chan->monitor_timer);
322 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300323
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300324 skb_queue_purge(&chan->srej_q);
325 skb_queue_purge(&chan->busy_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300326
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300327 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300328 list_del(&l->list);
329 kfree(l);
330 }
331 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200332}
333
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300334/* Must be called on unlocked socket. */
335static void l2cap_chan_close(struct sock *sk)
336{
337 l2cap_sock_clear_timer(sk);
338 lock_sock(sk);
339 __l2cap_chan_close(l2cap_pi(sk)->chan, ECONNRESET);
340 release_sock(sk);
341 l2cap_sock_kill(sk);
342}
343
344static void l2cap_chan_cleanup_listen(struct sock *parent)
345{
346 struct sock *sk;
347
348 BT_DBG("parent %p", parent);
349
350 /* Close not yet accepted channels */
351 while ((sk = bt_accept_dequeue(parent, NULL)))
352 l2cap_chan_close(sk);
353
354 parent->sk_state = BT_CLOSED;
355 sock_set_flag(parent, SOCK_ZAPPED);
356}
357
358void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
359{
360 struct l2cap_conn *conn = chan->conn;
361 struct sock *sk = chan->sk;
362
363 BT_DBG("chan %p state %d socket %p", chan, sk->sk_state, sk->sk_socket);
364
365 switch (sk->sk_state) {
366 case BT_LISTEN:
367 l2cap_chan_cleanup_listen(sk);
368 break;
369
370 case BT_CONNECTED:
371 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300372 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300373 conn->hcon->type == ACL_LINK) {
374 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
375 l2cap_send_disconn_req(conn, chan, reason);
376 } else
377 l2cap_chan_del(chan, reason);
378 break;
379
380 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300381 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300382 conn->hcon->type == ACL_LINK) {
383 struct l2cap_conn_rsp rsp;
384 __u16 result;
385
386 if (bt_sk(sk)->defer_setup)
387 result = L2CAP_CR_SEC_BLOCK;
388 else
389 result = L2CAP_CR_BAD_PSM;
390
391 rsp.scid = cpu_to_le16(chan->dcid);
392 rsp.dcid = cpu_to_le16(chan->scid);
393 rsp.result = cpu_to_le16(result);
394 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
395 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
396 sizeof(rsp), &rsp);
397 }
398
399 l2cap_chan_del(chan, reason);
400 break;
401
402 case BT_CONNECT:
403 case BT_DISCONN:
404 l2cap_chan_del(chan, reason);
405 break;
406
407 default:
408 sock_set_flag(sk, SOCK_ZAPPED);
409 break;
410 }
411}
412
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300413static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530414{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300415 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300416 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530417 case BT_SECURITY_HIGH:
418 return HCI_AT_DEDICATED_BONDING_MITM;
419 case BT_SECURITY_MEDIUM:
420 return HCI_AT_DEDICATED_BONDING;
421 default:
422 return HCI_AT_NO_BONDING;
423 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300424 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300425 if (chan->sec_level == BT_SECURITY_LOW)
426 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530427
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300428 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530429 return HCI_AT_NO_BONDING_MITM;
430 else
431 return HCI_AT_NO_BONDING;
432 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300433 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530434 case BT_SECURITY_HIGH:
435 return HCI_AT_GENERAL_BONDING_MITM;
436 case BT_SECURITY_MEDIUM:
437 return HCI_AT_GENERAL_BONDING;
438 default:
439 return HCI_AT_NO_BONDING;
440 }
441 }
442}
443
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200444/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300445static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200446{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300447 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100448 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200449
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300450 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100451
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300452 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200453}
454
Gustavo F. Padovan68983252011-02-04 03:02:31 -0200455u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200456{
457 u8 id;
458
459 /* Get next available identificator.
460 * 1 - 128 are used by kernel.
461 * 129 - 199 are reserved.
462 * 200 - 254 are used by utilities like l2ping, etc.
463 */
464
465 spin_lock_bh(&conn->lock);
466
467 if (++conn->tx_ident > 128)
468 conn->tx_ident = 1;
469
470 id = conn->tx_ident;
471
472 spin_unlock_bh(&conn->lock);
473
474 return id;
475}
476
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300477static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200478{
479 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200480 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200481
482 BT_DBG("code 0x%2.2x", code);
483
484 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300485 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200486
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200487 if (lmp_no_flush_capable(conn->hcon->hdev))
488 flags = ACL_START_NO_FLUSH;
489 else
490 flags = ACL_START;
491
492 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200493}
494
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300495static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300496{
497 struct sk_buff *skb;
498 struct l2cap_hdr *lh;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300499 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300500 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300501 struct sock *sk = (struct sock *)pi;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300502 int count, hlen = L2CAP_HDR_SIZE + 2;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200503 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300504
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300505 if (sk->sk_state != BT_CONNECTED)
506 return;
507
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300508 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300509 hlen += 2;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300510
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300511 BT_DBG("chan %p, control 0x%2.2x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300512
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300513 count = min_t(unsigned int, conn->mtu, hlen);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300514 control |= L2CAP_CTRL_FRAME_TYPE;
515
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300516 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300517 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300518 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300519 }
520
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300521 if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300522 control |= L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300523 chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300524 }
525
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300526 skb = bt_skb_alloc(count, GFP_ATOMIC);
527 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300528 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300529
530 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300531 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300532 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300533 put_unaligned_le16(control, skb_put(skb, 2));
534
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300535 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300536 u16 fcs = crc16(0, (u8 *)lh, count - 2);
537 put_unaligned_le16(fcs, skb_put(skb, 2));
538 }
539
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200540 if (lmp_no_flush_capable(conn->hcon->hdev))
541 flags = ACL_START_NO_FLUSH;
542 else
543 flags = ACL_START;
544
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300545 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300546}
547
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300548static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300549{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300550 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300551 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300552 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300553 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300554 control |= L2CAP_SUPER_RCV_READY;
555
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300556 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300557
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300558 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300559}
560
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300561static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300562{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300563 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300564}
565
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300566static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200567{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300568 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200569
570 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100571 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
572 return;
573
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300574 if (l2cap_check_security(chan) &&
575 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200576 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300577 req.scid = cpu_to_le16(chan->scid);
578 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200579
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300580 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300581 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200582
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300583 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
584 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200585 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200586 } else {
587 struct l2cap_info_req req;
588 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
589
590 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
591 conn->info_ident = l2cap_get_ident(conn);
592
593 mod_timer(&conn->info_timer, jiffies +
594 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
595
596 l2cap_send_cmd(conn, conn->info_ident,
597 L2CAP_INFO_REQ, sizeof(req), &req);
598 }
599}
600
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300601static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
602{
603 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300604 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300605 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
606
607 switch (mode) {
608 case L2CAP_MODE_ERTM:
609 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
610 case L2CAP_MODE_STREAMING:
611 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
612 default:
613 return 0x00;
614 }
615}
616
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300617static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300618{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300619 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300620 struct l2cap_disconn_req req;
621
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300622 if (!conn)
623 return;
624
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300625 sk = chan->sk;
626
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300627 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300628 del_timer(&chan->retrans_timer);
629 del_timer(&chan->monitor_timer);
630 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300631 }
632
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300633 req.dcid = cpu_to_le16(chan->dcid);
634 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300635 l2cap_send_cmd(conn, l2cap_get_ident(conn),
636 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300637
638 sk->sk_state = BT_DISCONN;
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300639 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300640}
641
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200643static void l2cap_conn_start(struct l2cap_conn *conn)
644{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300645 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200646
647 BT_DBG("conn %p", conn);
648
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300649 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200650
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300651 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300652 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300653
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200654 bh_lock_sock(sk);
655
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300656 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200657 bh_unlock_sock(sk);
658 continue;
659 }
660
661 if (sk->sk_state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300662 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300663
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300664 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300665 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300666 bh_unlock_sock(sk);
667 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200668 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300669
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300670 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300671 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300672 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300673 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300674 /* __l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300675 * so release the lock */
676 read_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300677 __l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300678 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300679 bh_unlock_sock(sk);
680 continue;
681 }
682
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300683 req.scid = cpu_to_le16(chan->scid);
684 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300685
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300686 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300687 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300688
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300689 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
690 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300691
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200692 } else if (sk->sk_state == BT_CONNECT2) {
693 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300694 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300695 rsp.scid = cpu_to_le16(chan->dcid);
696 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200697
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300698 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100699 if (bt_sk(sk)->defer_setup) {
700 struct sock *parent = bt_sk(sk)->parent;
701 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
702 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
703 parent->sk_data_ready(parent, 0);
704
705 } else {
706 sk->sk_state = BT_CONFIG;
707 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
708 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
709 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200710 } else {
711 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
712 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
713 }
714
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300715 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
716 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300717
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300718 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300719 rsp.result != L2CAP_CR_SUCCESS) {
720 bh_unlock_sock(sk);
721 continue;
722 }
723
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300724 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300725 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300726 l2cap_build_conf_req(chan, buf), buf);
727 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200728 }
729
730 bh_unlock_sock(sk);
731 }
732
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300733 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200734}
735
Ville Tervob62f3282011-02-10 22:38:50 -0300736/* Find socket with cid and source bdaddr.
737 * Returns closest match, locked.
738 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300739static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300740{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300741 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300742
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300743 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300744
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300745 list_for_each_entry(c, &chan_list, global_l) {
746 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300747
Ville Tervob62f3282011-02-10 22:38:50 -0300748 if (state && sk->sk_state != state)
749 continue;
750
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300751 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300752 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300753 if (!bacmp(&bt_sk(sk)->src, src)) {
754 read_unlock(&chan_list_lock);
755 return c;
756 }
Ville Tervob62f3282011-02-10 22:38:50 -0300757
758 /* Closest match */
759 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300760 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300761 }
762 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300763
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300764 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300765
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300766 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300767}
768
769static void l2cap_le_conn_ready(struct l2cap_conn *conn)
770{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300771 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300772 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300773
774 BT_DBG("");
775
776 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300777 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300778 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300779 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300780 return;
781
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300782 parent = pchan->sk;
783
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300784 bh_lock_sock(parent);
785
Ville Tervob62f3282011-02-10 22:38:50 -0300786 /* Check for backlog size */
787 if (sk_acceptq_is_full(parent)) {
788 BT_DBG("backlog full %d", parent->sk_ack_backlog);
789 goto clean;
790 }
791
792 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
793 if (!sk)
794 goto clean;
795
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300796 chan = l2cap_chan_create(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300797 if (!chan) {
798 l2cap_sock_kill(sk);
799 goto clean;
800 }
801
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300802 l2cap_pi(sk)->chan = chan;
803
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300804 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300805
806 hci_conn_hold(conn->hcon);
807
808 l2cap_sock_init(sk, parent);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300809
Ville Tervob62f3282011-02-10 22:38:50 -0300810 bacpy(&bt_sk(sk)->src, conn->src);
811 bacpy(&bt_sk(sk)->dst, conn->dst);
812
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300813 bt_accept_enqueue(parent, sk);
814
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300815 __l2cap_chan_add(conn, chan);
816
Ville Tervob62f3282011-02-10 22:38:50 -0300817 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
818
819 sk->sk_state = BT_CONNECTED;
820 parent->sk_data_ready(parent, 0);
821
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300822 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300823
824clean:
825 bh_unlock_sock(parent);
826}
827
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200828static void l2cap_conn_ready(struct l2cap_conn *conn)
829{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300830 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200831
832 BT_DBG("conn %p", conn);
833
Ville Tervob62f3282011-02-10 22:38:50 -0300834 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
835 l2cap_le_conn_ready(conn);
836
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300837 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200838
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300839 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300840 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300841
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200842 bh_lock_sock(sk);
843
Ville Tervoacd7d372011-02-10 22:38:49 -0300844 if (conn->hcon->type == LE_LINK) {
845 l2cap_sock_clear_timer(sk);
846 sk->sk_state = BT_CONNECTED;
847 sk->sk_state_change(sk);
848 }
849
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300850 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200851 l2cap_sock_clear_timer(sk);
852 sk->sk_state = BT_CONNECTED;
853 sk->sk_state_change(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200854 } else if (sk->sk_state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300855 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200856
857 bh_unlock_sock(sk);
858 }
859
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300860 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200861}
862
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200863/* Notify sockets that we cannot guaranty reliability anymore */
864static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
865{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300866 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200867
868 BT_DBG("conn %p", conn);
869
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300870 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200871
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300872 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300873 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300874
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300875 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200876 sk->sk_err = err;
877 }
878
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300879 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200880}
881
882static void l2cap_info_timeout(unsigned long arg)
883{
884 struct l2cap_conn *conn = (void *) arg;
885
Marcel Holtmann984947d2009-02-06 23:35:19 +0100886 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100887 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100888
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200889 l2cap_conn_start(conn);
890}
891
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
893{
Marcel Holtmann01394182006-07-03 10:02:46 +0200894 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895
Marcel Holtmann01394182006-07-03 10:02:46 +0200896 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 return conn;
898
Marcel Holtmann01394182006-07-03 10:02:46 +0200899 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
900 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902
903 hcon->l2cap_data = conn;
904 conn->hcon = hcon;
905
Marcel Holtmann01394182006-07-03 10:02:46 +0200906 BT_DBG("hcon %p conn %p", hcon, conn);
907
Ville Tervoacd7d372011-02-10 22:38:49 -0300908 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
909 conn->mtu = hcon->hdev->le_mtu;
910 else
911 conn->mtu = hcon->hdev->acl_mtu;
912
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 conn->src = &hcon->hdev->bdaddr;
914 conn->dst = &hcon->dst;
915
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200916 conn->feat_mask = 0;
917
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300919 rwlock_init(&conn->chan_lock);
920
921 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922
Ville Tervob62f3282011-02-10 22:38:50 -0300923 if (hcon->type != LE_LINK)
924 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +0000925 (unsigned long) conn);
926
Marcel Holtmann2950f212009-02-12 14:02:50 +0100927 conn->disc_reason = 0x13;
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 return conn;
930}
931
Marcel Holtmann01394182006-07-03 10:02:46 +0200932static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933{
Marcel Holtmann01394182006-07-03 10:02:46 +0200934 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300935 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936 struct sock *sk;
937
Marcel Holtmann01394182006-07-03 10:02:46 +0200938 if (!conn)
939 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940
941 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
942
Wei Yongjun7585b972009-02-25 18:29:52 +0800943 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944
945 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300946 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300947 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300949 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 bh_unlock_sock(sk);
951 l2cap_sock_kill(sk);
952 }
953
Dave Young8e8440f2008-03-03 12:18:55 -0800954 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
955 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -0800956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 hcon->l2cap_data = NULL;
958 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959}
960
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300961static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300963 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300964 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300965 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966}
967
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969
970/* Find socket with psm and source bdaddr.
971 * Returns closest match.
972 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300973static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300975 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300977 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +0000978
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300979 list_for_each_entry(c, &chan_list, global_l) {
980 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300981
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 if (state && sk->sk_state != state)
983 continue;
984
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300985 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300987 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +0200988 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300989 return c;
990 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
992 /* Closest match */
993 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300994 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 }
996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700997
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300998 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +0000999
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001000 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001}
1002
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001003int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001005 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 bdaddr_t *src = &bt_sk(sk)->src;
1007 bdaddr_t *dst = &bt_sk(sk)->dst;
1008 struct l2cap_conn *conn;
1009 struct hci_conn *hcon;
1010 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001011 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001012 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001014 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001015 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001017 hdev = hci_get_route(dst, src);
1018 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 return -EHOSTUNREACH;
1020
1021 hci_dev_lock_bh(hdev);
1022
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001023 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001024
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001025 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001026 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001027 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001028 else
1029 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001030 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001031
Ville Tervo30e76272011-02-22 16:10:53 -03001032 if (IS_ERR(hcon)) {
1033 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001035 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036
1037 conn = l2cap_conn_add(hcon, 0);
1038 if (!conn) {
1039 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001040 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 goto done;
1042 }
1043
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 /* Update source addr of the socket */
1045 bacpy(src, conn->src);
1046
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001047 l2cap_chan_add(conn, chan);
1048
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 sk->sk_state = BT_CONNECT;
1050 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
1051
1052 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001053 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 l2cap_sock_clear_timer(sk);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001055 if (l2cap_check_security(chan))
Johan Hedbergd00ef242011-01-19 12:06:51 +05301056 sk->sk_state = BT_CONNECTED;
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001057 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001058 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 }
1060
Ville Tervo30e76272011-02-22 16:10:53 -03001061 err = 0;
1062
Linus Torvalds1da177e2005-04-16 15:20:36 -07001063done:
1064 hci_dev_unlock_bh(hdev);
1065 hci_dev_put(hdev);
1066 return err;
1067}
1068
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001069int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001070{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001071 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001072 DECLARE_WAITQUEUE(wait, current);
1073 int err = 0;
1074 int timeo = HZ/5;
1075
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001076 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001077 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001078 set_current_state(TASK_INTERRUPTIBLE);
1079
1080 if (!timeo)
1081 timeo = HZ/5;
1082
1083 if (signal_pending(current)) {
1084 err = sock_intr_errno(timeo);
1085 break;
1086 }
1087
1088 release_sock(sk);
1089 timeo = schedule_timeout(timeo);
1090 lock_sock(sk);
1091
1092 err = sock_error(sk);
1093 if (err)
1094 break;
1095 }
1096 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001097 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001098 return err;
1099}
1100
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001101static void l2cap_monitor_timeout(unsigned long arg)
1102{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001103 struct l2cap_chan *chan = (void *) arg;
1104 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001105
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001106 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001107
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001108 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001109 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001110 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001111 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001112 return;
1113 }
1114
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001115 chan->retry_count++;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001116 __mod_monitor_timer();
1117
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001118 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001119 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001120}
1121
1122static void l2cap_retrans_timeout(unsigned long arg)
1123{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001124 struct l2cap_chan *chan = (void *) arg;
1125 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001126
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001127 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001128
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001129 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001130 chan->retry_count = 1;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001131 __mod_monitor_timer();
1132
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001133 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001134
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001135 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001136 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001137}
1138
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001139static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001140{
1141 struct sk_buff *skb;
1142
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001143 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001144 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001145 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001146 break;
1147
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001148 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001149 kfree_skb(skb);
1150
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001151 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001152 }
1153
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001154 if (!chan->unacked_frames)
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001155 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001156}
1157
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001158void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001159{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001160 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001161 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001162
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001163 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001164
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001165 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001166 flags = ACL_START_NO_FLUSH;
1167 else
1168 flags = ACL_START;
1169
1170 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001171}
1172
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001173void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001174{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001175 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001176 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001177
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001178 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001179 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001180 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001181 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001182
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001183 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001184 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1185 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001186 }
1187
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001188 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001189
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001190 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001191 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001192}
1193
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001194static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001195{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001196 struct sk_buff *skb, *tx_skb;
1197 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001198
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001199 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001200 if (!skb)
1201 return;
1202
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001203 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001204 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001205 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001206
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001207 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001208 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001209
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001210 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001211
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001212 if (chan->remote_max_tx &&
1213 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001214 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001215 return;
1216 }
1217
1218 tx_skb = skb_clone(skb, GFP_ATOMIC);
1219 bt_cb(skb)->retries++;
1220 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001221 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001222
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001223 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001224 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001225 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001226 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001227
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001228 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001229 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001230
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001231 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1232
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001233 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001234 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1235 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1236 }
1237
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001238 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001239}
1240
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001241int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001242{
1243 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001244 struct sock *sk = chan->sk;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001245 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001246 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001247
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001248 if (sk->sk_state != BT_CONNECTED)
1249 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001250
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001251 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001252
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001253 if (chan->remote_max_tx &&
1254 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001255 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001256 break;
1257 }
1258
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001259 tx_skb = skb_clone(skb, GFP_ATOMIC);
1260
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001261 bt_cb(skb)->retries++;
1262
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001263 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001264 control &= L2CAP_CTRL_SAR;
1265
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001266 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001267 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001268 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001269 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001270 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1271 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001272 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1273
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001274
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001275 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001276 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1277 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1278 }
1279
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001280 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001281
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001282 __mod_retrans_timer();
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001283
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001284 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1285 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001286
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301287 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001288 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301289
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001290 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001291
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001292 if (skb_queue_is_last(&chan->tx_q, skb))
1293 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001294 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001295 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001296
1297 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001298 }
1299
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001300 return nsent;
1301}
1302
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001303static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001304{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001305 int ret;
1306
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001307 if (!skb_queue_empty(&chan->tx_q))
1308 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001309
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001310 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001311 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001312 return ret;
1313}
1314
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001315static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001316{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001317 u16 control = 0;
1318
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001319 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001320
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001321 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001322 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001323 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1324 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001325 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001326 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001327
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001328 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001329 return;
1330
1331 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001332 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001333}
1334
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001335static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001336{
1337 struct srej_list *tail;
1338 u16 control;
1339
1340 control = L2CAP_SUPER_SELECT_REJECT;
1341 control |= L2CAP_CTRL_FINAL;
1342
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001343 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001344 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1345
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001346 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001347}
1348
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001349static 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 -07001350{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001351 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001352 struct sk_buff **frag;
1353 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001355 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001356 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001357
1358 sent += count;
1359 len -= count;
1360
1361 /* Continuation fragments (no L2CAP header) */
1362 frag = &skb_shinfo(skb)->frag_list;
1363 while (len) {
1364 count = min_t(unsigned int, conn->mtu, len);
1365
1366 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1367 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001368 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001369 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1370 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 sent += count;
1373 len -= count;
1374
1375 frag = &(*frag)->next;
1376 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001377
1378 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001379}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001381struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001382{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001383 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001384 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001385 struct sk_buff *skb;
1386 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1387 struct l2cap_hdr *lh;
1388
1389 BT_DBG("sk %p len %d", sk, (int)len);
1390
1391 count = min_t(unsigned int, (conn->mtu - hlen), len);
1392 skb = bt_skb_send_alloc(sk, count + hlen,
1393 msg->msg_flags & MSG_DONTWAIT, &err);
1394 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001395 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001396
1397 /* Create L2CAP header */
1398 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001399 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001400 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001401 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001402
1403 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1404 if (unlikely(err < 0)) {
1405 kfree_skb(skb);
1406 return ERR_PTR(err);
1407 }
1408 return skb;
1409}
1410
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001411struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001412{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001413 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001414 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001415 struct sk_buff *skb;
1416 int err, count, hlen = L2CAP_HDR_SIZE;
1417 struct l2cap_hdr *lh;
1418
1419 BT_DBG("sk %p len %d", sk, (int)len);
1420
1421 count = min_t(unsigned int, (conn->mtu - hlen), len);
1422 skb = bt_skb_send_alloc(sk, count + hlen,
1423 msg->msg_flags & MSG_DONTWAIT, &err);
1424 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001425 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001426
1427 /* Create L2CAP header */
1428 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001429 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001430 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1431
1432 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1433 if (unlikely(err < 0)) {
1434 kfree_skb(skb);
1435 return ERR_PTR(err);
1436 }
1437 return skb;
1438}
1439
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001440struct 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 -03001441{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001442 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001443 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001444 struct sk_buff *skb;
1445 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1446 struct l2cap_hdr *lh;
1447
1448 BT_DBG("sk %p len %d", sk, (int)len);
1449
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001450 if (!conn)
1451 return ERR_PTR(-ENOTCONN);
1452
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001453 if (sdulen)
1454 hlen += 2;
1455
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001456 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001457 hlen += 2;
1458
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001459 count = min_t(unsigned int, (conn->mtu - hlen), len);
1460 skb = bt_skb_send_alloc(sk, count + hlen,
1461 msg->msg_flags & MSG_DONTWAIT, &err);
1462 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001463 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464
1465 /* Create L2CAP header */
1466 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001467 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001468 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1469 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001470 if (sdulen)
1471 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001472
1473 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1474 if (unlikely(err < 0)) {
1475 kfree_skb(skb);
1476 return ERR_PTR(err);
1477 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001478
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001479 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001480 put_unaligned_le16(0, skb_put(skb, 2));
1481
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001482 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001483 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001484}
1485
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001486int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001487{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001488 struct sk_buff *skb;
1489 struct sk_buff_head sar_queue;
1490 u16 control;
1491 size_t size = 0;
1492
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001493 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001494 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001495 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001496 if (IS_ERR(skb))
1497 return PTR_ERR(skb);
1498
1499 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001500 len -= chan->remote_mps;
1501 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001502
1503 while (len > 0) {
1504 size_t buflen;
1505
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001506 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001507 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001508 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001509 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001510 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001511 buflen = len;
1512 }
1513
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001514 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001515 if (IS_ERR(skb)) {
1516 skb_queue_purge(&sar_queue);
1517 return PTR_ERR(skb);
1518 }
1519
1520 __skb_queue_tail(&sar_queue, skb);
1521 len -= buflen;
1522 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001523 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001524 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1525 if (chan->tx_send_head == NULL)
1526 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001527
1528 return size;
1529}
1530
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001531int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1532{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001533 struct sk_buff *skb;
1534 u16 control;
1535 int err;
1536
1537 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001538 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001539 skb = l2cap_create_connless_pdu(chan, msg, len);
1540 if (IS_ERR(skb))
1541 return PTR_ERR(skb);
1542
1543 l2cap_do_send(chan, skb);
1544 return len;
1545 }
1546
1547 switch (chan->mode) {
1548 case L2CAP_MODE_BASIC:
1549 /* Check outgoing MTU */
1550 if (len > chan->omtu)
1551 return -EMSGSIZE;
1552
1553 /* Create a basic PDU */
1554 skb = l2cap_create_basic_pdu(chan, msg, len);
1555 if (IS_ERR(skb))
1556 return PTR_ERR(skb);
1557
1558 l2cap_do_send(chan, skb);
1559 err = len;
1560 break;
1561
1562 case L2CAP_MODE_ERTM:
1563 case L2CAP_MODE_STREAMING:
1564 /* Entire SDU fits into one PDU */
1565 if (len <= chan->remote_mps) {
1566 control = L2CAP_SDU_UNSEGMENTED;
1567 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1568 0);
1569 if (IS_ERR(skb))
1570 return PTR_ERR(skb);
1571
1572 __skb_queue_tail(&chan->tx_q, skb);
1573
1574 if (chan->tx_send_head == NULL)
1575 chan->tx_send_head = skb;
1576
1577 } else {
1578 /* Segment SDU into multiples PDUs */
1579 err = l2cap_sar_segment_sdu(chan, msg, len);
1580 if (err < 0)
1581 return err;
1582 }
1583
1584 if (chan->mode == L2CAP_MODE_STREAMING) {
1585 l2cap_streaming_send(chan);
1586 err = len;
1587 break;
1588 }
1589
1590 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1591 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1592 err = len;
1593 break;
1594 }
1595
1596 err = l2cap_ertm_send(chan);
1597 if (err >= 0)
1598 err = len;
1599
1600 break;
1601
1602 default:
1603 BT_DBG("bad state %1.1x", chan->mode);
1604 err = -EBADFD;
1605 }
1606
1607 return err;
1608}
1609
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610static void l2cap_chan_ready(struct sock *sk)
1611{
1612 struct sock *parent = bt_sk(sk)->parent;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001613 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001614
1615 BT_DBG("sk %p, parent %p", sk, parent);
1616
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001617 chan->conf_state = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618 l2cap_sock_clear_timer(sk);
1619
1620 if (!parent) {
1621 /* Outgoing channel.
1622 * Wake up socket sleeping on connect.
1623 */
1624 sk->sk_state = BT_CONNECTED;
1625 sk->sk_state_change(sk);
1626 } else {
1627 /* Incoming channel.
1628 * Wake up socket sleeping on accept.
1629 */
1630 parent->sk_data_ready(parent, 0);
1631 }
1632}
1633
1634/* Copy frame to all raw sockets on that connection */
1635static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1636{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001637 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001638 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
1640 BT_DBG("conn %p", conn);
1641
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001642 read_lock(&conn->chan_lock);
1643 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001644 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001645 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001646 continue;
1647
1648 /* Don't send frame to the socket it came from */
1649 if (skb->sk == sk)
1650 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001651 nskb = skb_clone(skb, GFP_ATOMIC);
1652 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 continue;
1654
1655 if (sock_queue_rcv_skb(sk, nskb))
1656 kfree_skb(nskb);
1657 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001658 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659}
1660
1661/* ---- L2CAP signalling commands ---- */
1662static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1663 u8 code, u8 ident, u16 dlen, void *data)
1664{
1665 struct sk_buff *skb, **frag;
1666 struct l2cap_cmd_hdr *cmd;
1667 struct l2cap_hdr *lh;
1668 int len, count;
1669
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001670 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1671 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672
1673 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1674 count = min_t(unsigned int, conn->mtu, len);
1675
1676 skb = bt_skb_alloc(count, GFP_ATOMIC);
1677 if (!skb)
1678 return NULL;
1679
1680 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001681 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001682
1683 if (conn->hcon->type == LE_LINK)
1684 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1685 else
1686 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001687
1688 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1689 cmd->code = code;
1690 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001691 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001692
1693 if (dlen) {
1694 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1695 memcpy(skb_put(skb, count), data, count);
1696 data += count;
1697 }
1698
1699 len -= skb->len;
1700
1701 /* Continuation fragments (no L2CAP header) */
1702 frag = &skb_shinfo(skb)->frag_list;
1703 while (len) {
1704 count = min_t(unsigned int, conn->mtu, len);
1705
1706 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1707 if (!*frag)
1708 goto fail;
1709
1710 memcpy(skb_put(*frag, count), data, count);
1711
1712 len -= count;
1713 data += count;
1714
1715 frag = &(*frag)->next;
1716 }
1717
1718 return skb;
1719
1720fail:
1721 kfree_skb(skb);
1722 return NULL;
1723}
1724
1725static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1726{
1727 struct l2cap_conf_opt *opt = *ptr;
1728 int len;
1729
1730 len = L2CAP_CONF_OPT_SIZE + opt->len;
1731 *ptr += len;
1732
1733 *type = opt->type;
1734 *olen = opt->len;
1735
1736 switch (opt->len) {
1737 case 1:
1738 *val = *((u8 *) opt->val);
1739 break;
1740
1741 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001742 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 break;
1744
1745 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001746 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001747 break;
1748
1749 default:
1750 *val = (unsigned long) opt->val;
1751 break;
1752 }
1753
1754 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1755 return len;
1756}
1757
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1759{
1760 struct l2cap_conf_opt *opt = *ptr;
1761
1762 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1763
1764 opt->type = type;
1765 opt->len = len;
1766
1767 switch (len) {
1768 case 1:
1769 *((u8 *) opt->val) = val;
1770 break;
1771
1772 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001773 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774 break;
1775
1776 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001777 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 break;
1779
1780 default:
1781 memcpy(opt->val, (void *) val, len);
1782 break;
1783 }
1784
1785 *ptr += L2CAP_CONF_OPT_SIZE + len;
1786}
1787
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001788static void l2cap_ack_timeout(unsigned long arg)
1789{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001790 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001791
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001792 bh_lock_sock(chan->sk);
1793 l2cap_send_ack(chan);
1794 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001795}
1796
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001797static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001798{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001799 struct sock *sk = chan->sk;
1800
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001801 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001802 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001803 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001804 chan->num_acked = 0;
1805 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001806
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001807 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1808 (unsigned long) chan);
1809 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1810 (unsigned long) chan);
1811 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001812
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001813 skb_queue_head_init(&chan->srej_q);
1814 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001815
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001816 INIT_LIST_HEAD(&chan->srej_l);
1817
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001818 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001819
1820 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001821}
1822
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001823static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1824{
1825 switch (mode) {
1826 case L2CAP_MODE_STREAMING:
1827 case L2CAP_MODE_ERTM:
1828 if (l2cap_mode_supported(mode, remote_feat_mask))
1829 return mode;
1830 /* fall through */
1831 default:
1832 return L2CAP_MODE_BASIC;
1833 }
1834}
1835
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001836static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001837{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001839 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001840 void *ptr = req->data;
1841
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001842 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001844 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001845 goto done;
1846
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001847 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001848 case L2CAP_MODE_STREAMING:
1849 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001850 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001851 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001852
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001853 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001854 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001855 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001856 break;
1857 }
1858
1859done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001860 if (chan->imtu != L2CAP_DEFAULT_MTU)
1861 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001862
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001863 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001864 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001865 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1866 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001867 break;
1868
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001869 rfc.mode = L2CAP_MODE_BASIC;
1870 rfc.txwin_size = 0;
1871 rfc.max_transmit = 0;
1872 rfc.retrans_timeout = 0;
1873 rfc.monitor_timeout = 0;
1874 rfc.max_pdu_size = 0;
1875
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001876 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1877 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001878 break;
1879
1880 case L2CAP_MODE_ERTM:
1881 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001882 rfc.txwin_size = chan->tx_win;
1883 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001884 rfc.retrans_timeout = 0;
1885 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001886 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001887 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1888 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001889
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001890 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1891 (unsigned long) &rfc);
1892
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001893 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001894 break;
1895
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001896 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001897 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001898 chan->fcs = L2CAP_FCS_NONE;
1899 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001900 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001901 break;
1902
1903 case L2CAP_MODE_STREAMING:
1904 rfc.mode = L2CAP_MODE_STREAMING;
1905 rfc.txwin_size = 0;
1906 rfc.max_transmit = 0;
1907 rfc.retrans_timeout = 0;
1908 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001909 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001910 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1911 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001912
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001913 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1914 (unsigned long) &rfc);
1915
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001916 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001917 break;
1918
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001919 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001920 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001921 chan->fcs = L2CAP_FCS_NONE;
1922 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001923 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001924 break;
1925 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001926
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001927 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001928 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
1930 return ptr - data;
1931}
1932
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001933static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001934{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001935 struct l2cap_conf_rsp *rsp = data;
1936 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001937 void *req = chan->conf_req;
1938 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001939 int type, hint, olen;
1940 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02001941 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02001942 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001943 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001945 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01001946
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001947 while (len >= L2CAP_CONF_OPT_SIZE) {
1948 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03001950 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07001951 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001952
1953 switch (type) {
1954 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02001955 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001956 break;
1957
1958 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001959 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001960 break;
1961
1962 case L2CAP_CONF_QOS:
1963 break;
1964
Marcel Holtmann6464f352007-10-20 13:39:51 +02001965 case L2CAP_CONF_RFC:
1966 if (olen == sizeof(rfc))
1967 memcpy(&rfc, (void *) val, olen);
1968 break;
1969
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001970 case L2CAP_CONF_FCS:
1971 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001972 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001973
1974 break;
1975
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001976 default:
1977 if (hint)
1978 break;
1979
1980 result = L2CAP_CONF_UNKNOWN;
1981 *((u8 *) ptr++) = type;
1982 break;
1983 }
1984 }
1985
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001986 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001987 goto done;
1988
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001989 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001990 case L2CAP_MODE_STREAMING:
1991 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001992 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001993 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001994 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001995 break;
1996 }
1997
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001998 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001999 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002000
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002001 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002002 }
2003
2004done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002005 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002006 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002007 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002008
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002009 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002010 return -ECONNREFUSED;
2011
2012 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2013 sizeof(rfc), (unsigned long) &rfc);
2014 }
2015
2016
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002017 if (result == L2CAP_CONF_SUCCESS) {
2018 /* Configure output options and let the other side know
2019 * which ones we don't like. */
2020
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002021 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2022 result = L2CAP_CONF_UNACCEPT;
2023 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002024 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002025 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002026 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002027 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002028
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002029 switch (rfc.mode) {
2030 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002031 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002032 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002033 break;
2034
2035 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002036 chan->remote_tx_win = rfc.txwin_size;
2037 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002038
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002039 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2040 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002041
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002042 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002043
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002044 rfc.retrans_timeout =
2045 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2046 rfc.monitor_timeout =
2047 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002048
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002049 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002050
2051 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2052 sizeof(rfc), (unsigned long) &rfc);
2053
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002054 break;
2055
2056 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002057 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2058 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002059
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002060 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002061
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002062 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002063
2064 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2065 sizeof(rfc), (unsigned long) &rfc);
2066
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002067 break;
2068
2069 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002070 result = L2CAP_CONF_UNACCEPT;
2071
2072 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002073 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002074 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002075
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002076 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002077 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002079 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002080 rsp->result = cpu_to_le16(result);
2081 rsp->flags = cpu_to_le16(0x0000);
2082
2083 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002084}
2085
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002086static 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 -03002087{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002088 struct l2cap_conf_req *req = data;
2089 void *ptr = req->data;
2090 int type, olen;
2091 unsigned long val;
2092 struct l2cap_conf_rfc rfc;
2093
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002094 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002095
2096 while (len >= L2CAP_CONF_OPT_SIZE) {
2097 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2098
2099 switch (type) {
2100 case L2CAP_CONF_MTU:
2101 if (val < L2CAP_DEFAULT_MIN_MTU) {
2102 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002103 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002104 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002105 chan->imtu = val;
2106 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002107 break;
2108
2109 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002110 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002111 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002112 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002113 break;
2114
2115 case L2CAP_CONF_RFC:
2116 if (olen == sizeof(rfc))
2117 memcpy(&rfc, (void *)val, olen);
2118
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002119 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002120 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002121 return -ECONNREFUSED;
2122
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002123 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002124
2125 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2126 sizeof(rfc), (unsigned long) &rfc);
2127 break;
2128 }
2129 }
2130
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002131 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002132 return -ECONNREFUSED;
2133
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002134 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002135
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002136 if (*result == L2CAP_CONF_SUCCESS) {
2137 switch (rfc.mode) {
2138 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002139 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2140 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2141 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002142 break;
2143 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002144 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002145 }
2146 }
2147
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002148 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002149 req->flags = cpu_to_le16(0x0000);
2150
2151 return ptr - data;
2152}
2153
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002154static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155{
2156 struct l2cap_conf_rsp *rsp = data;
2157 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002159 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002161 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002162 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002163 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164
2165 return ptr - data;
2166}
2167
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002168void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002169{
2170 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002171 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002172 u8 buf[128];
2173
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002174 rsp.scid = cpu_to_le16(chan->dcid);
2175 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002176 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2177 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2178 l2cap_send_cmd(conn, chan->ident,
2179 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2180
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002181 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002182 return;
2183
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002184 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002185 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2186 l2cap_build_conf_req(chan, buf), buf);
2187 chan->num_conf_req++;
2188}
2189
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002190static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002191{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002192 int type, olen;
2193 unsigned long val;
2194 struct l2cap_conf_rfc rfc;
2195
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002196 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002197
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002198 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002199 return;
2200
2201 while (len >= L2CAP_CONF_OPT_SIZE) {
2202 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2203
2204 switch (type) {
2205 case L2CAP_CONF_RFC:
2206 if (olen == sizeof(rfc))
2207 memcpy(&rfc, (void *)val, olen);
2208 goto done;
2209 }
2210 }
2211
2212done:
2213 switch (rfc.mode) {
2214 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002215 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2216 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2217 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002218 break;
2219 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002220 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002221 }
2222}
2223
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002224static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2225{
2226 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2227
2228 if (rej->reason != 0x0000)
2229 return 0;
2230
2231 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2232 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002233 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002234
2235 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002236 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002237
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002238 l2cap_conn_start(conn);
2239 }
2240
2241 return 0;
2242}
2243
Linus Torvalds1da177e2005-04-16 15:20:36 -07002244static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2245{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002246 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2247 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002248 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002249 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002250 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002251
2252 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002253 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254
2255 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2256
2257 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002258 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2259 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002260 result = L2CAP_CR_BAD_PSM;
2261 goto sendresp;
2262 }
2263
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002264 parent = pchan->sk;
2265
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002266 bh_lock_sock(parent);
2267
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002268 /* Check if the ACL is secure enough (if not SDP) */
2269 if (psm != cpu_to_le16(0x0001) &&
2270 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002271 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002272 result = L2CAP_CR_SEC_BLOCK;
2273 goto response;
2274 }
2275
Linus Torvalds1da177e2005-04-16 15:20:36 -07002276 result = L2CAP_CR_NO_MEM;
2277
2278 /* Check for backlog size */
2279 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002280 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002281 goto response;
2282 }
2283
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002284 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 if (!sk)
2286 goto response;
2287
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002288 chan = l2cap_chan_create(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002289 if (!chan) {
2290 l2cap_sock_kill(sk);
2291 goto response;
2292 }
2293
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03002294 l2cap_pi(sk)->chan = chan;
2295
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002296 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297
2298 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002299 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2300 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301 sock_set_flag(sk, SOCK_ZAPPED);
2302 l2cap_sock_kill(sk);
2303 goto response;
2304 }
2305
2306 hci_conn_hold(conn->hcon);
2307
2308 l2cap_sock_init(sk, parent);
2309 bacpy(&bt_sk(sk)->src, conn->src);
2310 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002311 chan->psm = psm;
2312 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002313
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002314 bt_accept_enqueue(parent, sk);
2315
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002316 __l2cap_chan_add(conn, chan);
2317
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002318 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002319
2320 l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
2321
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002322 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323
Marcel Holtmann984947d2009-02-06 23:35:19 +01002324 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002325 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002326 if (bt_sk(sk)->defer_setup) {
2327 sk->sk_state = BT_CONNECT2;
2328 result = L2CAP_CR_PEND;
2329 status = L2CAP_CS_AUTHOR_PEND;
2330 parent->sk_data_ready(parent, 0);
2331 } else {
2332 sk->sk_state = BT_CONFIG;
2333 result = L2CAP_CR_SUCCESS;
2334 status = L2CAP_CS_NO_INFO;
2335 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002336 } else {
2337 sk->sk_state = BT_CONNECT2;
2338 result = L2CAP_CR_PEND;
2339 status = L2CAP_CS_AUTHEN_PEND;
2340 }
2341 } else {
2342 sk->sk_state = BT_CONNECT2;
2343 result = L2CAP_CR_PEND;
2344 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345 }
2346
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002347 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002348
2349response:
2350 bh_unlock_sock(parent);
2351
2352sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002353 rsp.scid = cpu_to_le16(scid);
2354 rsp.dcid = cpu_to_le16(dcid);
2355 rsp.result = cpu_to_le16(result);
2356 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002357 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002358
2359 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2360 struct l2cap_info_req info;
2361 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2362
2363 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2364 conn->info_ident = l2cap_get_ident(conn);
2365
2366 mod_timer(&conn->info_timer, jiffies +
2367 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2368
2369 l2cap_send_cmd(conn, conn->info_ident,
2370 L2CAP_INFO_REQ, sizeof(info), &info);
2371 }
2372
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002373 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002374 result == L2CAP_CR_SUCCESS) {
2375 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002376 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002377 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002378 l2cap_build_conf_req(chan, buf), buf);
2379 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002380 }
2381
Linus Torvalds1da177e2005-04-16 15:20:36 -07002382 return 0;
2383}
2384
2385static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2386{
2387 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2388 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002389 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002390 struct sock *sk;
2391 u8 req[128];
2392
2393 scid = __le16_to_cpu(rsp->scid);
2394 dcid = __le16_to_cpu(rsp->dcid);
2395 result = __le16_to_cpu(rsp->result);
2396 status = __le16_to_cpu(rsp->status);
2397
2398 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2399
2400 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002401 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002402 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002403 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002404 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002405 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002406 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002407 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408 }
2409
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002410 sk = chan->sk;
2411
Linus Torvalds1da177e2005-04-16 15:20:36 -07002412 switch (result) {
2413 case L2CAP_CR_SUCCESS:
2414 sk->sk_state = BT_CONFIG;
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002415 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002416 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002417 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002418
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002419 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002420 break;
2421
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002422 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002423
Linus Torvalds1da177e2005-04-16 15:20:36 -07002424 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002425 l2cap_build_conf_req(chan, req), req);
2426 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 break;
2428
2429 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002430 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002431 break;
2432
2433 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002434 /* don't delete l2cap channel if sk is owned by user */
2435 if (sock_owned_by_user(sk)) {
2436 sk->sk_state = BT_DISCONN;
2437 l2cap_sock_clear_timer(sk);
2438 l2cap_sock_set_timer(sk, HZ / 5);
2439 break;
2440 }
2441
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002442 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443 break;
2444 }
2445
2446 bh_unlock_sock(sk);
2447 return 0;
2448}
2449
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002450static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002451{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002452 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2453
Mat Martineau8c462b62010-08-24 15:35:42 -07002454 /* FCS is enabled only in ERTM or streaming mode, if one or both
2455 * sides request it.
2456 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002457 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002458 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002459 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002460 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002461}
2462
Al Viro88219a02007-07-29 00:17:25 -07002463static 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 -07002464{
2465 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2466 u16 dcid, flags;
2467 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002468 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002469 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002470 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471
2472 dcid = __le16_to_cpu(req->dcid);
2473 flags = __le16_to_cpu(req->flags);
2474
2475 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2476
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002477 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002478 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 return -ENOENT;
2480
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002481 sk = chan->sk;
2482
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002483 if (sk->sk_state != BT_CONFIG) {
2484 struct l2cap_cmd_rej rej;
2485
2486 rej.reason = cpu_to_le16(0x0002);
2487 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2488 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002489 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002490 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002491
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002492 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002493 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002494 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002495 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002496 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002497 L2CAP_CONF_REJECT, flags), rsp);
2498 goto unlock;
2499 }
2500
2501 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002502 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2503 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
2505 if (flags & 0x0001) {
2506 /* Incomplete config. Send empty response. */
2507 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002508 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002509 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510 goto unlock;
2511 }
2512
2513 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002514 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002515 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002516 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002517 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002518 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002520 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002521 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002522
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002523 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002524 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002525
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002526 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002527 goto unlock;
2528
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002529 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002530 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002531
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002533
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002534 chan->next_tx_seq = 0;
2535 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002536 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002537 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002538 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002539
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002541 goto unlock;
2542 }
2543
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002544 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002545 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002546 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002547 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002548 l2cap_build_conf_req(chan, buf), buf);
2549 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 }
2551
2552unlock:
2553 bh_unlock_sock(sk);
2554 return 0;
2555}
2556
2557static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2558{
2559 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2560 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002561 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002563 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002564
2565 scid = __le16_to_cpu(rsp->scid);
2566 flags = __le16_to_cpu(rsp->flags);
2567 result = __le16_to_cpu(rsp->result);
2568
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002569 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2570 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002572 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002573 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002574 return 0;
2575
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002576 sk = chan->sk;
2577
Linus Torvalds1da177e2005-04-16 15:20:36 -07002578 switch (result) {
2579 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002580 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 break;
2582
2583 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002584 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002585 char req[64];
2586
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002587 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002588 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002589 goto done;
2590 }
2591
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002592 /* throw out any old stored conf requests */
2593 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002594 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2595 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002596 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002597 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002598 goto done;
2599 }
2600
2601 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2602 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002603 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002604 if (result != L2CAP_CONF_SUCCESS)
2605 goto done;
2606 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607 }
2608
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002609 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002610 sk->sk_err = ECONNRESET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611 l2cap_sock_set_timer(sk, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002612 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 goto done;
2614 }
2615
2616 if (flags & 0x01)
2617 goto done;
2618
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002619 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002620
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002621 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002622 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002623
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002625 chan->next_tx_seq = 0;
2626 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002627 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002628 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002629 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002630
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631 l2cap_chan_ready(sk);
2632 }
2633
2634done:
2635 bh_unlock_sock(sk);
2636 return 0;
2637}
2638
2639static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2640{
2641 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2642 struct l2cap_disconn_rsp rsp;
2643 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002644 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 struct sock *sk;
2646
2647 scid = __le16_to_cpu(req->scid);
2648 dcid = __le16_to_cpu(req->dcid);
2649
2650 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2651
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002652 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002653 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002654 return 0;
2655
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002656 sk = chan->sk;
2657
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002658 rsp.dcid = cpu_to_le16(chan->scid);
2659 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2661
2662 sk->sk_shutdown = SHUTDOWN_MASK;
2663
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002664 /* don't delete l2cap channel if sk is owned by user */
2665 if (sock_owned_by_user(sk)) {
2666 sk->sk_state = BT_DISCONN;
2667 l2cap_sock_clear_timer(sk);
2668 l2cap_sock_set_timer(sk, HZ / 5);
2669 bh_unlock_sock(sk);
2670 return 0;
2671 }
2672
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002673 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002674 bh_unlock_sock(sk);
2675
2676 l2cap_sock_kill(sk);
2677 return 0;
2678}
2679
2680static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2681{
2682 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2683 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002684 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002685 struct sock *sk;
2686
2687 scid = __le16_to_cpu(rsp->scid);
2688 dcid = __le16_to_cpu(rsp->dcid);
2689
2690 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2691
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002692 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002693 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 return 0;
2695
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002696 sk = chan->sk;
2697
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002698 /* don't delete l2cap channel if sk is owned by user */
2699 if (sock_owned_by_user(sk)) {
2700 sk->sk_state = BT_DISCONN;
2701 l2cap_sock_clear_timer(sk);
2702 l2cap_sock_set_timer(sk, HZ / 5);
2703 bh_unlock_sock(sk);
2704 return 0;
2705 }
2706
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002707 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 bh_unlock_sock(sk);
2709
2710 l2cap_sock_kill(sk);
2711 return 0;
2712}
2713
2714static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2715{
2716 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 u16 type;
2718
2719 type = __le16_to_cpu(req->type);
2720
2721 BT_DBG("type 0x%4.4x", type);
2722
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002723 if (type == L2CAP_IT_FEAT_MASK) {
2724 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002725 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002726 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2727 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2728 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002729 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002730 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2731 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002732 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002733 l2cap_send_cmd(conn, cmd->ident,
2734 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002735 } else if (type == L2CAP_IT_FIXED_CHAN) {
2736 u8 buf[12];
2737 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2738 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2739 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2740 memcpy(buf + 4, l2cap_fixed_chan, 8);
2741 l2cap_send_cmd(conn, cmd->ident,
2742 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002743 } else {
2744 struct l2cap_info_rsp rsp;
2745 rsp.type = cpu_to_le16(type);
2746 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2747 l2cap_send_cmd(conn, cmd->ident,
2748 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
2751 return 0;
2752}
2753
2754static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2755{
2756 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2757 u16 type, result;
2758
2759 type = __le16_to_cpu(rsp->type);
2760 result = __le16_to_cpu(rsp->result);
2761
2762 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2763
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002764 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2765 if (cmd->ident != conn->info_ident ||
2766 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2767 return 0;
2768
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002769 del_timer(&conn->info_timer);
2770
Ville Tervoadb08ed2010-08-04 09:43:33 +03002771 if (result != L2CAP_IR_SUCCESS) {
2772 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2773 conn->info_ident = 0;
2774
2775 l2cap_conn_start(conn);
2776
2777 return 0;
2778 }
2779
Marcel Holtmann984947d2009-02-06 23:35:19 +01002780 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002781 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002782
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002783 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002784 struct l2cap_info_req req;
2785 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2786
2787 conn->info_ident = l2cap_get_ident(conn);
2788
2789 l2cap_send_cmd(conn, conn->info_ident,
2790 L2CAP_INFO_REQ, sizeof(req), &req);
2791 } else {
2792 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2793 conn->info_ident = 0;
2794
2795 l2cap_conn_start(conn);
2796 }
2797 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002798 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002799 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002800
2801 l2cap_conn_start(conn);
2802 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002803
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 return 0;
2805}
2806
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002807static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002808 u16 to_multiplier)
2809{
2810 u16 max_latency;
2811
2812 if (min > max || min < 6 || max > 3200)
2813 return -EINVAL;
2814
2815 if (to_multiplier < 10 || to_multiplier > 3200)
2816 return -EINVAL;
2817
2818 if (max >= to_multiplier * 8)
2819 return -EINVAL;
2820
2821 max_latency = (to_multiplier * 8 / max) - 1;
2822 if (latency > 499 || latency > max_latency)
2823 return -EINVAL;
2824
2825 return 0;
2826}
2827
2828static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2829 struct l2cap_cmd_hdr *cmd, u8 *data)
2830{
2831 struct hci_conn *hcon = conn->hcon;
2832 struct l2cap_conn_param_update_req *req;
2833 struct l2cap_conn_param_update_rsp rsp;
2834 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002835 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002836
2837 if (!(hcon->link_mode & HCI_LM_MASTER))
2838 return -EINVAL;
2839
2840 cmd_len = __le16_to_cpu(cmd->len);
2841 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2842 return -EPROTO;
2843
2844 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002845 min = __le16_to_cpu(req->min);
2846 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002847 latency = __le16_to_cpu(req->latency);
2848 to_multiplier = __le16_to_cpu(req->to_multiplier);
2849
2850 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2851 min, max, latency, to_multiplier);
2852
2853 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002854
2855 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2856 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002857 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2858 else
2859 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2860
2861 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2862 sizeof(rsp), &rsp);
2863
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002864 if (!err)
2865 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2866
Claudio Takahaside731152011-02-11 19:28:55 -02002867 return 0;
2868}
2869
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002870static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2871 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2872{
2873 int err = 0;
2874
2875 switch (cmd->code) {
2876 case L2CAP_COMMAND_REJ:
2877 l2cap_command_rej(conn, cmd, data);
2878 break;
2879
2880 case L2CAP_CONN_REQ:
2881 err = l2cap_connect_req(conn, cmd, data);
2882 break;
2883
2884 case L2CAP_CONN_RSP:
2885 err = l2cap_connect_rsp(conn, cmd, data);
2886 break;
2887
2888 case L2CAP_CONF_REQ:
2889 err = l2cap_config_req(conn, cmd, cmd_len, data);
2890 break;
2891
2892 case L2CAP_CONF_RSP:
2893 err = l2cap_config_rsp(conn, cmd, data);
2894 break;
2895
2896 case L2CAP_DISCONN_REQ:
2897 err = l2cap_disconnect_req(conn, cmd, data);
2898 break;
2899
2900 case L2CAP_DISCONN_RSP:
2901 err = l2cap_disconnect_rsp(conn, cmd, data);
2902 break;
2903
2904 case L2CAP_ECHO_REQ:
2905 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2906 break;
2907
2908 case L2CAP_ECHO_RSP:
2909 break;
2910
2911 case L2CAP_INFO_REQ:
2912 err = l2cap_information_req(conn, cmd, data);
2913 break;
2914
2915 case L2CAP_INFO_RSP:
2916 err = l2cap_information_rsp(conn, cmd, data);
2917 break;
2918
2919 default:
2920 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2921 err = -EINVAL;
2922 break;
2923 }
2924
2925 return err;
2926}
2927
2928static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2929 struct l2cap_cmd_hdr *cmd, u8 *data)
2930{
2931 switch (cmd->code) {
2932 case L2CAP_COMMAND_REJ:
2933 return 0;
2934
2935 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002936 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002937
2938 case L2CAP_CONN_PARAM_UPDATE_RSP:
2939 return 0;
2940
2941 default:
2942 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
2943 return -EINVAL;
2944 }
2945}
2946
2947static inline void l2cap_sig_channel(struct l2cap_conn *conn,
2948 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002949{
2950 u8 *data = skb->data;
2951 int len = skb->len;
2952 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002953 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954
2955 l2cap_raw_recv(conn, skb);
2956
2957 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07002958 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002959 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
2960 data += L2CAP_CMD_HDR_SIZE;
2961 len -= L2CAP_CMD_HDR_SIZE;
2962
Al Viro88219a02007-07-29 00:17:25 -07002963 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002964
Al Viro88219a02007-07-29 00:17:25 -07002965 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 -07002966
Al Viro88219a02007-07-29 00:17:25 -07002967 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002968 BT_DBG("corrupted command");
2969 break;
2970 }
2971
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002972 if (conn->hcon->type == LE_LINK)
2973 err = l2cap_le_sig_cmd(conn, &cmd, data);
2974 else
2975 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976
2977 if (err) {
2978 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03002979
2980 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002981
2982 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002983 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
2985 }
2986
Al Viro88219a02007-07-29 00:17:25 -07002987 data += cmd_len;
2988 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989 }
2990
2991 kfree_skb(skb);
2992}
2993
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002994static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002995{
2996 u16 our_fcs, rcv_fcs;
2997 int hdr_size = L2CAP_HDR_SIZE + 2;
2998
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002999 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003000 skb_trim(skb, skb->len - 2);
3001 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3002 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3003
3004 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003005 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003006 }
3007 return 0;
3008}
3009
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003010static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003011{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003012 u16 control = 0;
3013
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003014 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003015
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003016 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003017
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003018 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03003019 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003020 l2cap_send_sframe(chan, control);
3021 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003022 }
3023
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003024 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3025 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003026
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003027 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003028
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003029 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003030 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003031 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003032 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003033 }
3034}
3035
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003036static 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 -03003037{
3038 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003039 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003040
3041 bt_cb(skb)->tx_seq = tx_seq;
3042 bt_cb(skb)->sar = sar;
3043
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003044 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003045 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003046 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003047 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003048 }
3049
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003050 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003051 if (tx_seq_offset < 0)
3052 tx_seq_offset += 64;
3053
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003054 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003055 if (bt_cb(next_skb)->tx_seq == tx_seq)
3056 return -EINVAL;
3057
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003058 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003059 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003060 if (next_tx_seq_offset < 0)
3061 next_tx_seq_offset += 64;
3062
3063 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003064 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003065 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003066 }
3067
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003068 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003069 break;
3070
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003071 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003072
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003073 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003074
3075 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003076}
3077
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003078static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003079{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003080 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003081 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003082
3083 switch (control & L2CAP_CTRL_SAR) {
3084 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003085 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003086 goto drop;
3087
Ruiyi Zhang224f8af2011-05-13 13:07:52 +08003088 return sock_queue_rcv_skb(chan->sk, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003089
3090 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003091 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003092 goto drop;
3093
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003094 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003095
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003096 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003097 goto disconnect;
3098
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003099 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3100 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003101 return -ENOMEM;
3102
3103 /* pull sdu_len bytes only after alloc, because of Local Busy
3104 * condition we have to be sure that this will be executed
3105 * only once, i.e., when alloc does not fail */
3106 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003107
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003108 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003109
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003110 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003111 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003112 break;
3113
3114 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003115 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003116 goto disconnect;
3117
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003118 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003119 goto disconnect;
3120
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003121 chan->partial_sdu_len += skb->len;
3122 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003123 goto drop;
3124
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003125 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003126
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003127 break;
3128
3129 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003130 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003131 goto disconnect;
3132
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003133 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003134 goto disconnect;
3135
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003136 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003137 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003138
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003139 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003140 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003141
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003142 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003143 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003144
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003145 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003146 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003147
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003148 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003149 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003150 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003151 return -ENOMEM;
3152 }
3153
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003154 err = sock_queue_rcv_skb(chan->sk, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003155 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003156 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003157 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003158 return err;
3159 }
3160
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003161 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3162 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003163
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003164 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003165 break;
3166 }
3167
3168 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003169 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003170
3171drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003172 kfree_skb(chan->sdu);
3173 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003174
3175disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003176 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003177 kfree_skb(skb);
3178 return 0;
3179}
3180
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003181static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003182{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003183 struct sk_buff *skb;
3184 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003185 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003186
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003187 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003188 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003189 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003190 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003191 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003192 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003193 }
3194
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003195 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003196 }
3197
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003198 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003199 goto done;
3200
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003201 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003202 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003203 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003204 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003205
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003206 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003207 __mod_monitor_timer();
3208
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003209 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003210
3211done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003212 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3213 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003214
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003215 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003216
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003217 return 0;
3218}
3219
3220static void l2cap_busy_work(struct work_struct *work)
3221{
3222 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003223 struct l2cap_chan *chan =
3224 container_of(work, struct l2cap_chan, busy_work);
3225 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003226 int n_tries = 0, timeo = HZ/5, err;
3227 struct sk_buff *skb;
3228
3229 lock_sock(sk);
3230
3231 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003232 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003233 set_current_state(TASK_INTERRUPTIBLE);
3234
3235 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3236 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003237 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003238 break;
3239 }
3240
3241 if (!timeo)
3242 timeo = HZ/5;
3243
3244 if (signal_pending(current)) {
3245 err = sock_intr_errno(timeo);
3246 break;
3247 }
3248
3249 release_sock(sk);
3250 timeo = schedule_timeout(timeo);
3251 lock_sock(sk);
3252
3253 err = sock_error(sk);
3254 if (err)
3255 break;
3256
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003257 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003258 break;
3259 }
3260
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003261 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003262 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003263
3264 release_sock(sk);
3265}
3266
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003267static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003268{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003269 int sctrl, err;
3270
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003271 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003272 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003273 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003274 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003275
3276
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003277 }
3278
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003279 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003280 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003281 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003282 return err;
3283 }
3284
3285 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003286 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003287
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003288 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003289 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003290 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003291
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003292 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003293 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003294 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003295
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003296 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003297
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003298 del_timer(&chan->ack_timer);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003299
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003300 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003301
3302 return err;
3303}
3304
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003305static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003306{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003307 struct sk_buff *_skb;
3308 int err = -EINVAL;
3309
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003310 /*
3311 * TODO: We have to notify the userland if some data is lost with the
3312 * Streaming Mode.
3313 */
3314
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003315 switch (control & L2CAP_CTRL_SAR) {
3316 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003317 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003318 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003319 break;
3320 }
3321
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003322 err = sock_queue_rcv_skb(chan->sk, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003323 if (!err)
3324 return 0;
3325
3326 break;
3327
3328 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003329 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003330 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003331 break;
3332 }
3333
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003334 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003335 skb_pull(skb, 2);
3336
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003337 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003338 err = -EMSGSIZE;
3339 break;
3340 }
3341
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003342 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3343 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003344 err = -ENOMEM;
3345 break;
3346 }
3347
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003348 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003349
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003350 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003351 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003352 err = 0;
3353 break;
3354
3355 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003356 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003357 break;
3358
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003359 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003360
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003361 chan->partial_sdu_len += skb->len;
3362 if (chan->partial_sdu_len > chan->sdu_len)
3363 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003364 else
3365 err = 0;
3366
3367 break;
3368
3369 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003370 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003371 break;
3372
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003373 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003374
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003375 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003376 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003377
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003378 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003379 goto drop;
3380
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003381 if (chan->partial_sdu_len == chan->sdu_len) {
3382 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003383 err = sock_queue_rcv_skb(chan->sk, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003384 if (err < 0)
3385 kfree_skb(_skb);
3386 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003387 err = 0;
3388
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003389drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003390 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003391 break;
3392 }
3393
3394 kfree_skb(skb);
3395 return err;
3396}
3397
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003398static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003399{
3400 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003401 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003402
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003403 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003404 if (bt_cb(skb)->tx_seq != tx_seq)
3405 break;
3406
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003407 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003408 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003409 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003410 chan->buffer_seq_srej =
3411 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003412 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003413 }
3414}
3415
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003416static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003417{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003418 struct srej_list *l, *tmp;
3419 u16 control;
3420
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003421 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003422 if (l->tx_seq == tx_seq) {
3423 list_del(&l->list);
3424 kfree(l);
3425 return;
3426 }
3427 control = L2CAP_SUPER_SELECT_REJECT;
3428 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003429 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003430 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003431 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003432 }
3433}
3434
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003435static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003436{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003437 struct srej_list *new;
3438 u16 control;
3439
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003440 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003441 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003442 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003443 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003444
3445 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003446 new->tx_seq = chan->expected_tx_seq;
3447 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003448 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003449 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003450 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003451}
3452
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003453static 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 -03003454{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003455 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003456 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003457 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003458 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003459 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003460 int err = 0;
3461
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003462 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3463 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003464
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003465 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003466 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003467 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003468 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003469 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003470 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003471 }
3472
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003473 chan->expected_ack_seq = req_seq;
3474 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003475
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003476 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003477 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003478
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003479 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003480 if (tx_seq_offset < 0)
3481 tx_seq_offset += 64;
3482
3483 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003484 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003485 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003486 goto drop;
3487 }
3488
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003489 if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003490 goto drop;
3491
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003492 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003493 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003494
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003495 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003496 struct srej_list, list);
3497 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003498 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003499 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003500
3501 list_del(&first->list);
3502 kfree(first);
3503
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003504 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003505 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003506 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3507 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003508 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003509 }
3510 } else {
3511 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003512
3513 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003514 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003515 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003516
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003517 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003518 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003519 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003520 return 0;
3521 }
3522 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003523 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003524 }
3525 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003526 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003527 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003528 if (expected_tx_seq_offset < 0)
3529 expected_tx_seq_offset += 64;
3530
3531 /* duplicated tx_seq */
3532 if (tx_seq_offset < expected_tx_seq_offset)
3533 goto drop;
3534
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003535 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003536
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003537 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003538
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003539 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003540 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003541
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003542 __skb_queue_head_init(&chan->srej_q);
3543 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003544 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003545
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003546 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003547
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003548 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003549
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003550 del_timer(&chan->ack_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003551 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003552 return 0;
3553
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003554expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003555 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003556
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003557 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003558 bt_cb(skb)->tx_seq = tx_seq;
3559 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003560 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003561 return 0;
3562 }
3563
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003564 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003565 if (err < 0)
3566 return 0;
3567
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003568 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003569 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3570 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003571 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003572 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003573 }
3574
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003575 __mod_ack_timer();
3576
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003577 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3578 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003579 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003580
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003581 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003582
3583drop:
3584 kfree_skb(skb);
3585 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003586}
3587
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003588static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003589{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003590 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003591 rx_control);
3592
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003593 chan->expected_ack_seq = __get_reqseq(rx_control);
3594 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003595
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003596 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003597 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3598 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3599 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003600 (chan->unacked_frames > 0))
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003601 __mod_retrans_timer();
3602
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003603 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3604 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003605 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003606 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003607 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003608
3609 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003610 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003611
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003612 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3613 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003614 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003615 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003616
3617 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003618 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003619 (chan->unacked_frames > 0))
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003620 __mod_retrans_timer();
3621
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003622 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3623 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3624 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003625 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003626 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003627 }
3628}
3629
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003630static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003631{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003632 u8 tx_seq = __get_reqseq(rx_control);
3633
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003634 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003635
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003636 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003637
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003638 chan->expected_ack_seq = tx_seq;
3639 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003640
3641 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003642 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3643 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003644 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003645 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003646 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003647 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003648
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003649 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3650 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003651 }
3652}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003653static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003654{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003655 u8 tx_seq = __get_reqseq(rx_control);
3656
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003657 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003658
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003659 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003660
3661 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003662 chan->expected_ack_seq = tx_seq;
3663 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003664
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003665 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3666 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003667
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003668 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003669
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003670 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003671 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003672 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003673 }
3674 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003675 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003676 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003677 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003678 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003679 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003680 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003681 l2cap_retransmit_one_frame(chan, tx_seq);
3682 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003683 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003684 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003685 }
3686 }
3687}
3688
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003689static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003690{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003691 u8 tx_seq = __get_reqseq(rx_control);
3692
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003693 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003694
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003695 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003696 chan->expected_ack_seq = tx_seq;
3697 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003698
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003699 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003700 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003701
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003702 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003703 del_timer(&chan->retrans_timer);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003704 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003705 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003706 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003707 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003708
3709 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003710 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003711 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003712 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003713}
3714
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003715static 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 -03003716{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003717 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003718
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003719 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003720 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003721 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003722 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003723 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003724 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003725 }
3726
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003727 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3728 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003729 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003730 break;
3731
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003732 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003733 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003734 break;
3735
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003736 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003737 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003738 break;
3739
3740 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003741 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003742 break;
3743 }
3744
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003745 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003746 return 0;
3747}
3748
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003749static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3750{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003751 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003752 u16 control;
3753 u8 req_seq;
3754 int len, next_tx_seq_offset, req_seq_offset;
3755
3756 control = get_unaligned_le16(skb->data);
3757 skb_pull(skb, 2);
3758 len = skb->len;
3759
3760 /*
3761 * We can just drop the corrupted I-frame here.
3762 * Receiver will miss it and start proper recovery
3763 * procedures and ask retransmission.
3764 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003765 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003766 goto drop;
3767
3768 if (__is_sar_start(control) && __is_iframe(control))
3769 len -= 2;
3770
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003771 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003772 len -= 2;
3773
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003774 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003775 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003776 goto drop;
3777 }
3778
3779 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003780 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003781 if (req_seq_offset < 0)
3782 req_seq_offset += 64;
3783
3784 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003785 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003786 if (next_tx_seq_offset < 0)
3787 next_tx_seq_offset += 64;
3788
3789 /* check for invalid req-seq */
3790 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003791 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003792 goto drop;
3793 }
3794
3795 if (__is_iframe(control)) {
3796 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003797 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003798 goto drop;
3799 }
3800
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003801 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003802 } else {
3803 if (len != 0) {
3804 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003805 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003806 goto drop;
3807 }
3808
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003809 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003810 }
3811
3812 return 0;
3813
3814drop:
3815 kfree_skb(skb);
3816 return 0;
3817}
3818
Linus Torvalds1da177e2005-04-16 15:20:36 -07003819static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3820{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003821 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003822 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003823 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003824 u8 tx_seq;
3825 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003827 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003828 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003829 BT_DBG("unknown cid 0x%4.4x", cid);
3830 goto drop;
3831 }
3832
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003833 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003834
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003835 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836
3837 if (sk->sk_state != BT_CONNECTED)
3838 goto drop;
3839
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003840 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003841 case L2CAP_MODE_BASIC:
3842 /* If socket recv buffers overflows we drop data here
3843 * which is *bad* because L2CAP has to be reliable.
3844 * But we don't have any other choice. L2CAP doesn't
3845 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003847 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003848 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003849
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003850 if (!sock_queue_rcv_skb(sk, skb))
3851 goto done;
3852 break;
3853
3854 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003855 if (!sock_owned_by_user(sk)) {
3856 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003857 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003858 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003859 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003860 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003861
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003862 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003863
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003864 case L2CAP_MODE_STREAMING:
3865 control = get_unaligned_le16(skb->data);
3866 skb_pull(skb, 2);
3867 len = skb->len;
3868
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003869 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003870 goto drop;
3871
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003872 if (__is_sar_start(control))
3873 len -= 2;
3874
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003875 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003876 len -= 2;
3877
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003878 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003879 goto drop;
3880
3881 tx_seq = __get_txseq(control);
3882
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003883 if (chan->expected_tx_seq == tx_seq)
3884 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003885 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003886 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003887
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003888 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003889
3890 goto done;
3891
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003892 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003893 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003894 break;
3895 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003896
3897drop:
3898 kfree_skb(skb);
3899
3900done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003901 if (sk)
3902 bh_unlock_sock(sk);
3903
Linus Torvalds1da177e2005-04-16 15:20:36 -07003904 return 0;
3905}
3906
Al Viro8e036fc2007-07-29 00:16:36 -07003907static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003908{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003909 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003910 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003911
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003912 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3913 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003914 goto drop;
3915
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003916 sk = chan->sk;
3917
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003918 bh_lock_sock(sk);
3919
Linus Torvalds1da177e2005-04-16 15:20:36 -07003920 BT_DBG("sk %p, len %d", sk, skb->len);
3921
3922 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3923 goto drop;
3924
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003925 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003926 goto drop;
3927
3928 if (!sock_queue_rcv_skb(sk, skb))
3929 goto done;
3930
3931drop:
3932 kfree_skb(skb);
3933
3934done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003935 if (sk)
3936 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003937 return 0;
3938}
3939
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003940static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3941{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003942 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003943 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003944
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003945 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
3946 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003947 goto drop;
3948
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003949 sk = chan->sk;
3950
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003951 bh_lock_sock(sk);
3952
3953 BT_DBG("sk %p, len %d", sk, skb->len);
3954
3955 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3956 goto drop;
3957
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003958 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003959 goto drop;
3960
3961 if (!sock_queue_rcv_skb(sk, skb))
3962 goto done;
3963
3964drop:
3965 kfree_skb(skb);
3966
3967done:
3968 if (sk)
3969 bh_unlock_sock(sk);
3970 return 0;
3971}
3972
Linus Torvalds1da177e2005-04-16 15:20:36 -07003973static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
3974{
3975 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07003976 u16 cid, len;
3977 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978
3979 skb_pull(skb, L2CAP_HDR_SIZE);
3980 cid = __le16_to_cpu(lh->cid);
3981 len = __le16_to_cpu(lh->len);
3982
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003983 if (len != skb->len) {
3984 kfree_skb(skb);
3985 return;
3986 }
3987
Linus Torvalds1da177e2005-04-16 15:20:36 -07003988 BT_DBG("len %d, cid 0x%4.4x", len, cid);
3989
3990 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003991 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03003992 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07003993 l2cap_sig_channel(conn, skb);
3994 break;
3995
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03003996 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003997 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003998 skb_pull(skb, 2);
3999 l2cap_conless_channel(conn, psm, skb);
4000 break;
4001
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004002 case L2CAP_CID_LE_DATA:
4003 l2cap_att_channel(conn, cid, skb);
4004 break;
4005
Linus Torvalds1da177e2005-04-16 15:20:36 -07004006 default:
4007 l2cap_data_channel(conn, cid, skb);
4008 break;
4009 }
4010}
4011
4012/* ---- L2CAP interface with lower layer (HCI) ---- */
4013
4014static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4015{
4016 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004017 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
4019 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004020 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004021
4022 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4023
4024 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004025 read_lock(&chan_list_lock);
4026 list_for_each_entry(c, &chan_list, global_l) {
4027 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004028
Linus Torvalds1da177e2005-04-16 15:20:36 -07004029 if (sk->sk_state != BT_LISTEN)
4030 continue;
4031
4032 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004033 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004034 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004035 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004036 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004037 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4038 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004039 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004040 lm2 |= HCI_LM_MASTER;
4041 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004043 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004044
4045 return exact ? lm1 : lm2;
4046}
4047
4048static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4049{
Marcel Holtmann01394182006-07-03 10:02:46 +02004050 struct l2cap_conn *conn;
4051
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4053
Ville Tervoacd7d372011-02-10 22:38:49 -03004054 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004055 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004056
4057 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 conn = l2cap_conn_add(hcon, status);
4059 if (conn)
4060 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004061 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004062 l2cap_conn_del(hcon, bt_err(status));
4063
4064 return 0;
4065}
4066
Marcel Holtmann2950f212009-02-12 14:02:50 +01004067static int l2cap_disconn_ind(struct hci_conn *hcon)
4068{
4069 struct l2cap_conn *conn = hcon->l2cap_data;
4070
4071 BT_DBG("hcon %p", hcon);
4072
4073 if (hcon->type != ACL_LINK || !conn)
4074 return 0x13;
4075
4076 return conn->disc_reason;
4077}
4078
4079static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004080{
4081 BT_DBG("hcon %p reason %d", hcon, reason);
4082
Ville Tervoacd7d372011-02-10 22:38:49 -03004083 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004084 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004085
4086 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004087
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 return 0;
4089}
4090
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004091static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004092{
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004093 struct sock *sk = chan->sk;
4094
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004095 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004096 return;
4097
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004098 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004099 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004100 l2cap_sock_clear_timer(sk);
4101 l2cap_sock_set_timer(sk, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004102 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -03004103 __l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004104 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004105 if (chan->sec_level == BT_SECURITY_MEDIUM)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004106 l2cap_sock_clear_timer(sk);
4107 }
4108}
4109
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004110static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004111{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004112 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004113 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114
Marcel Holtmann01394182006-07-03 10:02:46 +02004115 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004117
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 BT_DBG("conn %p", conn);
4119
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004120 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004121
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004122 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004123 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004124
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 bh_lock_sock(sk);
4126
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004127 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004128 bh_unlock_sock(sk);
4129 continue;
4130 }
4131
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004132 if (!status && (sk->sk_state == BT_CONNECTED ||
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004133 sk->sk_state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004134 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004135 bh_unlock_sock(sk);
4136 continue;
4137 }
4138
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004139 if (sk->sk_state == BT_CONNECT) {
4140 if (!status) {
4141 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004142 req.scid = cpu_to_le16(chan->scid);
4143 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004144
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004145 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004146 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004147
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004148 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004149 L2CAP_CONN_REQ, sizeof(req), &req);
4150 } else {
4151 l2cap_sock_clear_timer(sk);
4152 l2cap_sock_set_timer(sk, HZ / 10);
4153 }
4154 } else if (sk->sk_state == BT_CONNECT2) {
4155 struct l2cap_conn_rsp rsp;
4156 __u16 result;
4157
4158 if (!status) {
4159 sk->sk_state = BT_CONFIG;
4160 result = L2CAP_CR_SUCCESS;
4161 } else {
4162 sk->sk_state = BT_DISCONN;
4163 l2cap_sock_set_timer(sk, HZ / 10);
4164 result = L2CAP_CR_SEC_BLOCK;
4165 }
4166
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004167 rsp.scid = cpu_to_le16(chan->dcid);
4168 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004169 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004170 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004171 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4172 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004173 }
4174
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 bh_unlock_sock(sk);
4176 }
4177
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004178 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004179
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 return 0;
4181}
4182
4183static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4184{
4185 struct l2cap_conn *conn = hcon->l2cap_data;
4186
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004187 if (!conn)
4188 conn = l2cap_conn_add(hcon, 0);
4189
4190 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191 goto drop;
4192
4193 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4194
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004195 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004197 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004198 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 int len;
4200
4201 if (conn->rx_len) {
4202 BT_ERR("Unexpected start frame (len %d)", skb->len);
4203 kfree_skb(conn->rx_skb);
4204 conn->rx_skb = NULL;
4205 conn->rx_len = 0;
4206 l2cap_conn_unreliable(conn, ECOMM);
4207 }
4208
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004209 /* Start fragment always begin with Basic L2CAP header */
4210 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 BT_ERR("Frame is too short (len %d)", skb->len);
4212 l2cap_conn_unreliable(conn, ECOMM);
4213 goto drop;
4214 }
4215
4216 hdr = (struct l2cap_hdr *) skb->data;
4217 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004218 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219
4220 if (len == skb->len) {
4221 /* Complete frame received */
4222 l2cap_recv_frame(conn, skb);
4223 return 0;
4224 }
4225
4226 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4227
4228 if (skb->len > len) {
4229 BT_ERR("Frame is too long (len %d, expected len %d)",
4230 skb->len, len);
4231 l2cap_conn_unreliable(conn, ECOMM);
4232 goto drop;
4233 }
4234
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004235 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004236
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004237 if (chan && chan->sk) {
4238 struct sock *sk = chan->sk;
4239
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004240 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004241 BT_ERR("Frame exceeding recv MTU (len %d, "
4242 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004243 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004244 bh_unlock_sock(sk);
4245 l2cap_conn_unreliable(conn, ECOMM);
4246 goto drop;
4247 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004248 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004249 }
4250
Linus Torvalds1da177e2005-04-16 15:20:36 -07004251 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004252 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4253 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004254 goto drop;
4255
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004256 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004257 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004258 conn->rx_len = len - skb->len;
4259 } else {
4260 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4261
4262 if (!conn->rx_len) {
4263 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4264 l2cap_conn_unreliable(conn, ECOMM);
4265 goto drop;
4266 }
4267
4268 if (skb->len > conn->rx_len) {
4269 BT_ERR("Fragment is too long (len %d, expected %d)",
4270 skb->len, conn->rx_len);
4271 kfree_skb(conn->rx_skb);
4272 conn->rx_skb = NULL;
4273 conn->rx_len = 0;
4274 l2cap_conn_unreliable(conn, ECOMM);
4275 goto drop;
4276 }
4277
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004278 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004279 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 conn->rx_len -= skb->len;
4281
4282 if (!conn->rx_len) {
4283 /* Complete frame received */
4284 l2cap_recv_frame(conn, conn->rx_skb);
4285 conn->rx_skb = NULL;
4286 }
4287 }
4288
4289drop:
4290 kfree_skb(skb);
4291 return 0;
4292}
4293
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004294static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004296 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004297
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004298 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004300 list_for_each_entry(c, &chan_list, global_l) {
4301 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004303 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 +01004304 batostr(&bt_sk(sk)->src),
4305 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004306 sk->sk_state, __le16_to_cpu(c->psm),
4307 c->scid, c->dcid, c->imtu, c->omtu,
4308 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004309 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004310
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004311 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004312
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004313 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314}
4315
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004316static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4317{
4318 return single_open(file, l2cap_debugfs_show, inode->i_private);
4319}
4320
4321static const struct file_operations l2cap_debugfs_fops = {
4322 .open = l2cap_debugfs_open,
4323 .read = seq_read,
4324 .llseek = seq_lseek,
4325 .release = single_release,
4326};
4327
4328static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330static struct hci_proto l2cap_hci_proto = {
4331 .name = "L2CAP",
4332 .id = HCI_PROTO_L2CAP,
4333 .connect_ind = l2cap_connect_ind,
4334 .connect_cfm = l2cap_connect_cfm,
4335 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004336 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004337 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338 .recv_acldata = l2cap_recv_acldata
4339};
4340
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004341int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342{
4343 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004344
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004345 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004346 if (err < 0)
4347 return err;
4348
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004349 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004350 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004351 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352 goto error;
4353 }
4354
4355 err = hci_register_proto(&l2cap_hci_proto);
4356 if (err < 0) {
4357 BT_ERR("L2CAP protocol registration failed");
4358 bt_sock_unregister(BTPROTO_L2CAP);
4359 goto error;
4360 }
4361
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004362 if (bt_debugfs) {
4363 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4364 bt_debugfs, NULL, &l2cap_debugfs_fops);
4365 if (!l2cap_debugfs)
4366 BT_ERR("Failed to create L2CAP debug file");
4367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369 return 0;
4370
4371error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004372 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004373 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004374 return err;
4375}
4376
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004377void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004378{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004379 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004381 flush_workqueue(_busy_wq);
4382 destroy_workqueue(_busy_wq);
4383
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4385 BT_ERR("L2CAP protocol unregistration failed");
4386
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004387 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388}
4389
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004390module_param(disable_ertm, bool, 0644);
4391MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");