blob: fce48f9b85bff3d424d49b070b87733881010345 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
57
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020058int disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020059
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070060static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Marcel Holtmanne1027a72009-02-09 09:18:02 +010061static u8 l2cap_fixed_chan[8] = { 0x02, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030063static struct workqueue_struct *_busy_wq;
64
Gustavo F. Padovan23691d72011-04-27 18:26:32 -030065LIST_HEAD(chan_list);
66DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Gustavo F. Padovan1890d362010-05-01 16:15:44 -030068static void l2cap_busy_work(struct work_struct *work);
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
71 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
73 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030074static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030075static void l2cap_send_disconn_req(struct l2cap_conn *conn,
76 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030078static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
79
Marcel Holtmann01394182006-07-03 10:02:46 +020080/* ---- L2CAP channels ---- */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030081static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020082{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030083 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030084
85 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030086 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030087 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020088 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030089 return NULL;
90
Marcel Holtmann01394182006-07-03 10:02:46 +020091}
92
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030093static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020094{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030095 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030096
97 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030098 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030099 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200100 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200102}
103
104/* Find channel with given SCID.
105 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200107{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300108 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109
110 read_lock(&conn->chan_lock);
111 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300112 if (c)
113 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300115 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200116}
117
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300118static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200119{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300120 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300121
122 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300123 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200125 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200127}
128
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200130{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300131 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300132
133 read_lock(&conn->chan_lock);
134 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300135 if (c)
136 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300138 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200139}
140
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300141static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300142{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300143 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300144
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300145 list_for_each_entry(c, &chan_list, global_l) {
146 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300147 goto found;
148 }
149
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300150 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300151found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300152 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300153}
154
155int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
156{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300157 int err;
158
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300159 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300161 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300162 err = -EADDRINUSE;
163 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300164 }
165
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300166 if (psm) {
167 chan->psm = psm;
168 chan->sport = psm;
169 err = 0;
170 } else {
171 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300172
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300173 err = -EINVAL;
174 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300175 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 chan->psm = cpu_to_le16(p);
177 chan->sport = cpu_to_le16(p);
178 err = 0;
179 break;
180 }
181 }
182
183done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300184 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300185 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300186}
187
188int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
189{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300190 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300191
192 chan->scid = scid;
193
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300194 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300195
196 return 0;
197}
198
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300199static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200200{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300201 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200202
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300203 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300204 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200205 return cid;
206 }
207
208 return 0;
209}
210
Gustavo F. 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
219void l2cap_chan_clear_timer(struct l2cap_chan *chan)
220{
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
253 __l2cap_chan_close(chan, reason);
254
255 bh_unlock_sock(sk);
256
257 l2cap_sock_kill(sk);
258 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 -0300386/* Must be called on unlocked socket. */
387static void l2cap_chan_close(struct sock *sk)
388{
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300389 l2cap_chan_clear_timer(l2cap_pi(sk)->chan);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300390 lock_sock(sk);
391 __l2cap_chan_close(l2cap_pi(sk)->chan, ECONNRESET);
392 release_sock(sk);
393 l2cap_sock_kill(sk);
394}
395
396static void l2cap_chan_cleanup_listen(struct sock *parent)
397{
398 struct sock *sk;
399
400 BT_DBG("parent %p", parent);
401
402 /* Close not yet accepted channels */
403 while ((sk = bt_accept_dequeue(parent, NULL)))
404 l2cap_chan_close(sk);
405
406 parent->sk_state = BT_CLOSED;
407 sock_set_flag(parent, SOCK_ZAPPED);
408}
409
410void __l2cap_chan_close(struct l2cap_chan *chan, int reason)
411{
412 struct l2cap_conn *conn = chan->conn;
413 struct sock *sk = chan->sk;
414
415 BT_DBG("chan %p state %d socket %p", chan, sk->sk_state, sk->sk_socket);
416
417 switch (sk->sk_state) {
418 case BT_LISTEN:
419 l2cap_chan_cleanup_listen(sk);
420 break;
421
422 case BT_CONNECTED:
423 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300424 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300425 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300426 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300427 l2cap_send_disconn_req(conn, chan, reason);
428 } else
429 l2cap_chan_del(chan, reason);
430 break;
431
432 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300433 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300434 conn->hcon->type == ACL_LINK) {
435 struct l2cap_conn_rsp rsp;
436 __u16 result;
437
438 if (bt_sk(sk)->defer_setup)
439 result = L2CAP_CR_SEC_BLOCK;
440 else
441 result = L2CAP_CR_BAD_PSM;
442
443 rsp.scid = cpu_to_le16(chan->dcid);
444 rsp.dcid = cpu_to_le16(chan->scid);
445 rsp.result = cpu_to_le16(result);
446 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
447 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
448 sizeof(rsp), &rsp);
449 }
450
451 l2cap_chan_del(chan, reason);
452 break;
453
454 case BT_CONNECT:
455 case BT_DISCONN:
456 l2cap_chan_del(chan, reason);
457 break;
458
459 default:
460 sock_set_flag(sk, SOCK_ZAPPED);
461 break;
462 }
463}
464
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300465static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530466{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300467 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300468 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530469 case BT_SECURITY_HIGH:
470 return HCI_AT_DEDICATED_BONDING_MITM;
471 case BT_SECURITY_MEDIUM:
472 return HCI_AT_DEDICATED_BONDING;
473 default:
474 return HCI_AT_NO_BONDING;
475 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300476 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300477 if (chan->sec_level == BT_SECURITY_LOW)
478 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530479
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300480 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530481 return HCI_AT_NO_BONDING_MITM;
482 else
483 return HCI_AT_NO_BONDING;
484 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300485 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530486 case BT_SECURITY_HIGH:
487 return HCI_AT_GENERAL_BONDING_MITM;
488 case BT_SECURITY_MEDIUM:
489 return HCI_AT_GENERAL_BONDING;
490 default:
491 return HCI_AT_NO_BONDING;
492 }
493 }
494}
495
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200496/* Service level security */
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300497static inline int l2cap_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200498{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300499 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100500 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200501
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300502 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100503
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300504 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200505}
506
Gustavo F. Padovan68983252011-02-04 03:02:31 -0200507u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200508{
509 u8 id;
510
511 /* Get next available identificator.
512 * 1 - 128 are used by kernel.
513 * 129 - 199 are reserved.
514 * 200 - 254 are used by utilities like l2ping, etc.
515 */
516
517 spin_lock_bh(&conn->lock);
518
519 if (++conn->tx_ident > 128)
520 conn->tx_ident = 1;
521
522 id = conn->tx_ident;
523
524 spin_unlock_bh(&conn->lock);
525
526 return id;
527}
528
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300529static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200530{
531 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200532 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200533
534 BT_DBG("code 0x%2.2x", code);
535
536 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300537 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200538
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200539 if (lmp_no_flush_capable(conn->hcon->hdev))
540 flags = ACL_START_NO_FLUSH;
541 else
542 flags = ACL_START;
543
544 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
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300597 hci_send_acl(chan->conn->hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300598}
599
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300600static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300601{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300602 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300603 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300604 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300605 } else
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300606 control |= L2CAP_SUPER_RCV_READY;
607
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -0300608 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300609
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300610 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300611}
612
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300613static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300614{
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300615 return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300616}
617
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300618static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200619{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300620 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200621
622 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100623 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
624 return;
625
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300626 if (l2cap_check_security(chan) &&
627 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200628 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300629 req.scid = cpu_to_le16(chan->scid);
630 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200631
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300632 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300633 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200634
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300635 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
636 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200637 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200638 } else {
639 struct l2cap_info_req req;
640 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
641
642 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
643 conn->info_ident = l2cap_get_ident(conn);
644
645 mod_timer(&conn->info_timer, jiffies +
646 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
647
648 l2cap_send_cmd(conn, conn->info_ident,
649 L2CAP_INFO_REQ, sizeof(req), &req);
650 }
651}
652
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300653static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
654{
655 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300656 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300657 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
658
659 switch (mode) {
660 case L2CAP_MODE_ERTM:
661 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
662 case L2CAP_MODE_STREAMING:
663 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
664 default:
665 return 0x00;
666 }
667}
668
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300669static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300670{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300671 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300672 struct l2cap_disconn_req req;
673
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300674 if (!conn)
675 return;
676
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300677 sk = chan->sk;
678
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300679 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300680 del_timer(&chan->retrans_timer);
681 del_timer(&chan->monitor_timer);
682 del_timer(&chan->ack_timer);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300683 }
684
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300685 req.dcid = cpu_to_le16(chan->dcid);
686 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300687 l2cap_send_cmd(conn, l2cap_get_ident(conn),
688 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300689
690 sk->sk_state = BT_DISCONN;
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300691 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300692}
693
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200695static void l2cap_conn_start(struct l2cap_conn *conn)
696{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300697 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200698
699 BT_DBG("conn %p", conn);
700
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300701 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200702
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300703 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300704 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300705
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200706 bh_lock_sock(sk);
707
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300708 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200709 bh_unlock_sock(sk);
710 continue;
711 }
712
713 if (sk->sk_state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300714 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300715
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300716 if (!l2cap_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300717 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300718 bh_unlock_sock(sk);
719 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200720 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300721
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300722 if (!l2cap_mode_supported(chan->mode,
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300723 conn->feat_mask)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300724 && chan->conf_state &
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300725 L2CAP_CONF_STATE2_DEVICE) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300726 /* __l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300727 * so release the lock */
728 read_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300729 __l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300730 read_lock_bh(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300731 bh_unlock_sock(sk);
732 continue;
733 }
734
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300735 req.scid = cpu_to_le16(chan->scid);
736 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300737
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300738 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300739 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300740
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300741 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
742 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300743
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200744 } else if (sk->sk_state == BT_CONNECT2) {
745 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300746 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300747 rsp.scid = cpu_to_le16(chan->dcid);
748 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200749
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300750 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100751 if (bt_sk(sk)->defer_setup) {
752 struct sock *parent = bt_sk(sk)->parent;
753 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
754 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
755 parent->sk_data_ready(parent, 0);
756
757 } else {
758 sk->sk_state = BT_CONFIG;
759 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
760 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
761 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200762 } else {
763 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
764 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
765 }
766
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300767 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
768 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300769
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300770 if (chan->conf_state & L2CAP_CONF_REQ_SENT ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300771 rsp.result != L2CAP_CR_SUCCESS) {
772 bh_unlock_sock(sk);
773 continue;
774 }
775
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300776 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300777 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300778 l2cap_build_conf_req(chan, buf), buf);
779 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200780 }
781
782 bh_unlock_sock(sk);
783 }
784
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300785 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200786}
787
Ville Tervob62f3282011-02-10 22:38:50 -0300788/* Find socket with cid and source bdaddr.
789 * Returns closest match, locked.
790 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300791static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300792{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300793 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300794
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300795 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300796
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300797 list_for_each_entry(c, &chan_list, global_l) {
798 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300799
Ville Tervob62f3282011-02-10 22:38:50 -0300800 if (state && sk->sk_state != state)
801 continue;
802
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300803 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300804 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300805 if (!bacmp(&bt_sk(sk)->src, src)) {
806 read_unlock(&chan_list_lock);
807 return c;
808 }
Ville Tervob62f3282011-02-10 22:38:50 -0300809
810 /* Closest match */
811 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300812 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300813 }
814 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300815
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300816 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300817
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300818 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300819}
820
821static void l2cap_le_conn_ready(struct l2cap_conn *conn)
822{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300823 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300824 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300825
826 BT_DBG("");
827
828 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300829 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300830 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300831 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300832 return;
833
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300834 parent = pchan->sk;
835
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300836 bh_lock_sock(parent);
837
Ville Tervob62f3282011-02-10 22:38:50 -0300838 /* Check for backlog size */
839 if (sk_acceptq_is_full(parent)) {
840 BT_DBG("backlog full %d", parent->sk_ack_backlog);
841 goto clean;
842 }
843
844 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
845 if (!sk)
846 goto clean;
847
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300848 chan = l2cap_chan_create(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300849 if (!chan) {
850 l2cap_sock_kill(sk);
851 goto clean;
852 }
853
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300854 l2cap_pi(sk)->chan = chan;
855
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300856 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300857
858 hci_conn_hold(conn->hcon);
859
860 l2cap_sock_init(sk, parent);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300861
Ville Tervob62f3282011-02-10 22:38:50 -0300862 bacpy(&bt_sk(sk)->src, conn->src);
863 bacpy(&bt_sk(sk)->dst, conn->dst);
864
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300865 bt_accept_enqueue(parent, sk);
866
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300867 __l2cap_chan_add(conn, chan);
868
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300869 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300870
871 sk->sk_state = BT_CONNECTED;
872 parent->sk_data_ready(parent, 0);
873
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300874 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300875
876clean:
877 bh_unlock_sock(parent);
878}
879
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200880static void l2cap_conn_ready(struct l2cap_conn *conn)
881{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300882 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200883
884 BT_DBG("conn %p", conn);
885
Ville Tervob62f3282011-02-10 22:38:50 -0300886 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
887 l2cap_le_conn_ready(conn);
888
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300889 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200890
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300891 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300892 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300893
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200894 bh_lock_sock(sk);
895
Ville Tervoacd7d372011-02-10 22:38:49 -0300896 if (conn->hcon->type == LE_LINK) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300897 l2cap_chan_clear_timer(chan);
Ville Tervoacd7d372011-02-10 22:38:49 -0300898 sk->sk_state = BT_CONNECTED;
899 sk->sk_state_change(sk);
900 }
901
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300902 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300903 l2cap_chan_clear_timer(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200904 sk->sk_state = BT_CONNECTED;
905 sk->sk_state_change(sk);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200906 } else if (sk->sk_state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300907 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200908
909 bh_unlock_sock(sk);
910 }
911
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300912 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200913}
914
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200915/* Notify sockets that we cannot guaranty reliability anymore */
916static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
917{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300918 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200919
920 BT_DBG("conn %p", conn);
921
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300922 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200923
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300924 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300925 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300926
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300927 if (chan->force_reliable)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200928 sk->sk_err = err;
929 }
930
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300931 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200932}
933
934static void l2cap_info_timeout(unsigned long arg)
935{
936 struct l2cap_conn *conn = (void *) arg;
937
Marcel Holtmann984947d2009-02-06 23:35:19 +0100938 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100939 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100940
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200941 l2cap_conn_start(conn);
942}
943
Linus Torvalds1da177e2005-04-16 15:20:36 -0700944static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
945{
Marcel Holtmann01394182006-07-03 10:02:46 +0200946 struct l2cap_conn *conn = hcon->l2cap_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947
Marcel Holtmann01394182006-07-03 10:02:46 +0200948 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 return conn;
950
Marcel Holtmann01394182006-07-03 10:02:46 +0200951 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
952 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954
955 hcon->l2cap_data = conn;
956 conn->hcon = hcon;
957
Marcel Holtmann01394182006-07-03 10:02:46 +0200958 BT_DBG("hcon %p conn %p", hcon, conn);
959
Ville Tervoacd7d372011-02-10 22:38:49 -0300960 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
961 conn->mtu = hcon->hdev->le_mtu;
962 else
963 conn->mtu = hcon->hdev->acl_mtu;
964
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965 conn->src = &hcon->hdev->bdaddr;
966 conn->dst = &hcon->dst;
967
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200968 conn->feat_mask = 0;
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300971 rwlock_init(&conn->chan_lock);
972
973 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974
Ville Tervob62f3282011-02-10 22:38:50 -0300975 if (hcon->type != LE_LINK)
976 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +0000977 (unsigned long) conn);
978
Marcel Holtmann2950f212009-02-12 14:02:50 +0100979 conn->disc_reason = 0x13;
980
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 return conn;
982}
983
Marcel Holtmann01394182006-07-03 10:02:46 +0200984static void l2cap_conn_del(struct hci_conn *hcon, int err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700985{
Marcel Holtmann01394182006-07-03 10:02:46 +0200986 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300987 struct l2cap_chan *chan, *l;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700988 struct sock *sk;
989
Marcel Holtmann01394182006-07-03 10:02:46 +0200990 if (!conn)
991 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992
993 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
994
Wei Yongjun7585b972009-02-25 18:29:52 +0800995 kfree_skb(conn->rx_skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996
997 /* Kill channels */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300998 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300999 sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 bh_lock_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001001 l2cap_chan_del(chan, err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002 bh_unlock_sock(sk);
1003 l2cap_sock_kill(sk);
1004 }
1005
Dave Young8e8440f2008-03-03 12:18:55 -08001006 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1007 del_timer_sync(&conn->info_timer);
Thomas Gleixner3ab22732008-02-26 17:42:56 -08001008
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 hcon->l2cap_data = NULL;
1010 kfree(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011}
1012
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001013static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001014{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001015 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001016 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001017 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018}
1019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021
1022/* Find socket with psm and source bdaddr.
1023 * Returns closest match.
1024 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001025static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001026{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001027 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001029 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001030
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001031 list_for_each_entry(c, &chan_list, global_l) {
1032 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001033
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034 if (state && sk->sk_state != state)
1035 continue;
1036
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001037 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001039 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001040 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001041 return c;
1042 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
1044 /* Closest match */
1045 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001046 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 }
1048 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001050 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001051
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001052 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053}
1054
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001055int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001057 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 bdaddr_t *src = &bt_sk(sk)->src;
1059 bdaddr_t *dst = &bt_sk(sk)->dst;
1060 struct l2cap_conn *conn;
1061 struct hci_conn *hcon;
1062 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001063 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001064 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001066 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001067 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001069 hdev = hci_get_route(dst, src);
1070 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001071 return -EHOSTUNREACH;
1072
1073 hci_dev_lock_bh(hdev);
1074
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001075 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001076
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001077 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001078 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001079 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001080 else
1081 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001082 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001083
Ville Tervo30e76272011-02-22 16:10:53 -03001084 if (IS_ERR(hcon)) {
1085 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001087 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088
1089 conn = l2cap_conn_add(hcon, 0);
1090 if (!conn) {
1091 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001092 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093 goto done;
1094 }
1095
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096 /* Update source addr of the socket */
1097 bacpy(src, conn->src);
1098
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001099 l2cap_chan_add(conn, chan);
1100
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 sk->sk_state = BT_CONNECT;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03001102 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103
1104 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001105 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -03001106 l2cap_chan_clear_timer(chan);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001107 if (l2cap_check_security(chan))
Johan Hedbergd00ef242011-01-19 12:06:51 +05301108 sk->sk_state = BT_CONNECTED;
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001109 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001110 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 }
1112
Ville Tervo30e76272011-02-22 16:10:53 -03001113 err = 0;
1114
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115done:
1116 hci_dev_unlock_bh(hdev);
1117 hci_dev_put(hdev);
1118 return err;
1119}
1120
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001121int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001122{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001123 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001124 DECLARE_WAITQUEUE(wait, current);
1125 int err = 0;
1126 int timeo = HZ/5;
1127
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001128 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001129 while ((chan->unacked_frames > 0 && chan->conn)) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001130 set_current_state(TASK_INTERRUPTIBLE);
1131
1132 if (!timeo)
1133 timeo = HZ/5;
1134
1135 if (signal_pending(current)) {
1136 err = sock_intr_errno(timeo);
1137 break;
1138 }
1139
1140 release_sock(sk);
1141 timeo = schedule_timeout(timeo);
1142 lock_sock(sk);
1143
1144 err = sock_error(sk);
1145 if (err)
1146 break;
1147 }
1148 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001149 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001150 return err;
1151}
1152
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001153static void l2cap_monitor_timeout(unsigned long arg)
1154{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001155 struct l2cap_chan *chan = (void *) arg;
1156 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001157
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001158 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001159
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001160 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001161 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001162 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001163 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001164 return;
1165 }
1166
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001167 chan->retry_count++;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001168 __mod_monitor_timer();
1169
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001170 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001171 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001172}
1173
1174static void l2cap_retrans_timeout(unsigned long arg)
1175{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001176 struct l2cap_chan *chan = (void *) arg;
1177 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001178
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001179 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001180
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001181 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001182 chan->retry_count = 1;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001183 __mod_monitor_timer();
1184
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001185 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001186
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001187 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001188 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001189}
1190
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001191static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001192{
1193 struct sk_buff *skb;
1194
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001195 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001196 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001197 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001198 break;
1199
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001200 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001201 kfree_skb(skb);
1202
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001203 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001204 }
1205
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001206 if (!chan->unacked_frames)
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001207 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001208}
1209
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001210void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001211{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001212 struct hci_conn *hcon = chan->conn->hcon;
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001213 u16 flags;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001214
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001215 BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001216
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001217 if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02001218 flags = ACL_START_NO_FLUSH;
1219 else
1220 flags = ACL_START;
1221
1222 hci_send_acl(hcon, skb, flags);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001223}
1224
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001225void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001226{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001227 struct sk_buff *skb;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001228 u16 control, fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001229
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001230 while ((skb = skb_dequeue(&chan->tx_q))) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001231 control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001232 control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001233 put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001234
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001235 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001236 fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
1237 put_unaligned_le16(fcs, skb->data + skb->len - 2);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001238 }
1239
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001240 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001241
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001242 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001243 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001244}
1245
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001246static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001247{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001248 struct sk_buff *skb, *tx_skb;
1249 u16 control, fcs;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001250
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001251 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001252 if (!skb)
1253 return;
1254
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001255 do {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001256 if (bt_cb(skb)->tx_seq == tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001257 break;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001258
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001259 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001260 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001261
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001262 } while ((skb = skb_queue_next(&chan->tx_q, skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001263
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001264 if (chan->remote_max_tx &&
1265 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001266 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001267 return;
1268 }
1269
1270 tx_skb = skb_clone(skb, GFP_ATOMIC);
1271 bt_cb(skb)->retries++;
1272 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Ruiyi Zhanga429b512011-04-18 11:04:30 +08001273 control &= L2CAP_CTRL_SAR;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001274
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001275 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001276 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001277 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001278 }
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001279
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001280 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001281 | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001282
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001283 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1284
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001285 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001286 fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
1287 put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
1288 }
1289
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001290 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001291}
1292
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001293int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001294{
1295 struct sk_buff *skb, *tx_skb;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001296 struct sock *sk = chan->sk;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001297 u16 control, fcs;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001298 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001299
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001300 if (sk->sk_state != BT_CONNECTED)
1301 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001302
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001303 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001304
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001305 if (chan->remote_max_tx &&
1306 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001307 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001308 break;
1309 }
1310
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001311 tx_skb = skb_clone(skb, GFP_ATOMIC);
1312
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001313 bt_cb(skb)->retries++;
1314
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001315 control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001316 control &= L2CAP_CTRL_SAR;
1317
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001318 if (chan->conn_state & L2CAP_CONN_SEND_FBIT) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001319 control |= L2CAP_CTRL_FINAL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001320 chan->conn_state &= ~L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03001321 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001322 control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
1323 | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001324 put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
1325
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001326
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001327 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001328 fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
1329 put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
1330 }
1331
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001332 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001333
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001334 __mod_retrans_timer();
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001335
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001336 bt_cb(skb)->tx_seq = chan->next_tx_seq;
1337 chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001338
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301339 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001340 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301341
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001342 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001343
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001344 if (skb_queue_is_last(&chan->tx_q, skb))
1345 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001346 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001347 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001348
1349 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001350 }
1351
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001352 return nsent;
1353}
1354
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001355static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001356{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001357 int ret;
1358
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001359 if (!skb_queue_empty(&chan->tx_q))
1360 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001361
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001362 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001363 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001364 return ret;
1365}
1366
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001367static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001368{
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001369 u16 control = 0;
1370
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001371 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001372
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001373 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001374 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001375 chan->conn_state |= L2CAP_CONN_RNR_SENT;
1376 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001377 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001378 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001379
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001380 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001381 return;
1382
1383 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001384 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001385}
1386
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001387static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001388{
1389 struct srej_list *tail;
1390 u16 control;
1391
1392 control = L2CAP_SUPER_SELECT_REJECT;
1393 control |= L2CAP_CTRL_FINAL;
1394
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001395 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001396 control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
1397
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001398 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001399}
1400
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001401static 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 -07001402{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001403 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001404 struct sk_buff **frag;
1405 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001406
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001407 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001408 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409
1410 sent += count;
1411 len -= count;
1412
1413 /* Continuation fragments (no L2CAP header) */
1414 frag = &skb_shinfo(skb)->frag_list;
1415 while (len) {
1416 count = min_t(unsigned int, conn->mtu, len);
1417
1418 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1419 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001420 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001421 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1422 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001423
1424 sent += count;
1425 len -= count;
1426
1427 frag = &(*frag)->next;
1428 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001429
1430 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001431}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001432
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001433struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001434{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001435 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001436 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001437 struct sk_buff *skb;
1438 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1439 struct l2cap_hdr *lh;
1440
1441 BT_DBG("sk %p len %d", sk, (int)len);
1442
1443 count = min_t(unsigned int, (conn->mtu - hlen), len);
1444 skb = bt_skb_send_alloc(sk, count + hlen,
1445 msg->msg_flags & MSG_DONTWAIT, &err);
1446 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001447 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001448
1449 /* Create L2CAP header */
1450 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001451 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001452 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001453 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001454
1455 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1456 if (unlikely(err < 0)) {
1457 kfree_skb(skb);
1458 return ERR_PTR(err);
1459 }
1460 return skb;
1461}
1462
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001463struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001465 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001466 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001467 struct sk_buff *skb;
1468 int err, count, hlen = L2CAP_HDR_SIZE;
1469 struct l2cap_hdr *lh;
1470
1471 BT_DBG("sk %p len %d", sk, (int)len);
1472
1473 count = min_t(unsigned int, (conn->mtu - hlen), len);
1474 skb = bt_skb_send_alloc(sk, count + hlen,
1475 msg->msg_flags & MSG_DONTWAIT, &err);
1476 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001477 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001478
1479 /* Create L2CAP header */
1480 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001481 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001482 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1483
1484 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1485 if (unlikely(err < 0)) {
1486 kfree_skb(skb);
1487 return ERR_PTR(err);
1488 }
1489 return skb;
1490}
1491
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001492struct 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 -03001493{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001494 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001495 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001496 struct sk_buff *skb;
1497 int err, count, hlen = L2CAP_HDR_SIZE + 2;
1498 struct l2cap_hdr *lh;
1499
1500 BT_DBG("sk %p len %d", sk, (int)len);
1501
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001502 if (!conn)
1503 return ERR_PTR(-ENOTCONN);
1504
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001505 if (sdulen)
1506 hlen += 2;
1507
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001508 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001509 hlen += 2;
1510
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001511 count = min_t(unsigned int, (conn->mtu - hlen), len);
1512 skb = bt_skb_send_alloc(sk, count + hlen,
1513 msg->msg_flags & MSG_DONTWAIT, &err);
1514 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001515 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001516
1517 /* Create L2CAP header */
1518 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001519 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001520 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1521 put_unaligned_le16(control, skb_put(skb, 2));
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001522 if (sdulen)
1523 put_unaligned_le16(sdulen, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001524
1525 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1526 if (unlikely(err < 0)) {
1527 kfree_skb(skb);
1528 return ERR_PTR(err);
1529 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001530
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001531 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001532 put_unaligned_le16(0, skb_put(skb, 2));
1533
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001534 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001535 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536}
1537
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001538int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001539{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001540 struct sk_buff *skb;
1541 struct sk_buff_head sar_queue;
1542 u16 control;
1543 size_t size = 0;
1544
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001545 skb_queue_head_init(&sar_queue);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001546 control = L2CAP_SDU_START;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001547 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001548 if (IS_ERR(skb))
1549 return PTR_ERR(skb);
1550
1551 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001552 len -= chan->remote_mps;
1553 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001554
1555 while (len > 0) {
1556 size_t buflen;
1557
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001558 if (len > chan->remote_mps) {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001559 control = L2CAP_SDU_CONTINUE;
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001560 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001561 } else {
Gustavo F. Padovan44651b82010-05-01 16:15:43 -03001562 control = L2CAP_SDU_END;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001563 buflen = len;
1564 }
1565
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001566 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001567 if (IS_ERR(skb)) {
1568 skb_queue_purge(&sar_queue);
1569 return PTR_ERR(skb);
1570 }
1571
1572 __skb_queue_tail(&sar_queue, skb);
1573 len -= buflen;
1574 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001575 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001576 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1577 if (chan->tx_send_head == NULL)
1578 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001579
1580 return size;
1581}
1582
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001583int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
1584{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001585 struct sk_buff *skb;
1586 u16 control;
1587 int err;
1588
1589 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001590 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001591 skb = l2cap_create_connless_pdu(chan, msg, len);
1592 if (IS_ERR(skb))
1593 return PTR_ERR(skb);
1594
1595 l2cap_do_send(chan, skb);
1596 return len;
1597 }
1598
1599 switch (chan->mode) {
1600 case L2CAP_MODE_BASIC:
1601 /* Check outgoing MTU */
1602 if (len > chan->omtu)
1603 return -EMSGSIZE;
1604
1605 /* Create a basic PDU */
1606 skb = l2cap_create_basic_pdu(chan, msg, len);
1607 if (IS_ERR(skb))
1608 return PTR_ERR(skb);
1609
1610 l2cap_do_send(chan, skb);
1611 err = len;
1612 break;
1613
1614 case L2CAP_MODE_ERTM:
1615 case L2CAP_MODE_STREAMING:
1616 /* Entire SDU fits into one PDU */
1617 if (len <= chan->remote_mps) {
1618 control = L2CAP_SDU_UNSEGMENTED;
1619 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1620 0);
1621 if (IS_ERR(skb))
1622 return PTR_ERR(skb);
1623
1624 __skb_queue_tail(&chan->tx_q, skb);
1625
1626 if (chan->tx_send_head == NULL)
1627 chan->tx_send_head = skb;
1628
1629 } else {
1630 /* Segment SDU into multiples PDUs */
1631 err = l2cap_sar_segment_sdu(chan, msg, len);
1632 if (err < 0)
1633 return err;
1634 }
1635
1636 if (chan->mode == L2CAP_MODE_STREAMING) {
1637 l2cap_streaming_send(chan);
1638 err = len;
1639 break;
1640 }
1641
1642 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
1643 (chan->conn_state & L2CAP_CONN_WAIT_F)) {
1644 err = len;
1645 break;
1646 }
1647
1648 err = l2cap_ertm_send(chan);
1649 if (err >= 0)
1650 err = len;
1651
1652 break;
1653
1654 default:
1655 BT_DBG("bad state %1.1x", chan->mode);
1656 err = -EBADFD;
1657 }
1658
1659 return err;
1660}
1661
Linus Torvalds1da177e2005-04-16 15:20:36 -07001662static void l2cap_chan_ready(struct sock *sk)
1663{
1664 struct sock *parent = bt_sk(sk)->parent;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001665 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666
1667 BT_DBG("sk %p, parent %p", sk, parent);
1668
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001669 chan->conf_state = 0;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03001670 l2cap_chan_clear_timer(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001671
1672 if (!parent) {
1673 /* Outgoing channel.
1674 * Wake up socket sleeping on connect.
1675 */
1676 sk->sk_state = BT_CONNECTED;
1677 sk->sk_state_change(sk);
1678 } else {
1679 /* Incoming channel.
1680 * Wake up socket sleeping on accept.
1681 */
1682 parent->sk_data_ready(parent, 0);
1683 }
1684}
1685
1686/* Copy frame to all raw sockets on that connection */
1687static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1688{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001690 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001691
1692 BT_DBG("conn %p", conn);
1693
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001694 read_lock(&conn->chan_lock);
1695 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001696 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001697 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 continue;
1699
1700 /* Don't send frame to the socket it came from */
1701 if (skb->sk == sk)
1702 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001703 nskb = skb_clone(skb, GFP_ATOMIC);
1704 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001705 continue;
1706
1707 if (sock_queue_rcv_skb(sk, nskb))
1708 kfree_skb(nskb);
1709 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001710 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001711}
1712
1713/* ---- L2CAP signalling commands ---- */
1714static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1715 u8 code, u8 ident, u16 dlen, void *data)
1716{
1717 struct sk_buff *skb, **frag;
1718 struct l2cap_cmd_hdr *cmd;
1719 struct l2cap_hdr *lh;
1720 int len, count;
1721
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001722 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1723 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001724
1725 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1726 count = min_t(unsigned int, conn->mtu, len);
1727
1728 skb = bt_skb_alloc(count, GFP_ATOMIC);
1729 if (!skb)
1730 return NULL;
1731
1732 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001733 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001734
1735 if (conn->hcon->type == LE_LINK)
1736 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1737 else
1738 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739
1740 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1741 cmd->code = code;
1742 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001743 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744
1745 if (dlen) {
1746 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1747 memcpy(skb_put(skb, count), data, count);
1748 data += count;
1749 }
1750
1751 len -= skb->len;
1752
1753 /* Continuation fragments (no L2CAP header) */
1754 frag = &skb_shinfo(skb)->frag_list;
1755 while (len) {
1756 count = min_t(unsigned int, conn->mtu, len);
1757
1758 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1759 if (!*frag)
1760 goto fail;
1761
1762 memcpy(skb_put(*frag, count), data, count);
1763
1764 len -= count;
1765 data += count;
1766
1767 frag = &(*frag)->next;
1768 }
1769
1770 return skb;
1771
1772fail:
1773 kfree_skb(skb);
1774 return NULL;
1775}
1776
1777static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1778{
1779 struct l2cap_conf_opt *opt = *ptr;
1780 int len;
1781
1782 len = L2CAP_CONF_OPT_SIZE + opt->len;
1783 *ptr += len;
1784
1785 *type = opt->type;
1786 *olen = opt->len;
1787
1788 switch (opt->len) {
1789 case 1:
1790 *val = *((u8 *) opt->val);
1791 break;
1792
1793 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001794 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 break;
1796
1797 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001798 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 break;
1800
1801 default:
1802 *val = (unsigned long) opt->val;
1803 break;
1804 }
1805
1806 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1807 return len;
1808}
1809
Linus Torvalds1da177e2005-04-16 15:20:36 -07001810static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1811{
1812 struct l2cap_conf_opt *opt = *ptr;
1813
1814 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1815
1816 opt->type = type;
1817 opt->len = len;
1818
1819 switch (len) {
1820 case 1:
1821 *((u8 *) opt->val) = val;
1822 break;
1823
1824 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001825 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 break;
1827
1828 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001829 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 break;
1831
1832 default:
1833 memcpy(opt->val, (void *) val, len);
1834 break;
1835 }
1836
1837 *ptr += L2CAP_CONF_OPT_SIZE + len;
1838}
1839
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001840static void l2cap_ack_timeout(unsigned long arg)
1841{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001842 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001843
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001844 bh_lock_sock(chan->sk);
1845 l2cap_send_ack(chan);
1846 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001847}
1848
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001849static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001850{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001851 struct sock *sk = chan->sk;
1852
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001853 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001854 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001855 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001856 chan->num_acked = 0;
1857 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001858
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001859 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1860 (unsigned long) chan);
1861 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1862 (unsigned long) chan);
1863 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001864
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001865 skb_queue_head_init(&chan->srej_q);
1866 skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001867
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001868 INIT_LIST_HEAD(&chan->srej_l);
1869
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03001870 INIT_WORK(&chan->busy_work, l2cap_busy_work);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001871
1872 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001873}
1874
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001875static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1876{
1877 switch (mode) {
1878 case L2CAP_MODE_STREAMING:
1879 case L2CAP_MODE_ERTM:
1880 if (l2cap_mode_supported(mode, remote_feat_mask))
1881 return mode;
1882 /* fall through */
1883 default:
1884 return L2CAP_MODE_BASIC;
1885 }
1886}
1887
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03001888static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001891 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 void *ptr = req->data;
1893
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001894 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001895
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001896 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001897 goto done;
1898
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001899 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001900 case L2CAP_MODE_STREAMING:
1901 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001902 if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001903 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03001904
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03001905 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001906 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001907 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001908 break;
1909 }
1910
1911done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001912 if (chan->imtu != L2CAP_DEFAULT_MTU)
1913 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02001914
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03001915 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001916 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001917 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
1918 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001919 break;
1920
Gustavo F. Padovan62547752010-06-08 20:05:31 -03001921 rfc.mode = L2CAP_MODE_BASIC;
1922 rfc.txwin_size = 0;
1923 rfc.max_transmit = 0;
1924 rfc.retrans_timeout = 0;
1925 rfc.monitor_timeout = 0;
1926 rfc.max_pdu_size = 0;
1927
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001928 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1929 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001930 break;
1931
1932 case L2CAP_MODE_ERTM:
1933 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001934 rfc.txwin_size = chan->tx_win;
1935 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001936 rfc.retrans_timeout = 0;
1937 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001938 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001939 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1940 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001941
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001942 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1943 (unsigned long) &rfc);
1944
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001945 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001946 break;
1947
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001948 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001949 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001950 chan->fcs = L2CAP_FCS_NONE;
1951 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001952 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001953 break;
1954
1955 case L2CAP_MODE_STREAMING:
1956 rfc.mode = L2CAP_MODE_STREAMING;
1957 rfc.txwin_size = 0;
1958 rfc.max_transmit = 0;
1959 rfc.retrans_timeout = 0;
1960 rfc.monitor_timeout = 0;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001961 rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001962 if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
1963 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001964
Gustavo F. Padovan63406502010-08-03 23:49:29 -03001965 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
1966 (unsigned long) &rfc);
1967
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001968 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001969 break;
1970
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001971 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03001972 chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001973 chan->fcs = L2CAP_FCS_NONE;
1974 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001975 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07001976 break;
1977 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001979 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001980 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
1982 return ptr - data;
1983}
1984
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001985static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001987 struct l2cap_conf_rsp *rsp = data;
1988 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001989 void *req = chan->conf_req;
1990 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001991 int type, hint, olen;
1992 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02001993 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Marcel Holtmann861d6882007-10-20 13:37:06 +02001994 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001995 u16 result = L2CAP_CONF_SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001996
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03001997 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01001998
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02001999 while (len >= L2CAP_CONF_OPT_SIZE) {
2000 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002002 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002003 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002004
2005 switch (type) {
2006 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002007 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002008 break;
2009
2010 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002011 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002012 break;
2013
2014 case L2CAP_CONF_QOS:
2015 break;
2016
Marcel Holtmann6464f352007-10-20 13:39:51 +02002017 case L2CAP_CONF_RFC:
2018 if (olen == sizeof(rfc))
2019 memcpy(&rfc, (void *) val, olen);
2020 break;
2021
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002022 case L2CAP_CONF_FCS:
2023 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002024 chan->conf_state |= L2CAP_CONF_NO_FCS_RECV;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002025
2026 break;
2027
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002028 default:
2029 if (hint)
2030 break;
2031
2032 result = L2CAP_CONF_UNKNOWN;
2033 *((u8 *) ptr++) = type;
2034 break;
2035 }
2036 }
2037
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002038 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002039 goto done;
2040
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002041 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002042 case L2CAP_MODE_STREAMING:
2043 case L2CAP_MODE_ERTM:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002044 if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002045 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002046 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002047 break;
2048 }
2049
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002050 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002051 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002052
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002053 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002054 }
2055
2056done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002057 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002058 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002059 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002060
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002061 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002062 return -ECONNREFUSED;
2063
2064 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2065 sizeof(rfc), (unsigned long) &rfc);
2066 }
2067
2068
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002069 if (result == L2CAP_CONF_SUCCESS) {
2070 /* Configure output options and let the other side know
2071 * which ones we don't like. */
2072
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002073 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2074 result = L2CAP_CONF_UNACCEPT;
2075 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002076 chan->omtu = mtu;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002077 chan->conf_state |= L2CAP_CONF_MTU_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002078 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002079 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002080
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002081 switch (rfc.mode) {
2082 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002083 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002084 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002085 break;
2086
2087 case L2CAP_MODE_ERTM:
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002088 chan->remote_tx_win = rfc.txwin_size;
2089 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002090
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002091 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2092 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002093
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002094 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002095
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002096 rfc.retrans_timeout =
2097 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2098 rfc.monitor_timeout =
2099 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002100
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002101 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002102
2103 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2104 sizeof(rfc), (unsigned long) &rfc);
2105
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002106 break;
2107
2108 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002109 if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
2110 rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
Gustavo F. Padovan1c762152010-05-01 16:15:40 -03002111
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002112 chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002113
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002114 chan->conf_state |= L2CAP_CONF_MODE_DONE;
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002115
2116 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2117 sizeof(rfc), (unsigned long) &rfc);
2118
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002119 break;
2120
2121 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002122 result = L2CAP_CONF_UNACCEPT;
2123
2124 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002125 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002126 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002127
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002128 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002129 chan->conf_state |= L2CAP_CONF_OUTPUT_DONE;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002130 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002131 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002132 rsp->result = cpu_to_le16(result);
2133 rsp->flags = cpu_to_le16(0x0000);
2134
2135 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136}
2137
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002138static 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 -03002139{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002140 struct l2cap_conf_req *req = data;
2141 void *ptr = req->data;
2142 int type, olen;
2143 unsigned long val;
2144 struct l2cap_conf_rfc rfc;
2145
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002146 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002147
2148 while (len >= L2CAP_CONF_OPT_SIZE) {
2149 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2150
2151 switch (type) {
2152 case L2CAP_CONF_MTU:
2153 if (val < L2CAP_DEFAULT_MIN_MTU) {
2154 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002155 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002156 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002157 chan->imtu = val;
2158 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002159 break;
2160
2161 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002162 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002163 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002164 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002165 break;
2166
2167 case L2CAP_CONF_RFC:
2168 if (olen == sizeof(rfc))
2169 memcpy(&rfc, (void *)val, olen);
2170
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002171 if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002172 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002173 return -ECONNREFUSED;
2174
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002175 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002176
2177 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2178 sizeof(rfc), (unsigned long) &rfc);
2179 break;
2180 }
2181 }
2182
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002183 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002184 return -ECONNREFUSED;
2185
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002186 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002187
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002188 if (*result == L2CAP_CONF_SUCCESS) {
2189 switch (rfc.mode) {
2190 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002191 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2192 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2193 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002194 break;
2195 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002196 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002197 }
2198 }
2199
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002200 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002201 req->flags = cpu_to_le16(0x0000);
2202
2203 return ptr - data;
2204}
2205
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002206static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002207{
2208 struct l2cap_conf_rsp *rsp = data;
2209 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002210
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002211 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002212
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002213 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002214 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002215 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002216
2217 return ptr - data;
2218}
2219
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002220void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002221{
2222 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002223 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002224 u8 buf[128];
2225
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002226 rsp.scid = cpu_to_le16(chan->dcid);
2227 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002228 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2229 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2230 l2cap_send_cmd(conn, chan->ident,
2231 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2232
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002233 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002234 return;
2235
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002236 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002237 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2238 l2cap_build_conf_req(chan, buf), buf);
2239 chan->num_conf_req++;
2240}
2241
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002242static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002243{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002244 int type, olen;
2245 unsigned long val;
2246 struct l2cap_conf_rfc rfc;
2247
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002248 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002249
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002250 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002251 return;
2252
2253 while (len >= L2CAP_CONF_OPT_SIZE) {
2254 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2255
2256 switch (type) {
2257 case L2CAP_CONF_RFC:
2258 if (olen == sizeof(rfc))
2259 memcpy(&rfc, (void *)val, olen);
2260 goto done;
2261 }
2262 }
2263
2264done:
2265 switch (rfc.mode) {
2266 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002267 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2268 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2269 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002270 break;
2271 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002272 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002273 }
2274}
2275
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002276static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2277{
2278 struct l2cap_cmd_rej *rej = (struct l2cap_cmd_rej *) data;
2279
2280 if (rej->reason != 0x0000)
2281 return 0;
2282
2283 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2284 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002285 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002286
2287 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002288 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002289
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002290 l2cap_conn_start(conn);
2291 }
2292
2293 return 0;
2294}
2295
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2297{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2299 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002300 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002301 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002302 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
2304 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002305 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002306
2307 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2308
2309 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002310 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2311 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002312 result = L2CAP_CR_BAD_PSM;
2313 goto sendresp;
2314 }
2315
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002316 parent = pchan->sk;
2317
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002318 bh_lock_sock(parent);
2319
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002320 /* Check if the ACL is secure enough (if not SDP) */
2321 if (psm != cpu_to_le16(0x0001) &&
2322 !hci_conn_check_link_mode(conn->hcon)) {
Marcel Holtmann2950f212009-02-12 14:02:50 +01002323 conn->disc_reason = 0x05;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002324 result = L2CAP_CR_SEC_BLOCK;
2325 goto response;
2326 }
2327
Linus Torvalds1da177e2005-04-16 15:20:36 -07002328 result = L2CAP_CR_NO_MEM;
2329
2330 /* Check for backlog size */
2331 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002332 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002333 goto response;
2334 }
2335
YOSHIFUJI Hideaki3b1e0a62008-03-26 02:26:21 +09002336 sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002337 if (!sk)
2338 goto response;
2339
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002340 chan = l2cap_chan_create(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002341 if (!chan) {
2342 l2cap_sock_kill(sk);
2343 goto response;
2344 }
2345
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03002346 l2cap_pi(sk)->chan = chan;
2347
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002348 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002349
2350 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002351 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2352 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002353 sock_set_flag(sk, SOCK_ZAPPED);
2354 l2cap_sock_kill(sk);
2355 goto response;
2356 }
2357
2358 hci_conn_hold(conn->hcon);
2359
2360 l2cap_sock_init(sk, parent);
2361 bacpy(&bt_sk(sk)->src, conn->src);
2362 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002363 chan->psm = psm;
2364 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002365
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002366 bt_accept_enqueue(parent, sk);
2367
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002368 __l2cap_chan_add(conn, chan);
2369
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002370 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002371
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002372 l2cap_chan_set_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002374 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002375
Marcel Holtmann984947d2009-02-06 23:35:19 +01002376 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03002377 if (l2cap_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002378 if (bt_sk(sk)->defer_setup) {
2379 sk->sk_state = BT_CONNECT2;
2380 result = L2CAP_CR_PEND;
2381 status = L2CAP_CS_AUTHOR_PEND;
2382 parent->sk_data_ready(parent, 0);
2383 } else {
2384 sk->sk_state = BT_CONFIG;
2385 result = L2CAP_CR_SUCCESS;
2386 status = L2CAP_CS_NO_INFO;
2387 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002388 } else {
2389 sk->sk_state = BT_CONNECT2;
2390 result = L2CAP_CR_PEND;
2391 status = L2CAP_CS_AUTHEN_PEND;
2392 }
2393 } else {
2394 sk->sk_state = BT_CONNECT2;
2395 result = L2CAP_CR_PEND;
2396 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397 }
2398
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002399 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002400
2401response:
2402 bh_unlock_sock(parent);
2403
2404sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002405 rsp.scid = cpu_to_le16(scid);
2406 rsp.dcid = cpu_to_le16(dcid);
2407 rsp.result = cpu_to_le16(result);
2408 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002409 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002410
2411 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2412 struct l2cap_info_req info;
2413 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2414
2415 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2416 conn->info_ident = l2cap_get_ident(conn);
2417
2418 mod_timer(&conn->info_timer, jiffies +
2419 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2420
2421 l2cap_send_cmd(conn, conn->info_ident,
2422 L2CAP_INFO_REQ, sizeof(info), &info);
2423 }
2424
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002425 if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002426 result == L2CAP_CR_SUCCESS) {
2427 u8 buf[128];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002428 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002429 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002430 l2cap_build_conf_req(chan, buf), buf);
2431 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002432 }
2433
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434 return 0;
2435}
2436
2437static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2438{
2439 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2440 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002441 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442 struct sock *sk;
2443 u8 req[128];
2444
2445 scid = __le16_to_cpu(rsp->scid);
2446 dcid = __le16_to_cpu(rsp->dcid);
2447 result = __le16_to_cpu(rsp->result);
2448 status = __le16_to_cpu(rsp->status);
2449
2450 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2451
2452 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002453 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002454 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002455 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002456 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002457 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002458 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002459 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 }
2461
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002462 sk = chan->sk;
2463
Linus Torvalds1da177e2005-04-16 15:20:36 -07002464 switch (result) {
2465 case L2CAP_CR_SUCCESS:
2466 sk->sk_state = BT_CONFIG;
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002467 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002468 chan->dcid = dcid;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002469 chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002470
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002471 if (chan->conf_state & L2CAP_CONF_REQ_SENT)
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002472 break;
2473
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002474 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002475
Linus Torvalds1da177e2005-04-16 15:20:36 -07002476 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002477 l2cap_build_conf_req(chan, req), req);
2478 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002479 break;
2480
2481 case L2CAP_CR_PEND:
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002482 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483 break;
2484
2485 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002486 /* don't delete l2cap channel if sk is owned by user */
2487 if (sock_owned_by_user(sk)) {
2488 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002489 l2cap_chan_clear_timer(chan);
2490 l2cap_chan_set_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002491 break;
2492 }
2493
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002494 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002495 break;
2496 }
2497
2498 bh_unlock_sock(sk);
2499 return 0;
2500}
2501
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002502static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002503{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002504 struct l2cap_pinfo *pi = l2cap_pi(chan->sk);
2505
Mat Martineau8c462b62010-08-24 15:35:42 -07002506 /* FCS is enabled only in ERTM or streaming mode, if one or both
2507 * sides request it.
2508 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002509 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002510 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002511 else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002512 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002513}
2514
Al Viro88219a02007-07-29 00:17:25 -07002515static 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 -07002516{
2517 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2518 u16 dcid, flags;
2519 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002520 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002521 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002522 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523
2524 dcid = __le16_to_cpu(req->dcid);
2525 flags = __le16_to_cpu(req->flags);
2526
2527 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2528
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002529 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002530 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 return -ENOENT;
2532
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002533 sk = chan->sk;
2534
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002535 if (sk->sk_state != BT_CONFIG) {
2536 struct l2cap_cmd_rej rej;
2537
2538 rej.reason = cpu_to_le16(0x0002);
2539 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2540 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002541 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002542 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002543
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002544 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002545 len = cmd_len - sizeof(*req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002546 if (chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002547 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_REJECT, flags), rsp);
2550 goto unlock;
2551 }
2552
2553 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002554 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2555 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002556
2557 if (flags & 0x0001) {
2558 /* Incomplete config. Send empty response. */
2559 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002560 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002561 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 goto unlock;
2563 }
2564
2565 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002566 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002567 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002568 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002569 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002570 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002572 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002573 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002574
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002575 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002576 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002577
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002578 if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002579 goto unlock;
2580
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002581 if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002582 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002583
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002585
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002586 chan->next_tx_seq = 0;
2587 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002588 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002589 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002590 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002591
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002593 goto unlock;
2594 }
2595
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002596 if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002597 u8 buf[64];
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002598 chan->conf_state |= L2CAP_CONF_REQ_SENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002600 l2cap_build_conf_req(chan, buf), buf);
2601 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602 }
2603
2604unlock:
2605 bh_unlock_sock(sk);
2606 return 0;
2607}
2608
2609static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2610{
2611 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2612 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002613 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002615 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002616
2617 scid = __le16_to_cpu(rsp->scid);
2618 flags = __le16_to_cpu(rsp->flags);
2619 result = __le16_to_cpu(rsp->result);
2620
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002621 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2622 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002624 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002625 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626 return 0;
2627
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002628 sk = chan->sk;
2629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 switch (result) {
2631 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002632 l2cap_conf_rfc_get(chan, rsp->data, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 break;
2634
2635 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002636 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002637 char req[64];
2638
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002639 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002640 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002641 goto done;
2642 }
2643
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002644 /* throw out any old stored conf requests */
2645 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002646 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2647 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002648 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002649 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002650 goto done;
2651 }
2652
2653 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2654 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002655 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002656 if (result != L2CAP_CONF_SUCCESS)
2657 goto done;
2658 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002659 }
2660
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002661 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002662 sk->sk_err = ECONNRESET;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002663 l2cap_chan_set_timer(chan, HZ * 5);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002664 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665 goto done;
2666 }
2667
2668 if (flags & 0x01)
2669 goto done;
2670
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002671 chan->conf_state |= L2CAP_CONF_INPUT_DONE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002673 if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002674 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002675
Linus Torvalds1da177e2005-04-16 15:20:36 -07002676 sk->sk_state = BT_CONNECTED;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002677 chan->next_tx_seq = 0;
2678 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002679 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002680 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002681 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 l2cap_chan_ready(sk);
2684 }
2685
2686done:
2687 bh_unlock_sock(sk);
2688 return 0;
2689}
2690
2691static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2692{
2693 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2694 struct l2cap_disconn_rsp rsp;
2695 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002696 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 struct sock *sk;
2698
2699 scid = __le16_to_cpu(req->scid);
2700 dcid = __le16_to_cpu(req->dcid);
2701
2702 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2703
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002704 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002705 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002706 return 0;
2707
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002708 sk = chan->sk;
2709
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002710 rsp.dcid = cpu_to_le16(chan->scid);
2711 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002712 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2713
2714 sk->sk_shutdown = SHUTDOWN_MASK;
2715
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002716 /* don't delete l2cap channel if sk is owned by user */
2717 if (sock_owned_by_user(sk)) {
2718 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002719 l2cap_chan_clear_timer(chan);
2720 l2cap_chan_set_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002721 bh_unlock_sock(sk);
2722 return 0;
2723 }
2724
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002725 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 bh_unlock_sock(sk);
2727
2728 l2cap_sock_kill(sk);
2729 return 0;
2730}
2731
2732static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2733{
2734 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2735 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002736 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 struct sock *sk;
2738
2739 scid = __le16_to_cpu(rsp->scid);
2740 dcid = __le16_to_cpu(rsp->dcid);
2741
2742 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
2743
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002744 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002745 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746 return 0;
2747
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002748 sk = chan->sk;
2749
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002750 /* don't delete l2cap channel if sk is owned by user */
2751 if (sock_owned_by_user(sk)) {
2752 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03002753 l2cap_chan_clear_timer(chan);
2754 l2cap_chan_set_timer(chan, HZ / 5);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002755 bh_unlock_sock(sk);
2756 return 0;
2757 }
2758
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002759 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002760 bh_unlock_sock(sk);
2761
2762 l2cap_sock_kill(sk);
2763 return 0;
2764}
2765
2766static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2767{
2768 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 u16 type;
2770
2771 type = __le16_to_cpu(req->type);
2772
2773 BT_DBG("type 0x%4.4x", type);
2774
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002775 if (type == L2CAP_IT_FEAT_MASK) {
2776 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07002777 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002778 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2779 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2780 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03002781 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002782 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
2783 | L2CAP_FEAT_FCS;
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03002784 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002785 l2cap_send_cmd(conn, cmd->ident,
2786 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002787 } else if (type == L2CAP_IT_FIXED_CHAN) {
2788 u8 buf[12];
2789 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
2790 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2791 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
2792 memcpy(buf + 4, l2cap_fixed_chan, 8);
2793 l2cap_send_cmd(conn, cmd->ident,
2794 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02002795 } else {
2796 struct l2cap_info_rsp rsp;
2797 rsp.type = cpu_to_le16(type);
2798 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
2799 l2cap_send_cmd(conn, cmd->ident,
2800 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
2801 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002802
2803 return 0;
2804}
2805
2806static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2807{
2808 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
2809 u16 type, result;
2810
2811 type = __le16_to_cpu(rsp->type);
2812 result = __le16_to_cpu(rsp->result);
2813
2814 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
2815
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02002816 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
2817 if (cmd->ident != conn->info_ident ||
2818 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
2819 return 0;
2820
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002821 del_timer(&conn->info_timer);
2822
Ville Tervoadb08ed2010-08-04 09:43:33 +03002823 if (result != L2CAP_IR_SUCCESS) {
2824 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2825 conn->info_ident = 0;
2826
2827 l2cap_conn_start(conn);
2828
2829 return 0;
2830 }
2831
Marcel Holtmann984947d2009-02-06 23:35:19 +01002832 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07002833 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002834
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002835 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002836 struct l2cap_info_req req;
2837 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
2838
2839 conn->info_ident = l2cap_get_ident(conn);
2840
2841 l2cap_send_cmd(conn, conn->info_ident,
2842 L2CAP_INFO_REQ, sizeof(req), &req);
2843 } else {
2844 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
2845 conn->info_ident = 0;
2846
2847 l2cap_conn_start(conn);
2848 }
2849 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01002850 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002851 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002852
2853 l2cap_conn_start(conn);
2854 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002855
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856 return 0;
2857}
2858
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002859static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02002860 u16 to_multiplier)
2861{
2862 u16 max_latency;
2863
2864 if (min > max || min < 6 || max > 3200)
2865 return -EINVAL;
2866
2867 if (to_multiplier < 10 || to_multiplier > 3200)
2868 return -EINVAL;
2869
2870 if (max >= to_multiplier * 8)
2871 return -EINVAL;
2872
2873 max_latency = (to_multiplier * 8 / max) - 1;
2874 if (latency > 499 || latency > max_latency)
2875 return -EINVAL;
2876
2877 return 0;
2878}
2879
2880static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
2881 struct l2cap_cmd_hdr *cmd, u8 *data)
2882{
2883 struct hci_conn *hcon = conn->hcon;
2884 struct l2cap_conn_param_update_req *req;
2885 struct l2cap_conn_param_update_rsp rsp;
2886 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002887 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02002888
2889 if (!(hcon->link_mode & HCI_LM_MASTER))
2890 return -EINVAL;
2891
2892 cmd_len = __le16_to_cpu(cmd->len);
2893 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
2894 return -EPROTO;
2895
2896 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03002897 min = __le16_to_cpu(req->min);
2898 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02002899 latency = __le16_to_cpu(req->latency);
2900 to_multiplier = __le16_to_cpu(req->to_multiplier);
2901
2902 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
2903 min, max, latency, to_multiplier);
2904
2905 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002906
2907 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
2908 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02002909 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
2910 else
2911 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
2912
2913 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
2914 sizeof(rsp), &rsp);
2915
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02002916 if (!err)
2917 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
2918
Claudio Takahaside731152011-02-11 19:28:55 -02002919 return 0;
2920}
2921
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002922static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
2923 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
2924{
2925 int err = 0;
2926
2927 switch (cmd->code) {
2928 case L2CAP_COMMAND_REJ:
2929 l2cap_command_rej(conn, cmd, data);
2930 break;
2931
2932 case L2CAP_CONN_REQ:
2933 err = l2cap_connect_req(conn, cmd, data);
2934 break;
2935
2936 case L2CAP_CONN_RSP:
2937 err = l2cap_connect_rsp(conn, cmd, data);
2938 break;
2939
2940 case L2CAP_CONF_REQ:
2941 err = l2cap_config_req(conn, cmd, cmd_len, data);
2942 break;
2943
2944 case L2CAP_CONF_RSP:
2945 err = l2cap_config_rsp(conn, cmd, data);
2946 break;
2947
2948 case L2CAP_DISCONN_REQ:
2949 err = l2cap_disconnect_req(conn, cmd, data);
2950 break;
2951
2952 case L2CAP_DISCONN_RSP:
2953 err = l2cap_disconnect_rsp(conn, cmd, data);
2954 break;
2955
2956 case L2CAP_ECHO_REQ:
2957 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
2958 break;
2959
2960 case L2CAP_ECHO_RSP:
2961 break;
2962
2963 case L2CAP_INFO_REQ:
2964 err = l2cap_information_req(conn, cmd, data);
2965 break;
2966
2967 case L2CAP_INFO_RSP:
2968 err = l2cap_information_rsp(conn, cmd, data);
2969 break;
2970
2971 default:
2972 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
2973 err = -EINVAL;
2974 break;
2975 }
2976
2977 return err;
2978}
2979
2980static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
2981 struct l2cap_cmd_hdr *cmd, u8 *data)
2982{
2983 switch (cmd->code) {
2984 case L2CAP_COMMAND_REJ:
2985 return 0;
2986
2987 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02002988 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02002989
2990 case L2CAP_CONN_PARAM_UPDATE_RSP:
2991 return 0;
2992
2993 default:
2994 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
2995 return -EINVAL;
2996 }
2997}
2998
2999static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3000 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001{
3002 u8 *data = skb->data;
3003 int len = skb->len;
3004 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003005 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003006
3007 l2cap_raw_recv(conn, skb);
3008
3009 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003010 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3012 data += L2CAP_CMD_HDR_SIZE;
3013 len -= L2CAP_CMD_HDR_SIZE;
3014
Al Viro88219a02007-07-29 00:17:25 -07003015 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016
Al Viro88219a02007-07-29 00:17:25 -07003017 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 -07003018
Al Viro88219a02007-07-29 00:17:25 -07003019 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003020 BT_DBG("corrupted command");
3021 break;
3022 }
3023
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003024 if (conn->hcon->type == LE_LINK)
3025 err = l2cap_le_sig_cmd(conn, &cmd, data);
3026 else
3027 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028
3029 if (err) {
3030 struct l2cap_cmd_rej rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003031
3032 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033
3034 /* FIXME: Map err to a valid reason */
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07003035 rej.reason = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003036 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3037 }
3038
Al Viro88219a02007-07-29 00:17:25 -07003039 data += cmd_len;
3040 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041 }
3042
3043 kfree_skb(skb);
3044}
3045
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003046static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003047{
3048 u16 our_fcs, rcv_fcs;
3049 int hdr_size = L2CAP_HDR_SIZE + 2;
3050
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003051 if (chan->fcs == L2CAP_FCS_CRC16) {
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003052 skb_trim(skb, skb->len - 2);
3053 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3054 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3055
3056 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003057 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003058 }
3059 return 0;
3060}
3061
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003062static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003063{
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003064 u16 control = 0;
3065
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003066 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003067
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003068 control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003069
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003070 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan64988862010-05-10 14:54:14 -03003071 control |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003072 l2cap_send_sframe(chan, control);
3073 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003074 }
3075
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003076 if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY)
3077 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003078
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003079 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003080
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003081 if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003082 chan->frames_sent == 0) {
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003083 control |= L2CAP_SUPER_RCV_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003084 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003085 }
3086}
3087
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003088static 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 -03003089{
3090 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003091 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003092
3093 bt_cb(skb)->tx_seq = tx_seq;
3094 bt_cb(skb)->sar = sar;
3095
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003096 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003097 if (!next_skb) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003098 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003099 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003100 }
3101
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003102 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003103 if (tx_seq_offset < 0)
3104 tx_seq_offset += 64;
3105
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003106 do {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003107 if (bt_cb(next_skb)->tx_seq == tx_seq)
3108 return -EINVAL;
3109
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003110 next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003111 chan->buffer_seq) % 64;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003112 if (next_tx_seq_offset < 0)
3113 next_tx_seq_offset += 64;
3114
3115 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003116 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003117 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003118 }
3119
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003120 if (skb_queue_is_last(&chan->srej_q, next_skb))
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003121 break;
3122
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003123 } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb)));
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003124
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003125 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003126
3127 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003128}
3129
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003130static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003131{
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003132 struct sk_buff *_skb;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003133 int err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003134
3135 switch (control & L2CAP_CTRL_SAR) {
3136 case L2CAP_SDU_UNSEGMENTED:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003137 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003138 goto drop;
3139
Ruiyi Zhang224f8af2011-05-13 13:07:52 +08003140 return sock_queue_rcv_skb(chan->sk, skb);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003141
3142 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003143 if (chan->conn_state & L2CAP_CONN_SAR_SDU)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003144 goto drop;
3145
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003146 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003147
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003148 if (chan->sdu_len > chan->imtu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003149 goto disconnect;
3150
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003151 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3152 if (!chan->sdu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003153 return -ENOMEM;
3154
3155 /* pull sdu_len bytes only after alloc, because of Local Busy
3156 * condition we have to be sure that this will be executed
3157 * only once, i.e., when alloc does not fail */
3158 skb_pull(skb, 2);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003159
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003160 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003161
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003162 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003163 chan->partial_sdu_len = skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003164 break;
3165
3166 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003167 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003168 goto disconnect;
3169
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003170 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003171 goto disconnect;
3172
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003173 chan->partial_sdu_len += skb->len;
3174 if (chan->partial_sdu_len > chan->sdu_len)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003175 goto drop;
3176
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003177 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003178
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003179 break;
3180
3181 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003182 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003183 goto disconnect;
3184
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003185 if (!chan->sdu)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003186 goto disconnect;
3187
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003188 if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003189 chan->partial_sdu_len += skb->len;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003190
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003191 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003192 goto drop;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003193
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003194 if (chan->partial_sdu_len != chan->sdu_len)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003195 goto drop;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003196
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003197 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003198 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003199
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003200 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003201 if (!_skb) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003202 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003203 return -ENOMEM;
3204 }
3205
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003206 err = sock_queue_rcv_skb(chan->sk, _skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003207 if (err < 0) {
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003208 kfree_skb(_skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003209 chan->conn_state |= L2CAP_CONN_SAR_RETRY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003210 return err;
3211 }
3212
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003213 chan->conn_state &= ~L2CAP_CONN_SAR_RETRY;
3214 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003215
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003216 kfree_skb(chan->sdu);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003217 break;
3218 }
3219
3220 kfree_skb(skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003221 return 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003222
3223drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003224 kfree_skb(chan->sdu);
3225 chan->sdu = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003226
3227disconnect:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003228 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003229 kfree_skb(skb);
3230 return 0;
3231}
3232
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003233static int l2cap_try_push_rx_skb(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003234{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003235 struct sk_buff *skb;
3236 u16 control;
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003237 int err;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003238
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003239 while ((skb = skb_dequeue(&chan->busy_q))) {
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003240 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003241 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003242 if (err < 0) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003243 skb_queue_head(&chan->busy_q, skb);
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003244 return -EBUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003245 }
3246
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003247 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003248 }
3249
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003250 if (!(chan->conn_state & L2CAP_CONN_RNR_SENT))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003251 goto done;
3252
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003253 control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003254 control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003255 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003256 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003257
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003258 del_timer(&chan->retrans_timer);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003259 __mod_monitor_timer();
3260
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003261 chan->conn_state |= L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003262
3263done:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003264 chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY;
3265 chan->conn_state &= ~L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003266
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003267 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003268
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003269 return 0;
3270}
3271
3272static void l2cap_busy_work(struct work_struct *work)
3273{
3274 DECLARE_WAITQUEUE(wait, current);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003275 struct l2cap_chan *chan =
3276 container_of(work, struct l2cap_chan, busy_work);
3277 struct sock *sk = chan->sk;
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003278 int n_tries = 0, timeo = HZ/5, err;
3279 struct sk_buff *skb;
3280
3281 lock_sock(sk);
3282
3283 add_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003284 while ((skb = skb_peek(&chan->busy_q))) {
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003285 set_current_state(TASK_INTERRUPTIBLE);
3286
3287 if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) {
3288 err = -EBUSY;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003289 l2cap_send_disconn_req(chan->conn, chan, EBUSY);
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003290 break;
3291 }
3292
3293 if (!timeo)
3294 timeo = HZ/5;
3295
3296 if (signal_pending(current)) {
3297 err = sock_intr_errno(timeo);
3298 break;
3299 }
3300
3301 release_sock(sk);
3302 timeo = schedule_timeout(timeo);
3303 lock_sock(sk);
3304
3305 err = sock_error(sk);
3306 if (err)
3307 break;
3308
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003309 if (l2cap_try_push_rx_skb(chan) == 0)
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003310 break;
3311 }
3312
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003313 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02003314 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003315
3316 release_sock(sk);
3317}
3318
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003319static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003320{
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003321 int sctrl, err;
3322
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003323 if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) {
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003324 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003325 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003326 return l2cap_try_push_rx_skb(chan);
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003327
3328
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003329 }
3330
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003331 err = l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003332 if (err >= 0) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003333 chan->buffer_seq = (chan->buffer_seq + 1) % 64;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003334 return err;
3335 }
3336
3337 /* Busy Condition */
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003338 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003339
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003340 chan->conn_state |= L2CAP_CONN_LOCAL_BUSY;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003341 bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003342 __skb_queue_tail(&chan->busy_q, skb);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003343
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003344 sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003345 sctrl |= L2CAP_SUPER_RCV_NOT_READY;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003346 l2cap_send_sframe(chan, sctrl);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003347
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003348 chan->conn_state |= L2CAP_CONN_RNR_SENT;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003349
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003350 del_timer(&chan->ack_timer);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003351
Gustavo F. Padovan311bb892011-03-25 20:41:00 -03003352 queue_work(_busy_wq, &chan->busy_work);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003353
3354 return err;
3355}
3356
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003357static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003358{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003359 struct sk_buff *_skb;
3360 int err = -EINVAL;
3361
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003362 /*
3363 * TODO: We have to notify the userland if some data is lost with the
3364 * Streaming Mode.
3365 */
3366
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003367 switch (control & L2CAP_CTRL_SAR) {
3368 case L2CAP_SDU_UNSEGMENTED:
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. Padovan525cd182011-03-25 19:43:39 -03003374 err = sock_queue_rcv_skb(chan->sk, skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003375 if (!err)
3376 return 0;
3377
3378 break;
3379
3380 case L2CAP_SDU_START:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003381 if (chan->conn_state & L2CAP_CONN_SAR_SDU) {
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003382 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003383 break;
3384 }
3385
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003386 chan->sdu_len = get_unaligned_le16(skb->data);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003387 skb_pull(skb, 2);
3388
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003389 if (chan->sdu_len > chan->imtu) {
Gustavo F. Padovan052897c2010-05-01 16:15:40 -03003390 err = -EMSGSIZE;
3391 break;
3392 }
3393
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003394 chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC);
3395 if (!chan->sdu) {
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003396 err = -ENOMEM;
3397 break;
3398 }
3399
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003400 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003401
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003402 chan->conn_state |= L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003403 chan->partial_sdu_len = skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003404 err = 0;
3405 break;
3406
3407 case L2CAP_SDU_CONTINUE:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003408 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003409 break;
3410
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003411 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003412
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003413 chan->partial_sdu_len += skb->len;
3414 if (chan->partial_sdu_len > chan->sdu_len)
3415 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003416 else
3417 err = 0;
3418
3419 break;
3420
3421 case L2CAP_SDU_END:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003422 if (!(chan->conn_state & L2CAP_CONN_SAR_SDU))
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003423 break;
3424
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003425 memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003426
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003427 chan->conn_state &= ~L2CAP_CONN_SAR_SDU;
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003428 chan->partial_sdu_len += skb->len;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003429
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003430 if (chan->partial_sdu_len > chan->imtu)
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003431 goto drop;
3432
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003433 if (chan->partial_sdu_len == chan->sdu_len) {
3434 _skb = skb_clone(chan->sdu, GFP_ATOMIC);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003435 err = sock_queue_rcv_skb(chan->sk, _skb);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003436 if (err < 0)
3437 kfree_skb(_skb);
3438 }
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003439 err = 0;
3440
Gustavo F. Padovan36f2fd52010-05-01 16:15:37 -03003441drop:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003442 kfree_skb(chan->sdu);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03003443 break;
3444 }
3445
3446 kfree_skb(skb);
3447 return err;
3448}
3449
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003450static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003451{
3452 struct sk_buff *skb;
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003453 u16 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003454
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003455 while ((skb = skb_peek(&chan->srej_q))) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003456 if (bt_cb(skb)->tx_seq != tx_seq)
3457 break;
3458
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003459 skb = skb_dequeue(&chan->srej_q);
Gustavo F. Padovanafefdbc2010-05-01 16:15:43 -03003460 control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003461 l2cap_ertm_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003462 chan->buffer_seq_srej =
3463 (chan->buffer_seq_srej + 1) % 64;
Gustavo F. Padovan8ff50ec2010-05-10 19:34:11 -03003464 tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003465 }
3466}
3467
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003468static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003469{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003470 struct srej_list *l, *tmp;
3471 u16 control;
3472
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003473 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003474 if (l->tx_seq == tx_seq) {
3475 list_del(&l->list);
3476 kfree(l);
3477 return;
3478 }
3479 control = L2CAP_SUPER_SELECT_REJECT;
3480 control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003481 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003482 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003483 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003484 }
3485}
3486
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003487static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003488{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003489 struct srej_list *new;
3490 u16 control;
3491
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003492 while (tx_seq != chan->expected_tx_seq) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003493 control = L2CAP_SUPER_SELECT_REJECT;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003494 control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003495 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003496
3497 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003498 new->tx_seq = chan->expected_tx_seq;
3499 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003500 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003501 }
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003502 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003503}
3504
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003505static 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 -03003506{
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003507 u8 tx_seq = __get_txseq(rx_control);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003508 u8 req_seq = __get_reqseq(rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003509 u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003510 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003511 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003512 int err = 0;
3513
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003514 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
3515 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003516
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003517 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003518 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003519 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003520 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003521 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003522 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003523 }
3524
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003525 chan->expected_ack_seq = req_seq;
3526 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003527
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003528 if (tx_seq == chan->expected_tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003529 goto expected;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003530
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003531 tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003532 if (tx_seq_offset < 0)
3533 tx_seq_offset += 64;
3534
3535 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003536 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003537 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003538 goto drop;
3539 }
3540
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003541 if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003542 goto drop;
3543
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003544 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003545 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003546
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003547 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003548 struct srej_list, list);
3549 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003550 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003551 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003552
3553 list_del(&first->list);
3554 kfree(first);
3555
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003556 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003557 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003558 chan->conn_state &= ~L2CAP_CONN_SREJ_SENT;
3559 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003560 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003561 }
3562 } else {
3563 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003564
3565 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003566 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003567 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003568
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003569 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003570 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003571 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003572 return 0;
3573 }
3574 }
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003575 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003576 }
3577 } else {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003578 expected_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003579 (chan->expected_tx_seq - chan->buffer_seq) % 64;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003580 if (expected_tx_seq_offset < 0)
3581 expected_tx_seq_offset += 64;
3582
3583 /* duplicated tx_seq */
3584 if (tx_seq_offset < expected_tx_seq_offset)
3585 goto drop;
3586
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003587 chan->conn_state |= L2CAP_CONN_SREJ_SENT;
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003588
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003589 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003590
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003591 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003592 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003593
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003594 __skb_queue_head_init(&chan->srej_q);
3595 __skb_queue_head_init(&chan->busy_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003596 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003597
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003598 chan->conn_state |= L2CAP_CONN_SEND_PBIT;
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003599
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003600 l2cap_send_srejframe(chan, tx_seq);
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003601
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003602 del_timer(&chan->ack_timer);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003603 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003604 return 0;
3605
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003606expected:
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003607 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003608
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003609 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003610 bt_cb(skb)->tx_seq = tx_seq;
3611 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003612 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003613 return 0;
3614 }
3615
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003616 err = l2cap_push_rx_skb(chan, skb, rx_control);
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003617 if (err < 0)
3618 return 0;
3619
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003620 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003621 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3622 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003623 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003624 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003625 }
3626
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003627 __mod_ack_timer();
3628
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003629 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3630 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003631 l2cap_send_ack(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003632
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003633 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003634
3635drop:
3636 kfree_skb(skb);
3637 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003638}
3639
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003640static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003641{
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003642 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003643 rx_control);
3644
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003645 chan->expected_ack_seq = __get_reqseq(rx_control);
3646 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003647
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003648 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003649 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3650 if (chan->conn_state & L2CAP_CONN_SREJ_SENT) {
3651 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003652 (chan->unacked_frames > 0))
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003653 __mod_retrans_timer();
3654
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003655 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3656 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003657 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003658 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003659 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003660
3661 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003662 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003663
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003664 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3665 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003666 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003667 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003668
3669 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003670 if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003671 (chan->unacked_frames > 0))
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003672 __mod_retrans_timer();
3673
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003674 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
3675 if (chan->conn_state & L2CAP_CONN_SREJ_SENT)
3676 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003677 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003678 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003679 }
3680}
3681
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003682static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003683{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003684 u8 tx_seq = __get_reqseq(rx_control);
3685
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003686 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003687
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003688 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003689
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003690 chan->expected_ack_seq = tx_seq;
3691 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003692
3693 if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003694 if (chan->conn_state & L2CAP_CONN_REJ_ACT)
3695 chan->conn_state &= ~L2CAP_CONN_REJ_ACT;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003696 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003697 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003698 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003699 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003700
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003701 if (chan->conn_state & L2CAP_CONN_WAIT_F)
3702 chan->conn_state |= L2CAP_CONN_REJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003703 }
3704}
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003705static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003706{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003707 u8 tx_seq = __get_reqseq(rx_control);
3708
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003709 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003710
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003711 chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003712
3713 if (rx_control & L2CAP_CTRL_POLL) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003714 chan->expected_ack_seq = tx_seq;
3715 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003716
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003717 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
3718 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003719
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003720 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03003721
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003722 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 } else if (rx_control & L2CAP_CTRL_FINAL) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003727 if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003728 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003729 chan->conn_state &= ~L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003730 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003731 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003732 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003733 l2cap_retransmit_one_frame(chan, tx_seq);
3734 if (chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003735 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003736 chan->conn_state |= L2CAP_CONN_SREJ_ACT;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003737 }
3738 }
3739}
3740
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003741static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003742{
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003743 u8 tx_seq = __get_reqseq(rx_control);
3744
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003745 BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003746
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003747 chan->conn_state |= L2CAP_CONN_REMOTE_BUSY;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003748 chan->expected_ack_seq = tx_seq;
3749 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003750
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003751 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003752 chan->conn_state |= L2CAP_CONN_SEND_FBIT;
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03003753
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003754 if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003755 del_timer(&chan->retrans_timer);
Gustavo F. Padovana2e12a22010-05-05 19:58:27 -03003756 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003757 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003758 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003759 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003760
3761 if (rx_control & L2CAP_CTRL_POLL)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003762 l2cap_send_srejtail(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03003763 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003764 l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003765}
3766
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003767static 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 -03003768{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003769 BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003770
Gustavo F. Padovan9b16dc62010-05-05 20:05:57 -03003771 if (L2CAP_CTRL_FINAL & rx_control &&
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003772 chan->conn_state & L2CAP_CONN_WAIT_F) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03003773 del_timer(&chan->monitor_timer);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003774 if (chan->unacked_frames > 0)
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003775 __mod_retrans_timer();
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003776 chan->conn_state &= ~L2CAP_CONN_WAIT_F;
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003777 }
3778
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003779 switch (rx_control & L2CAP_CTRL_SUPERVISE) {
3780 case L2CAP_SUPER_RCV_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003781 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003782 break;
3783
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003784 case L2CAP_SUPER_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003785 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003786 break;
3787
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003788 case L2CAP_SUPER_SELECT_REJECT:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003789 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003790 break;
3791
3792 case L2CAP_SUPER_RCV_NOT_READY:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003793 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003794 break;
3795 }
3796
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03003797 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003798 return 0;
3799}
3800
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003801static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
3802{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003803 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003804 u16 control;
3805 u8 req_seq;
3806 int len, next_tx_seq_offset, req_seq_offset;
3807
3808 control = get_unaligned_le16(skb->data);
3809 skb_pull(skb, 2);
3810 len = skb->len;
3811
3812 /*
3813 * We can just drop the corrupted I-frame here.
3814 * Receiver will miss it and start proper recovery
3815 * procedures and ask retransmission.
3816 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003817 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003818 goto drop;
3819
3820 if (__is_sar_start(control) && __is_iframe(control))
3821 len -= 2;
3822
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003823 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003824 len -= 2;
3825
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003826 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003827 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003828 goto drop;
3829 }
3830
3831 req_seq = __get_reqseq(control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003832 req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003833 if (req_seq_offset < 0)
3834 req_seq_offset += 64;
3835
3836 next_tx_seq_offset =
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003837 (chan->next_tx_seq - chan->expected_ack_seq) % 64;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003838 if (next_tx_seq_offset < 0)
3839 next_tx_seq_offset += 64;
3840
3841 /* check for invalid req-seq */
3842 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003843 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003844 goto drop;
3845 }
3846
3847 if (__is_iframe(control)) {
3848 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003849 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003850 goto drop;
3851 }
3852
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003853 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003854 } else {
3855 if (len != 0) {
3856 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003857 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003858 goto drop;
3859 }
3860
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003861 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003862 }
3863
3864 return 0;
3865
3866drop:
3867 kfree_skb(skb);
3868 return 0;
3869}
3870
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
3872{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003873 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07003874 struct sock *sk = NULL;
Nathan Holstein51893f82010-06-09 15:46:25 -04003875 u16 control;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003876 u8 tx_seq;
3877 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003878
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003879 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003880 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003881 BT_DBG("unknown cid 0x%4.4x", cid);
3882 goto drop;
3883 }
3884
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003885 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003886
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003887 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003888
3889 if (sk->sk_state != BT_CONNECTED)
3890 goto drop;
3891
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003892 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003893 case L2CAP_MODE_BASIC:
3894 /* If socket recv buffers overflows we drop data here
3895 * which is *bad* because L2CAP has to be reliable.
3896 * But we don't have any other choice. L2CAP doesn't
3897 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003898
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003899 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003900 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003901
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003902 if (!sock_queue_rcv_skb(sk, skb))
3903 goto done;
3904 break;
3905
3906 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003907 if (!sock_owned_by_user(sk)) {
3908 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003909 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03003910 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003911 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03003912 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003913
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02003914 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003915
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003916 case L2CAP_MODE_STREAMING:
3917 control = get_unaligned_le16(skb->data);
3918 skb_pull(skb, 2);
3919 len = skb->len;
3920
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003921 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03003922 goto drop;
3923
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003924 if (__is_sar_start(control))
3925 len -= 2;
3926
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003927 if (chan->fcs == L2CAP_FCS_CRC16)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003928 len -= 2;
3929
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003930 if (len > chan->mps || len < 0 || __is_sframe(control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003931 goto drop;
3932
3933 tx_seq = __get_txseq(control);
3934
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003935 if (chan->expected_tx_seq == tx_seq)
3936 chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003937 else
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003938 chan->expected_tx_seq = (tx_seq + 1) % 64;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003939
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003940 l2cap_streaming_reassembly_sdu(chan, skb, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03003941
3942 goto done;
3943
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003944 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003945 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003946 break;
3947 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003948
3949drop:
3950 kfree_skb(skb);
3951
3952done:
Marcel Holtmann01394182006-07-03 10:02:46 +02003953 if (sk)
3954 bh_unlock_sock(sk);
3955
Linus Torvalds1da177e2005-04-16 15:20:36 -07003956 return 0;
3957}
3958
Al Viro8e036fc2007-07-29 00:16:36 -07003959static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003960{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003961 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003962 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003963
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003964 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
3965 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003966 goto drop;
3967
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003968 sk = chan->sk;
3969
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00003970 bh_lock_sock(sk);
3971
Linus Torvalds1da177e2005-04-16 15:20:36 -07003972 BT_DBG("sk %p, len %d", sk, skb->len);
3973
3974 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
3975 goto drop;
3976
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003977 if (l2cap_pi(sk)->chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003978 goto drop;
3979
3980 if (!sock_queue_rcv_skb(sk, skb))
3981 goto done;
3982
3983drop:
3984 kfree_skb(skb);
3985
3986done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03003987 if (sk)
3988 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003989 return 0;
3990}
3991
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003992static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
3993{
David S. Miller6dcae1e2011-05-16 23:09:26 -04003994 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003995 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003996
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03003997 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
3998 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03003999 goto drop;
4000
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004001 sk = chan->sk;
4002
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004003 bh_lock_sock(sk);
4004
4005 BT_DBG("sk %p, len %d", sk, skb->len);
4006
4007 if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
4008 goto drop;
4009
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004010 if (l2cap_pi(sk)->chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004011 goto drop;
4012
4013 if (!sock_queue_rcv_skb(sk, skb))
4014 goto done;
4015
4016drop:
4017 kfree_skb(skb);
4018
4019done:
4020 if (sk)
4021 bh_unlock_sock(sk);
4022 return 0;
4023}
4024
Linus Torvalds1da177e2005-04-16 15:20:36 -07004025static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4026{
4027 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004028 u16 cid, len;
4029 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004030
4031 skb_pull(skb, L2CAP_HDR_SIZE);
4032 cid = __le16_to_cpu(lh->cid);
4033 len = __le16_to_cpu(lh->len);
4034
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004035 if (len != skb->len) {
4036 kfree_skb(skb);
4037 return;
4038 }
4039
Linus Torvalds1da177e2005-04-16 15:20:36 -07004040 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4041
4042 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004043 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004044 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004045 l2cap_sig_channel(conn, skb);
4046 break;
4047
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004048 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004049 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004050 skb_pull(skb, 2);
4051 l2cap_conless_channel(conn, psm, skb);
4052 break;
4053
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004054 case L2CAP_CID_LE_DATA:
4055 l2cap_att_channel(conn, cid, skb);
4056 break;
4057
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 default:
4059 l2cap_data_channel(conn, cid, skb);
4060 break;
4061 }
4062}
4063
4064/* ---- L2CAP interface with lower layer (HCI) ---- */
4065
4066static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4067{
4068 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004069 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004070
4071 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004072 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004073
4074 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4075
4076 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004077 read_lock(&chan_list_lock);
4078 list_for_each_entry(c, &chan_list, global_l) {
4079 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004080
Linus Torvalds1da177e2005-04-16 15:20:36 -07004081 if (sk->sk_state != BT_LISTEN)
4082 continue;
4083
4084 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004085 lm1 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004086 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004087 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004088 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004089 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4090 lm2 |= HCI_LM_ACCEPT;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004091 if (c->role_switch)
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004092 lm2 |= HCI_LM_MASTER;
4093 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004094 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004095 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096
4097 return exact ? lm1 : lm2;
4098}
4099
4100static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4101{
Marcel Holtmann01394182006-07-03 10:02:46 +02004102 struct l2cap_conn *conn;
4103
Linus Torvalds1da177e2005-04-16 15:20:36 -07004104 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4105
Ville Tervoacd7d372011-02-10 22:38:49 -03004106 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004107 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004108
4109 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004110 conn = l2cap_conn_add(hcon, status);
4111 if (conn)
4112 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004113 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07004114 l2cap_conn_del(hcon, bt_err(status));
4115
4116 return 0;
4117}
4118
Marcel Holtmann2950f212009-02-12 14:02:50 +01004119static int l2cap_disconn_ind(struct hci_conn *hcon)
4120{
4121 struct l2cap_conn *conn = hcon->l2cap_data;
4122
4123 BT_DBG("hcon %p", hcon);
4124
4125 if (hcon->type != ACL_LINK || !conn)
4126 return 0x13;
4127
4128 return conn->disc_reason;
4129}
4130
4131static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132{
4133 BT_DBG("hcon %p reason %d", hcon, reason);
4134
Ville Tervoacd7d372011-02-10 22:38:49 -03004135 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004136 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004137
4138 l2cap_conn_del(hcon, bt_err(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004139
Linus Torvalds1da177e2005-04-16 15:20:36 -07004140 return 0;
4141}
4142
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004143static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004144{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004145 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004146 return;
4147
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004148 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004149 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004150 l2cap_chan_clear_timer(chan);
4151 l2cap_chan_set_timer(chan, HZ * 5);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004152 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -03004153 __l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004154 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004155 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004156 l2cap_chan_clear_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004157 }
4158}
4159
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004160static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004161{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004162 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004163 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164
Marcel Holtmann01394182006-07-03 10:02:46 +02004165 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004166 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004167
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168 BT_DBG("conn %p", conn);
4169
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004170 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004172 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004173 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004174
Linus Torvalds1da177e2005-04-16 15:20:36 -07004175 bh_lock_sock(sk);
4176
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004177 if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004178 bh_unlock_sock(sk);
4179 continue;
4180 }
4181
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004182 if (!status && (sk->sk_state == BT_CONNECTED ||
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004183 sk->sk_state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004184 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004185 bh_unlock_sock(sk);
4186 continue;
4187 }
4188
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004189 if (sk->sk_state == BT_CONNECT) {
4190 if (!status) {
4191 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004192 req.scid = cpu_to_le16(chan->scid);
4193 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004194
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004195 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03004196 chan->conf_state |= L2CAP_CONF_CONNECT_PEND;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004197
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004198 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004199 L2CAP_CONN_REQ, sizeof(req), &req);
4200 } else {
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004201 l2cap_chan_clear_timer(chan);
4202 l2cap_chan_set_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004203 }
4204 } else if (sk->sk_state == BT_CONNECT2) {
4205 struct l2cap_conn_rsp rsp;
4206 __u16 result;
4207
4208 if (!status) {
4209 sk->sk_state = BT_CONFIG;
4210 result = L2CAP_CR_SUCCESS;
4211 } else {
4212 sk->sk_state = BT_DISCONN;
Gustavo F. Padovanab078012011-05-02 18:25:01 -03004213 l2cap_chan_set_timer(chan, HZ / 10);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004214 result = L2CAP_CR_SEC_BLOCK;
4215 }
4216
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004217 rsp.scid = cpu_to_le16(chan->dcid);
4218 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004219 rsp.result = cpu_to_le16(result);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02004220 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004221 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4222 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004223 }
4224
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225 bh_unlock_sock(sk);
4226 }
4227
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004228 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004229
Linus Torvalds1da177e2005-04-16 15:20:36 -07004230 return 0;
4231}
4232
4233static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4234{
4235 struct l2cap_conn *conn = hcon->l2cap_data;
4236
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004237 if (!conn)
4238 conn = l2cap_conn_add(hcon, 0);
4239
4240 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004241 goto drop;
4242
4243 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4244
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004245 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004247 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004248 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249 int len;
4250
4251 if (conn->rx_len) {
4252 BT_ERR("Unexpected start frame (len %d)", skb->len);
4253 kfree_skb(conn->rx_skb);
4254 conn->rx_skb = NULL;
4255 conn->rx_len = 0;
4256 l2cap_conn_unreliable(conn, ECOMM);
4257 }
4258
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004259 /* Start fragment always begin with Basic L2CAP header */
4260 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261 BT_ERR("Frame is too short (len %d)", skb->len);
4262 l2cap_conn_unreliable(conn, ECOMM);
4263 goto drop;
4264 }
4265
4266 hdr = (struct l2cap_hdr *) skb->data;
4267 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004268 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269
4270 if (len == skb->len) {
4271 /* Complete frame received */
4272 l2cap_recv_frame(conn, skb);
4273 return 0;
4274 }
4275
4276 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4277
4278 if (skb->len > len) {
4279 BT_ERR("Frame is too long (len %d, expected len %d)",
4280 skb->len, len);
4281 l2cap_conn_unreliable(conn, ECOMM);
4282 goto drop;
4283 }
4284
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004285 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004286
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004287 if (chan && chan->sk) {
4288 struct sock *sk = chan->sk;
4289
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004290 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004291 BT_ERR("Frame exceeding recv MTU (len %d, "
4292 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004293 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004294 bh_unlock_sock(sk);
4295 l2cap_conn_unreliable(conn, ECOMM);
4296 goto drop;
4297 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004298 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004299 }
4300
Linus Torvalds1da177e2005-04-16 15:20:36 -07004301 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004302 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4303 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004304 goto drop;
4305
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004306 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004307 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004308 conn->rx_len = len - skb->len;
4309 } else {
4310 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4311
4312 if (!conn->rx_len) {
4313 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4314 l2cap_conn_unreliable(conn, ECOMM);
4315 goto drop;
4316 }
4317
4318 if (skb->len > conn->rx_len) {
4319 BT_ERR("Fragment is too long (len %d, expected %d)",
4320 skb->len, conn->rx_len);
4321 kfree_skb(conn->rx_skb);
4322 conn->rx_skb = NULL;
4323 conn->rx_len = 0;
4324 l2cap_conn_unreliable(conn, ECOMM);
4325 goto drop;
4326 }
4327
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004328 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004329 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004330 conn->rx_len -= skb->len;
4331
4332 if (!conn->rx_len) {
4333 /* Complete frame received */
4334 l2cap_recv_frame(conn, conn->rx_skb);
4335 conn->rx_skb = NULL;
4336 }
4337 }
4338
4339drop:
4340 kfree_skb(skb);
4341 return 0;
4342}
4343
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004344static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004345{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004346 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004348 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004349
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004350 list_for_each_entry(c, &chan_list, global_l) {
4351 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004352
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004353 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 +01004354 batostr(&bt_sk(sk)->src),
4355 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004356 sk->sk_state, __le16_to_cpu(c->psm),
4357 c->scid, c->dcid, c->imtu, c->omtu,
4358 c->sec_level, c->mode);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004359 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004360
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004361 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004362
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004363 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364}
4365
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004366static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4367{
4368 return single_open(file, l2cap_debugfs_show, inode->i_private);
4369}
4370
4371static const struct file_operations l2cap_debugfs_fops = {
4372 .open = l2cap_debugfs_open,
4373 .read = seq_read,
4374 .llseek = seq_lseek,
4375 .release = single_release,
4376};
4377
4378static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380static struct hci_proto l2cap_hci_proto = {
4381 .name = "L2CAP",
4382 .id = HCI_PROTO_L2CAP,
4383 .connect_ind = l2cap_connect_ind,
4384 .connect_cfm = l2cap_connect_cfm,
4385 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004386 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004387 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388 .recv_acldata = l2cap_recv_acldata
4389};
4390
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004391int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392{
4393 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004394
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004395 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 if (err < 0)
4397 return err;
4398
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004399 _busy_wq = create_singlethread_workqueue("l2cap");
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004400 if (!_busy_wq) {
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004401 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 goto error;
4403 }
4404
4405 err = hci_register_proto(&l2cap_hci_proto);
4406 if (err < 0) {
4407 BT_ERR("L2CAP protocol registration failed");
4408 bt_sock_unregister(BTPROTO_L2CAP);
4409 goto error;
4410 }
4411
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004412 if (bt_debugfs) {
4413 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4414 bt_debugfs, NULL, &l2cap_debugfs_fops);
4415 if (!l2cap_debugfs)
4416 BT_ERR("Failed to create L2CAP debug file");
4417 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
Linus Torvalds1da177e2005-04-16 15:20:36 -07004419 return 0;
4420
4421error:
Anderson Lizardob78d7b4f2010-11-29 12:15:50 -04004422 destroy_workqueue(_busy_wq);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004423 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 return err;
4425}
4426
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004427void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004429 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03004431 flush_workqueue(_busy_wq);
4432 destroy_workqueue(_busy_wq);
4433
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4435 BT_ERR("L2CAP protocol unregistration failed");
4436
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004437 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438}
4439
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004440module_param(disable_ertm, bool, 0644);
4441MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");