blob: 26925a8f8ead311a9e34808d687a93e1d9f65318 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020059int disable_ertm;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +030060int enable_hs;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030076static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
77
Marcel Holtmann01394182006-07-03 10:02:46 +020078/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030079
80static inline void chan_hold(struct l2cap_chan *c)
81{
82 atomic_inc(&c->refcnt);
83}
84
85static inline void chan_put(struct l2cap_chan *c)
86{
87 if (atomic_dec_and_test(&c->refcnt))
88 kfree(c);
89}
90
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020092{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030093 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030094
95 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030096 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020098 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030099 return NULL;
100
Marcel Holtmann01394182006-07-03 10:02:46 +0200101}
102
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300103static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200104{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300105 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106
107 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300108 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300111 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200112}
113
114/* Find channel with given SCID.
115 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200117{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300118 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119
120 read_lock(&conn->chan_lock);
121 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300122 if (c)
123 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200126}
127
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200129{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300130 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300131
132 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300133 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300136 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200137}
138
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300139static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200140{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300141 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300142
143 read_lock(&conn->chan_lock);
144 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300145 if (c)
146 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300147 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200149}
150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300152{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 list_for_each_entry(c, &chan_list, global_l) {
156 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300157 goto found;
158 }
159
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300160 c = NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300161found:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300162 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300163}
164
165int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
166{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 int err;
168
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300169 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300170
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300171 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300172 err = -EADDRINUSE;
173 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300174 }
175
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300176 if (psm) {
177 chan->psm = psm;
178 chan->sport = psm;
179 err = 0;
180 } else {
181 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300182
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300183 err = -EINVAL;
184 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300185 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300186 chan->psm = cpu_to_le16(p);
187 chan->sport = cpu_to_le16(p);
188 err = 0;
189 break;
190 }
191 }
192
193done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300194 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300195 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300196}
197
198int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
199{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300200 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300201
202 chan->scid = scid;
203
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300204 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300205
206 return 0;
207}
208
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300209static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200210{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300211 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200212
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300213 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300214 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200215 return cid;
216 }
217
218 return 0;
219}
220
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300221static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300222{
Andrei Emeltchenko457f4852011-10-31 16:17:21 +0200223 BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300224
Mat Martineau942ecc92011-06-29 14:35:21 -0700225 if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
Mat Martineau774e5652011-06-29 14:35:20 -0700226 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300227}
228
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300229static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300230{
Mat Martineau774e5652011-06-29 14:35:20 -0700231 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300232
Mat Martineau774e5652011-06-29 14:35:20 -0700233 if (timer_pending(timer) && del_timer(timer))
234 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300235}
236
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300237static void l2cap_state_change(struct l2cap_chan *chan, int state)
238{
239 chan->state = state;
240 chan->ops->state_change(chan->data, state);
241}
242
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300243static void l2cap_chan_timeout(unsigned long arg)
244{
245 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
246 struct sock *sk = chan->sk;
247 int reason;
248
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300249 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300250
251 bh_lock_sock(sk);
252
253 if (sock_owned_by_user(sk)) {
254 /* sk is owned by user. Try again later */
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -0200255 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300256 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300257 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258 return;
259 }
260
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300261 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300262 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300263 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300264 chan->sec_level != BT_SECURITY_SDP)
265 reason = ECONNREFUSED;
266 else
267 reason = ETIMEDOUT;
268
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300269 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300270
271 bh_unlock_sock(sk);
272
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300273 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300274 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300275}
276
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300277struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200278{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300279 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200280
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300281 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
282 if (!chan)
283 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200284
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300285 chan->sk = sk;
286
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300287 write_lock_bh(&chan_list_lock);
288 list_add(&chan->global_l, &chan_list);
289 write_unlock_bh(&chan_list_lock);
290
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300291 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
292
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300293 chan->state = BT_OPEN;
294
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300295 atomic_set(&chan->refcnt, 1);
296
Szymon Jancabc545b2011-11-03 16:05:44 +0100297 BT_DBG("sk %p chan %p", sk, chan);
298
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300299 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200300}
301
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300302void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300303{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300304 write_lock_bh(&chan_list_lock);
305 list_del(&chan->global_l);
306 write_unlock_bh(&chan_list_lock);
307
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300308 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300309}
310
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300311static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200312{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300313 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300314 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200315
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200316 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100317
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300318 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200319
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300320 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300321 if (conn->hcon->type == LE_LINK) {
322 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300323 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300324 chan->scid = L2CAP_CID_LE_DATA;
325 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300326 } else {
327 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300328 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300329 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300330 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300331 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200332 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300333 chan->scid = L2CAP_CID_CONN_LESS;
334 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300335 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200336 } else {
337 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300338 chan->scid = L2CAP_CID_SIGNALING;
339 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300340 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200341 }
342
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300343 chan->local_id = L2CAP_BESTEFFORT_ID;
344 chan->local_stype = L2CAP_SERV_BESTEFFORT;
345 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
346 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
347 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
348 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
349
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300350 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300351
352 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200353}
354
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900355/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200356 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300357static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200358{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300359 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300360 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200361 struct sock *parent = bt_sk(sk)->parent;
362
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300363 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200364
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300365 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200366
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900367 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300368 /* Delete from channel list */
369 write_lock_bh(&conn->chan_lock);
370 list_del(&chan->list);
371 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300372 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300373
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300374 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200375 hci_conn_put(conn->hcon);
376 }
377
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300378 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200379 sock_set_flag(sk, SOCK_ZAPPED);
380
381 if (err)
382 sk->sk_err = err;
383
384 if (parent) {
385 bt_accept_unlink(sk);
386 parent->sk_data_ready(parent, 0);
387 } else
388 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300389
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300390 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
391 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300392 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300393
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300394 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300395
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300396 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300397 struct srej_list *l, *tmp;
398
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300399 __clear_retrans_timer(chan);
400 __clear_monitor_timer(chan);
401 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300402
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300403 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300404
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300405 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300406 list_del(&l->list);
407 kfree(l);
408 }
409 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200410}
411
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300412static void l2cap_chan_cleanup_listen(struct sock *parent)
413{
414 struct sock *sk;
415
416 BT_DBG("parent %p", parent);
417
418 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300419 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300420 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300421 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300422 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300423 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300424 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300425 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300426 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300427}
428
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300429void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300430{
431 struct l2cap_conn *conn = chan->conn;
432 struct sock *sk = chan->sk;
433
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300434 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300435
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300436 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300437 case BT_LISTEN:
438 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300439
440 l2cap_state_change(chan, BT_CLOSED);
441 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442 break;
443
444 case BT_CONNECTED:
445 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300446 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300447 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300448 __clear_chan_timer(chan);
449 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300450 l2cap_send_disconn_req(conn, chan, reason);
451 } else
452 l2cap_chan_del(chan, reason);
453 break;
454
455 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300456 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300457 conn->hcon->type == ACL_LINK) {
458 struct l2cap_conn_rsp rsp;
459 __u16 result;
460
461 if (bt_sk(sk)->defer_setup)
462 result = L2CAP_CR_SEC_BLOCK;
463 else
464 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300465 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300466
467 rsp.scid = cpu_to_le16(chan->dcid);
468 rsp.dcid = cpu_to_le16(chan->scid);
469 rsp.result = cpu_to_le16(result);
470 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
471 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
472 sizeof(rsp), &rsp);
473 }
474
475 l2cap_chan_del(chan, reason);
476 break;
477
478 case BT_CONNECT:
479 case BT_DISCONN:
480 l2cap_chan_del(chan, reason);
481 break;
482
483 default:
484 sock_set_flag(sk, SOCK_ZAPPED);
485 break;
486 }
487}
488
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300489static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530490{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300491 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300492 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530493 case BT_SECURITY_HIGH:
494 return HCI_AT_DEDICATED_BONDING_MITM;
495 case BT_SECURITY_MEDIUM:
496 return HCI_AT_DEDICATED_BONDING;
497 default:
498 return HCI_AT_NO_BONDING;
499 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300500 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300501 if (chan->sec_level == BT_SECURITY_LOW)
502 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530503
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300504 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530505 return HCI_AT_NO_BONDING_MITM;
506 else
507 return HCI_AT_NO_BONDING;
508 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300509 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530510 case BT_SECURITY_HIGH:
511 return HCI_AT_GENERAL_BONDING_MITM;
512 case BT_SECURITY_MEDIUM:
513 return HCI_AT_GENERAL_BONDING;
514 default:
515 return HCI_AT_NO_BONDING;
516 }
517 }
518}
519
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200520/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200521int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200522{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300523 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100524 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200525
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300526 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100527
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300528 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200529}
530
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200531static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200532{
533 u8 id;
534
535 /* Get next available identificator.
536 * 1 - 128 are used by kernel.
537 * 129 - 199 are reserved.
538 * 200 - 254 are used by utilities like l2ping, etc.
539 */
540
541 spin_lock_bh(&conn->lock);
542
543 if (++conn->tx_ident > 128)
544 conn->tx_ident = 1;
545
546 id = conn->tx_ident;
547
548 spin_unlock_bh(&conn->lock);
549
550 return id;
551}
552
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300553static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200554{
555 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200556 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200557
558 BT_DBG("code 0x%2.2x", code);
559
560 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300561 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200562
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200563 if (lmp_no_flush_capable(conn->hcon->hdev))
564 flags = ACL_START_NO_FLUSH;
565 else
566 flags = ACL_START;
567
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700568 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200569 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700570
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200571 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200572}
573
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200574static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
575{
576 struct hci_conn *hcon = chan->conn->hcon;
577 u16 flags;
578
579 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
580 skb->priority);
581
582 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
583 lmp_no_flush_capable(hcon->hdev))
584 flags = ACL_START_NO_FLUSH;
585 else
586 flags = ACL_START;
587
588 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
589 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590}
591
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300592static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300593{
594 struct sk_buff *skb;
595 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300596 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300597 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300598
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300599 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300600 return;
601
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300602 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
603 hlen = L2CAP_EXT_HDR_SIZE;
604 else
605 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300606
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300607 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300608 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300609
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300610 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300611
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300612 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300613
614 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300615
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300616 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300617 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300618
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300619 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300620 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300621
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622 skb = bt_skb_alloc(count, GFP_ATOMIC);
623 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300624 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300625
626 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300627 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300628 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300629
630 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300631
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300632 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300633 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
634 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300635 }
636
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200637 skb->priority = HCI_PRIO_MAX;
638 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300639}
640
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300641static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300642{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300643 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300644 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300645 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300646 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300647 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300648
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300649 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300650
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300651 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300652}
653
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300654static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300655{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300656 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300657}
658
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300659static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200660{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300661 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200662
663 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100664 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
665 return;
666
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200667 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300668 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200669 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300670 req.scid = cpu_to_le16(chan->scid);
671 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200672
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300673 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300674 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200675
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300676 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
677 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200678 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200679 } else {
680 struct l2cap_info_req req;
681 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
682
683 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
684 conn->info_ident = l2cap_get_ident(conn);
685
686 mod_timer(&conn->info_timer, jiffies +
687 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
688
689 l2cap_send_cmd(conn, conn->info_ident,
690 L2CAP_INFO_REQ, sizeof(req), &req);
691 }
692}
693
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300694static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
695{
696 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300697 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300698 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
699
700 switch (mode) {
701 case L2CAP_MODE_ERTM:
702 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
703 case L2CAP_MODE_STREAMING:
704 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
705 default:
706 return 0x00;
707 }
708}
709
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300710static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300711{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300712 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300713 struct l2cap_disconn_req req;
714
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300715 if (!conn)
716 return;
717
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300718 sk = chan->sk;
719
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300720 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300721 __clear_retrans_timer(chan);
722 __clear_monitor_timer(chan);
723 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300724 }
725
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300726 req.dcid = cpu_to_le16(chan->dcid);
727 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300728 l2cap_send_cmd(conn, l2cap_get_ident(conn),
729 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300730
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300731 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300732 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300733}
734
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200736static void l2cap_conn_start(struct l2cap_conn *conn)
737{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300738 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200739
740 BT_DBG("conn %p", conn);
741
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300742 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200743
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300744 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300745 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300746
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200747 bh_lock_sock(sk);
748
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300749 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200750 bh_unlock_sock(sk);
751 continue;
752 }
753
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300754 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300755 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300756
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200757 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300758 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300759 bh_unlock_sock(sk);
760 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200761 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300762
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300763 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
764 && test_bit(CONF_STATE2_DEVICE,
765 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300766 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300767 * so release the lock */
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300768 read_unlock(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300769 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300770 read_lock(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300771 bh_unlock_sock(sk);
772 continue;
773 }
774
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300775 req.scid = cpu_to_le16(chan->scid);
776 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300777
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300778 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300779 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300780
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300781 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
782 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300783
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300784 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200785 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300786 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300787 rsp.scid = cpu_to_le16(chan->dcid);
788 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200789
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200790 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100791 if (bt_sk(sk)->defer_setup) {
792 struct sock *parent = bt_sk(sk)->parent;
793 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
794 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000795 if (parent)
796 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100797
798 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300799 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100800 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
801 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
802 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200803 } else {
804 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
805 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
806 }
807
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300808 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
809 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300810
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300811 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300812 rsp.result != L2CAP_CR_SUCCESS) {
813 bh_unlock_sock(sk);
814 continue;
815 }
816
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300817 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300818 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300819 l2cap_build_conf_req(chan, buf), buf);
820 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200821 }
822
823 bh_unlock_sock(sk);
824 }
825
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300826 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200827}
828
Ville Tervob62f3282011-02-10 22:38:50 -0300829/* Find socket with cid and source bdaddr.
830 * Returns closest match, locked.
831 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300832static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300833{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300834 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300835
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300836 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300837
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300838 list_for_each_entry(c, &chan_list, global_l) {
839 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300840
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300841 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300842 continue;
843
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300844 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300845 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300846 if (!bacmp(&bt_sk(sk)->src, src)) {
847 read_unlock(&chan_list_lock);
848 return c;
849 }
Ville Tervob62f3282011-02-10 22:38:50 -0300850
851 /* Closest match */
852 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300853 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300854 }
855 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300856
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300857 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300858
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300859 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300860}
861
862static void l2cap_le_conn_ready(struct l2cap_conn *conn)
863{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300864 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300865 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300866
867 BT_DBG("");
868
869 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300870 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300871 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300872 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300873 return;
874
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300875 parent = pchan->sk;
876
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300877 bh_lock_sock(parent);
878
Ville Tervob62f3282011-02-10 22:38:50 -0300879 /* Check for backlog size */
880 if (sk_acceptq_is_full(parent)) {
881 BT_DBG("backlog full %d", parent->sk_ack_backlog);
882 goto clean;
883 }
884
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300885 chan = pchan->ops->new_connection(pchan->data);
886 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300887 goto clean;
888
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300889 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300890
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300891 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300892
893 hci_conn_hold(conn->hcon);
894
Ville Tervob62f3282011-02-10 22:38:50 -0300895 bacpy(&bt_sk(sk)->src, conn->src);
896 bacpy(&bt_sk(sk)->dst, conn->dst);
897
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300898 bt_accept_enqueue(parent, sk);
899
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300900 __l2cap_chan_add(conn, chan);
901
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300902 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300903
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300904 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300905 parent->sk_data_ready(parent, 0);
906
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300907 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300908
909clean:
910 bh_unlock_sock(parent);
911}
912
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300913static void l2cap_chan_ready(struct sock *sk)
914{
915 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
916 struct sock *parent = bt_sk(sk)->parent;
917
918 BT_DBG("sk %p, parent %p", sk, parent);
919
920 chan->conf_state = 0;
921 __clear_chan_timer(chan);
922
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300923 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300924 sk->sk_state_change(sk);
925
926 if (parent)
927 parent->sk_data_ready(parent, 0);
928}
929
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200930static void l2cap_conn_ready(struct l2cap_conn *conn)
931{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300932 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200933
934 BT_DBG("conn %p", conn);
935
Ville Tervob62f3282011-02-10 22:38:50 -0300936 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
937 l2cap_le_conn_ready(conn);
938
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300939 if (conn->hcon->out && conn->hcon->type == LE_LINK)
940 smp_conn_security(conn, conn->hcon->pending_sec_level);
941
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300942 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200943
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300944 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300945 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300946
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200947 bh_lock_sock(sk);
948
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300949 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300950 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300951 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300952
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300953 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300954 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300955 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200956 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300957
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300958 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300959 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200960
961 bh_unlock_sock(sk);
962 }
963
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300964 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200965}
966
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200967/* Notify sockets that we cannot guaranty reliability anymore */
968static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
969{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300970 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971
972 BT_DBG("conn %p", conn);
973
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300974 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200975
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300976 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300977 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300978
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300979 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980 sk->sk_err = err;
981 }
982
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300983 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200984}
985
986static void l2cap_info_timeout(unsigned long arg)
987{
988 struct l2cap_conn *conn = (void *) arg;
989
Marcel Holtmann984947d2009-02-06 23:35:19 +0100990 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100991 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100992
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200993 l2cap_conn_start(conn);
994}
995
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300996static void l2cap_conn_del(struct hci_conn *hcon, int err)
997{
998 struct l2cap_conn *conn = hcon->l2cap_data;
999 struct l2cap_chan *chan, *l;
1000 struct sock *sk;
1001
1002 if (!conn)
1003 return;
1004
1005 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1006
1007 kfree_skb(conn->rx_skb);
1008
1009 /* Kill channels */
1010 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1011 sk = chan->sk;
1012 bh_lock_sock(sk);
1013 l2cap_chan_del(chan, err);
1014 bh_unlock_sock(sk);
1015 chan->ops->close(chan->data);
1016 }
1017
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001018 hci_chan_del(conn->hchan);
1019
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001020 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1021 del_timer_sync(&conn->info_timer);
1022
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001023 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001024 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001025 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001026 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001027
1028 hcon->l2cap_data = NULL;
1029 kfree(conn);
1030}
1031
1032static void security_timeout(unsigned long arg)
1033{
1034 struct l2cap_conn *conn = (void *) arg;
1035
1036 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1037}
1038
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1040{
Marcel Holtmann01394182006-07-03 10:02:46 +02001041 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001042 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043
Marcel Holtmann01394182006-07-03 10:02:46 +02001044 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return conn;
1046
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001047 hchan = hci_chan_create(hcon);
1048 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001051 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1052 if (!conn) {
1053 hci_chan_del(hchan);
1054 return NULL;
1055 }
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 hcon->l2cap_data = conn;
1058 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001059 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001060
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001061 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001062
Ville Tervoacd7d372011-02-10 22:38:49 -03001063 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1064 conn->mtu = hcon->hdev->le_mtu;
1065 else
1066 conn->mtu = hcon->hdev->acl_mtu;
1067
Linus Torvalds1da177e2005-04-16 15:20:36 -07001068 conn->src = &hcon->hdev->bdaddr;
1069 conn->dst = &hcon->dst;
1070
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001071 conn->feat_mask = 0;
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001074 rwlock_init(&conn->chan_lock);
1075
1076 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001078 if (hcon->type == LE_LINK)
1079 setup_timer(&conn->security_timer, security_timeout,
1080 (unsigned long) conn);
1081 else
Ville Tervob62f3282011-02-10 22:38:50 -03001082 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001083 (unsigned long) conn);
1084
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001085 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001086
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087 return conn;
1088}
1089
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001090static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001092 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001093 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001094 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095}
1096
Linus Torvalds1da177e2005-04-16 15:20:36 -07001097/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001098
1099/* Find socket with psm and source bdaddr.
1100 * Returns closest match.
1101 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001102static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001104 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001106 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001107
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001108 list_for_each_entry(c, &chan_list, global_l) {
1109 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001110
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001111 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 continue;
1113
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001114 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001116 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001117 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001118 return c;
1119 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
1121 /* Closest match */
1122 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 }
1125 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001127 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001128
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001129 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130}
1131
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001132int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001134 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 bdaddr_t *src = &bt_sk(sk)->src;
1136 bdaddr_t *dst = &bt_sk(sk)->dst;
1137 struct l2cap_conn *conn;
1138 struct hci_conn *hcon;
1139 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001140 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001141 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001143 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001144 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001146 hdev = hci_get_route(dst, src);
1147 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148 return -EHOSTUNREACH;
1149
1150 hci_dev_lock_bh(hdev);
1151
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001152 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001153
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001154 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001155 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001156 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001157 else
1158 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001159 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001160
Ville Tervo30e76272011-02-22 16:10:53 -03001161 if (IS_ERR(hcon)) {
1162 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001164 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
1166 conn = l2cap_conn_add(hcon, 0);
1167 if (!conn) {
1168 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001169 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 goto done;
1171 }
1172
Linus Torvalds1da177e2005-04-16 15:20:36 -07001173 /* Update source addr of the socket */
1174 bacpy(src, conn->src);
1175
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001176 l2cap_chan_add(conn, chan);
1177
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001178 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001179 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180
1181 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001182 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001183 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001184 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001185 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001186 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001187 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 }
1189
Ville Tervo30e76272011-02-22 16:10:53 -03001190 err = 0;
1191
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192done:
1193 hci_dev_unlock_bh(hdev);
1194 hci_dev_put(hdev);
1195 return err;
1196}
1197
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001198int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001199{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001200 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001201 DECLARE_WAITQUEUE(wait, current);
1202 int err = 0;
1203 int timeo = HZ/5;
1204
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001205 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001206 set_current_state(TASK_INTERRUPTIBLE);
1207 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001208 if (!timeo)
1209 timeo = HZ/5;
1210
1211 if (signal_pending(current)) {
1212 err = sock_intr_errno(timeo);
1213 break;
1214 }
1215
1216 release_sock(sk);
1217 timeo = schedule_timeout(timeo);
1218 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001219 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001220
1221 err = sock_error(sk);
1222 if (err)
1223 break;
1224 }
1225 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001226 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001227 return err;
1228}
1229
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001230static void l2cap_monitor_timeout(unsigned long arg)
1231{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001232 struct l2cap_chan *chan = (void *) arg;
1233 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001234
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001235 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001236
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001237 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001238 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001239 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001240 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001241 return;
1242 }
1243
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001244 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001245 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001246
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001247 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001248 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001249}
1250
1251static void l2cap_retrans_timeout(unsigned long arg)
1252{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001253 struct l2cap_chan *chan = (void *) arg;
1254 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001255
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001256 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001257
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001258 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001259 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001260 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001261
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001262 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001263
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001264 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001265 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001266}
1267
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001268static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001269{
1270 struct sk_buff *skb;
1271
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001272 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001273 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001274 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001275 break;
1276
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001277 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001278 kfree_skb(skb);
1279
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001280 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001281 }
1282
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001283 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001284 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001285}
1286
Szymon Janc67c9e842011-07-28 16:24:33 +02001287static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001288{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001289 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001290 u32 control;
1291 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001292
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001293 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001294 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001295 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001296 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001297
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001298 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001299 fcs = crc16(0, (u8 *)skb->data,
1300 skb->len - L2CAP_FCS_SIZE);
1301 put_unaligned_le16(fcs,
1302 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001303 }
1304
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001305 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001306
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001307 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001308 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001309}
1310
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001311static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001312{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001313 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001314 u16 fcs;
1315 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001316
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001317 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001318 if (!skb)
1319 return;
1320
Szymon Jancd1726b62011-11-16 09:32:20 +01001321 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001322 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001323 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001324
Szymon Jancd1726b62011-11-16 09:32:20 +01001325 skb = skb_queue_next(&chan->tx_q, skb);
1326 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001327
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001328 if (chan->remote_max_tx &&
1329 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001330 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001331 return;
1332 }
1333
1334 tx_skb = skb_clone(skb, GFP_ATOMIC);
1335 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001336
1337 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001338 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001339
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001340 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001341 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001342
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001343 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001344 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001345
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001346 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001347
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001348 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001349 fcs = crc16(0, (u8 *)tx_skb->data,
1350 tx_skb->len - L2CAP_FCS_SIZE);
1351 put_unaligned_le16(fcs,
1352 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001353 }
1354
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001355 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001356}
1357
Szymon Janc67c9e842011-07-28 16:24:33 +02001358static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001359{
1360 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001361 u16 fcs;
1362 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001363 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001364
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001365 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001366 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001367
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001368 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001369
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001370 if (chan->remote_max_tx &&
1371 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001372 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001373 break;
1374 }
1375
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001376 tx_skb = skb_clone(skb, GFP_ATOMIC);
1377
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001378 bt_cb(skb)->retries++;
1379
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001380 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001381 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001382
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001383 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001384 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001385
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001386 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001387 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001388
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001389 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001390
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001391 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001392 fcs = crc16(0, (u8 *)skb->data,
1393 tx_skb->len - L2CAP_FCS_SIZE);
1394 put_unaligned_le16(fcs, skb->data +
1395 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001396 }
1397
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001398 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001399
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001400 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001401
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001402 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001403
1404 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001405
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301406 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001407 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301408
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001409 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001410
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001411 if (skb_queue_is_last(&chan->tx_q, skb))
1412 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001413 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001414 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001415
1416 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001417 }
1418
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001419 return nsent;
1420}
1421
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001422static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001423{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001424 int ret;
1425
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001426 if (!skb_queue_empty(&chan->tx_q))
1427 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001428
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001429 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001430 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001431 return ret;
1432}
1433
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001434static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001435{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001436 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001437
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001438 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001439
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001440 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001441 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001442 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001443 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001444 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001445 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001446
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001447 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001448 return;
1449
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001450 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001451 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001452}
1453
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001454static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001455{
1456 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001457 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001458
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001459 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001460 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001461
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001462 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001463 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001464
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001465 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001466}
1467
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001468static 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 -07001469{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001470 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001471 struct sk_buff **frag;
1472 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001474 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001475 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476
1477 sent += count;
1478 len -= count;
1479
1480 /* Continuation fragments (no L2CAP header) */
1481 frag = &skb_shinfo(skb)->frag_list;
1482 while (len) {
1483 count = min_t(unsigned int, conn->mtu, len);
1484
1485 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1486 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001487 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001488 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1489 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001491 (*frag)->priority = skb->priority;
1492
Linus Torvalds1da177e2005-04-16 15:20:36 -07001493 sent += count;
1494 len -= count;
1495
1496 frag = &(*frag)->next;
1497 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
1499 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001500}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001502static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1503 struct msghdr *msg, size_t len,
1504 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001505{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001506 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001507 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001508 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001509 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001510 struct l2cap_hdr *lh;
1511
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001512 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001513
1514 count = min_t(unsigned int, (conn->mtu - hlen), len);
1515 skb = bt_skb_send_alloc(sk, count + hlen,
1516 msg->msg_flags & MSG_DONTWAIT, &err);
1517 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001518 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001519
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001520 skb->priority = priority;
1521
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001522 /* Create L2CAP header */
1523 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001524 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001525 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001526 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001527
1528 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1529 if (unlikely(err < 0)) {
1530 kfree_skb(skb);
1531 return ERR_PTR(err);
1532 }
1533 return skb;
1534}
1535
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001536static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1537 struct msghdr *msg, size_t len,
1538 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001539{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001540 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001541 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001542 struct sk_buff *skb;
1543 int err, count, hlen = L2CAP_HDR_SIZE;
1544 struct l2cap_hdr *lh;
1545
1546 BT_DBG("sk %p len %d", sk, (int)len);
1547
1548 count = min_t(unsigned int, (conn->mtu - hlen), len);
1549 skb = bt_skb_send_alloc(sk, count + hlen,
1550 msg->msg_flags & MSG_DONTWAIT, &err);
1551 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001552 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001553
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001554 skb->priority = priority;
1555
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001556 /* Create L2CAP header */
1557 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001558 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001559 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1560
1561 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1562 if (unlikely(err < 0)) {
1563 kfree_skb(skb);
1564 return ERR_PTR(err);
1565 }
1566 return skb;
1567}
1568
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001569static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1570 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001571 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001572{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001573 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001574 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001575 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001576 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001577 struct l2cap_hdr *lh;
1578
1579 BT_DBG("sk %p len %d", sk, (int)len);
1580
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001581 if (!conn)
1582 return ERR_PTR(-ENOTCONN);
1583
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001584 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1585 hlen = L2CAP_EXT_HDR_SIZE;
1586 else
1587 hlen = L2CAP_ENH_HDR_SIZE;
1588
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001589 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001590 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001591
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001592 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001593 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001594
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595 count = min_t(unsigned int, (conn->mtu - hlen), len);
1596 skb = bt_skb_send_alloc(sk, count + hlen,
1597 msg->msg_flags & MSG_DONTWAIT, &err);
1598 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001599 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001600
1601 /* Create L2CAP header */
1602 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001603 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001604 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001605
1606 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1607
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001608 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001609 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001610
1611 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1612 if (unlikely(err < 0)) {
1613 kfree_skb(skb);
1614 return ERR_PTR(err);
1615 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001616
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001617 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001618 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001619
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001620 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001621 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622}
1623
Szymon Janc67c9e842011-07-28 16:24:33 +02001624static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001625{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001626 struct sk_buff *skb;
1627 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001628 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001629 size_t size = 0;
1630
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001631 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001632 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001633 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001634 if (IS_ERR(skb))
1635 return PTR_ERR(skb);
1636
1637 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001638 len -= chan->remote_mps;
1639 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001640
1641 while (len > 0) {
1642 size_t buflen;
1643
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001644 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001645 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001646 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001647 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001648 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001649 buflen = len;
1650 }
1651
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001652 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001653 if (IS_ERR(skb)) {
1654 skb_queue_purge(&sar_queue);
1655 return PTR_ERR(skb);
1656 }
1657
1658 __skb_queue_tail(&sar_queue, skb);
1659 len -= buflen;
1660 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001661 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001662 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1663 if (chan->tx_send_head == NULL)
1664 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001665
1666 return size;
1667}
1668
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001669int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1670 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001671{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001672 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001673 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001674 int err;
1675
1676 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001677 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001678 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001679 if (IS_ERR(skb))
1680 return PTR_ERR(skb);
1681
1682 l2cap_do_send(chan, skb);
1683 return len;
1684 }
1685
1686 switch (chan->mode) {
1687 case L2CAP_MODE_BASIC:
1688 /* Check outgoing MTU */
1689 if (len > chan->omtu)
1690 return -EMSGSIZE;
1691
1692 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001693 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001694 if (IS_ERR(skb))
1695 return PTR_ERR(skb);
1696
1697 l2cap_do_send(chan, skb);
1698 err = len;
1699 break;
1700
1701 case L2CAP_MODE_ERTM:
1702 case L2CAP_MODE_STREAMING:
1703 /* Entire SDU fits into one PDU */
1704 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001705 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001706 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1707 0);
1708 if (IS_ERR(skb))
1709 return PTR_ERR(skb);
1710
1711 __skb_queue_tail(&chan->tx_q, skb);
1712
1713 if (chan->tx_send_head == NULL)
1714 chan->tx_send_head = skb;
1715
1716 } else {
1717 /* Segment SDU into multiples PDUs */
1718 err = l2cap_sar_segment_sdu(chan, msg, len);
1719 if (err < 0)
1720 return err;
1721 }
1722
1723 if (chan->mode == L2CAP_MODE_STREAMING) {
1724 l2cap_streaming_send(chan);
1725 err = len;
1726 break;
1727 }
1728
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001729 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1730 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001731 err = len;
1732 break;
1733 }
1734
1735 err = l2cap_ertm_send(chan);
1736 if (err >= 0)
1737 err = len;
1738
1739 break;
1740
1741 default:
1742 BT_DBG("bad state %1.1x", chan->mode);
1743 err = -EBADFD;
1744 }
1745
1746 return err;
1747}
1748
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749/* Copy frame to all raw sockets on that connection */
1750static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1751{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001752 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001753 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754
1755 BT_DBG("conn %p", conn);
1756
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001757 read_lock(&conn->chan_lock);
1758 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001759 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001760 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 continue;
1762
1763 /* Don't send frame to the socket it came from */
1764 if (skb->sk == sk)
1765 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001766 nskb = skb_clone(skb, GFP_ATOMIC);
1767 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 continue;
1769
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001770 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 kfree_skb(nskb);
1772 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001773 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774}
1775
1776/* ---- L2CAP signalling commands ---- */
1777static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1778 u8 code, u8 ident, u16 dlen, void *data)
1779{
1780 struct sk_buff *skb, **frag;
1781 struct l2cap_cmd_hdr *cmd;
1782 struct l2cap_hdr *lh;
1783 int len, count;
1784
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001785 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1786 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
1788 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1789 count = min_t(unsigned int, conn->mtu, len);
1790
1791 skb = bt_skb_alloc(count, GFP_ATOMIC);
1792 if (!skb)
1793 return NULL;
1794
1795 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001796 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001797
1798 if (conn->hcon->type == LE_LINK)
1799 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1800 else
1801 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802
1803 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1804 cmd->code = code;
1805 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001806 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
1808 if (dlen) {
1809 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1810 memcpy(skb_put(skb, count), data, count);
1811 data += count;
1812 }
1813
1814 len -= skb->len;
1815
1816 /* Continuation fragments (no L2CAP header) */
1817 frag = &skb_shinfo(skb)->frag_list;
1818 while (len) {
1819 count = min_t(unsigned int, conn->mtu, len);
1820
1821 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1822 if (!*frag)
1823 goto fail;
1824
1825 memcpy(skb_put(*frag, count), data, count);
1826
1827 len -= count;
1828 data += count;
1829
1830 frag = &(*frag)->next;
1831 }
1832
1833 return skb;
1834
1835fail:
1836 kfree_skb(skb);
1837 return NULL;
1838}
1839
1840static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1841{
1842 struct l2cap_conf_opt *opt = *ptr;
1843 int len;
1844
1845 len = L2CAP_CONF_OPT_SIZE + opt->len;
1846 *ptr += len;
1847
1848 *type = opt->type;
1849 *olen = opt->len;
1850
1851 switch (opt->len) {
1852 case 1:
1853 *val = *((u8 *) opt->val);
1854 break;
1855
1856 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001857 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 break;
1859
1860 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001861 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862 break;
1863
1864 default:
1865 *val = (unsigned long) opt->val;
1866 break;
1867 }
1868
1869 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1870 return len;
1871}
1872
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1874{
1875 struct l2cap_conf_opt *opt = *ptr;
1876
1877 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1878
1879 opt->type = type;
1880 opt->len = len;
1881
1882 switch (len) {
1883 case 1:
1884 *((u8 *) opt->val) = val;
1885 break;
1886
1887 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001888 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 break;
1890
1891 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001892 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001893 break;
1894
1895 default:
1896 memcpy(opt->val, (void *) val, len);
1897 break;
1898 }
1899
1900 *ptr += L2CAP_CONF_OPT_SIZE + len;
1901}
1902
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001903static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1904{
1905 struct l2cap_conf_efs efs;
1906
1907 switch(chan->mode) {
1908 case L2CAP_MODE_ERTM:
1909 efs.id = chan->local_id;
1910 efs.stype = chan->local_stype;
1911 efs.msdu = cpu_to_le16(chan->local_msdu);
1912 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1913 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1914 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1915 break;
1916
1917 case L2CAP_MODE_STREAMING:
1918 efs.id = 1;
1919 efs.stype = L2CAP_SERV_BESTEFFORT;
1920 efs.msdu = cpu_to_le16(chan->local_msdu);
1921 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1922 efs.acc_lat = 0;
1923 efs.flush_to = 0;
1924 break;
1925
1926 default:
1927 return;
1928 }
1929
1930 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1931 (unsigned long) &efs);
1932}
1933
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001934static void l2cap_ack_timeout(unsigned long arg)
1935{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001936 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001937
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001938 bh_lock_sock(chan->sk);
1939 l2cap_send_ack(chan);
1940 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001941}
1942
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001943static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001944{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001945 struct sock *sk = chan->sk;
1946
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001947 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001948 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001949 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001950 chan->num_acked = 0;
1951 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001952
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001953 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1954 (unsigned long) chan);
1955 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1956 (unsigned long) chan);
1957 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001958
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001959 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001960
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001961 INIT_LIST_HEAD(&chan->srej_l);
1962
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001963
1964 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001965}
1966
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001967static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1968{
1969 switch (mode) {
1970 case L2CAP_MODE_STREAMING:
1971 case L2CAP_MODE_ERTM:
1972 if (l2cap_mode_supported(mode, remote_feat_mask))
1973 return mode;
1974 /* fall through */
1975 default:
1976 return L2CAP_MODE_BASIC;
1977 }
1978}
1979
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001980static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
1981{
1982 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
1983}
1984
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001985static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
1986{
1987 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
1988}
1989
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001990static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
1991{
1992 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001993 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001994 /* use extended control field */
1995 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001996 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
1997 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001998 chan->tx_win = min_t(u16, chan->tx_win,
1999 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002000 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2001 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002002}
2003
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002004static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002007 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002009 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002011 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002012
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002013 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002014 goto done;
2015
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002016 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002017 case L2CAP_MODE_STREAMING:
2018 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002019 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002020 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002021
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002022 if (__l2cap_efs_supported(chan))
2023 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2024
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002025 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002026 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002027 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002028 break;
2029 }
2030
2031done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002032 if (chan->imtu != L2CAP_DEFAULT_MTU)
2033 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002034
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002035 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002036 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002037 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2038 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002039 break;
2040
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002041 rfc.mode = L2CAP_MODE_BASIC;
2042 rfc.txwin_size = 0;
2043 rfc.max_transmit = 0;
2044 rfc.retrans_timeout = 0;
2045 rfc.monitor_timeout = 0;
2046 rfc.max_pdu_size = 0;
2047
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002048 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2049 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002050 break;
2051
2052 case L2CAP_MODE_ERTM:
2053 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002054 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002055 rfc.retrans_timeout = 0;
2056 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002057
2058 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2059 L2CAP_EXT_HDR_SIZE -
2060 L2CAP_SDULEN_SIZE -
2061 L2CAP_FCS_SIZE);
2062 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002063
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002064 l2cap_txwin_setup(chan);
2065
2066 rfc.txwin_size = min_t(u16, chan->tx_win,
2067 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002068
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002069 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2070 (unsigned long) &rfc);
2071
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002072 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2073 l2cap_add_opt_efs(&ptr, chan);
2074
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002075 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002076 break;
2077
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002078 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002079 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002080 chan->fcs = L2CAP_FCS_NONE;
2081 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002082 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002083
2084 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2085 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2086 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002087 break;
2088
2089 case L2CAP_MODE_STREAMING:
2090 rfc.mode = L2CAP_MODE_STREAMING;
2091 rfc.txwin_size = 0;
2092 rfc.max_transmit = 0;
2093 rfc.retrans_timeout = 0;
2094 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002095
2096 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2097 L2CAP_EXT_HDR_SIZE -
2098 L2CAP_SDULEN_SIZE -
2099 L2CAP_FCS_SIZE);
2100 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002101
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002102 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2103 (unsigned long) &rfc);
2104
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002105 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2106 l2cap_add_opt_efs(&ptr, chan);
2107
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002108 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002109 break;
2110
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002111 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002112 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002113 chan->fcs = L2CAP_FCS_NONE;
2114 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002115 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002116 break;
2117 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002119 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002120 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002121
2122 return ptr - data;
2123}
2124
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002125static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002126{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002127 struct l2cap_conf_rsp *rsp = data;
2128 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002129 void *req = chan->conf_req;
2130 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002131 int type, hint, olen;
2132 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002133 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002134 struct l2cap_conf_efs efs;
2135 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002136 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002137 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002138 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002139
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002140 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002141
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002142 while (len >= L2CAP_CONF_OPT_SIZE) {
2143 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002144
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002145 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002146 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002147
2148 switch (type) {
2149 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002150 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002151 break;
2152
2153 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002154 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002155 break;
2156
2157 case L2CAP_CONF_QOS:
2158 break;
2159
Marcel Holtmann6464f352007-10-20 13:39:51 +02002160 case L2CAP_CONF_RFC:
2161 if (olen == sizeof(rfc))
2162 memcpy(&rfc, (void *) val, olen);
2163 break;
2164
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002165 case L2CAP_CONF_FCS:
2166 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002167 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002168 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002169
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002170 case L2CAP_CONF_EFS:
2171 remote_efs = 1;
2172 if (olen == sizeof(efs))
2173 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002174 break;
2175
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002176 case L2CAP_CONF_EWS:
2177 if (!enable_hs)
2178 return -ECONNREFUSED;
2179
2180 set_bit(FLAG_EXT_CTRL, &chan->flags);
2181 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002182 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002183 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002184 break;
2185
2186 default:
2187 if (hint)
2188 break;
2189
2190 result = L2CAP_CONF_UNKNOWN;
2191 *((u8 *) ptr++) = type;
2192 break;
2193 }
2194 }
2195
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002196 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002197 goto done;
2198
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002199 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002200 case L2CAP_MODE_STREAMING:
2201 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002202 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002203 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002204 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002205 break;
2206 }
2207
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002208 if (remote_efs) {
2209 if (__l2cap_efs_supported(chan))
2210 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2211 else
2212 return -ECONNREFUSED;
2213 }
2214
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002215 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002216 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002217
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002218 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002219 }
2220
2221done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002222 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002223 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002224 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002225
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002226 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002227 return -ECONNREFUSED;
2228
2229 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2230 sizeof(rfc), (unsigned long) &rfc);
2231 }
2232
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002233 if (result == L2CAP_CONF_SUCCESS) {
2234 /* Configure output options and let the other side know
2235 * which ones we don't like. */
2236
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002237 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2238 result = L2CAP_CONF_UNACCEPT;
2239 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002240 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002241 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002242 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002243 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002244
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002245 if (remote_efs) {
2246 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2247 efs.stype != L2CAP_SERV_NOTRAFIC &&
2248 efs.stype != chan->local_stype) {
2249
2250 result = L2CAP_CONF_UNACCEPT;
2251
2252 if (chan->num_conf_req >= 1)
2253 return -ECONNREFUSED;
2254
2255 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002256 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002257 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002258 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002259 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002260 result = L2CAP_CONF_PENDING;
2261 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002262 }
2263 }
2264
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002265 switch (rfc.mode) {
2266 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002267 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002268 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002269 break;
2270
2271 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002272 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2273 chan->remote_tx_win = rfc.txwin_size;
2274 else
2275 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2276
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002277 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002278
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002279 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2280 chan->conn->mtu -
2281 L2CAP_EXT_HDR_SIZE -
2282 L2CAP_SDULEN_SIZE -
2283 L2CAP_FCS_SIZE);
2284 rfc.max_pdu_size = cpu_to_le16(size);
2285 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002286
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002287 rfc.retrans_timeout =
2288 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2289 rfc.monitor_timeout =
2290 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002291
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002292 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002293
2294 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2295 sizeof(rfc), (unsigned long) &rfc);
2296
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002297 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2298 chan->remote_id = efs.id;
2299 chan->remote_stype = efs.stype;
2300 chan->remote_msdu = le16_to_cpu(efs.msdu);
2301 chan->remote_flush_to =
2302 le32_to_cpu(efs.flush_to);
2303 chan->remote_acc_lat =
2304 le32_to_cpu(efs.acc_lat);
2305 chan->remote_sdu_itime =
2306 le32_to_cpu(efs.sdu_itime);
2307 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2308 sizeof(efs), (unsigned long) &efs);
2309 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002310 break;
2311
2312 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002313 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2314 chan->conn->mtu -
2315 L2CAP_EXT_HDR_SIZE -
2316 L2CAP_SDULEN_SIZE -
2317 L2CAP_FCS_SIZE);
2318 rfc.max_pdu_size = cpu_to_le16(size);
2319 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002320
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002321 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002322
2323 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2324 sizeof(rfc), (unsigned long) &rfc);
2325
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002326 break;
2327
2328 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002329 result = L2CAP_CONF_UNACCEPT;
2330
2331 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002332 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002333 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002334
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002335 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002336 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002337 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002338 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002339 rsp->result = cpu_to_le16(result);
2340 rsp->flags = cpu_to_le16(0x0000);
2341
2342 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002343}
2344
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002345static 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 -03002346{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002347 struct l2cap_conf_req *req = data;
2348 void *ptr = req->data;
2349 int type, olen;
2350 unsigned long val;
2351 struct l2cap_conf_rfc rfc;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002352 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002353
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002354 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002355
2356 while (len >= L2CAP_CONF_OPT_SIZE) {
2357 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2358
2359 switch (type) {
2360 case L2CAP_CONF_MTU:
2361 if (val < L2CAP_DEFAULT_MIN_MTU) {
2362 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002363 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002364 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002365 chan->imtu = val;
2366 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002367 break;
2368
2369 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002370 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002371 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002372 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002373 break;
2374
2375 case L2CAP_CONF_RFC:
2376 if (olen == sizeof(rfc))
2377 memcpy(&rfc, (void *)val, olen);
2378
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002379 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002380 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002381 return -ECONNREFUSED;
2382
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002383 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002384
2385 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2386 sizeof(rfc), (unsigned long) &rfc);
2387 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002388
2389 case L2CAP_CONF_EWS:
2390 chan->tx_win = min_t(u16, val,
2391 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002392 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2393 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002394 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002395
2396 case L2CAP_CONF_EFS:
2397 if (olen == sizeof(efs))
2398 memcpy(&efs, (void *)val, olen);
2399
2400 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2401 efs.stype != L2CAP_SERV_NOTRAFIC &&
2402 efs.stype != chan->local_stype)
2403 return -ECONNREFUSED;
2404
2405 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2406 sizeof(efs), (unsigned long) &efs);
2407 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002408 }
2409 }
2410
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002411 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002412 return -ECONNREFUSED;
2413
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002414 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002415
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002416 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002417 switch (rfc.mode) {
2418 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002419 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2420 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2421 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002422
2423 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2424 chan->local_msdu = le16_to_cpu(efs.msdu);
2425 chan->local_sdu_itime =
2426 le32_to_cpu(efs.sdu_itime);
2427 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2428 chan->local_flush_to =
2429 le32_to_cpu(efs.flush_to);
2430 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002431 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002432
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002433 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002434 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002435 }
2436 }
2437
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002438 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002439 req->flags = cpu_to_le16(0x0000);
2440
2441 return ptr - data;
2442}
2443
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002444static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445{
2446 struct l2cap_conf_rsp *rsp = data;
2447 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002448
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002449 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002451 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002452 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002453 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002454
2455 return ptr - data;
2456}
2457
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002458void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002459{
2460 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002461 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002462 u8 buf[128];
2463
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002464 rsp.scid = cpu_to_le16(chan->dcid);
2465 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002466 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2467 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2468 l2cap_send_cmd(conn, chan->ident,
2469 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2470
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002471 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002472 return;
2473
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002474 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2475 l2cap_build_conf_req(chan, buf), buf);
2476 chan->num_conf_req++;
2477}
2478
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002479static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002480{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002481 int type, olen;
2482 unsigned long val;
2483 struct l2cap_conf_rfc rfc;
2484
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002485 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002486
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002487 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002488 return;
2489
2490 while (len >= L2CAP_CONF_OPT_SIZE) {
2491 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2492
2493 switch (type) {
2494 case L2CAP_CONF_RFC:
2495 if (olen == sizeof(rfc))
2496 memcpy(&rfc, (void *)val, olen);
2497 goto done;
2498 }
2499 }
2500
2501done:
2502 switch (rfc.mode) {
2503 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002504 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2505 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2506 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002507 break;
2508 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002509 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002510 }
2511}
2512
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002513static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2514{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002515 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002516
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002517 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002518 return 0;
2519
2520 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2521 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002522 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002523
2524 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002525 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002526
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002527 l2cap_conn_start(conn);
2528 }
2529
2530 return 0;
2531}
2532
Linus Torvalds1da177e2005-04-16 15:20:36 -07002533static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2534{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002535 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2536 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002537 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002538 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002539 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
2541 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002542 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002543
2544 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2545
2546 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002547 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2548 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002549 result = L2CAP_CR_BAD_PSM;
2550 goto sendresp;
2551 }
2552
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002553 parent = pchan->sk;
2554
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002555 bh_lock_sock(parent);
2556
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002557 /* Check if the ACL is secure enough (if not SDP) */
2558 if (psm != cpu_to_le16(0x0001) &&
2559 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002560 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002561 result = L2CAP_CR_SEC_BLOCK;
2562 goto response;
2563 }
2564
Linus Torvalds1da177e2005-04-16 15:20:36 -07002565 result = L2CAP_CR_NO_MEM;
2566
2567 /* Check for backlog size */
2568 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002569 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570 goto response;
2571 }
2572
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002573 chan = pchan->ops->new_connection(pchan->data);
2574 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002575 goto response;
2576
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002577 sk = chan->sk;
2578
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002579 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580
2581 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002582 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2583 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002585 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002586 goto response;
2587 }
2588
2589 hci_conn_hold(conn->hcon);
2590
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591 bacpy(&bt_sk(sk)->src, conn->src);
2592 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002593 chan->psm = psm;
2594 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002595
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002596 bt_accept_enqueue(parent, sk);
2597
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002598 __l2cap_chan_add(conn, chan);
2599
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002600 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002602 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002604 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
Marcel Holtmann984947d2009-02-06 23:35:19 +01002606 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002607 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002608 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002609 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002610 result = L2CAP_CR_PEND;
2611 status = L2CAP_CS_AUTHOR_PEND;
2612 parent->sk_data_ready(parent, 0);
2613 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002614 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002615 result = L2CAP_CR_SUCCESS;
2616 status = L2CAP_CS_NO_INFO;
2617 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002618 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002619 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002620 result = L2CAP_CR_PEND;
2621 status = L2CAP_CS_AUTHEN_PEND;
2622 }
2623 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002624 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002625 result = L2CAP_CR_PEND;
2626 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627 }
2628
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002629 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630
2631response:
2632 bh_unlock_sock(parent);
2633
2634sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002635 rsp.scid = cpu_to_le16(scid);
2636 rsp.dcid = cpu_to_le16(dcid);
2637 rsp.result = cpu_to_le16(result);
2638 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002640
2641 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2642 struct l2cap_info_req info;
2643 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2644
2645 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2646 conn->info_ident = l2cap_get_ident(conn);
2647
2648 mod_timer(&conn->info_timer, jiffies +
2649 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2650
2651 l2cap_send_cmd(conn, conn->info_ident,
2652 L2CAP_INFO_REQ, sizeof(info), &info);
2653 }
2654
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002655 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002656 result == L2CAP_CR_SUCCESS) {
2657 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002658 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002659 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002660 l2cap_build_conf_req(chan, buf), buf);
2661 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002662 }
2663
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664 return 0;
2665}
2666
2667static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2668{
2669 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2670 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002671 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002672 struct sock *sk;
2673 u8 req[128];
2674
2675 scid = __le16_to_cpu(rsp->scid);
2676 dcid = __le16_to_cpu(rsp->dcid);
2677 result = __le16_to_cpu(rsp->result);
2678 status = __le16_to_cpu(rsp->status);
2679
2680 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2681
2682 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002683 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002684 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002685 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002687 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002688 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002689 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 }
2691
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002692 sk = chan->sk;
2693
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694 switch (result) {
2695 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002696 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002697 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002698 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002699 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002700
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002701 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002702 break;
2703
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002705 l2cap_build_conf_req(chan, req), req);
2706 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 break;
2708
2709 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002710 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002711 break;
2712
2713 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002714 /* don't delete l2cap channel if sk is owned by user */
2715 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002716 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002717 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002718 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002719 break;
2720 }
2721
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002722 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 break;
2724 }
2725
2726 bh_unlock_sock(sk);
2727 return 0;
2728}
2729
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002730static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002731{
2732 /* FCS is enabled only in ERTM or streaming mode, if one or both
2733 * sides request it.
2734 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002735 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002736 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002737 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002738 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002739}
2740
Al Viro88219a02007-07-29 00:17:25 -07002741static 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 -07002742{
2743 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2744 u16 dcid, flags;
2745 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002746 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002747 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002748 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749
2750 dcid = __le16_to_cpu(req->dcid);
2751 flags = __le16_to_cpu(req->flags);
2752
2753 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2754
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002755 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002756 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757 return -ENOENT;
2758
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002759 sk = chan->sk;
2760
David S. Miller033b1142011-07-21 13:38:42 -07002761 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002762 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002763
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002764 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2765 rej.scid = cpu_to_le16(chan->scid);
2766 rej.dcid = cpu_to_le16(chan->dcid);
2767
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002768 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2769 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002770 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002771 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002772
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002773 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002774 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002775 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002776 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002777 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002778 L2CAP_CONF_REJECT, flags), rsp);
2779 goto unlock;
2780 }
2781
2782 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002783 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2784 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002785
2786 if (flags & 0x0001) {
2787 /* Incomplete config. Send empty response. */
2788 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002789 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002790 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791 goto unlock;
2792 }
2793
2794 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002795 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002796 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002797 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002799 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002801 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002802 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002803
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002804 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002805 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002806
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002807 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002808 goto unlock;
2809
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002810 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002811 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002812
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002813 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002814
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002815 chan->next_tx_seq = 0;
2816 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002817 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002818 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002819 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002820
Linus Torvalds1da177e2005-04-16 15:20:36 -07002821 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002822 goto unlock;
2823 }
2824
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002825 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002826 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002828 l2cap_build_conf_req(chan, buf), buf);
2829 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 }
2831
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002832 /* Got Conf Rsp PENDING from remote side and asume we sent
2833 Conf Rsp PENDING in the code above */
2834 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2835 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2836
2837 /* check compatibility */
2838
2839 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2840 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2841
2842 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002843 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002844 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2845 }
2846
Linus Torvalds1da177e2005-04-16 15:20:36 -07002847unlock:
2848 bh_unlock_sock(sk);
2849 return 0;
2850}
2851
2852static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2853{
2854 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2855 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002856 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002858 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002859
2860 scid = __le16_to_cpu(rsp->scid);
2861 flags = __le16_to_cpu(rsp->flags);
2862 result = __le16_to_cpu(rsp->result);
2863
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002864 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2865 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002867 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002868 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 return 0;
2870
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002871 sk = chan->sk;
2872
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 switch (result) {
2874 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002875 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002876 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 break;
2878
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002879 case L2CAP_CONF_PENDING:
2880 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2881
2882 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2883 char buf[64];
2884
2885 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2886 buf, &result);
2887 if (len < 0) {
2888 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2889 goto done;
2890 }
2891
2892 /* check compatibility */
2893
2894 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2895 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2896
2897 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002898 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002899 L2CAP_CONF_SUCCESS, 0x0000), buf);
2900 }
2901 goto done;
2902
Linus Torvalds1da177e2005-04-16 15:20:36 -07002903 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002904 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002905 char req[64];
2906
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002907 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002908 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002909 goto done;
2910 }
2911
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002912 /* throw out any old stored conf requests */
2913 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002914 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2915 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002916 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002917 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002918 goto done;
2919 }
2920
2921 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2922 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002923 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002924 if (result != L2CAP_CONF_SUCCESS)
2925 goto done;
2926 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 }
2928
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002929 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002930 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002931 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002932 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002933 goto done;
2934 }
2935
2936 if (flags & 0x01)
2937 goto done;
2938
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002939 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002940
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002941 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002942 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002943
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002944 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002945 chan->next_tx_seq = 0;
2946 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002947 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002948 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002949 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002950
Linus Torvalds1da177e2005-04-16 15:20:36 -07002951 l2cap_chan_ready(sk);
2952 }
2953
2954done:
2955 bh_unlock_sock(sk);
2956 return 0;
2957}
2958
2959static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2960{
2961 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2962 struct l2cap_disconn_rsp rsp;
2963 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002964 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002965 struct sock *sk;
2966
2967 scid = __le16_to_cpu(req->scid);
2968 dcid = __le16_to_cpu(req->dcid);
2969
2970 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2971
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002972 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002973 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 return 0;
2975
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002976 sk = chan->sk;
2977
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002978 rsp.dcid = cpu_to_le16(chan->scid);
2979 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002980 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2981
2982 sk->sk_shutdown = SHUTDOWN_MASK;
2983
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002984 /* don't delete l2cap channel if sk is owned by user */
2985 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002986 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002987 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002988 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002989 bh_unlock_sock(sk);
2990 return 0;
2991 }
2992
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002993 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 bh_unlock_sock(sk);
2995
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002996 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997 return 0;
2998}
2999
3000static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3001{
3002 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3003 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003004 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003005 struct sock *sk;
3006
3007 scid = __le16_to_cpu(rsp->scid);
3008 dcid = __le16_to_cpu(rsp->dcid);
3009
3010 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3011
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003012 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003013 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003014 return 0;
3015
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003016 sk = chan->sk;
3017
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003018 /* don't delete l2cap channel if sk is owned by user */
3019 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003020 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03003021 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02003022 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003023 bh_unlock_sock(sk);
3024 return 0;
3025 }
3026
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003027 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 bh_unlock_sock(sk);
3029
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003030 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 return 0;
3032}
3033
3034static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3035{
3036 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 u16 type;
3038
3039 type = __le16_to_cpu(req->type);
3040
3041 BT_DBG("type 0x%4.4x", type);
3042
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003043 if (type == L2CAP_IT_FEAT_MASK) {
3044 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003045 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003046 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3047 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3048 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003049 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003050 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3051 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003052 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003053 feat_mask |= L2CAP_FEAT_EXT_FLOW
3054 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003055
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003056 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003057 l2cap_send_cmd(conn, cmd->ident,
3058 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003059 } else if (type == L2CAP_IT_FIXED_CHAN) {
3060 u8 buf[12];
3061 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003062
3063 if (enable_hs)
3064 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3065 else
3066 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3067
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003068 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3069 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003070 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003071 l2cap_send_cmd(conn, cmd->ident,
3072 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003073 } else {
3074 struct l2cap_info_rsp rsp;
3075 rsp.type = cpu_to_le16(type);
3076 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3077 l2cap_send_cmd(conn, cmd->ident,
3078 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3079 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003080
3081 return 0;
3082}
3083
3084static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3085{
3086 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3087 u16 type, result;
3088
3089 type = __le16_to_cpu(rsp->type);
3090 result = __le16_to_cpu(rsp->result);
3091
3092 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3093
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003094 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3095 if (cmd->ident != conn->info_ident ||
3096 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3097 return 0;
3098
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003099 del_timer(&conn->info_timer);
3100
Ville Tervoadb08ed2010-08-04 09:43:33 +03003101 if (result != L2CAP_IR_SUCCESS) {
3102 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3103 conn->info_ident = 0;
3104
3105 l2cap_conn_start(conn);
3106
3107 return 0;
3108 }
3109
Marcel Holtmann984947d2009-02-06 23:35:19 +01003110 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003111 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003112
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003113 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003114 struct l2cap_info_req req;
3115 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3116
3117 conn->info_ident = l2cap_get_ident(conn);
3118
3119 l2cap_send_cmd(conn, conn->info_ident,
3120 L2CAP_INFO_REQ, sizeof(req), &req);
3121 } else {
3122 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3123 conn->info_ident = 0;
3124
3125 l2cap_conn_start(conn);
3126 }
3127 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003128 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003129 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003130
3131 l2cap_conn_start(conn);
3132 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003133
Linus Torvalds1da177e2005-04-16 15:20:36 -07003134 return 0;
3135}
3136
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003137static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3138 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3139 void *data)
3140{
3141 struct l2cap_create_chan_req *req = data;
3142 struct l2cap_create_chan_rsp rsp;
3143 u16 psm, scid;
3144
3145 if (cmd_len != sizeof(*req))
3146 return -EPROTO;
3147
3148 if (!enable_hs)
3149 return -EINVAL;
3150
3151 psm = le16_to_cpu(req->psm);
3152 scid = le16_to_cpu(req->scid);
3153
3154 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3155
3156 /* Placeholder: Always reject */
3157 rsp.dcid = 0;
3158 rsp.scid = cpu_to_le16(scid);
3159 rsp.result = L2CAP_CR_NO_MEM;
3160 rsp.status = L2CAP_CS_NO_INFO;
3161
3162 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3163 sizeof(rsp), &rsp);
3164
3165 return 0;
3166}
3167
3168static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3169 struct l2cap_cmd_hdr *cmd, void *data)
3170{
3171 BT_DBG("conn %p", conn);
3172
3173 return l2cap_connect_rsp(conn, cmd, data);
3174}
3175
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003176static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3177 u16 icid, u16 result)
3178{
3179 struct l2cap_move_chan_rsp rsp;
3180
3181 BT_DBG("icid %d, result %d", icid, result);
3182
3183 rsp.icid = cpu_to_le16(icid);
3184 rsp.result = cpu_to_le16(result);
3185
3186 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3187}
3188
3189static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3190 struct l2cap_chan *chan, u16 icid, u16 result)
3191{
3192 struct l2cap_move_chan_cfm cfm;
3193 u8 ident;
3194
3195 BT_DBG("icid %d, result %d", icid, result);
3196
3197 ident = l2cap_get_ident(conn);
3198 if (chan)
3199 chan->ident = ident;
3200
3201 cfm.icid = cpu_to_le16(icid);
3202 cfm.result = cpu_to_le16(result);
3203
3204 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3205}
3206
3207static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3208 u16 icid)
3209{
3210 struct l2cap_move_chan_cfm_rsp rsp;
3211
3212 BT_DBG("icid %d", icid);
3213
3214 rsp.icid = cpu_to_le16(icid);
3215 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3216}
3217
3218static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3219 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3220{
3221 struct l2cap_move_chan_req *req = data;
3222 u16 icid = 0;
3223 u16 result = L2CAP_MR_NOT_ALLOWED;
3224
3225 if (cmd_len != sizeof(*req))
3226 return -EPROTO;
3227
3228 icid = le16_to_cpu(req->icid);
3229
3230 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3231
3232 if (!enable_hs)
3233 return -EINVAL;
3234
3235 /* Placeholder: Always refuse */
3236 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3237
3238 return 0;
3239}
3240
3241static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3242 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3243{
3244 struct l2cap_move_chan_rsp *rsp = data;
3245 u16 icid, result;
3246
3247 if (cmd_len != sizeof(*rsp))
3248 return -EPROTO;
3249
3250 icid = le16_to_cpu(rsp->icid);
3251 result = le16_to_cpu(rsp->result);
3252
3253 BT_DBG("icid %d, result %d", icid, result);
3254
3255 /* Placeholder: Always unconfirmed */
3256 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3257
3258 return 0;
3259}
3260
3261static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3262 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3263{
3264 struct l2cap_move_chan_cfm *cfm = data;
3265 u16 icid, result;
3266
3267 if (cmd_len != sizeof(*cfm))
3268 return -EPROTO;
3269
3270 icid = le16_to_cpu(cfm->icid);
3271 result = le16_to_cpu(cfm->result);
3272
3273 BT_DBG("icid %d, result %d", icid, result);
3274
3275 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3276
3277 return 0;
3278}
3279
3280static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3281 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3282{
3283 struct l2cap_move_chan_cfm_rsp *rsp = data;
3284 u16 icid;
3285
3286 if (cmd_len != sizeof(*rsp))
3287 return -EPROTO;
3288
3289 icid = le16_to_cpu(rsp->icid);
3290
3291 BT_DBG("icid %d", icid);
3292
3293 return 0;
3294}
3295
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003296static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003297 u16 to_multiplier)
3298{
3299 u16 max_latency;
3300
3301 if (min > max || min < 6 || max > 3200)
3302 return -EINVAL;
3303
3304 if (to_multiplier < 10 || to_multiplier > 3200)
3305 return -EINVAL;
3306
3307 if (max >= to_multiplier * 8)
3308 return -EINVAL;
3309
3310 max_latency = (to_multiplier * 8 / max) - 1;
3311 if (latency > 499 || latency > max_latency)
3312 return -EINVAL;
3313
3314 return 0;
3315}
3316
3317static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3318 struct l2cap_cmd_hdr *cmd, u8 *data)
3319{
3320 struct hci_conn *hcon = conn->hcon;
3321 struct l2cap_conn_param_update_req *req;
3322 struct l2cap_conn_param_update_rsp rsp;
3323 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003324 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003325
3326 if (!(hcon->link_mode & HCI_LM_MASTER))
3327 return -EINVAL;
3328
3329 cmd_len = __le16_to_cpu(cmd->len);
3330 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3331 return -EPROTO;
3332
3333 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003334 min = __le16_to_cpu(req->min);
3335 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003336 latency = __le16_to_cpu(req->latency);
3337 to_multiplier = __le16_to_cpu(req->to_multiplier);
3338
3339 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3340 min, max, latency, to_multiplier);
3341
3342 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003343
3344 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3345 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003346 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3347 else
3348 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3349
3350 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3351 sizeof(rsp), &rsp);
3352
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003353 if (!err)
3354 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3355
Claudio Takahaside731152011-02-11 19:28:55 -02003356 return 0;
3357}
3358
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003359static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3360 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3361{
3362 int err = 0;
3363
3364 switch (cmd->code) {
3365 case L2CAP_COMMAND_REJ:
3366 l2cap_command_rej(conn, cmd, data);
3367 break;
3368
3369 case L2CAP_CONN_REQ:
3370 err = l2cap_connect_req(conn, cmd, data);
3371 break;
3372
3373 case L2CAP_CONN_RSP:
3374 err = l2cap_connect_rsp(conn, cmd, data);
3375 break;
3376
3377 case L2CAP_CONF_REQ:
3378 err = l2cap_config_req(conn, cmd, cmd_len, data);
3379 break;
3380
3381 case L2CAP_CONF_RSP:
3382 err = l2cap_config_rsp(conn, cmd, data);
3383 break;
3384
3385 case L2CAP_DISCONN_REQ:
3386 err = l2cap_disconnect_req(conn, cmd, data);
3387 break;
3388
3389 case L2CAP_DISCONN_RSP:
3390 err = l2cap_disconnect_rsp(conn, cmd, data);
3391 break;
3392
3393 case L2CAP_ECHO_REQ:
3394 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3395 break;
3396
3397 case L2CAP_ECHO_RSP:
3398 break;
3399
3400 case L2CAP_INFO_REQ:
3401 err = l2cap_information_req(conn, cmd, data);
3402 break;
3403
3404 case L2CAP_INFO_RSP:
3405 err = l2cap_information_rsp(conn, cmd, data);
3406 break;
3407
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003408 case L2CAP_CREATE_CHAN_REQ:
3409 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3410 break;
3411
3412 case L2CAP_CREATE_CHAN_RSP:
3413 err = l2cap_create_channel_rsp(conn, cmd, data);
3414 break;
3415
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003416 case L2CAP_MOVE_CHAN_REQ:
3417 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3418 break;
3419
3420 case L2CAP_MOVE_CHAN_RSP:
3421 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3422 break;
3423
3424 case L2CAP_MOVE_CHAN_CFM:
3425 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3426 break;
3427
3428 case L2CAP_MOVE_CHAN_CFM_RSP:
3429 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3430 break;
3431
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003432 default:
3433 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3434 err = -EINVAL;
3435 break;
3436 }
3437
3438 return err;
3439}
3440
3441static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3442 struct l2cap_cmd_hdr *cmd, u8 *data)
3443{
3444 switch (cmd->code) {
3445 case L2CAP_COMMAND_REJ:
3446 return 0;
3447
3448 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003449 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003450
3451 case L2CAP_CONN_PARAM_UPDATE_RSP:
3452 return 0;
3453
3454 default:
3455 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3456 return -EINVAL;
3457 }
3458}
3459
3460static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3461 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003462{
3463 u8 *data = skb->data;
3464 int len = skb->len;
3465 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003466 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003467
3468 l2cap_raw_recv(conn, skb);
3469
3470 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003471 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003472 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3473 data += L2CAP_CMD_HDR_SIZE;
3474 len -= L2CAP_CMD_HDR_SIZE;
3475
Al Viro88219a02007-07-29 00:17:25 -07003476 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477
Al Viro88219a02007-07-29 00:17:25 -07003478 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 -07003479
Al Viro88219a02007-07-29 00:17:25 -07003480 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003481 BT_DBG("corrupted command");
3482 break;
3483 }
3484
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003485 if (conn->hcon->type == LE_LINK)
3486 err = l2cap_le_sig_cmd(conn, &cmd, data);
3487 else
3488 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003489
3490 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003491 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003492
3493 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494
3495 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003496 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003497 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3498 }
3499
Al Viro88219a02007-07-29 00:17:25 -07003500 data += cmd_len;
3501 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003502 }
3503
3504 kfree_skb(skb);
3505}
3506
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003507static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003508{
3509 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003510 int hdr_size;
3511
3512 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3513 hdr_size = L2CAP_EXT_HDR_SIZE;
3514 else
3515 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003516
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003517 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003518 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003519 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3520 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3521
3522 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003523 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003524 }
3525 return 0;
3526}
3527
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003528static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003529{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003530 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003531
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003532 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003533
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003534 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003535
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003536 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003537 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003538 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003539 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003540 }
3541
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003542 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003543 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003544
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003545 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003546
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003547 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003548 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003549 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003550 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003551 }
3552}
3553
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003554static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003555{
3556 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003557 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003558
3559 bt_cb(skb)->tx_seq = tx_seq;
3560 bt_cb(skb)->sar = sar;
3561
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003562 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003563
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003564 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003565
Szymon Janc039d9572011-11-16 09:32:19 +01003566 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003567 if (bt_cb(next_skb)->tx_seq == tx_seq)
3568 return -EINVAL;
3569
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003570 next_tx_seq_offset = __seq_offset(chan,
3571 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003572
3573 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003574 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003575 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003576 }
3577
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003578 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003579 next_skb = NULL;
3580 else
3581 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3582 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003583
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003584 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003585
3586 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003587}
3588
Mat Martineau84084a32011-07-22 14:54:00 -07003589static void append_skb_frag(struct sk_buff *skb,
3590 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003591{
Mat Martineau84084a32011-07-22 14:54:00 -07003592 /* skb->len reflects data in skb as well as all fragments
3593 * skb->data_len reflects only data in fragments
3594 */
3595 if (!skb_has_frag_list(skb))
3596 skb_shinfo(skb)->frag_list = new_frag;
3597
3598 new_frag->next = NULL;
3599
3600 (*last_frag)->next = new_frag;
3601 *last_frag = new_frag;
3602
3603 skb->len += new_frag->len;
3604 skb->data_len += new_frag->len;
3605 skb->truesize += new_frag->truesize;
3606}
3607
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003608static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003609{
3610 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003611
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003612 switch (__get_ctrl_sar(chan, control)) {
3613 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003614 if (chan->sdu)
3615 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003616
Mat Martineau84084a32011-07-22 14:54:00 -07003617 err = chan->ops->recv(chan->data, skb);
3618 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003619
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003620 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003621 if (chan->sdu)
3622 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003623
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003624 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003625 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003626
Mat Martineau84084a32011-07-22 14:54:00 -07003627 if (chan->sdu_len > chan->imtu) {
3628 err = -EMSGSIZE;
3629 break;
3630 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003631
Mat Martineau84084a32011-07-22 14:54:00 -07003632 if (skb->len >= chan->sdu_len)
3633 break;
3634
3635 chan->sdu = skb;
3636 chan->sdu_last_frag = skb;
3637
3638 skb = NULL;
3639 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003640 break;
3641
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003642 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003643 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003644 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003645
Mat Martineau84084a32011-07-22 14:54:00 -07003646 append_skb_frag(chan->sdu, skb,
3647 &chan->sdu_last_frag);
3648 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003649
Mat Martineau84084a32011-07-22 14:54:00 -07003650 if (chan->sdu->len >= chan->sdu_len)
3651 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003652
Mat Martineau84084a32011-07-22 14:54:00 -07003653 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003654 break;
3655
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003656 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003657 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003658 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003659
Mat Martineau84084a32011-07-22 14:54:00 -07003660 append_skb_frag(chan->sdu, skb,
3661 &chan->sdu_last_frag);
3662 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003663
Mat Martineau84084a32011-07-22 14:54:00 -07003664 if (chan->sdu->len != chan->sdu_len)
3665 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003666
Mat Martineau84084a32011-07-22 14:54:00 -07003667 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003668
Mat Martineau84084a32011-07-22 14:54:00 -07003669 if (!err) {
3670 /* Reassembly complete */
3671 chan->sdu = NULL;
3672 chan->sdu_last_frag = NULL;
3673 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003674 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003675 break;
3676 }
3677
Mat Martineau84084a32011-07-22 14:54:00 -07003678 if (err) {
3679 kfree_skb(skb);
3680 kfree_skb(chan->sdu);
3681 chan->sdu = NULL;
3682 chan->sdu_last_frag = NULL;
3683 chan->sdu_len = 0;
3684 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003685
Mat Martineau84084a32011-07-22 14:54:00 -07003686 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003687}
3688
Mat Martineau26f880d2011-07-07 09:39:01 -07003689static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003690{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003691 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003692
Mat Martineau26f880d2011-07-07 09:39:01 -07003693 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003694
Mat Martineau26f880d2011-07-07 09:39:01 -07003695 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3696
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003697 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003698 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003699 l2cap_send_sframe(chan, control);
3700
3701 set_bit(CONN_RNR_SENT, &chan->conn_state);
3702
3703 __clear_ack_timer(chan);
3704}
3705
3706static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3707{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003708 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003709
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003710 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003711 goto done;
3712
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003713 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003714 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003715 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003716 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003717 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003718
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003719 __clear_retrans_timer(chan);
3720 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003721
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003722 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003723
3724done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003725 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3726 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003727
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003728 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003729}
3730
Mat Martineaue3281402011-07-07 09:39:02 -07003731void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003732{
Mat Martineaue3281402011-07-07 09:39:02 -07003733 if (chan->mode == L2CAP_MODE_ERTM) {
3734 if (busy)
3735 l2cap_ertm_enter_local_busy(chan);
3736 else
3737 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003738 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003739}
3740
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003741static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003742{
3743 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003744 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003745
Mat Martineaue3281402011-07-07 09:39:02 -07003746 while ((skb = skb_peek(&chan->srej_q)) &&
3747 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3748 int err;
3749
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003750 if (bt_cb(skb)->tx_seq != tx_seq)
3751 break;
3752
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003753 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003754 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003755 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003756
3757 if (err < 0) {
3758 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3759 break;
3760 }
3761
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003762 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3763 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003764 }
3765}
3766
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003767static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003768{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003769 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003770 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003771
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003772 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003773 if (l->tx_seq == tx_seq) {
3774 list_del(&l->list);
3775 kfree(l);
3776 return;
3777 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003778 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003779 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003780 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003781 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003782 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003783 }
3784}
3785
Szymon Jancaef89f22011-11-16 09:32:18 +01003786static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003787{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003788 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003789 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003790
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003791 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003792 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003793 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003794 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003795
3796 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003797 if (!new)
3798 return -ENOMEM;
3799
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003800 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003801
3802 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3803
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003804 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003805 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003806
3807 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003808
3809 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003810}
3811
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003812static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003813{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003814 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003815 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003816 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003817 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003818 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003819 int err = 0;
3820
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003821 BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003822 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003823
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003824 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003825 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003826 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003827 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003828 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003829 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003830 }
3831
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003832 chan->expected_ack_seq = req_seq;
3833 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003834
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003835 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003836
3837 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003838 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003839 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003840 goto drop;
3841 }
3842
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003843 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003844 goto drop;
3845
Mat Martineau02f1b642011-06-29 14:35:19 -07003846 if (tx_seq == chan->expected_tx_seq)
3847 goto expected;
3848
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003849 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003850 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003851
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003852 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003853 struct srej_list, list);
3854 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003855 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003856 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003857
3858 list_del(&first->list);
3859 kfree(first);
3860
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003861 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003862 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003863 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003864 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003865 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003866 }
3867 } else {
3868 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003869
3870 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003871 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003872 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003873
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003874 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003875 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003876 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003877 return 0;
3878 }
3879 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003880
3881 err = l2cap_send_srejframe(chan, tx_seq);
3882 if (err < 0) {
3883 l2cap_send_disconn_req(chan->conn, chan, -err);
3884 return err;
3885 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003886 }
3887 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003888 expected_tx_seq_offset = __seq_offset(chan,
3889 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003890
3891 /* duplicated tx_seq */
3892 if (tx_seq_offset < expected_tx_seq_offset)
3893 goto drop;
3894
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003895 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003896
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003897 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003898
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003899 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003900 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003901
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003902 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003903 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003904
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003905 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003906
Szymon Jancaef89f22011-11-16 09:32:18 +01003907 err = l2cap_send_srejframe(chan, tx_seq);
3908 if (err < 0) {
3909 l2cap_send_disconn_req(chan->conn, chan, -err);
3910 return err;
3911 }
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003912
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003913 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003914 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003915 return 0;
3916
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003917expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003918 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003919
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003920 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003921 bt_cb(skb)->tx_seq = tx_seq;
3922 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003923 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003924 return 0;
3925 }
3926
Mat Martineau84084a32011-07-22 14:54:00 -07003927 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003928 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3929
Mat Martineaue3281402011-07-07 09:39:02 -07003930 if (err < 0) {
3931 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3932 return err;
3933 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003934
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003935 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003936 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003937 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003938 }
3939
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003940
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003941 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3942 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003943 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003944 else
3945 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003946
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003947 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003948
3949drop:
3950 kfree_skb(skb);
3951 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003952}
3953
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003954static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003955{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003956 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003957 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003958
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003959 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003960 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003961
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003962 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003963 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3964 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3965 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003966 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003967 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003968
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003969 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003970 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003971 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003972 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003973 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003974
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003975 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003976 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003977
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003978 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003979 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003980
3981 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003982 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003983 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003984 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003985
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003986 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
3987 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003988 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003989 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003990 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003991 }
3992}
3993
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003994static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003995{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003996 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003997
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003998 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003999
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004000 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004001
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004002 chan->expected_ack_seq = tx_seq;
4003 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004004
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004005 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004006 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004007 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004008 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004009 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004010
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004011 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4012 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004013 }
4014}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004015static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004016{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004017 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004018
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004019 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004020
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004021 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004022
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004023 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004024 chan->expected_ack_seq = tx_seq;
4025 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004026
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004027 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004028 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004029
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004030 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004031
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004032 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004033 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004034 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004035 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004036 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004037 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004038 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004039 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004040 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004041 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004042 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004043 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004044 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004045 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004046 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004047 }
4048 }
4049}
4050
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004051static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004052{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004053 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004054
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004055 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004056
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004057 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004058 chan->expected_ack_seq = tx_seq;
4059 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004060
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004061 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004062 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004063
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004064 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004065 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004066 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004067 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004068 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004069 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004070
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004071 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004072 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004073 } else {
4074 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4075 l2cap_send_sframe(chan, rx_control);
4076 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004077}
4078
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004079static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004080{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004081 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004082
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004083 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004084 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004085 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004086 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004087 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004088 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004089 }
4090
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004091 switch (__get_ctrl_super(chan, rx_control)) {
4092 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004093 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004094 break;
4095
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004096 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004097 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004098 break;
4099
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004100 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004101 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004102 break;
4103
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004104 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004105 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004106 break;
4107 }
4108
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004109 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004110 return 0;
4111}
4112
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004113static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4114{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004115 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004116 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004117 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004118 int len, next_tx_seq_offset, req_seq_offset;
4119
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004120 control = __get_control(chan, skb->data);
4121 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004122 len = skb->len;
4123
4124 /*
4125 * We can just drop the corrupted I-frame here.
4126 * Receiver will miss it and start proper recovery
4127 * procedures and ask retransmission.
4128 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004129 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004130 goto drop;
4131
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004132 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004133 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004134
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004135 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004136 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004137
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004138 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004139 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004140 goto drop;
4141 }
4142
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004143 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004144
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004145 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4146
4147 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4148 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004149
4150 /* check for invalid req-seq */
4151 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004152 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004153 goto drop;
4154 }
4155
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004156 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004157 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004158 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004159 goto drop;
4160 }
4161
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004162 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004163 } else {
4164 if (len != 0) {
4165 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004166 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004167 goto drop;
4168 }
4169
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004170 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004171 }
4172
4173 return 0;
4174
4175drop:
4176 kfree_skb(skb);
4177 return 0;
4178}
4179
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4181{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004182 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004183 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004184 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004185 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004186 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004188 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004189 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004190 BT_DBG("unknown cid 0x%4.4x", cid);
4191 goto drop;
4192 }
4193
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004194 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004195
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004196 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004197
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004198 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004199 goto drop;
4200
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004201 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004202 case L2CAP_MODE_BASIC:
4203 /* If socket recv buffers overflows we drop data here
4204 * which is *bad* because L2CAP has to be reliable.
4205 * But we don't have any other choice. L2CAP doesn't
4206 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004208 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004209 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004210
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004211 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004212 goto done;
4213 break;
4214
4215 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004216 if (!sock_owned_by_user(sk)) {
4217 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004218 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004219 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004220 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004221 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004222
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004223 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004224
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004225 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004226 control = __get_control(chan, skb->data);
4227 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004228 len = skb->len;
4229
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004230 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004231 goto drop;
4232
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004233 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004234 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004235
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004236 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004237 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004238
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004239 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004240 goto drop;
4241
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004242 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004243
Mat Martineau84084a32011-07-22 14:54:00 -07004244 if (chan->expected_tx_seq != tx_seq) {
4245 /* Frame(s) missing - must discard partial SDU */
4246 kfree_skb(chan->sdu);
4247 chan->sdu = NULL;
4248 chan->sdu_last_frag = NULL;
4249 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004250
Mat Martineau84084a32011-07-22 14:54:00 -07004251 /* TODO: Notify userland of missing data */
4252 }
4253
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004254 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004255
4256 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4257 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004258
4259 goto done;
4260
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004261 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004262 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004263 break;
4264 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004265
4266drop:
4267 kfree_skb(skb);
4268
4269done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004270 if (sk)
4271 bh_unlock_sock(sk);
4272
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273 return 0;
4274}
4275
Al Viro8e036fc2007-07-29 00:16:36 -07004276static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004278 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004279 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004281 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4282 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004283 goto drop;
4284
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004285 sk = chan->sk;
4286
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004287 bh_lock_sock(sk);
4288
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 BT_DBG("sk %p, len %d", sk, skb->len);
4290
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004291 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 goto drop;
4293
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004294 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 goto drop;
4296
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004297 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004298 goto done;
4299
4300drop:
4301 kfree_skb(skb);
4302
4303done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004304 if (sk)
4305 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 return 0;
4307}
4308
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004309static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4310{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004311 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004312 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004313
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004314 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4315 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004316 goto drop;
4317
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004318 sk = chan->sk;
4319
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004320 bh_lock_sock(sk);
4321
4322 BT_DBG("sk %p, len %d", sk, skb->len);
4323
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004324 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004325 goto drop;
4326
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004327 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004328 goto drop;
4329
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004330 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004331 goto done;
4332
4333drop:
4334 kfree_skb(skb);
4335
4336done:
4337 if (sk)
4338 bh_unlock_sock(sk);
4339 return 0;
4340}
4341
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4343{
4344 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004345 u16 cid, len;
4346 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004347
4348 skb_pull(skb, L2CAP_HDR_SIZE);
4349 cid = __le16_to_cpu(lh->cid);
4350 len = __le16_to_cpu(lh->len);
4351
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004352 if (len != skb->len) {
4353 kfree_skb(skb);
4354 return;
4355 }
4356
Linus Torvalds1da177e2005-04-16 15:20:36 -07004357 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4358
4359 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004360 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004361 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004362 l2cap_sig_channel(conn, skb);
4363 break;
4364
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004365 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004366 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004367 skb_pull(skb, 2);
4368 l2cap_conless_channel(conn, psm, skb);
4369 break;
4370
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004371 case L2CAP_CID_LE_DATA:
4372 l2cap_att_channel(conn, cid, skb);
4373 break;
4374
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004375 case L2CAP_CID_SMP:
4376 if (smp_sig_channel(conn, skb))
4377 l2cap_conn_del(conn->hcon, EACCES);
4378 break;
4379
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 default:
4381 l2cap_data_channel(conn, cid, skb);
4382 break;
4383 }
4384}
4385
4386/* ---- L2CAP interface with lower layer (HCI) ---- */
4387
4388static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4389{
4390 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004391 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392
4393 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004394 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004395
4396 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4397
4398 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004399 read_lock(&chan_list_lock);
4400 list_for_each_entry(c, &chan_list, global_l) {
4401 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004402
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004403 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004404 continue;
4405
4406 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004407 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004408 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004409 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004410 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004411 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4412 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004413 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004414 lm2 |= HCI_LM_MASTER;
4415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004417 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004418
4419 return exact ? lm1 : lm2;
4420}
4421
4422static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4423{
Marcel Holtmann01394182006-07-03 10:02:46 +02004424 struct l2cap_conn *conn;
4425
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4427
Ville Tervoacd7d372011-02-10 22:38:49 -03004428 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004429 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430
4431 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004432 conn = l2cap_conn_add(hcon, status);
4433 if (conn)
4434 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004435 } else
Joe Perchese1750722011-06-29 18:18:29 -07004436 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437
4438 return 0;
4439}
4440
Marcel Holtmann2950f212009-02-12 14:02:50 +01004441static int l2cap_disconn_ind(struct hci_conn *hcon)
4442{
4443 struct l2cap_conn *conn = hcon->l2cap_data;
4444
4445 BT_DBG("hcon %p", hcon);
4446
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004447 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004448 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004449
4450 return conn->disc_reason;
4451}
4452
4453static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454{
4455 BT_DBG("hcon %p reason %d", hcon, reason);
4456
Ville Tervoacd7d372011-02-10 22:38:49 -03004457 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004458 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459
Joe Perchese1750722011-06-29 18:18:29 -07004460 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004461
Linus Torvalds1da177e2005-04-16 15:20:36 -07004462 return 0;
4463}
4464
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004465static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004466{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004467 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004468 return;
4469
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004470 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004471 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004472 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004473 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004474 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004475 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004476 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004477 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004478 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004479 }
4480}
4481
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004482static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004484 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004485 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486
Marcel Holtmann01394182006-07-03 10:02:46 +02004487 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004489
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490 BT_DBG("conn %p", conn);
4491
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004492 if (hcon->type == LE_LINK) {
4493 smp_distribute_keys(conn, 0);
4494 del_timer(&conn->security_timer);
4495 }
4496
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004497 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004499 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004500 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004501
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 bh_lock_sock(sk);
4503
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004504 BT_DBG("chan->scid %d", chan->scid);
4505
4506 if (chan->scid == L2CAP_CID_LE_DATA) {
4507 if (!status && encrypt) {
4508 chan->sec_level = hcon->sec_level;
4509 l2cap_chan_ready(sk);
4510 }
4511
4512 bh_unlock_sock(sk);
4513 continue;
4514 }
4515
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004516 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004517 bh_unlock_sock(sk);
4518 continue;
4519 }
4520
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004521 if (!status && (chan->state == BT_CONNECTED ||
4522 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004523 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004524 bh_unlock_sock(sk);
4525 continue;
4526 }
4527
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004528 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004529 if (!status) {
4530 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004531 req.scid = cpu_to_le16(chan->scid);
4532 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004533
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004534 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004535 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004536
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004537 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004538 L2CAP_CONN_REQ, sizeof(req), &req);
4539 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004540 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004541 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004542 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004543 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004544 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004545 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004546
4547 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004548 if (bt_sk(sk)->defer_setup) {
4549 struct sock *parent = bt_sk(sk)->parent;
4550 res = L2CAP_CR_PEND;
4551 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004552 if (parent)
4553 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004554 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004555 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004556 res = L2CAP_CR_SUCCESS;
4557 stat = L2CAP_CS_NO_INFO;
4558 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004559 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004560 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004561 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004562 res = L2CAP_CR_SEC_BLOCK;
4563 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004564 }
4565
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004566 rsp.scid = cpu_to_le16(chan->dcid);
4567 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004568 rsp.result = cpu_to_le16(res);
4569 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004570 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4571 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004572 }
4573
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574 bh_unlock_sock(sk);
4575 }
4576
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004577 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004578
Linus Torvalds1da177e2005-04-16 15:20:36 -07004579 return 0;
4580}
4581
4582static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4583{
4584 struct l2cap_conn *conn = hcon->l2cap_data;
4585
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004586 if (!conn)
4587 conn = l2cap_conn_add(hcon, 0);
4588
4589 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004590 goto drop;
4591
4592 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4593
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004594 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004596 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004597 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598 int len;
4599
4600 if (conn->rx_len) {
4601 BT_ERR("Unexpected start frame (len %d)", skb->len);
4602 kfree_skb(conn->rx_skb);
4603 conn->rx_skb = NULL;
4604 conn->rx_len = 0;
4605 l2cap_conn_unreliable(conn, ECOMM);
4606 }
4607
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004608 /* Start fragment always begin with Basic L2CAP header */
4609 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 BT_ERR("Frame is too short (len %d)", skb->len);
4611 l2cap_conn_unreliable(conn, ECOMM);
4612 goto drop;
4613 }
4614
4615 hdr = (struct l2cap_hdr *) skb->data;
4616 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004617 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004618
4619 if (len == skb->len) {
4620 /* Complete frame received */
4621 l2cap_recv_frame(conn, skb);
4622 return 0;
4623 }
4624
4625 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4626
4627 if (skb->len > len) {
4628 BT_ERR("Frame is too long (len %d, expected len %d)",
4629 skb->len, len);
4630 l2cap_conn_unreliable(conn, ECOMM);
4631 goto drop;
4632 }
4633
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004634 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004635
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004636 if (chan && chan->sk) {
4637 struct sock *sk = chan->sk;
4638
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004639 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004640 BT_ERR("Frame exceeding recv MTU (len %d, "
4641 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004642 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004643 bh_unlock_sock(sk);
4644 l2cap_conn_unreliable(conn, ECOMM);
4645 goto drop;
4646 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004647 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004648 }
4649
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004651 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4652 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 goto drop;
4654
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004655 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004656 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004657 conn->rx_len = len - skb->len;
4658 } else {
4659 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4660
4661 if (!conn->rx_len) {
4662 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4663 l2cap_conn_unreliable(conn, ECOMM);
4664 goto drop;
4665 }
4666
4667 if (skb->len > conn->rx_len) {
4668 BT_ERR("Fragment is too long (len %d, expected %d)",
4669 skb->len, conn->rx_len);
4670 kfree_skb(conn->rx_skb);
4671 conn->rx_skb = NULL;
4672 conn->rx_len = 0;
4673 l2cap_conn_unreliable(conn, ECOMM);
4674 goto drop;
4675 }
4676
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004677 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004678 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004679 conn->rx_len -= skb->len;
4680
4681 if (!conn->rx_len) {
4682 /* Complete frame received */
4683 l2cap_recv_frame(conn, conn->rx_skb);
4684 conn->rx_skb = NULL;
4685 }
4686 }
4687
4688drop:
4689 kfree_skb(skb);
4690 return 0;
4691}
4692
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004693static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004695 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004696
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004697 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004699 list_for_each_entry(c, &chan_list, global_l) {
4700 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004701
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004702 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 +01004703 batostr(&bt_sk(sk)->src),
4704 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004705 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004706 c->scid, c->dcid, c->imtu, c->omtu,
4707 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004708}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004710 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004711
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004712 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713}
4714
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004715static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4716{
4717 return single_open(file, l2cap_debugfs_show, inode->i_private);
4718}
4719
4720static const struct file_operations l2cap_debugfs_fops = {
4721 .open = l2cap_debugfs_open,
4722 .read = seq_read,
4723 .llseek = seq_lseek,
4724 .release = single_release,
4725};
4726
4727static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729static struct hci_proto l2cap_hci_proto = {
4730 .name = "L2CAP",
4731 .id = HCI_PROTO_L2CAP,
4732 .connect_ind = l2cap_connect_ind,
4733 .connect_cfm = l2cap_connect_cfm,
4734 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004735 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004736 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737 .recv_acldata = l2cap_recv_acldata
4738};
4739
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004740int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741{
4742 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004743
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004744 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 if (err < 0)
4746 return err;
4747
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 err = hci_register_proto(&l2cap_hci_proto);
4749 if (err < 0) {
4750 BT_ERR("L2CAP protocol registration failed");
4751 bt_sock_unregister(BTPROTO_L2CAP);
4752 goto error;
4753 }
4754
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004755 if (bt_debugfs) {
4756 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4757 bt_debugfs, NULL, &l2cap_debugfs_fops);
4758 if (!l2cap_debugfs)
4759 BT_ERR("Failed to create L2CAP debug file");
4760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 return 0;
4763
4764error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004765 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766 return err;
4767}
4768
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004769void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004771 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004772
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4774 BT_ERR("L2CAP protocol unregistration failed");
4775
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004776 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004777}
4778
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004779module_param(disable_ertm, bool, 0644);
4780MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03004781
4782module_param(enable_hs, bool, 0644);
4783MODULE_PARM_DESC(enable_hs, "Enable High Speed");