blob: 3a121ac6b31000d7048c92e2c9e5aac0430c6983 [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
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
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. Padovanab078012011-05-02 18:25:01 -0300211static void l2cap_chan_set_timer(struct l2cap_chan *chan, long timeout)
212{
213 BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->sk->sk_state,
214 timeout);
215 if (!mod_timer(&chan->chan_timer, jiffies + timeout))
216 sock_hold(chan->sk);
217}
218
Gustavo F. Padovan500698d2011-05-04 19:35:27 -0300219static void l2cap_chan_clear_timer(struct l2cap_chan *chan)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300220{
221 BT_DBG("chan %p state %d", chan, chan->sk->sk_state);
222
223 if (timer_pending(&chan->chan_timer) && del_timer(&chan->chan_timer))
224 __sock_put(chan->sk);
225}
226
227static void l2cap_chan_timeout(unsigned long arg)
228{
229 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
230 struct sock *sk = chan->sk;
231 int reason;
232
233 BT_DBG("chan %p state %d", chan, sk->sk_state);
234
235 bh_lock_sock(sk);
236
237 if (sock_owned_by_user(sk)) {
238 /* sk is owned by user. Try again later */
239 l2cap_chan_set_timer(chan, HZ / 5);
240 bh_unlock_sock(sk);
241 sock_put(sk);
242 return;
243 }
244
245 if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
246 reason = ECONNREFUSED;
247 else if (sk->sk_state == BT_CONNECT &&
248 chan->sec_level != BT_SECURITY_SDP)
249 reason = ECONNREFUSED;
250 else
251 reason = ETIMEDOUT;
252
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300253 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300254
255 bh_unlock_sock(sk);
256
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300257 chan->ops->close(chan->data);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258 sock_put(sk);
259}
260
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300261struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200262{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300263 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200264
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300265 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
266 if (!chan)
267 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200268
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300269 chan->sk = sk;
270
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300271 write_lock_bh(&chan_list_lock);
272 list_add(&chan->global_l, &chan_list);
273 write_unlock_bh(&chan_list_lock);
274
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300275 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
276
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300277 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200278}
279
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300280void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300281{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300282 write_lock_bh(&chan_list_lock);
283 list_del(&chan->global_l);
284 write_unlock_bh(&chan_list_lock);
285
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300286 kfree(chan);
287}
288
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300289static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200290{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300291 struct sock *sk = chan->sk;
Marcel Holtmann01394182006-07-03 10:02:46 +0200292
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300293 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300294 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200295
Marcel Holtmann2950f212009-02-12 14:02:50 +0100296 conn->disc_reason = 0x13;
297
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300298 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200299
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300300 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300301 if (conn->hcon->type == LE_LINK) {
302 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300303 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300304 chan->scid = L2CAP_CID_LE_DATA;
305 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300306 } else {
307 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300308 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300309 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300310 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300311 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200312 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300313 chan->scid = L2CAP_CID_CONN_LESS;
314 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300315 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200316 } else {
317 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300318 chan->scid = L2CAP_CID_SIGNALING;
319 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300320 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200321 }
322
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300323 sock_hold(sk);
324
325 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200326}
327
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900328/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200329 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300330static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200331{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300332 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300333 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200334 struct sock *parent = bt_sk(sk)->parent;
335
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300336 l2cap_chan_clear_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200337
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300338 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200339
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900340 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300341 /* Delete from channel list */
342 write_lock_bh(&conn->chan_lock);
343 list_del(&chan->list);
344 write_unlock_bh(&conn->chan_lock);
345 __sock_put(sk);
346
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300347 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200348 hci_conn_put(conn->hcon);
349 }
350
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200351 sk->sk_state = BT_CLOSED;
Marcel Holtmann01394182006-07-03 10:02:46 +0200352 sock_set_flag(sk, SOCK_ZAPPED);
353
354 if (err)
355 sk->sk_err = err;
356
357 if (parent) {
358 bt_accept_unlink(sk);
359 parent->sk_data_ready(parent, 0);
360 } else
361 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300362
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300363 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
364 chan->conf_state & L2CAP_CONF_INPUT_DONE))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300365 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300366
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300367 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300368
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300369 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300370 struct srej_list *l, *tmp;
371
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300372 del_timer(&chan->retrans_timer);
373 del_timer(&chan->monitor_timer);
374 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300375
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300376 skb_queue_purge(&chan->srej_q);
377 skb_queue_purge(&chan->busy_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300378
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300379 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300380 list_del(&l->list);
381 kfree(l);
382 }
383 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200384}
385
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300386static void l2cap_chan_cleanup_listen(struct sock *parent)
387{
388 struct sock *sk;
389
390 BT_DBG("parent %p", parent);
391
392 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300393 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300394 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
395 l2cap_chan_clear_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300396 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300397 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300398 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300399 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300400 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300401
402 parent->sk_state = BT_CLOSED;
403 sock_set_flag(parent, SOCK_ZAPPED);
404}
405
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300406void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300407{
408 struct l2cap_conn *conn = chan->conn;
409 struct sock *sk = chan->sk;
410
411 BT_DBG("chan %p state %d socket %p", chan, sk->sk_state, sk->sk_socket);
412
413 switch (sk->sk_state) {
414 case BT_LISTEN:
415 l2cap_chan_cleanup_listen(sk);
416 break;
417
418 case BT_CONNECTED:
419 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300420 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300421 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovan500698d2011-05-04 19:35:27 -0300422 l2cap_chan_clear_timer(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300423 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300424 l2cap_send_disconn_req(conn, chan, reason);
425 } else
426 l2cap_chan_del(chan, reason);
427 break;
428
429 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300430 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300431 conn->hcon->type == ACL_LINK) {
432 struct l2cap_conn_rsp rsp;
433 __u16 result;
434
435 if (bt_sk(sk)->defer_setup)
436 result = L2CAP_CR_SEC_BLOCK;
437 else
438 result = L2CAP_CR_BAD_PSM;
Mat Martineaud8d69c52011-06-03 16:21:07 -0700439 sk->sk_state = BT_DISCONN;
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300440
441 rsp.scid = cpu_to_le16(chan->dcid);
442 rsp.dcid = cpu_to_le16(chan->scid);
443 rsp.result = cpu_to_le16(result);
444 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
445 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
446 sizeof(rsp), &rsp);
447 }
448
449 l2cap_chan_del(chan, reason);
450 break;
451
452 case BT_CONNECT:
453 case BT_DISCONN:
454 l2cap_chan_del(chan, reason);
455 break;
456
457 default:
458 sock_set_flag(sk, SOCK_ZAPPED);
459 break;
460 }
461}
462
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300463static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530464{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300465 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300466 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530467 case BT_SECURITY_HIGH:
468 return HCI_AT_DEDICATED_BONDING_MITM;
469 case BT_SECURITY_MEDIUM:
470 return HCI_AT_DEDICATED_BONDING;
471 default:
472 return HCI_AT_NO_BONDING;
473 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300474 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300475 if (chan->sec_level == BT_SECURITY_LOW)
476 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530477
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300478 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530479 return HCI_AT_NO_BONDING_MITM;
480 else
481 return HCI_AT_NO_BONDING;
482 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300483 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530484 case BT_SECURITY_HIGH:
485 return HCI_AT_GENERAL_BONDING_MITM;
486 case BT_SECURITY_MEDIUM:
487 return HCI_AT_GENERAL_BONDING;
488 default:
489 return HCI_AT_NO_BONDING;
490 }
491 }
492}
493
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200494/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300495static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200496{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300497 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100498 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200499
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300500 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100501
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300502 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200503}
504
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200505static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200506{
507 u8 id;
508
509 /* Get next available identificator.
510 * 1 - 128 are used by kernel.
511 * 129 - 199 are reserved.
512 * 200 - 254 are used by utilities like l2ping, etc.
513 */
514
515 spin_lock_bh(&conn->lock);
516
517 if (++conn->tx_ident > 128)
518 conn->tx_ident = 1;
519
520 id = conn->tx_ident;
521
522 spin_unlock_bh(&conn->lock);
523
524 return id;
525}
526
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300527static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200528{
529 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200530 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200531
532 BT_DBG("code 0x%2.2x", code);
533
534 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300535 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200536
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200537 if (lmp_no_flush_capable(conn->hcon->hdev))
538 flags = ACL_START_NO_FLUSH;
539 else
540 flags = ACL_START;
541
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700542 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
543
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200544 hci_send_acl(conn->hcon, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200545}
546
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300547static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300548{
549 struct sk_buff *skb;
550 struct l2cap_hdr *lh;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300551 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300552 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300553 struct sock *sk = (struct sock *)pi;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300554 int count, hlen = L2CAP_HDR_SIZE + 2;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200555 u8 flags;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300556
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300557 if (sk->sk_state != BT_CONNECTED)
558 return;
559
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300560 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300561 hlen += 2;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300562
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300563 BT_DBG("chan %p, control 0x%2.2x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300564
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300565 count = min_t(unsigned int, conn->mtu, hlen);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300566 control |= L2CAP_CTRL_FRAME_TYPE;
567
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300568 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300569 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300570 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300571 }
572
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300573 if (chan->conn_state & L2CAP_CONN_SEND_PBIT) {
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300574 control |= L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300575 chan->conn_state &= ~L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300576 }
577
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300578 skb = bt_skb_alloc(count, GFP_ATOMIC);
579 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300580 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300581
582 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300583 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300584 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300585 put_unaligned_le16(control, skb_put(skb, 2));
586
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300587 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300588 u16 fcs = crc16(0, (u8 *)lh, count - 2);
589 put_unaligned_le16(fcs, skb_put(skb, 2));
590 }
591
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200592 if (lmp_no_flush_capable(conn->hcon->hdev))
593 flags = ACL_START_NO_FLUSH;
594 else
595 flags = ACL_START;
596
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700597 bt_cb(skb)->force_active = chan->force_active;
598
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300599 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300600}
601
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300602static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300603{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300604 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300605 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300606 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300607 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300608 control |= L2CAP_SUPER_RCV_READY;
609
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300610 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300611
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300612 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300613}
614
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300615static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300616{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300617 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300618}
619
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300620static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200621{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300622 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200623
624 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100625 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
626 return;
627
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300628 if (l2cap_check_security(chan) &&
629 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200630 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300631 req.scid = cpu_to_le16(chan->scid);
632 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200633
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300634 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300635 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200636
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300637 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
638 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200639 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200640 } else {
641 struct l2cap_info_req req;
642 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
643
644 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
645 conn->info_ident = l2cap_get_ident(conn);
646
647 mod_timer(&conn->info_timer, jiffies +
648 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
649
650 l2cap_send_cmd(conn, conn->info_ident,
651 L2CAP_INFO_REQ, sizeof(req), &req);
652 }
653}
654
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300655static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
656{
657 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300658 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300659 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
660
661 switch (mode) {
662 case L2CAP_MODE_ERTM:
663 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
664 case L2CAP_MODE_STREAMING:
665 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
666 default:
667 return 0x00;
668 }
669}
670
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300671static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300672{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300673 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300674 struct l2cap_disconn_req req;
675
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300676 if (!conn)
677 return;
678
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300679 sk = chan->sk;
680
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300681 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300682 del_timer(&chan->retrans_timer);
683 del_timer(&chan->monitor_timer);
684 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300685 }
686
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300687 req.dcid = cpu_to_le16(chan->dcid);
688 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300689 l2cap_send_cmd(conn, l2cap_get_ident(conn),
690 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300691
692 sk->sk_state = BT_DISCONN;
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300693 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300694}
695
Linus Torvalds1da177e2005-04-16 15:20:36 -0700696/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200697static void l2cap_conn_start(struct l2cap_conn *conn)
698{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300699 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200700
701 BT_DBG("conn %p", conn);
702
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300703 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200704
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300705 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300706 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300707
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200708 bh_lock_sock(sk);
709
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300710 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200711 bh_unlock_sock(sk);
712 continue;
713 }
714
715 if (sk->sk_state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300716 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300717
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300718 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300719 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300720 bh_unlock_sock(sk);
721 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200722 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300723
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300724 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300725 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300726 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300727 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300728 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300729 * so release the lock */
730 read_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300731 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300732 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300733 bh_unlock_sock(sk);
734 continue;
735 }
736
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300737 req.scid = cpu_to_le16(chan->scid);
738 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300739
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300740 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300741 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300742
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300743 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
744 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300745
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200746 } else if (sk->sk_state == BT_CONNECT2) {
747 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300748 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300749 rsp.scid = cpu_to_le16(chan->dcid);
750 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200751
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300752 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100753 if (bt_sk(sk)->defer_setup) {
754 struct sock *parent = bt_sk(sk)->parent;
755 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
756 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
757 parent->sk_data_ready(parent, 0);
758
759 } else {
760 sk->sk_state = BT_CONFIG;
761 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
762 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
763 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200764 } else {
765 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
766 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
767 }
768
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300769 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
770 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300771
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300772 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300773 rsp.result != L2CAP_CR_SUCCESS) {
774 bh_unlock_sock(sk);
775 continue;
776 }
777
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300778 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300779 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300780 l2cap_build_conf_req(chan, buf), buf);
781 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200782 }
783
784 bh_unlock_sock(sk);
785 }
786
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300787 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200788}
789
Ville Tervob62f3282011-02-10 22:38:50 -0300790/* Find socket with cid and source bdaddr.
791 * Returns closest match, locked.
792 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300793static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300794{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300795 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300796
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300797 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300798
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300799 list_for_each_entry(c, &chan_list, global_l) {
800 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300801
Ville Tervob62f3282011-02-10 22:38:50 -0300802 if (state && sk->sk_state != state)
803 continue;
804
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300805 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300806 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300807 if (!bacmp(&bt_sk(sk)->src, src)) {
808 read_unlock(&chan_list_lock);
809 return c;
810 }
Ville Tervob62f3282011-02-10 22:38:50 -0300811
812 /* Closest match */
813 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300814 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300815 }
816 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300817
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300818 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300819
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300820 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300821}
822
823static void l2cap_le_conn_ready(struct l2cap_conn *conn)
824{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300825 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300826 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300827
828 BT_DBG("");
829
830 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300831 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300832 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300833 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300834 return;
835
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300836 parent = pchan->sk;
837
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300838 bh_lock_sock(parent);
839
Ville Tervob62f3282011-02-10 22:38:50 -0300840 /* Check for backlog size */
841 if (sk_acceptq_is_full(parent)) {
842 BT_DBG("backlog full %d", parent->sk_ack_backlog);
843 goto clean;
844 }
845
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300846 chan = pchan->ops->new_connection(pchan->data);
847 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300848 goto clean;
849
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300850 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300851
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300852 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300853
854 hci_conn_hold(conn->hcon);
855
Ville Tervob62f3282011-02-10 22:38:50 -0300856 bacpy(&bt_sk(sk)->src, conn->src);
857 bacpy(&bt_sk(sk)->dst, conn->dst);
858
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300859 bt_accept_enqueue(parent, sk);
860
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300861 __l2cap_chan_add(conn, chan);
862
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300863 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300864
865 sk->sk_state = BT_CONNECTED;
866 parent->sk_data_ready(parent, 0);
867
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300868 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300869
870clean:
871 bh_unlock_sock(parent);
872}
873
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200874static void l2cap_conn_ready(struct l2cap_conn *conn)
875{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300876 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200877
878 BT_DBG("conn %p", conn);
879
Ville Tervob62f3282011-02-10 22:38:50 -0300880 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
881 l2cap_le_conn_ready(conn);
882
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300883 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200884
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300885 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300886 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300887
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200888 bh_lock_sock(sk);
889
Ville Tervoacd7d372011-02-10 22:38:49 -0300890 if (conn->hcon->type == LE_LINK) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300891 l2cap_chan_clear_timer(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300892 sk->sk_state = BT_CONNECTED;
893 sk->sk_state_change(sk);
894 }
895
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300896 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300897 l2cap_chan_clear_timer(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200898 sk->sk_state = BT_CONNECTED;
899 sk->sk_state_change(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200900 } else if (sk->sk_state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300901 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200902
903 bh_unlock_sock(sk);
904 }
905
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300906 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200907}
908
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200909/* Notify sockets that we cannot guaranty reliability anymore */
910static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
911{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300912 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200913
914 BT_DBG("conn %p", conn);
915
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300916 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200917
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300918 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300919 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300920
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300921 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200922 sk->sk_err = err;
923 }
924
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300925 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200926}
927
928static void l2cap_info_timeout(unsigned long arg)
929{
930 struct l2cap_conn *conn = (void *) arg;
931
Marcel Holtmann984947d2009-02-06 23:35:19 +0100932 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100933 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100934
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200935 l2cap_conn_start(conn);
936}
937
Linus Torvalds1da177e2005-04-16 15:20:36 -0700938static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
939{
Marcel Holtmann01394182006-07-03 10:02:46 +0200940 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941
Marcel Holtmann01394182006-07-03 10:02:46 +0200942 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943 return conn;
944
Marcel Holtmann01394182006-07-03 10:02:46 +0200945 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
946 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
949 hcon->l2cap_data = conn;
950 conn->hcon = hcon;
951
Marcel Holtmann01394182006-07-03 10:02:46 +0200952 BT_DBG("hcon %p conn %p", hcon, conn);
953
Ville Tervoacd7d372011-02-10 22:38:49 -0300954 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
955 conn->mtu = hcon->hdev->le_mtu;
956 else
957 conn->mtu = hcon->hdev->acl_mtu;
958
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 conn->src = &hcon->hdev->bdaddr;
960 conn->dst = &hcon->dst;
961
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200962 conn->feat_mask = 0;
963
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300965 rwlock_init(&conn->chan_lock);
966
967 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700968
Ville Tervob62f3282011-02-10 22:38:50 -0300969 if (hcon->type != LE_LINK)
970 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +0000971 (unsigned long) conn);
972
Marcel Holtmann2950f212009-02-12 14:02:50 +0100973 conn->disc_reason = 0x13;
974
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975 return conn;
976}
977
Marcel Holtmann01394182006-07-03 10:02:46 +0200978static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Marcel Holtmann01394182006-07-03 10:02:46 +0200980 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300981 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 struct sock *sk;
983
Marcel Holtmann01394182006-07-03 10:02:46 +0200984 if (!conn)
985 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986
987 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
988
Wei Yongjun7585b972009-02-25 18:29:52 +0800989 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700990
991 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300992 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300993 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300995 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 bh_unlock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300997 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 }
999
Dave Young8e8440f2008-03-03 12:18:55 -08001000 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1001 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -08001002
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 hcon->l2cap_data = NULL;
1004 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005}
1006
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001007static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001009 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001010 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001011 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012}
1013
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015
1016/* Find socket with psm and source bdaddr.
1017 * Returns closest match.
1018 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001019static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001021 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001023 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001024
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001025 list_for_each_entry(c, &chan_list, global_l) {
1026 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001027
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 if (state && sk->sk_state != state)
1029 continue;
1030
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001031 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001033 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001034 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001035 return c;
1036 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037
1038 /* Closest match */
1039 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001040 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 }
1042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001044 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001045
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001046 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047}
1048
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001049int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001051 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052 bdaddr_t *src = &bt_sk(sk)->src;
1053 bdaddr_t *dst = &bt_sk(sk)->dst;
1054 struct l2cap_conn *conn;
1055 struct hci_conn *hcon;
1056 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001057 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001058 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001060 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001061 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001063 hdev = hci_get_route(dst, src);
1064 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return -EHOSTUNREACH;
1066
1067 hci_dev_lock_bh(hdev);
1068
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001069 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001070
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001071 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001072 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001073 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001074 else
1075 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001076 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001077
Ville Tervo30e76272011-02-22 16:10:53 -03001078 if (IS_ERR(hcon)) {
1079 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
1083 conn = l2cap_conn_add(hcon, 0);
1084 if (!conn) {
1085 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001086 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 goto done;
1088 }
1089
Linus Torvalds1da177e2005-04-16 15:20:36 -07001090 /* Update source addr of the socket */
1091 bacpy(src, conn->src);
1092
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001093 l2cap_chan_add(conn, chan);
1094
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 sk->sk_state = BT_CONNECT;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03001096 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097
1098 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001099 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -03001100 l2cap_chan_clear_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001101 if (l2cap_check_security(chan))
Johan Hedbergd00ef242011-01-19 12:06:51 +05301102 sk->sk_state = BT_CONNECTED;
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001103 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001104 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105 }
1106
Ville Tervo30e76272011-02-22 16:10:53 -03001107 err = 0;
1108
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109done:
1110 hci_dev_unlock_bh(hdev);
1111 hci_dev_put(hdev);
1112 return err;
1113}
1114
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001115int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001116{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001117 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001118 DECLARE_WAITQUEUE(wait, current);
1119 int err = 0;
1120 int timeo = HZ/5;
1121
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001122 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001123 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001124 set_current_state(TASK_INTERRUPTIBLE);
1125
1126 if (!timeo)
1127 timeo = HZ/5;
1128
1129 if (signal_pending(current)) {
1130 err = sock_intr_errno(timeo);
1131 break;
1132 }
1133
1134 release_sock(sk);
1135 timeo = schedule_timeout(timeo);
1136 lock_sock(sk);
1137
1138 err = sock_error(sk);
1139 if (err)
1140 break;
1141 }
1142 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001143 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001144 return err;
1145}
1146
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001147static void l2cap_monitor_timeout(unsigned long arg)
1148{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001149 struct l2cap_chan *chan = (void *) arg;
1150 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001151
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001152 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001153
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001154 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001155 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001156 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001157 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001158 return;
1159 }
1160
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001161 chan->retry_count++;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001162 __mod_monitor_timer();
1163
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001164 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001165 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001166}
1167
1168static void l2cap_retrans_timeout(unsigned long arg)
1169{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001170 struct l2cap_chan *chan = (void *) arg;
1171 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001172
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001173 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001174
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001175 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001176 chan->retry_count = 1;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001177 __mod_monitor_timer();
1178
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001179 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001180
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001181 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001182 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001183}
1184
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001185static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001186{
1187 struct sk_buff *skb;
1188
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001189 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001190 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001191 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001192 break;
1193
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001194 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001195 kfree_skb(skb);
1196
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001197 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001198 }
1199
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001200 if (!chan->unacked_frames)
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001201 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001202}
1203
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001204void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001205{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001206 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001207 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001208
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001209 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001210
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001211 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001212 flags = ACL_START_NO_FLUSH;
1213 else
1214 flags = ACL_START;
1215
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -07001216 bt_cb(skb)->force_active = chan->force_active;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001217 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001218}
1219
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001220void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001221{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001222 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001223 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001224
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001225 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001226 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001227 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001228 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001229
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001230 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001231 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1232 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001233 }
1234
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001235 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001236
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001237 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001238 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001239}
1240
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001241static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001242{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001243 struct sk_buff *skb, *tx_skb;
1244 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001245
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001246 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001247 if (!skb)
1248 return;
1249
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001250 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001251 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001252 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001253
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001254 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001255 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001256
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001257 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001258
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001259 if (chan->remote_max_tx &&
1260 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001261 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001262 return;
1263 }
1264
1265 tx_skb = skb_clone(skb, GFP_ATOMIC);
1266 bt_cb(skb)->retries++;
1267 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001268 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001269
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001270 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001271 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001272 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001273 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001274
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001275 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001276 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001277
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001278 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1279
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001280 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001281 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1282 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1283 }
1284
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001285 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001286}
1287
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001288int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001289{
1290 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001291 struct sock *sk = chan->sk;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001292 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001293 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001294
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001295 if (sk->sk_state != BT_CONNECTED)
1296 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001297
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001298 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001299
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001300 if (chan->remote_max_tx &&
1301 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001302 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001303 break;
1304 }
1305
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001306 tx_skb = skb_clone(skb, GFP_ATOMIC);
1307
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001308 bt_cb(skb)->retries++;
1309
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001310 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001311 control &= L2CAP_CTRL_SAR;
1312
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001313 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001314 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001315 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001316 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001317 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1318 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001319 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1320
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001321
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001322 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001323 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1324 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1325 }
1326
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001327 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001328
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001329 __mod_retrans_timer();
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001330
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001331 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1332 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001333
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301334 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001335 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301336
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001337 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001338
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001339 if (skb_queue_is_last(&chan->tx_q, skb))
1340 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001341 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001342 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001343
1344 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001345 }
1346
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001347 return nsent;
1348}
1349
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001350static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001351{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001352 int ret;
1353
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001354 if (!skb_queue_empty(&chan->tx_q))
1355 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001356
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001357 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001358 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001359 return ret;
1360}
1361
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001362static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001363{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001364 u16 control = 0;
1365
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001366 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001367
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001368 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001369 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001370 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1371 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001372 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001373 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001374
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001375 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001376 return;
1377
1378 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001379 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001380}
1381
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001382static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001383{
1384 struct srej_list *tail;
1385 u16 control;
1386
1387 control = L2CAP_SUPER_SELECT_REJECT;
1388 control |= L2CAP_CTRL_FINAL;
1389
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001390 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001391 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1392
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001393 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001394}
1395
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001396static 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 -07001397{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001398 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001399 struct sk_buff **frag;
1400 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001402 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001403 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001404
1405 sent += count;
1406 len -= count;
1407
1408 /* Continuation fragments (no L2CAP header) */
1409 frag = &skb_shinfo(skb)->frag_list;
1410 while (len) {
1411 count = min_t(unsigned int, conn->mtu, len);
1412
1413 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1414 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001415 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001416 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1417 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
1419 sent += count;
1420 len -= count;
1421
1422 frag = &(*frag)->next;
1423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424
1425 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001426}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001428struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001429{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001430 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001431 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001432 struct sk_buff *skb;
1433 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1434 struct l2cap_hdr *lh;
1435
1436 BT_DBG("sk %p len %d", sk, (int)len);
1437
1438 count = min_t(unsigned int, (conn->mtu - hlen), len);
1439 skb = bt_skb_send_alloc(sk, count + hlen,
1440 msg->msg_flags & MSG_DONTWAIT, &err);
1441 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001442 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001443
1444 /* Create L2CAP header */
1445 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001446 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001447 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001448 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001449
1450 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1451 if (unlikely(err < 0)) {
1452 kfree_skb(skb);
1453 return ERR_PTR(err);
1454 }
1455 return skb;
1456}
1457
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001458struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001459{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001460 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001461 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001462 struct sk_buff *skb;
1463 int err, count, hlen = L2CAP_HDR_SIZE;
1464 struct l2cap_hdr *lh;
1465
1466 BT_DBG("sk %p len %d", sk, (int)len);
1467
1468 count = min_t(unsigned int, (conn->mtu - hlen), len);
1469 skb = bt_skb_send_alloc(sk, count + hlen,
1470 msg->msg_flags & MSG_DONTWAIT, &err);
1471 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001472 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001473
1474 /* Create L2CAP header */
1475 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001476 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001477 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1478
1479 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1480 if (unlikely(err < 0)) {
1481 kfree_skb(skb);
1482 return ERR_PTR(err);
1483 }
1484 return skb;
1485}
1486
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001487struct 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 -03001488{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001489 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001490 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001491 struct sk_buff *skb;
1492 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1493 struct l2cap_hdr *lh;
1494
1495 BT_DBG("sk %p len %d", sk, (int)len);
1496
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001497 if (!conn)
1498 return ERR_PTR(-ENOTCONN);
1499
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001500 if (sdulen)
1501 hlen += 2;
1502
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001503 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001504 hlen += 2;
1505
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001506 count = min_t(unsigned int, (conn->mtu - hlen), len);
1507 skb = bt_skb_send_alloc(sk, count + hlen,
1508 msg->msg_flags & MSG_DONTWAIT, &err);
1509 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001510 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001511
1512 /* Create L2CAP header */
1513 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001514 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001515 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1516 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001517 if (sdulen)
1518 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001519
1520 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1521 if (unlikely(err < 0)) {
1522 kfree_skb(skb);
1523 return ERR_PTR(err);
1524 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001525
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001526 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001527 put_unaligned_le16(0, skb_put(skb, 2));
1528
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001529 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001530 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001531}
1532
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001533int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001534{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001535 struct sk_buff *skb;
1536 struct sk_buff_head sar_queue;
1537 u16 control;
1538 size_t size = 0;
1539
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001540 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001541 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001542 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001543 if (IS_ERR(skb))
1544 return PTR_ERR(skb);
1545
1546 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001547 len -= chan->remote_mps;
1548 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001549
1550 while (len > 0) {
1551 size_t buflen;
1552
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001553 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001554 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001555 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001556 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001557 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001558 buflen = len;
1559 }
1560
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001561 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001562 if (IS_ERR(skb)) {
1563 skb_queue_purge(&sar_queue);
1564 return PTR_ERR(skb);
1565 }
1566
1567 __skb_queue_tail(&sar_queue, skb);
1568 len -= buflen;
1569 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001570 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001571 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1572 if (chan->tx_send_head == NULL)
1573 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001574
1575 return size;
1576}
1577
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001578int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1579{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001580 struct sk_buff *skb;
1581 u16 control;
1582 int err;
1583
1584 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001585 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001586 skb = l2cap_create_connless_pdu(chan, msg, len);
1587 if (IS_ERR(skb))
1588 return PTR_ERR(skb);
1589
1590 l2cap_do_send(chan, skb);
1591 return len;
1592 }
1593
1594 switch (chan->mode) {
1595 case L2CAP_MODE_BASIC:
1596 /* Check outgoing MTU */
1597 if (len > chan->omtu)
1598 return -EMSGSIZE;
1599
1600 /* Create a basic PDU */
1601 skb = l2cap_create_basic_pdu(chan, msg, len);
1602 if (IS_ERR(skb))
1603 return PTR_ERR(skb);
1604
1605 l2cap_do_send(chan, skb);
1606 err = len;
1607 break;
1608
1609 case L2CAP_MODE_ERTM:
1610 case L2CAP_MODE_STREAMING:
1611 /* Entire SDU fits into one PDU */
1612 if (len <= chan->remote_mps) {
1613 control = L2CAP_SDU_UNSEGMENTED;
1614 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1615 0);
1616 if (IS_ERR(skb))
1617 return PTR_ERR(skb);
1618
1619 __skb_queue_tail(&chan->tx_q, skb);
1620
1621 if (chan->tx_send_head == NULL)
1622 chan->tx_send_head = skb;
1623
1624 } else {
1625 /* Segment SDU into multiples PDUs */
1626 err = l2cap_sar_segment_sdu(chan, msg, len);
1627 if (err < 0)
1628 return err;
1629 }
1630
1631 if (chan->mode == L2CAP_MODE_STREAMING) {
1632 l2cap_streaming_send(chan);
1633 err = len;
1634 break;
1635 }
1636
1637 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1638 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1639 err = len;
1640 break;
1641 }
1642
1643 err = l2cap_ertm_send(chan);
1644 if (err >= 0)
1645 err = len;
1646
1647 break;
1648
1649 default:
1650 BT_DBG("bad state %1.1x", chan->mode);
1651 err = -EBADFD;
1652 }
1653
1654 return err;
1655}
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657static void l2cap_chan_ready(struct sock *sk)
1658{
1659 struct sock *parent = bt_sk(sk)->parent;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001660 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001661
1662 BT_DBG("sk %p, parent %p", sk, parent);
1663
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001664 chan->conf_state = 0;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03001665 l2cap_chan_clear_timer(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 if (!parent) {
1668 /* Outgoing channel.
1669 * Wake up socket sleeping on connect.
1670 */
1671 sk->sk_state = BT_CONNECTED;
1672 sk->sk_state_change(sk);
1673 } else {
1674 /* Incoming channel.
1675 * Wake up socket sleeping on accept.
1676 */
1677 parent->sk_data_ready(parent, 0);
1678 }
1679}
1680
1681/* Copy frame to all raw sockets on that connection */
1682static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1683{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001685 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686
1687 BT_DBG("conn %p", conn);
1688
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001689 read_lock(&conn->chan_lock);
1690 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001691 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001692 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 continue;
1694
1695 /* Don't send frame to the socket it came from */
1696 if (skb->sk == sk)
1697 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001698 nskb = skb_clone(skb, GFP_ATOMIC);
1699 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 continue;
1701
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001702 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 kfree_skb(nskb);
1704 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001705 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001706}
1707
1708/* ---- L2CAP signalling commands ---- */
1709static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1710 u8 code, u8 ident, u16 dlen, void *data)
1711{
1712 struct sk_buff *skb, **frag;
1713 struct l2cap_cmd_hdr *cmd;
1714 struct l2cap_hdr *lh;
1715 int len, count;
1716
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001717 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1718 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001719
1720 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1721 count = min_t(unsigned int, conn->mtu, len);
1722
1723 skb = bt_skb_alloc(count, GFP_ATOMIC);
1724 if (!skb)
1725 return NULL;
1726
1727 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001728 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001729
1730 if (conn->hcon->type == LE_LINK)
1731 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1732 else
1733 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734
1735 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1736 cmd->code = code;
1737 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001738 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 if (dlen) {
1741 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1742 memcpy(skb_put(skb, count), data, count);
1743 data += count;
1744 }
1745
1746 len -= skb->len;
1747
1748 /* Continuation fragments (no L2CAP header) */
1749 frag = &skb_shinfo(skb)->frag_list;
1750 while (len) {
1751 count = min_t(unsigned int, conn->mtu, len);
1752
1753 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1754 if (!*frag)
1755 goto fail;
1756
1757 memcpy(skb_put(*frag, count), data, count);
1758
1759 len -= count;
1760 data += count;
1761
1762 frag = &(*frag)->next;
1763 }
1764
1765 return skb;
1766
1767fail:
1768 kfree_skb(skb);
1769 return NULL;
1770}
1771
1772static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1773{
1774 struct l2cap_conf_opt *opt = *ptr;
1775 int len;
1776
1777 len = L2CAP_CONF_OPT_SIZE + opt->len;
1778 *ptr += len;
1779
1780 *type = opt->type;
1781 *olen = opt->len;
1782
1783 switch (opt->len) {
1784 case 1:
1785 *val = *((u8 *) opt->val);
1786 break;
1787
1788 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001789 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 break;
1791
1792 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001793 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 break;
1795
1796 default:
1797 *val = (unsigned long) opt->val;
1798 break;
1799 }
1800
1801 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1802 return len;
1803}
1804
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1806{
1807 struct l2cap_conf_opt *opt = *ptr;
1808
1809 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1810
1811 opt->type = type;
1812 opt->len = len;
1813
1814 switch (len) {
1815 case 1:
1816 *((u8 *) opt->val) = val;
1817 break;
1818
1819 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001820 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001821 break;
1822
1823 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001824 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 break;
1826
1827 default:
1828 memcpy(opt->val, (void *) val, len);
1829 break;
1830 }
1831
1832 *ptr += L2CAP_CONF_OPT_SIZE + len;
1833}
1834
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001835static void l2cap_ack_timeout(unsigned long arg)
1836{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001837 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001838
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001839 bh_lock_sock(chan->sk);
1840 l2cap_send_ack(chan);
1841 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001842}
1843
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001844static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001845{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001846 struct sock *sk = chan->sk;
1847
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001848 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001849 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001850 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001851 chan->num_acked = 0;
1852 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001853
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001854 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1855 (unsigned long) chan);
1856 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1857 (unsigned long) chan);
1858 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001859
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001860 skb_queue_head_init(&chan->srej_q);
1861 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001862
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001863 INIT_LIST_HEAD(&chan->srej_l);
1864
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001865 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001866
1867 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001868}
1869
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001870static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1871{
1872 switch (mode) {
1873 case L2CAP_MODE_STREAMING:
1874 case L2CAP_MODE_ERTM:
1875 if (l2cap_mode_supported(mode, remote_feat_mask))
1876 return mode;
1877 /* fall through */
1878 default:
1879 return L2CAP_MODE_BASIC;
1880 }
1881}
1882
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001883static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001886 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001887 void *ptr = req->data;
1888
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001889 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001891 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001892 goto done;
1893
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001894 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001895 case L2CAP_MODE_STREAMING:
1896 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001897 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001898 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001899
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001900 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001901 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001902 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001903 break;
1904 }
1905
1906done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001907 if (chan->imtu != L2CAP_DEFAULT_MTU)
1908 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001909
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001910 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001911 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001912 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1913 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001914 break;
1915
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001916 rfc.mode = L2CAP_MODE_BASIC;
1917 rfc.txwin_size = 0;
1918 rfc.max_transmit = 0;
1919 rfc.retrans_timeout = 0;
1920 rfc.monitor_timeout = 0;
1921 rfc.max_pdu_size = 0;
1922
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001923 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1924 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001925 break;
1926
1927 case L2CAP_MODE_ERTM:
1928 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001929 rfc.txwin_size = chan->tx_win;
1930 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001931 rfc.retrans_timeout = 0;
1932 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001933 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001934 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1935 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001936
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001937 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1938 (unsigned long) &rfc);
1939
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001940 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001941 break;
1942
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001943 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001944 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001945 chan->fcs = L2CAP_FCS_NONE;
1946 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001947 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001948 break;
1949
1950 case L2CAP_MODE_STREAMING:
1951 rfc.mode = L2CAP_MODE_STREAMING;
1952 rfc.txwin_size = 0;
1953 rfc.max_transmit = 0;
1954 rfc.retrans_timeout = 0;
1955 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001956 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001957 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1958 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001959
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001960 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1961 (unsigned long) &rfc);
1962
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001963 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001964 break;
1965
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001966 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001967 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001968 chan->fcs = L2CAP_FCS_NONE;
1969 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001970 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001971 break;
1972 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001973
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001974 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001975 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976
1977 return ptr - data;
1978}
1979
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001980static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001982 struct l2cap_conf_rsp *rsp = data;
1983 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001984 void *req = chan->conf_req;
1985 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001986 int type, hint, olen;
1987 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02001988 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02001989 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001990 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001992 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01001993
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001994 while (len >= L2CAP_CONF_OPT_SIZE) {
1995 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03001997 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07001998 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001999
2000 switch (type) {
2001 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002002 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002003 break;
2004
2005 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002006 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002007 break;
2008
2009 case L2CAP_CONF_QOS:
2010 break;
2011
Marcel Holtmann6464f352007-10-20 13:39:51 +02002012 case L2CAP_CONF_RFC:
2013 if (olen == sizeof(rfc))
2014 memcpy(&rfc, (void *) val, olen);
2015 break;
2016
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002017 case L2CAP_CONF_FCS:
2018 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002019 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002020
2021 break;
2022
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002023 default:
2024 if (hint)
2025 break;
2026
2027 result = L2CAP_CONF_UNKNOWN;
2028 *((u8 *) ptr++) = type;
2029 break;
2030 }
2031 }
2032
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002033 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002034 goto done;
2035
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002036 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002037 case L2CAP_MODE_STREAMING:
2038 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002039 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002040 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002041 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002042 break;
2043 }
2044
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002045 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002046 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002047
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002048 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002049 }
2050
2051done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002052 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002053 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002054 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002055
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002056 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002057 return -ECONNREFUSED;
2058
2059 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2060 sizeof(rfc), (unsigned long) &rfc);
2061 }
2062
2063
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002064 if (result == L2CAP_CONF_SUCCESS) {
2065 /* Configure output options and let the other side know
2066 * which ones we don't like. */
2067
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002068 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2069 result = L2CAP_CONF_UNACCEPT;
2070 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002071 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002072 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002073 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002074 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002075
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002076 switch (rfc.mode) {
2077 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002078 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002079 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002080 break;
2081
2082 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002083 chan->remote_tx_win = rfc.txwin_size;
2084 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002085
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002086 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2087 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002088
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002089 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002090
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002091 rfc.retrans_timeout =
2092 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2093 rfc.monitor_timeout =
2094 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002095
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002096 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002097
2098 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2099 sizeof(rfc), (unsigned long) &rfc);
2100
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002101 break;
2102
2103 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002104 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2105 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002106
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002107 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002108
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002109 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002110
2111 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2112 sizeof(rfc), (unsigned long) &rfc);
2113
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002114 break;
2115
2116 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002117 result = L2CAP_CONF_UNACCEPT;
2118
2119 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002120 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002121 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002122
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002123 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002124 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002125 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002126 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002127 rsp->result = cpu_to_le16(result);
2128 rsp->flags = cpu_to_le16(0x0000);
2129
2130 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002131}
2132
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002133static 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 -03002134{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002135 struct l2cap_conf_req *req = data;
2136 void *ptr = req->data;
2137 int type, olen;
2138 unsigned long val;
2139 struct l2cap_conf_rfc rfc;
2140
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002141 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002142
2143 while (len >= L2CAP_CONF_OPT_SIZE) {
2144 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2145
2146 switch (type) {
2147 case L2CAP_CONF_MTU:
2148 if (val < L2CAP_DEFAULT_MIN_MTU) {
2149 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002150 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002151 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002152 chan->imtu = val;
2153 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002154 break;
2155
2156 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002157 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002158 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002159 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002160 break;
2161
2162 case L2CAP_CONF_RFC:
2163 if (olen == sizeof(rfc))
2164 memcpy(&rfc, (void *)val, olen);
2165
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002166 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002167 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002168 return -ECONNREFUSED;
2169
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002170 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002171
2172 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2173 sizeof(rfc), (unsigned long) &rfc);
2174 break;
2175 }
2176 }
2177
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002178 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002179 return -ECONNREFUSED;
2180
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002181 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002182
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002183 if (*result == L2CAP_CONF_SUCCESS) {
2184 switch (rfc.mode) {
2185 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002186 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2187 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2188 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002189 break;
2190 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002191 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002192 }
2193 }
2194
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002195 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002196 req->flags = cpu_to_le16(0x0000);
2197
2198 return ptr - data;
2199}
2200
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002201static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202{
2203 struct l2cap_conf_rsp *rsp = data;
2204 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002206 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002208 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002209 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002210 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002211
2212 return ptr - data;
2213}
2214
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002215void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002216{
2217 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002218 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002219 u8 buf[128];
2220
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002221 rsp.scid = cpu_to_le16(chan->dcid);
2222 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002223 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2224 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2225 l2cap_send_cmd(conn, chan->ident,
2226 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2227
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002228 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002229 return;
2230
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002231 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002232 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2233 l2cap_build_conf_req(chan, buf), buf);
2234 chan->num_conf_req++;
2235}
2236
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002237static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002238{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002239 int type, olen;
2240 unsigned long val;
2241 struct l2cap_conf_rfc rfc;
2242
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002243 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002244
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002245 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002246 return;
2247
2248 while (len >= L2CAP_CONF_OPT_SIZE) {
2249 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2250
2251 switch (type) {
2252 case L2CAP_CONF_RFC:
2253 if (olen == sizeof(rfc))
2254 memcpy(&rfc, (void *)val, olen);
2255 goto done;
2256 }
2257 }
2258
2259done:
2260 switch (rfc.mode) {
2261 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002262 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2263 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2264 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002265 break;
2266 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002267 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002268 }
2269}
2270
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002271static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2272{
2273 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2274
2275 if (rej->reason != 0x0000)
2276 return 0;
2277
2278 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2279 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002280 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002281
2282 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002283 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002284
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002285 l2cap_conn_start(conn);
2286 }
2287
2288 return 0;
2289}
2290
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2292{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002293 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2294 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002295 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002296 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002297 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298
2299 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002300 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
2302 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2303
2304 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002305 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2306 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002307 result = L2CAP_CR_BAD_PSM;
2308 goto sendresp;
2309 }
2310
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002311 parent = pchan->sk;
2312
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002313 bh_lock_sock(parent);
2314
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002315 /* Check if the ACL is secure enough (if not SDP) */
2316 if (psm != cpu_to_le16(0x0001) &&
2317 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002318 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002319 result = L2CAP_CR_SEC_BLOCK;
2320 goto response;
2321 }
2322
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323 result = L2CAP_CR_NO_MEM;
2324
2325 /* Check for backlog size */
2326 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002327 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 goto response;
2329 }
2330
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002331 chan = pchan->ops->new_connection(pchan->data);
2332 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 goto response;
2334
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002335 sk = chan->sk;
2336
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002337 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338
2339 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002340 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2341 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002342 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002343 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002344 goto response;
2345 }
2346
2347 hci_conn_hold(conn->hcon);
2348
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349 bacpy(&bt_sk(sk)->src, conn->src);
2350 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002351 chan->psm = psm;
2352 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002354 bt_accept_enqueue(parent, sk);
2355
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002356 __l2cap_chan_add(conn, chan);
2357
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002358 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002359
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002360 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002361
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002362 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002363
Marcel Holtmann984947d2009-02-06 23:35:19 +01002364 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002365 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002366 if (bt_sk(sk)->defer_setup) {
2367 sk->sk_state = BT_CONNECT2;
2368 result = L2CAP_CR_PEND;
2369 status = L2CAP_CS_AUTHOR_PEND;
2370 parent->sk_data_ready(parent, 0);
2371 } else {
2372 sk->sk_state = BT_CONFIG;
2373 result = L2CAP_CR_SUCCESS;
2374 status = L2CAP_CS_NO_INFO;
2375 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002376 } else {
2377 sk->sk_state = BT_CONNECT2;
2378 result = L2CAP_CR_PEND;
2379 status = L2CAP_CS_AUTHEN_PEND;
2380 }
2381 } else {
2382 sk->sk_state = BT_CONNECT2;
2383 result = L2CAP_CR_PEND;
2384 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002387 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002388
2389response:
2390 bh_unlock_sock(parent);
2391
2392sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002393 rsp.scid = cpu_to_le16(scid);
2394 rsp.dcid = cpu_to_le16(dcid);
2395 rsp.result = cpu_to_le16(result);
2396 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002398
2399 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2400 struct l2cap_info_req info;
2401 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2402
2403 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2404 conn->info_ident = l2cap_get_ident(conn);
2405
2406 mod_timer(&conn->info_timer, jiffies +
2407 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2408
2409 l2cap_send_cmd(conn, conn->info_ident,
2410 L2CAP_INFO_REQ, sizeof(info), &info);
2411 }
2412
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002413 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002414 result == L2CAP_CR_SUCCESS) {
2415 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002416 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002417 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002418 l2cap_build_conf_req(chan, buf), buf);
2419 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002420 }
2421
Linus Torvalds1da177e2005-04-16 15:20:36 -07002422 return 0;
2423}
2424
2425static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2426{
2427 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2428 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002429 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430 struct sock *sk;
2431 u8 req[128];
2432
2433 scid = __le16_to_cpu(rsp->scid);
2434 dcid = __le16_to_cpu(rsp->dcid);
2435 result = __le16_to_cpu(rsp->result);
2436 status = __le16_to_cpu(rsp->status);
2437
2438 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2439
2440 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002441 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002442 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002443 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002445 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002446 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002447 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448 }
2449
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002450 sk = chan->sk;
2451
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 switch (result) {
2453 case L2CAP_CR_SUCCESS:
2454 sk->sk_state = BT_CONFIG;
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002455 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002456 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002457 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002458
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002459 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002460 break;
2461
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002462 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002465 l2cap_build_conf_req(chan, req), req);
2466 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002467 break;
2468
2469 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002470 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002471 break;
2472
2473 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002474 /* don't delete l2cap channel if sk is owned by user */
2475 if (sock_owned_by_user(sk)) {
2476 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002477 l2cap_chan_clear_timer(chan);
2478 l2cap_chan_set_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002479 break;
2480 }
2481
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002482 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 break;
2484 }
2485
2486 bh_unlock_sock(sk);
2487 return 0;
2488}
2489
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002490static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002491{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002492 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2493
Mat Martineau8c462b62010-08-24 15:35:42 -07002494 /* FCS is enabled only in ERTM or streaming mode, if one or both
2495 * sides request it.
2496 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002497 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002498 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002499 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002500 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002501}
2502
Al Viro88219a02007-07-29 00:17:25 -07002503static 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 -07002504{
2505 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2506 u16 dcid, flags;
2507 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002508 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002509 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002510 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002511
2512 dcid = __le16_to_cpu(req->dcid);
2513 flags = __le16_to_cpu(req->flags);
2514
2515 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2516
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002517 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002518 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 return -ENOENT;
2520
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002521 sk = chan->sk;
2522
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002523 if (sk->sk_state != BT_CONFIG) {
2524 struct l2cap_cmd_rej rej;
2525
2526 rej.reason = cpu_to_le16(0x0002);
2527 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2528 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002529 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002530 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002531
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002532 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002533 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002534 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002535 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002536 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002537 L2CAP_CONF_REJECT, flags), rsp);
2538 goto unlock;
2539 }
2540
2541 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002542 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2543 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002544
2545 if (flags & 0x0001) {
2546 /* Incomplete config. Send empty response. */
2547 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002548 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002549 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002550 goto unlock;
2551 }
2552
2553 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002554 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002555 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002556 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002557 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002558 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002559
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002560 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002561 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002562
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002563 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002564 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002565
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002566 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002567 goto unlock;
2568
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002569 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002570 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002571
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002573
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002574 chan->next_tx_seq = 0;
2575 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002576 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002577 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002578 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002579
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002581 goto unlock;
2582 }
2583
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002584 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002585 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002586 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002588 l2cap_build_conf_req(chan, buf), buf);
2589 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002590 }
2591
2592unlock:
2593 bh_unlock_sock(sk);
2594 return 0;
2595}
2596
2597static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2598{
2599 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2600 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002601 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002603 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 scid = __le16_to_cpu(rsp->scid);
2606 flags = __le16_to_cpu(rsp->flags);
2607 result = __le16_to_cpu(rsp->result);
2608
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002609 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2610 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002612 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002613 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 return 0;
2615
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002616 sk = chan->sk;
2617
Linus Torvalds1da177e2005-04-16 15:20:36 -07002618 switch (result) {
2619 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002620 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621 break;
2622
2623 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002624 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002625 char req[64];
2626
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002627 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002628 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002629 goto done;
2630 }
2631
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002632 /* throw out any old stored conf requests */
2633 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002634 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2635 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002636 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002637 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002638 goto done;
2639 }
2640
2641 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2642 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002643 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002644 if (result != L2CAP_CONF_SUCCESS)
2645 goto done;
2646 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 }
2648
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002649 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002650 sk->sk_err = ECONNRESET;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002651 l2cap_chan_set_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002652 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002653 goto done;
2654 }
2655
2656 if (flags & 0x01)
2657 goto done;
2658
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002659 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002661 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002662 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002665 chan->next_tx_seq = 0;
2666 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002667 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002668 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002669 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002670
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671 l2cap_chan_ready(sk);
2672 }
2673
2674done:
2675 bh_unlock_sock(sk);
2676 return 0;
2677}
2678
2679static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2680{
2681 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2682 struct l2cap_disconn_rsp rsp;
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(req->scid);
2688 dcid = __le16_to_cpu(req->dcid);
2689
2690 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2691
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002692 chan = l2cap_get_chan_by_scid(conn, dcid);
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
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002698 rsp.dcid = cpu_to_le16(chan->scid);
2699 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2701
2702 sk->sk_shutdown = SHUTDOWN_MASK;
2703
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002704 /* don't delete l2cap channel if sk is owned by user */
2705 if (sock_owned_by_user(sk)) {
2706 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002707 l2cap_chan_clear_timer(chan);
2708 l2cap_chan_set_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002709 bh_unlock_sock(sk);
2710 return 0;
2711 }
2712
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002713 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714 bh_unlock_sock(sk);
2715
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002716 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 return 0;
2718}
2719
2720static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2721{
2722 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2723 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002724 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002725 struct sock *sk;
2726
2727 scid = __le16_to_cpu(rsp->scid);
2728 dcid = __le16_to_cpu(rsp->dcid);
2729
2730 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2731
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002732 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002733 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 return 0;
2735
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002736 sk = chan->sk;
2737
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002738 /* don't delete l2cap channel if sk is owned by user */
2739 if (sock_owned_by_user(sk)) {
2740 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002741 l2cap_chan_clear_timer(chan);
2742 l2cap_chan_set_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002743 bh_unlock_sock(sk);
2744 return 0;
2745 }
2746
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002747 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 bh_unlock_sock(sk);
2749
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002750 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return 0;
2752}
2753
2754static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2755{
2756 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 u16 type;
2758
2759 type = __le16_to_cpu(req->type);
2760
2761 BT_DBG("type 0x%4.4x", type);
2762
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002763 if (type == L2CAP_IT_FEAT_MASK) {
2764 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002765 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002766 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2767 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2768 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002769 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002770 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2771 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002772 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002773 l2cap_send_cmd(conn, cmd->ident,
2774 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002775 } else if (type == L2CAP_IT_FIXED_CHAN) {
2776 u8 buf[12];
2777 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2778 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2779 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2780 memcpy(buf + 4, l2cap_fixed_chan, 8);
2781 l2cap_send_cmd(conn, cmd->ident,
2782 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002783 } else {
2784 struct l2cap_info_rsp rsp;
2785 rsp.type = cpu_to_le16(type);
2786 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2787 l2cap_send_cmd(conn, cmd->ident,
2788 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2789 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002790
2791 return 0;
2792}
2793
2794static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2795{
2796 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2797 u16 type, result;
2798
2799 type = __le16_to_cpu(rsp->type);
2800 result = __le16_to_cpu(rsp->result);
2801
2802 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2803
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002804 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2805 if (cmd->ident != conn->info_ident ||
2806 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2807 return 0;
2808
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002809 del_timer(&conn->info_timer);
2810
Ville Tervoadb08ed2010-08-04 09:43:33 +03002811 if (result != L2CAP_IR_SUCCESS) {
2812 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2813 conn->info_ident = 0;
2814
2815 l2cap_conn_start(conn);
2816
2817 return 0;
2818 }
2819
Marcel Holtmann984947d2009-02-06 23:35:19 +01002820 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002821 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002822
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002823 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002824 struct l2cap_info_req req;
2825 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2826
2827 conn->info_ident = l2cap_get_ident(conn);
2828
2829 l2cap_send_cmd(conn, conn->info_ident,
2830 L2CAP_INFO_REQ, sizeof(req), &req);
2831 } else {
2832 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2833 conn->info_ident = 0;
2834
2835 l2cap_conn_start(conn);
2836 }
2837 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002838 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002839 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002840
2841 l2cap_conn_start(conn);
2842 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002843
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844 return 0;
2845}
2846
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002847static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002848 u16 to_multiplier)
2849{
2850 u16 max_latency;
2851
2852 if (min > max || min < 6 || max > 3200)
2853 return -EINVAL;
2854
2855 if (to_multiplier < 10 || to_multiplier > 3200)
2856 return -EINVAL;
2857
2858 if (max >= to_multiplier * 8)
2859 return -EINVAL;
2860
2861 max_latency = (to_multiplier * 8 / max) - 1;
2862 if (latency > 499 || latency > max_latency)
2863 return -EINVAL;
2864
2865 return 0;
2866}
2867
2868static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2869 struct l2cap_cmd_hdr *cmd, u8 *data)
2870{
2871 struct hci_conn *hcon = conn->hcon;
2872 struct l2cap_conn_param_update_req *req;
2873 struct l2cap_conn_param_update_rsp rsp;
2874 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002875 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002876
2877 if (!(hcon->link_mode & HCI_LM_MASTER))
2878 return -EINVAL;
2879
2880 cmd_len = __le16_to_cpu(cmd->len);
2881 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2882 return -EPROTO;
2883
2884 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002885 min = __le16_to_cpu(req->min);
2886 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002887 latency = __le16_to_cpu(req->latency);
2888 to_multiplier = __le16_to_cpu(req->to_multiplier);
2889
2890 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2891 min, max, latency, to_multiplier);
2892
2893 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002894
2895 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2896 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002897 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2898 else
2899 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2900
2901 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2902 sizeof(rsp), &rsp);
2903
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002904 if (!err)
2905 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2906
Claudio Takahaside731152011-02-11 19:28:55 -02002907 return 0;
2908}
2909
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002910static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2911 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2912{
2913 int err = 0;
2914
2915 switch (cmd->code) {
2916 case L2CAP_COMMAND_REJ:
2917 l2cap_command_rej(conn, cmd, data);
2918 break;
2919
2920 case L2CAP_CONN_REQ:
2921 err = l2cap_connect_req(conn, cmd, data);
2922 break;
2923
2924 case L2CAP_CONN_RSP:
2925 err = l2cap_connect_rsp(conn, cmd, data);
2926 break;
2927
2928 case L2CAP_CONF_REQ:
2929 err = l2cap_config_req(conn, cmd, cmd_len, data);
2930 break;
2931
2932 case L2CAP_CONF_RSP:
2933 err = l2cap_config_rsp(conn, cmd, data);
2934 break;
2935
2936 case L2CAP_DISCONN_REQ:
2937 err = l2cap_disconnect_req(conn, cmd, data);
2938 break;
2939
2940 case L2CAP_DISCONN_RSP:
2941 err = l2cap_disconnect_rsp(conn, cmd, data);
2942 break;
2943
2944 case L2CAP_ECHO_REQ:
2945 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2946 break;
2947
2948 case L2CAP_ECHO_RSP:
2949 break;
2950
2951 case L2CAP_INFO_REQ:
2952 err = l2cap_information_req(conn, cmd, data);
2953 break;
2954
2955 case L2CAP_INFO_RSP:
2956 err = l2cap_information_rsp(conn, cmd, data);
2957 break;
2958
2959 default:
2960 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2961 err = -EINVAL;
2962 break;
2963 }
2964
2965 return err;
2966}
2967
2968static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2969 struct l2cap_cmd_hdr *cmd, u8 *data)
2970{
2971 switch (cmd->code) {
2972 case L2CAP_COMMAND_REJ:
2973 return 0;
2974
2975 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002976 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002977
2978 case L2CAP_CONN_PARAM_UPDATE_RSP:
2979 return 0;
2980
2981 default:
2982 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
2983 return -EINVAL;
2984 }
2985}
2986
2987static inline void l2cap_sig_channel(struct l2cap_conn *conn,
2988 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002989{
2990 u8 *data = skb->data;
2991 int len = skb->len;
2992 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002993 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994
2995 l2cap_raw_recv(conn, skb);
2996
2997 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07002998 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002999 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3000 data += L2CAP_CMD_HDR_SIZE;
3001 len -= L2CAP_CMD_HDR_SIZE;
3002
Al Viro88219a02007-07-29 00:17:25 -07003003 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003004
Al Viro88219a02007-07-29 00:17:25 -07003005 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 -07003006
Al Viro88219a02007-07-29 00:17:25 -07003007 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 BT_DBG("corrupted command");
3009 break;
3010 }
3011
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003012 if (conn->hcon->type == LE_LINK)
3013 err = l2cap_le_sig_cmd(conn, &cmd, data);
3014 else
3015 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
3017 if (err) {
3018 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003019
3020 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003021
3022 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07003023 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3025 }
3026
Al Viro88219a02007-07-29 00:17:25 -07003027 data += cmd_len;
3028 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003029 }
3030
3031 kfree_skb(skb);
3032}
3033
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003034static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003035{
3036 u16 our_fcs, rcv_fcs;
3037 int hdr_size = L2CAP_HDR_SIZE + 2;
3038
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003039 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003040 skb_trim(skb, skb->len - 2);
3041 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3042 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3043
3044 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003045 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003046 }
3047 return 0;
3048}
3049
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003050static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003051{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003052 u16 control = 0;
3053
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003054 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003055
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003056 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003057
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003058 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03003059 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003060 l2cap_send_sframe(chan, control);
3061 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003062 }
3063
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003064 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3065 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003066
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003067 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003068
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003069 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003070 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003071 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003072 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003073 }
3074}
3075
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003076static 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 -03003077{
3078 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003079 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003080
3081 bt_cb(skb)->tx_seq = tx_seq;
3082 bt_cb(skb)->sar = sar;
3083
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003084 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003085 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003086 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003087 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003088 }
3089
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003090 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003091 if (tx_seq_offset < 0)
3092 tx_seq_offset += 64;
3093
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003094 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003095 if (bt_cb(next_skb)->tx_seq == tx_seq)
3096 return -EINVAL;
3097
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003098 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003099 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc112010-05-31 18:35:44 -03003100 if (next_tx_seq_offset < 0)
3101 next_tx_seq_offset += 64;
3102
3103 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003104 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003105 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003106 }
3107
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003108 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003109 break;
3110
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003111 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003112
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003113 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003114
3115 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003116}
3117
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003118static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003119{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003120 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003121 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003122
3123 switch (control & L2CAP_CTRL_SAR) {
3124 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003125 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003126 goto drop;
3127
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003128 return chan->ops->recv(chan->data, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003129
3130 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003131 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003132 goto drop;
3133
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003134 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003135
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003136 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003137 goto disconnect;
3138
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003139 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3140 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003141 return -ENOMEM;
3142
3143 /* pull sdu_len bytes only after alloc, because of Local Busy
3144 * condition we have to be sure that this will be executed
3145 * only once, i.e., when alloc does not fail */
3146 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003147
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003148 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003149
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003150 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003151 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003152 break;
3153
3154 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003155 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003156 goto disconnect;
3157
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003158 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003159 goto disconnect;
3160
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003161 chan->partial_sdu_len += skb->len;
3162 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003163 goto drop;
3164
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003165 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003166
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003167 break;
3168
3169 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003170 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003171 goto disconnect;
3172
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003173 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003174 goto disconnect;
3175
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003176 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003177 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003178
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003179 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003180 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003181
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003182 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003183 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003184
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003185 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003186 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003187
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003188 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003189 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003190 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003191 return -ENOMEM;
3192 }
3193
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003194 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003195 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003196 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003197 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003198 return err;
3199 }
3200
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003201 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3202 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003203
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003204 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003205 break;
3206 }
3207
3208 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003209 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003210
3211drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003212 kfree_skb(chan->sdu);
3213 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003214
3215disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003216 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003217 kfree_skb(skb);
3218 return 0;
3219}
3220
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003221static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003222{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003223 struct sk_buff *skb;
3224 u16 control;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003225 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003226
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003227 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003228 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003229 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003230 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003231 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003232 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003233 }
3234
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003235 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003236 }
3237
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003238 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003239 goto done;
3240
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003241 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003242 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003243 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003244 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003245
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003246 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003247 __mod_monitor_timer();
3248
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003249 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003250
3251done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003252 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3253 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003254
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003255 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003256
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003257 return 0;
3258}
3259
3260static void l2cap_busy_work(struct work_struct *work)
3261{
3262 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003263 struct l2cap_chan *chan =
3264 container_of(work, struct l2cap_chan, busy_work);
3265 struct sock *sk = chan->sk;
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003266 int n_tries = 0, timeo = HZ/5, err;
3267 struct sk_buff *skb;
3268
3269 lock_sock(sk);
3270
3271 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003272 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003273 set_current_state(TASK_INTERRUPTIBLE);
3274
3275 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3276 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003277 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003278 break;
3279 }
3280
3281 if (!timeo)
3282 timeo = HZ/5;
3283
3284 if (signal_pending(current)) {
3285 err = sock_intr_errno(timeo);
3286 break;
3287 }
3288
3289 release_sock(sk);
3290 timeo = schedule_timeout(timeo);
3291 lock_sock(sk);
3292
3293 err = sock_error(sk);
3294 if (err)
3295 break;
3296
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003297 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003298 break;
3299 }
3300
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003301 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003302 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003303
3304 release_sock(sk);
3305}
3306
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003307static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003308{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003309 int sctrl, err;
3310
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003311 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003312 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003313 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003314 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003315
3316
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003317 }
3318
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003319 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003320 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003321 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003322 return err;
3323 }
3324
3325 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003326 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003327
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003328 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003329 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003330 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003331
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003332 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003333 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003334 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003335
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003336 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003337
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003338 del_timer(&chan->ack_timer);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003339
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003340 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003341
3342 return err;
3343}
3344
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003345static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003346{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003347 struct sk_buff *_skb;
3348 int err = -EINVAL;
3349
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003350 /*
3351 * TODO: We have to notify the userland if some data is lost with the
3352 * Streaming Mode.
3353 */
3354
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003355 switch (control & L2CAP_CTRL_SAR) {
3356 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003357 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003358 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003359 break;
3360 }
3361
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003362 err = chan->ops->recv(chan->data, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003363 if (!err)
3364 return 0;
3365
3366 break;
3367
3368 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003369 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003370 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003371 break;
3372 }
3373
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003374 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003375 skb_pull(skb, 2);
3376
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003377 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003378 err = -EMSGSIZE;
3379 break;
3380 }
3381
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003382 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3383 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003384 err = -ENOMEM;
3385 break;
3386 }
3387
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003388 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003389
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003390 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003391 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003392 err = 0;
3393 break;
3394
3395 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003396 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003397 break;
3398
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003399 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003400
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003401 chan->partial_sdu_len += skb->len;
3402 if (chan->partial_sdu_len > chan->sdu_len)
3403 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003404 else
3405 err = 0;
3406
3407 break;
3408
3409 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003410 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003411 break;
3412
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003413 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003414
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003415 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003416 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003417
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003418 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003419 goto drop;
3420
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003421 if (chan->partial_sdu_len == chan->sdu_len) {
3422 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003423 err = chan->ops->recv(chan->data, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003424 if (err < 0)
3425 kfree_skb(_skb);
3426 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003427 err = 0;
3428
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003429drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003430 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003431 break;
3432 }
3433
3434 kfree_skb(skb);
3435 return err;
3436}
3437
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003438static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003439{
3440 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003441 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003442
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003443 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003444 if (bt_cb(skb)->tx_seq != tx_seq)
3445 break;
3446
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003447 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003448 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003449 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003450 chan->buffer_seq_srej =
3451 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003452 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003453 }
3454}
3455
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003456static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003457{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003458 struct srej_list *l, *tmp;
3459 u16 control;
3460
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003461 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003462 if (l->tx_seq == tx_seq) {
3463 list_del(&l->list);
3464 kfree(l);
3465 return;
3466 }
3467 control = L2CAP_SUPER_SELECT_REJECT;
3468 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003469 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003470 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003471 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003472 }
3473}
3474
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003475static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003476{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003477 struct srej_list *new;
3478 u16 control;
3479
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003480 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003481 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003482 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003483 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003484
3485 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003486 new->tx_seq = chan->expected_tx_seq;
3487 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003488 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003489 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003490 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003491}
3492
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003493static 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 -03003494{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003495 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003496 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003497 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003498 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003499 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003500 int err = 0;
3501
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003502 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3503 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003504
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003505 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003506 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003507 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003508 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003509 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003510 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003511 }
3512
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003513 chan->expected_ack_seq = req_seq;
3514 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003515
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003516 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003517 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003518
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003519 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003520 if (tx_seq_offset < 0)
3521 tx_seq_offset += 64;
3522
3523 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003524 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003525 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003526 goto drop;
3527 }
3528
Mat Martineaue6949282011-06-03 16:21:10 -07003529 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003530 goto drop;
3531
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003532 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003533 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003534
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003535 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003536 struct srej_list, list);
3537 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003538 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003539 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003540
3541 list_del(&first->list);
3542 kfree(first);
3543
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003544 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003545 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003546 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3547 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003548 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003549 }
3550 } else {
3551 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003552
3553 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003554 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003555 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003556
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003557 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003558 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003559 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003560 return 0;
3561 }
3562 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003563 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003564 }
3565 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003566 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003567 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003568 if (expected_tx_seq_offset < 0)
3569 expected_tx_seq_offset += 64;
3570
3571 /* duplicated tx_seq */
3572 if (tx_seq_offset < expected_tx_seq_offset)
3573 goto drop;
3574
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003575 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003576
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003577 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003578
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003579 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003580 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003581
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003582 __skb_queue_head_init(&chan->srej_q);
3583 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003584 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003585
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003586 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003587
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003588 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003589
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003590 del_timer(&chan->ack_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003591 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003592 return 0;
3593
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003594expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003595 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003596
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003597 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003598 bt_cb(skb)->tx_seq = tx_seq;
3599 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003600 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003601 return 0;
3602 }
3603
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003604 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003605 if (err < 0)
3606 return 0;
3607
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003608 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003609 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3610 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003611 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003612 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003613 }
3614
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003615 __mod_ack_timer();
3616
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003617 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3618 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003619 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003620
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003621 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003622
3623drop:
3624 kfree_skb(skb);
3625 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003626}
3627
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003628static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003629{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003630 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003631 rx_control);
3632
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003633 chan->expected_ack_seq = __get_reqseq(rx_control);
3634 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003635
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003636 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003637 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3638 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3639 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003640 (chan->unacked_frames > 0))
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003641 __mod_retrans_timer();
3642
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003643 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3644 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003645 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003646 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003647 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003648
3649 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003650 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003651
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003652 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3653 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003654 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003655 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003656
3657 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003658 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003659 (chan->unacked_frames > 0))
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003660 __mod_retrans_timer();
3661
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003662 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3663 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3664 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003665 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003666 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003667 }
3668}
3669
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003670static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003671{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003672 u8 tx_seq = __get_reqseq(rx_control);
3673
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003674 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003675
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003676 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003677
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003678 chan->expected_ack_seq = tx_seq;
3679 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003680
3681 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003682 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3683 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003684 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003685 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003686 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003687 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003688
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003689 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3690 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003691 }
3692}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003693static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003694{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003695 u8 tx_seq = __get_reqseq(rx_control);
3696
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003697 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003698
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003699 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003700
3701 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003702 chan->expected_ack_seq = tx_seq;
3703 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003704
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003705 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3706 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003707
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003708 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003709
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003710 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003711 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003712 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003713 }
3714 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003715 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003716 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003717 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003718 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003719 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003720 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003721 l2cap_retransmit_one_frame(chan, tx_seq);
3722 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003723 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003724 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003725 }
3726 }
3727}
3728
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003729static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003730{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003731 u8 tx_seq = __get_reqseq(rx_control);
3732
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003733 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003734
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003735 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003736 chan->expected_ack_seq = tx_seq;
3737 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003738
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003739 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003740 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003741
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003742 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003743 del_timer(&chan->retrans_timer);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003744 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003745 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003746 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003747 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003748
3749 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003750 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003751 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003752 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003753}
3754
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003755static 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 -03003756{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003757 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003758
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003759 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003760 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003761 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003762 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003763 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003764 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003765 }
3766
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003767 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3768 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003769 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003770 break;
3771
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003772 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003773 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003774 break;
3775
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003776 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003777 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003778 break;
3779
3780 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003781 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003782 break;
3783 }
3784
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003785 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003786 return 0;
3787}
3788
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003789static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3790{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003791 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003792 u16 control;
3793 u8 req_seq;
3794 int len, next_tx_seq_offset, req_seq_offset;
3795
3796 control = get_unaligned_le16(skb->data);
3797 skb_pull(skb, 2);
3798 len = skb->len;
3799
3800 /*
3801 * We can just drop the corrupted I-frame here.
3802 * Receiver will miss it and start proper recovery
3803 * procedures and ask retransmission.
3804 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003805 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003806 goto drop;
3807
3808 if (__is_sar_start(control) && __is_iframe(control))
3809 len -= 2;
3810
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003811 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003812 len -= 2;
3813
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003814 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003815 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003816 goto drop;
3817 }
3818
3819 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003820 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003821 if (req_seq_offset < 0)
3822 req_seq_offset += 64;
3823
3824 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003825 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003826 if (next_tx_seq_offset < 0)
3827 next_tx_seq_offset += 64;
3828
3829 /* check for invalid req-seq */
3830 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003831 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003832 goto drop;
3833 }
3834
3835 if (__is_iframe(control)) {
3836 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003837 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003838 goto drop;
3839 }
3840
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003841 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003842 } else {
3843 if (len != 0) {
3844 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003845 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003846 goto drop;
3847 }
3848
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003849 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003850 }
3851
3852 return 0;
3853
3854drop:
3855 kfree_skb(skb);
3856 return 0;
3857}
3858
Linus Torvalds1da177e2005-04-16 15:20:36 -07003859static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3860{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003861 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003862 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003863 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003864 u8 tx_seq;
3865 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003866
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003867 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003868 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003869 BT_DBG("unknown cid 0x%4.4x", cid);
3870 goto drop;
3871 }
3872
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003873 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003874
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003875 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003876
3877 if (sk->sk_state != BT_CONNECTED)
3878 goto drop;
3879
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003880 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003881 case L2CAP_MODE_BASIC:
3882 /* If socket recv buffers overflows we drop data here
3883 * which is *bad* because L2CAP has to be reliable.
3884 * But we don't have any other choice. L2CAP doesn't
3885 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003886
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003887 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003888 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003889
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003890 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003891 goto done;
3892 break;
3893
3894 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003895 if (!sock_owned_by_user(sk)) {
3896 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003897 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003898 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003899 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003900 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003901
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003902 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003903
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003904 case L2CAP_MODE_STREAMING:
3905 control = get_unaligned_le16(skb->data);
3906 skb_pull(skb, 2);
3907 len = skb->len;
3908
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003909 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003910 goto drop;
3911
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003912 if (__is_sar_start(control))
3913 len -= 2;
3914
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003915 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003916 len -= 2;
3917
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003918 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003919 goto drop;
3920
3921 tx_seq = __get_txseq(control);
3922
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003923 if (chan->expected_tx_seq == tx_seq)
3924 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003925 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003926 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003927
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003928 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003929
3930 goto done;
3931
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003932 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003933 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003934 break;
3935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003936
3937drop:
3938 kfree_skb(skb);
3939
3940done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003941 if (sk)
3942 bh_unlock_sock(sk);
3943
Linus Torvalds1da177e2005-04-16 15:20:36 -07003944 return 0;
3945}
3946
Al Viro8e036fc2007-07-29 00:16:36 -07003947static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003949 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003950 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003951
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003952 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3953 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003954 goto drop;
3955
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003956 sk = chan->sk;
3957
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003958 bh_lock_sock(sk);
3959
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960 BT_DBG("sk %p, len %d", sk, skb->len);
3961
3962 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3963 goto drop;
3964
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003965 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 goto drop;
3967
Gustavo F. Padovan23070492011-05-16 17:57:22 -03003968 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07003969 goto done;
3970
3971drop:
3972 kfree_skb(skb);
3973
3974done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003975 if (sk)
3976 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003977 return 0;
3978}
3979
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003980static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3981{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003982 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003983 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003984
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003985 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
3986 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003987 goto drop;
3988
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003989 sk = chan->sk;
3990
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003991 bh_lock_sock(sk);
3992
3993 BT_DBG("sk %p, len %d", sk, skb->len);
3994
3995 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3996 goto drop;
3997
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003998 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003999 goto drop;
4000
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004001 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004002 goto done;
4003
4004drop:
4005 kfree_skb(skb);
4006
4007done:
4008 if (sk)
4009 bh_unlock_sock(sk);
4010 return 0;
4011}
4012
Linus Torvalds1da177e2005-04-16 15:20:36 -07004013static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4014{
4015 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004016 u16 cid, len;
4017 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004018
4019 skb_pull(skb, L2CAP_HDR_SIZE);
4020 cid = __le16_to_cpu(lh->cid);
4021 len = __le16_to_cpu(lh->len);
4022
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004023 if (len != skb->len) {
4024 kfree_skb(skb);
4025 return;
4026 }
4027
Linus Torvalds1da177e2005-04-16 15:20:36 -07004028 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4029
4030 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004031 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004032 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004033 l2cap_sig_channel(conn, skb);
4034 break;
4035
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004036 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004037 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 skb_pull(skb, 2);
4039 l2cap_conless_channel(conn, psm, skb);
4040 break;
4041
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004042 case L2CAP_CID_LE_DATA:
4043 l2cap_att_channel(conn, cid, skb);
4044 break;
4045
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 default:
4047 l2cap_data_channel(conn, cid, skb);
4048 break;
4049 }
4050}
4051
4052/* ---- L2CAP interface with lower layer (HCI) ---- */
4053
4054static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4055{
4056 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004057 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058
4059 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004060 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004061
4062 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4063
4064 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004065 read_lock(&chan_list_lock);
4066 list_for_each_entry(c, &chan_list, global_l) {
4067 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004068
Linus Torvalds1da177e2005-04-16 15:20:36 -07004069 if (sk->sk_state != BT_LISTEN)
4070 continue;
4071
4072 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004073 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004074 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004075 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004076 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004077 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4078 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004079 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004080 lm2 |= HCI_LM_MASTER;
4081 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004082 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004083 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004084
4085 return exact ? lm1 : lm2;
4086}
4087
4088static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4089{
Marcel Holtmann01394182006-07-03 10:02:46 +02004090 struct l2cap_conn *conn;
4091
Linus Torvalds1da177e2005-04-16 15:20:36 -07004092 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4093
Ville Tervoacd7d372011-02-10 22:38:49 -03004094 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004095 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096
4097 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004098 conn = l2cap_conn_add(hcon, status);
4099 if (conn)
4100 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004101 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004102 l2cap_conn_del(hcon, bt_err(status));
4103
4104 return 0;
4105}
4106
Marcel Holtmann2950f212009-02-12 14:02:50 +01004107static int l2cap_disconn_ind(struct hci_conn *hcon)
4108{
4109 struct l2cap_conn *conn = hcon->l2cap_data;
4110
4111 BT_DBG("hcon %p", hcon);
4112
4113 if (hcon->type != ACL_LINK || !conn)
4114 return 0x13;
4115
4116 return conn->disc_reason;
4117}
4118
4119static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004120{
4121 BT_DBG("hcon %p reason %d", hcon, reason);
4122
Ville Tervoacd7d372011-02-10 22:38:49 -03004123 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004124 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125
4126 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004127
Linus Torvalds1da177e2005-04-16 15:20:36 -07004128 return 0;
4129}
4130
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004131static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004132{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004133 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004134 return;
4135
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004136 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004137 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004138 l2cap_chan_clear_timer(chan);
4139 l2cap_chan_set_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004140 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004141 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004142 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004143 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004144 l2cap_chan_clear_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004145 }
4146}
4147
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004148static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004149{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004150 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004151 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004152
Marcel Holtmann01394182006-07-03 10:02:46 +02004153 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004154 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004155
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 BT_DBG("conn %p", conn);
4157
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004158 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004160 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004161 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004162
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 bh_lock_sock(sk);
4164
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004165 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004166 bh_unlock_sock(sk);
4167 continue;
4168 }
4169
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004170 if (!status && (sk->sk_state == BT_CONNECTED ||
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004171 sk->sk_state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004172 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004173 bh_unlock_sock(sk);
4174 continue;
4175 }
4176
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004177 if (sk->sk_state == BT_CONNECT) {
4178 if (!status) {
4179 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004180 req.scid = cpu_to_le16(chan->scid);
4181 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004182
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004183 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004184 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004185
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004186 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004187 L2CAP_CONN_REQ, sizeof(req), &req);
4188 } else {
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004189 l2cap_chan_clear_timer(chan);
4190 l2cap_chan_set_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004191 }
4192 } else if (sk->sk_state == BT_CONNECT2) {
4193 struct l2cap_conn_rsp rsp;
4194 __u16 result;
4195
4196 if (!status) {
4197 sk->sk_state = BT_CONFIG;
4198 result = L2CAP_CR_SUCCESS;
4199 } else {
4200 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004201 l2cap_chan_set_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004202 result = L2CAP_CR_SEC_BLOCK;
4203 }
4204
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004205 rsp.scid = cpu_to_le16(chan->dcid);
4206 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004207 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004208 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004209 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4210 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004211 }
4212
Linus Torvalds1da177e2005-04-16 15:20:36 -07004213 bh_unlock_sock(sk);
4214 }
4215
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004216 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004217
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 return 0;
4219}
4220
4221static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4222{
4223 struct l2cap_conn *conn = hcon->l2cap_data;
4224
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004225 if (!conn)
4226 conn = l2cap_conn_add(hcon, 0);
4227
4228 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 goto drop;
4230
4231 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4232
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004233 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004235 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004236 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237 int len;
4238
4239 if (conn->rx_len) {
4240 BT_ERR("Unexpected start frame (len %d)", skb->len);
4241 kfree_skb(conn->rx_skb);
4242 conn->rx_skb = NULL;
4243 conn->rx_len = 0;
4244 l2cap_conn_unreliable(conn, ECOMM);
4245 }
4246
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004247 /* Start fragment always begin with Basic L2CAP header */
4248 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 BT_ERR("Frame is too short (len %d)", skb->len);
4250 l2cap_conn_unreliable(conn, ECOMM);
4251 goto drop;
4252 }
4253
4254 hdr = (struct l2cap_hdr *) skb->data;
4255 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004256 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004257
4258 if (len == skb->len) {
4259 /* Complete frame received */
4260 l2cap_recv_frame(conn, skb);
4261 return 0;
4262 }
4263
4264 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4265
4266 if (skb->len > len) {
4267 BT_ERR("Frame is too long (len %d, expected len %d)",
4268 skb->len, len);
4269 l2cap_conn_unreliable(conn, ECOMM);
4270 goto drop;
4271 }
4272
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004273 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004274
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004275 if (chan && chan->sk) {
4276 struct sock *sk = chan->sk;
4277
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004278 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004279 BT_ERR("Frame exceeding recv MTU (len %d, "
4280 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004281 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004282 bh_unlock_sock(sk);
4283 l2cap_conn_unreliable(conn, ECOMM);
4284 goto drop;
4285 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004286 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004287 }
4288
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004290 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4291 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 goto drop;
4293
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004294 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004295 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 conn->rx_len = len - skb->len;
4297 } else {
4298 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4299
4300 if (!conn->rx_len) {
4301 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4302 l2cap_conn_unreliable(conn, ECOMM);
4303 goto drop;
4304 }
4305
4306 if (skb->len > conn->rx_len) {
4307 BT_ERR("Fragment is too long (len %d, expected %d)",
4308 skb->len, conn->rx_len);
4309 kfree_skb(conn->rx_skb);
4310 conn->rx_skb = NULL;
4311 conn->rx_len = 0;
4312 l2cap_conn_unreliable(conn, ECOMM);
4313 goto drop;
4314 }
4315
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004316 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004317 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 conn->rx_len -= skb->len;
4319
4320 if (!conn->rx_len) {
4321 /* Complete frame received */
4322 l2cap_recv_frame(conn, conn->rx_skb);
4323 conn->rx_skb = NULL;
4324 }
4325 }
4326
4327drop:
4328 kfree_skb(skb);
4329 return 0;
4330}
4331
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004332static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004333{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004334 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004335
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004336 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004337
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004338 list_for_each_entry(c, &chan_list, global_l) {
4339 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004341 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 +01004342 batostr(&bt_sk(sk)->src),
4343 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004344 sk->sk_state, __le16_to_cpu(c->psm),
4345 c->scid, c->dcid, c->imtu, c->omtu,
4346 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004347 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004348
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004349 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004350
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004351 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352}
4353
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004354static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4355{
4356 return single_open(file, l2cap_debugfs_show, inode->i_private);
4357}
4358
4359static const struct file_operations l2cap_debugfs_fops = {
4360 .open = l2cap_debugfs_open,
4361 .read = seq_read,
4362 .llseek = seq_lseek,
4363 .release = single_release,
4364};
4365
4366static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367
Linus Torvalds1da177e2005-04-16 15:20:36 -07004368static struct hci_proto l2cap_hci_proto = {
4369 .name = "L2CAP",
4370 .id = HCI_PROTO_L2CAP,
4371 .connect_ind = l2cap_connect_ind,
4372 .connect_cfm = l2cap_connect_cfm,
4373 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004374 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004375 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 .recv_acldata = l2cap_recv_acldata
4377};
4378
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004379int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380{
4381 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004382
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004383 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 if (err < 0)
4385 return err;
4386
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004387 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004388 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004389 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 goto error;
4391 }
4392
4393 err = hci_register_proto(&l2cap_hci_proto);
4394 if (err < 0) {
4395 BT_ERR("L2CAP protocol registration failed");
4396 bt_sock_unregister(BTPROTO_L2CAP);
4397 goto error;
4398 }
4399
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004400 if (bt_debugfs) {
4401 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4402 bt_debugfs, NULL, &l2cap_debugfs_fops);
4403 if (!l2cap_debugfs)
4404 BT_ERR("Failed to create L2CAP debug file");
4405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 return 0;
4408
4409error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004410 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004411 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 return err;
4413}
4414
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004415void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004417 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004419 flush_workqueue(_busy_wq);
4420 destroy_workqueue(_busy_wq);
4421
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4423 BT_ERR("L2CAP protocol unregistration failed");
4424
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004425 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426}
4427
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004428module_param(disable_ertm, bool, 0644);
4429MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");