blob: d6165199fc8b59559dda85a1de0635193362970c [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;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020060
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070061static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070062static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Johannes Bergb5ad8b72011-06-01 08:54:45 +020064static LIST_HEAD(chan_list);
65static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
Linus Torvalds1da177e2005-04-16 15:20:36 -070067static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
68 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030069static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
70 void *data);
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -030071static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030072static void l2cap_send_disconn_req(struct l2cap_conn *conn,
73 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070074
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030075static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
76
Marcel Holtmann01394182006-07-03 10:02:46 +020077/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030078
79static inline void chan_hold(struct l2cap_chan *c)
80{
81 atomic_inc(&c->refcnt);
82}
83
84static inline void chan_put(struct l2cap_chan *c)
85{
86 if (atomic_dec_and_test(&c->refcnt))
87 kfree(c);
88}
89
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030090static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020091{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030092 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030093
94 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030095 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030096 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020097 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030098 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +020099}
100
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300101static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200102{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300103 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300104
105 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300106 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300107 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200108 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110}
111
112/* Find channel with given SCID.
113 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300114static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200115{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300116 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300117
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200118 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300120 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300121 lock_sock(c->sk);
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200122 mutex_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300123 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200124}
125
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300126static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200127{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300128 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129
130 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300131 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300132 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200133 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135}
136
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300137static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200138{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300139 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300140
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200141 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300142 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300143 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300144 lock_sock(c->sk);
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200145 mutex_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300146 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200147}
148
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300149static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300150{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300152
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153 list_for_each_entry(c, &chan_list, global_l) {
154 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100155 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300156 }
Szymon Janc250938c2011-11-16 09:32:22 +0100157 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300158}
159
160int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
161{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300162 int err;
163
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300164 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300165
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300167 err = -EADDRINUSE;
168 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300169 }
170
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300171 if (psm) {
172 chan->psm = psm;
173 chan->sport = psm;
174 err = 0;
175 } else {
176 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300177
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300178 err = -EINVAL;
179 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300180 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300181 chan->psm = cpu_to_le16(p);
182 chan->sport = cpu_to_le16(p);
183 err = 0;
184 break;
185 }
186 }
187
188done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300189 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300190 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300191}
192
193int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
194{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300195 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300196
197 chan->scid = scid;
198
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300199 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300200
201 return 0;
202}
203
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300204static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200205{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300206 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200207
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300208 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300209 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200210 return cid;
211 }
212
213 return 0;
214}
215
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300216static void l2cap_set_timer(struct l2cap_chan *chan, struct delayed_work *work, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300217{
Andrei Emeltchenko457f4852011-10-31 16:17:21 +0200218 BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300219
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300220 cancel_delayed_work_sync(work);
221
222 schedule_delayed_work(work, timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300223}
224
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300225static void l2cap_clear_timer(struct delayed_work *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300226{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300227 cancel_delayed_work_sync(work);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300228}
229
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200230static char *state_to_string(int state)
231{
232 switch(state) {
233 case BT_CONNECTED:
234 return "BT_CONNECTED";
235 case BT_OPEN:
236 return "BT_OPEN";
237 case BT_BOUND:
238 return "BT_BOUND";
239 case BT_LISTEN:
240 return "BT_LISTEN";
241 case BT_CONNECT:
242 return "BT_CONNECT";
243 case BT_CONNECT2:
244 return "BT_CONNECT2";
245 case BT_CONFIG:
246 return "BT_CONFIG";
247 case BT_DISCONN:
248 return "BT_DISCONN";
249 case BT_CLOSED:
250 return "BT_CLOSED";
251 }
252
253 return "invalid state";
254}
255
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300256static void l2cap_state_change(struct l2cap_chan *chan, int state)
257{
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200258 BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
259 state_to_string(state));
260
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300261 chan->state = state;
262 chan->ops->state_change(chan->data, state);
263}
264
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300265static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300266{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300267 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
268 chan_timer.work);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300269 struct sock *sk = chan->sk;
270 int reason;
271
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300272 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300273
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300274 lock_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300275
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300276 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300277 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300278 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300279 chan->sec_level != BT_SECURITY_SDP)
280 reason = ECONNREFUSED;
281 else
282 reason = ETIMEDOUT;
283
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300284 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300285
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300286 release_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300287
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300288 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300289 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300290}
291
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300292struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200293{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300294 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200295
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300296 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
297 if (!chan)
298 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200299
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300300 chan->sk = sk;
301
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300302 write_lock_bh(&chan_list_lock);
303 list_add(&chan->global_l, &chan_list);
304 write_unlock_bh(&chan_list_lock);
305
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300306 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300307
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300308 chan->state = BT_OPEN;
309
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300310 atomic_set(&chan->refcnt, 1);
311
Szymon Jancabc545b2011-11-03 16:05:44 +0100312 BT_DBG("sk %p chan %p", sk, chan);
313
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300314 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200315}
316
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300317void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300318{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300319 write_lock_bh(&chan_list_lock);
320 list_del(&chan->global_l);
321 write_unlock_bh(&chan_list_lock);
322
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300323 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300324}
325
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300326static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200327{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300328 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300329 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200330
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200331 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100332
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300333 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200334
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300335 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300336 if (conn->hcon->type == LE_LINK) {
337 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300338 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300339 chan->scid = L2CAP_CID_LE_DATA;
340 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300341 } else {
342 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300343 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300344 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300345 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300346 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200347 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300348 chan->scid = L2CAP_CID_CONN_LESS;
349 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300350 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200351 } else {
352 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300353 chan->scid = L2CAP_CID_SIGNALING;
354 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300355 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200356 }
357
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300358 chan->local_id = L2CAP_BESTEFFORT_ID;
359 chan->local_stype = L2CAP_SERV_BESTEFFORT;
360 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
361 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
362 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
363 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
364
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300365 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300366
367 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200368}
369
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900370/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200371 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300372static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200373{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300374 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300375 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200376 struct sock *parent = bt_sk(sk)->parent;
377
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300378 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200379
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300380 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200381
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900382 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300383 /* Delete from channel list */
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200384 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300385 list_del(&chan->list);
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200386 mutex_unlock(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300387 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300388
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300389 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200390 hci_conn_put(conn->hcon);
391 }
392
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300393 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200394 sock_set_flag(sk, SOCK_ZAPPED);
395
396 if (err)
397 sk->sk_err = err;
398
399 if (parent) {
400 bt_accept_unlink(sk);
401 parent->sk_data_ready(parent, 0);
402 } else
403 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300404
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300405 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
406 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300407 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300408
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300409 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300410
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300411 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300412 struct srej_list *l, *tmp;
413
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300414 __clear_retrans_timer(chan);
415 __clear_monitor_timer(chan);
416 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300417
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300418 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300419
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300420 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300421 list_del(&l->list);
422 kfree(l);
423 }
424 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200425}
426
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300427static void l2cap_chan_cleanup_listen(struct sock *parent)
428{
429 struct sock *sk;
430
431 BT_DBG("parent %p", parent);
432
433 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300434 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300435 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300436 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300437 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300438 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300439 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300440 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300441 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442}
443
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300444void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300445{
446 struct l2cap_conn *conn = chan->conn;
447 struct sock *sk = chan->sk;
448
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300449 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300450
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300451 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300452 case BT_LISTEN:
453 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300454
455 l2cap_state_change(chan, BT_CLOSED);
456 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300457 break;
458
459 case BT_CONNECTED:
460 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300461 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300462 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300463 __clear_chan_timer(chan);
464 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300465 l2cap_send_disconn_req(conn, chan, reason);
466 } else
467 l2cap_chan_del(chan, reason);
468 break;
469
470 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300471 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300472 conn->hcon->type == ACL_LINK) {
473 struct l2cap_conn_rsp rsp;
474 __u16 result;
475
476 if (bt_sk(sk)->defer_setup)
477 result = L2CAP_CR_SEC_BLOCK;
478 else
479 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300480 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300481
482 rsp.scid = cpu_to_le16(chan->dcid);
483 rsp.dcid = cpu_to_le16(chan->scid);
484 rsp.result = cpu_to_le16(result);
485 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
486 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
487 sizeof(rsp), &rsp);
488 }
489
490 l2cap_chan_del(chan, reason);
491 break;
492
493 case BT_CONNECT:
494 case BT_DISCONN:
495 l2cap_chan_del(chan, reason);
496 break;
497
498 default:
499 sock_set_flag(sk, SOCK_ZAPPED);
500 break;
501 }
502}
503
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300504static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530505{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300506 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300507 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530508 case BT_SECURITY_HIGH:
509 return HCI_AT_DEDICATED_BONDING_MITM;
510 case BT_SECURITY_MEDIUM:
511 return HCI_AT_DEDICATED_BONDING;
512 default:
513 return HCI_AT_NO_BONDING;
514 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300515 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300516 if (chan->sec_level == BT_SECURITY_LOW)
517 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530518
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300519 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530520 return HCI_AT_NO_BONDING_MITM;
521 else
522 return HCI_AT_NO_BONDING;
523 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300524 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530525 case BT_SECURITY_HIGH:
526 return HCI_AT_GENERAL_BONDING_MITM;
527 case BT_SECURITY_MEDIUM:
528 return HCI_AT_GENERAL_BONDING;
529 default:
530 return HCI_AT_NO_BONDING;
531 }
532 }
533}
534
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200535/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200536int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200537{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300538 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100539 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200540
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300541 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100542
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300543 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200544}
545
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200546static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200547{
548 u8 id;
549
550 /* Get next available identificator.
551 * 1 - 128 are used by kernel.
552 * 129 - 199 are reserved.
553 * 200 - 254 are used by utilities like l2ping, etc.
554 */
555
556 spin_lock_bh(&conn->lock);
557
558 if (++conn->tx_ident > 128)
559 conn->tx_ident = 1;
560
561 id = conn->tx_ident;
562
563 spin_unlock_bh(&conn->lock);
564
565 return id;
566}
567
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300568static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200569{
570 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200571 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200572
573 BT_DBG("code 0x%2.2x", code);
574
575 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300576 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200577
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200578 if (lmp_no_flush_capable(conn->hcon->hdev))
579 flags = ACL_START_NO_FLUSH;
580 else
581 flags = ACL_START;
582
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700583 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200584 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700585
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200586 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200587}
588
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200589static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
590{
591 struct hci_conn *hcon = chan->conn->hcon;
592 u16 flags;
593
594 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
595 skb->priority);
596
597 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
598 lmp_no_flush_capable(hcon->hdev))
599 flags = ACL_START_NO_FLUSH;
600 else
601 flags = ACL_START;
602
603 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
604 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605}
606
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300607static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300608{
609 struct sk_buff *skb;
610 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300611 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300612 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300613
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300614 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300615 return;
616
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300617 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
618 hlen = L2CAP_EXT_HDR_SIZE;
619 else
620 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300621
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300623 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300624
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300625 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300626
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300627 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300628
629 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300630
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300631 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300632 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300633
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300634 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300635 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300636
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300637 skb = bt_skb_alloc(count, GFP_ATOMIC);
638 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300639 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300640
641 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300642 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300643 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300644
645 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300646
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300647 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300648 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
649 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300650 }
651
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200652 skb->priority = HCI_PRIO_MAX;
653 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300654}
655
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300656static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300657{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300658 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300659 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300660 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300661 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300662 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300663
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300664 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300665
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300666 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300667}
668
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300669static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300670{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300671 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300672}
673
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300674static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200675{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300676 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200677
678 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100679 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
680 return;
681
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200682 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300683 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200684 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300685 req.scid = cpu_to_le16(chan->scid);
686 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200687
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300688 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300689 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200690
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300691 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
692 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200693 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200694 } else {
695 struct l2cap_info_req req;
696 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
697
698 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
699 conn->info_ident = l2cap_get_ident(conn);
700
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200701 schedule_delayed_work(&conn->info_work,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200702 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
703
704 l2cap_send_cmd(conn, conn->info_ident,
705 L2CAP_INFO_REQ, sizeof(req), &req);
706 }
707}
708
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300709static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
710{
711 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300712 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300713 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
714
715 switch (mode) {
716 case L2CAP_MODE_ERTM:
717 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
718 case L2CAP_MODE_STREAMING:
719 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
720 default:
721 return 0x00;
722 }
723}
724
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300725static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300726{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300727 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300728 struct l2cap_disconn_req req;
729
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300730 if (!conn)
731 return;
732
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300733 sk = chan->sk;
734
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300735 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300736 __clear_retrans_timer(chan);
737 __clear_monitor_timer(chan);
738 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300739 }
740
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300741 req.dcid = cpu_to_le16(chan->dcid);
742 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300743 l2cap_send_cmd(conn, l2cap_get_ident(conn),
744 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300745
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300746 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300747 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300748}
749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200751static void l2cap_conn_start(struct l2cap_conn *conn)
752{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300753 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200754
755 BT_DBG("conn %p", conn);
756
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200757 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200758
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300759 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300760 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300761
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200762 bh_lock_sock(sk);
763
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300764 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200765 bh_unlock_sock(sk);
766 continue;
767 }
768
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300769 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300770 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300771
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200772 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300773 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300774 bh_unlock_sock(sk);
775 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200776 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300777
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300778 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
779 && test_bit(CONF_STATE2_DEVICE,
780 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300781 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300782 * so release the lock */
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200783 mutex_unlock(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300784 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200785 utex_lock(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300786 bh_unlock_sock(sk);
787 continue;
788 }
789
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300790 req.scid = cpu_to_le16(chan->scid);
791 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300792
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300793 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300794 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300795
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300796 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
797 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300798
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300799 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200800 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300801 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300802 rsp.scid = cpu_to_le16(chan->dcid);
803 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200804
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200805 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100806 if (bt_sk(sk)->defer_setup) {
807 struct sock *parent = bt_sk(sk)->parent;
808 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
809 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000810 if (parent)
811 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100812
813 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300814 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100815 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
816 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
817 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200818 } else {
819 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
820 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
821 }
822
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300823 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
824 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300825
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300826 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300827 rsp.result != L2CAP_CR_SUCCESS) {
828 bh_unlock_sock(sk);
829 continue;
830 }
831
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300832 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300833 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300834 l2cap_build_conf_req(chan, buf), buf);
835 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200836 }
837
838 bh_unlock_sock(sk);
839 }
840
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200841 mutex_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200842}
843
Ville Tervob62f3282011-02-10 22:38:50 -0300844/* Find socket with cid and source bdaddr.
845 * Returns closest match, locked.
846 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300847static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300848{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300850
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300851 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300852
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300853 list_for_each_entry(c, &chan_list, global_l) {
854 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300855
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300856 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300857 continue;
858
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300859 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300860 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300861 if (!bacmp(&bt_sk(sk)->src, src)) {
862 read_unlock(&chan_list_lock);
863 return c;
864 }
Ville Tervob62f3282011-02-10 22:38:50 -0300865
866 /* Closest match */
867 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300868 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300869 }
870 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300871
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300872 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300873
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300874 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300875}
876
877static void l2cap_le_conn_ready(struct l2cap_conn *conn)
878{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300879 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300880 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300881
882 BT_DBG("");
883
884 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300885 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300886 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300887 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300888 return;
889
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300890 parent = pchan->sk;
891
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300892 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300893
Ville Tervob62f3282011-02-10 22:38:50 -0300894 /* Check for backlog size */
895 if (sk_acceptq_is_full(parent)) {
896 BT_DBG("backlog full %d", parent->sk_ack_backlog);
897 goto clean;
898 }
899
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300900 chan = pchan->ops->new_connection(pchan->data);
901 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300902 goto clean;
903
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300904 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300905
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200906 mutex_lock(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300907
908 hci_conn_hold(conn->hcon);
909
Ville Tervob62f3282011-02-10 22:38:50 -0300910 bacpy(&bt_sk(sk)->src, conn->src);
911 bacpy(&bt_sk(sk)->dst, conn->dst);
912
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300913 bt_accept_enqueue(parent, sk);
914
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300915 __l2cap_chan_add(conn, chan);
916
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300917 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300918
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300919 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300920 parent->sk_data_ready(parent, 0);
921
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200922 mutex_unlock(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300923
924clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300925 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300926}
927
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300928static void l2cap_chan_ready(struct sock *sk)
929{
930 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
931 struct sock *parent = bt_sk(sk)->parent;
932
933 BT_DBG("sk %p, parent %p", sk, parent);
934
935 chan->conf_state = 0;
936 __clear_chan_timer(chan);
937
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300938 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300939 sk->sk_state_change(sk);
940
941 if (parent)
942 parent->sk_data_ready(parent, 0);
943}
944
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200945static void l2cap_conn_ready(struct l2cap_conn *conn)
946{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300947 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200948
949 BT_DBG("conn %p", conn);
950
Ville Tervob62f3282011-02-10 22:38:50 -0300951 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
952 l2cap_le_conn_ready(conn);
953
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300954 if (conn->hcon->out && conn->hcon->type == LE_LINK)
955 smp_conn_security(conn, conn->hcon->pending_sec_level);
956
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200957 mutex_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200958
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300959 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300960 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300961
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200962 bh_lock_sock(sk);
963
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300964 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300965 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300966 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300967
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300968 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300969 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300970 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300972
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300973 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300974 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200975
976 bh_unlock_sock(sk);
977 }
978
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200979 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980}
981
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200982/* Notify sockets that we cannot guaranty reliability anymore */
983static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
984{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300985 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200986
987 BT_DBG("conn %p", conn);
988
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200989 mutex_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200990
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300991 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300992 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300993
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300994 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200995 sk->sk_err = err;
996 }
997
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -0200998 mutex_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200999}
1000
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02001001static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001002{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02001003 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1004 info_work.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001005
Marcel Holtmann984947d2009-02-06 23:35:19 +01001006 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01001007 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01001008
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001009 l2cap_conn_start(conn);
1010}
1011
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001012static void l2cap_conn_del(struct hci_conn *hcon, int err)
1013{
1014 struct l2cap_conn *conn = hcon->l2cap_data;
1015 struct l2cap_chan *chan, *l;
1016 struct sock *sk;
1017
1018 if (!conn)
1019 return;
1020
1021 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1022
1023 kfree_skb(conn->rx_skb);
1024
1025 /* Kill channels */
1026 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1027 sk = chan->sk;
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001028 lock_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001029 l2cap_chan_del(chan, err);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001030 release_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001031 chan->ops->close(chan->data);
1032 }
1033
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001034 hci_chan_del(conn->hchan);
1035
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001036 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02001037 cancel_delayed_work_sync(&conn->info_work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001038
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001039 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001040 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001041 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001042 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001043
1044 hcon->l2cap_data = NULL;
1045 kfree(conn);
1046}
1047
1048static void security_timeout(unsigned long arg)
1049{
1050 struct l2cap_conn *conn = (void *) arg;
1051
1052 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1053}
1054
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1056{
Marcel Holtmann01394182006-07-03 10:02:46 +02001057 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001058 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059
Marcel Holtmann01394182006-07-03 10:02:46 +02001060 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 return conn;
1062
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001063 hchan = hci_chan_create(hcon);
1064 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001067 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1068 if (!conn) {
1069 hci_chan_del(hchan);
1070 return NULL;
1071 }
1072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 hcon->l2cap_data = conn;
1074 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001075 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001077 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001078
Ville Tervoacd7d372011-02-10 22:38:49 -03001079 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1080 conn->mtu = hcon->hdev->le_mtu;
1081 else
1082 conn->mtu = hcon->hdev->acl_mtu;
1083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 conn->src = &hcon->hdev->bdaddr;
1085 conn->dst = &hcon->dst;
1086
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001087 conn->feat_mask = 0;
1088
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 spin_lock_init(&conn->lock);
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02001090 mutex_init(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001091
1092 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001094 if (hcon->type == LE_LINK)
1095 setup_timer(&conn->security_timer, security_timeout,
1096 (unsigned long) conn);
1097 else
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02001098 INIT_DELAYED_WORK(&conn->info_work, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001099
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001100 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001101
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 return conn;
1103}
1104
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001105static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106{
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02001107 mutex_lock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001108 __l2cap_chan_add(conn, chan);
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02001109 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110}
1111
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113
1114/* Find socket with psm and source bdaddr.
1115 * Returns closest match.
1116 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001117static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001121 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001122
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 list_for_each_entry(c, &chan_list, global_l) {
1124 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001125
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001126 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 continue;
1128
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001129 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001131 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001132 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001133 return c;
1134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
1136 /* Closest match */
1137 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001138 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 }
1140 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001142 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001143
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001144 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145}
1146
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001147inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001149 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151 struct l2cap_conn *conn;
1152 struct hci_conn *hcon;
1153 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001154 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001155 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001157 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001158 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001160 hdev = hci_get_route(dst, src);
1161 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162 return -EHOSTUNREACH;
1163
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001164 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001166 lock_sock(sk);
1167
1168 /* PSM must be odd and lsb of upper byte must be 0 */
1169 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1170 chan->chan_type != L2CAP_CHAN_RAW) {
1171 err = -EINVAL;
1172 goto done;
1173 }
1174
1175 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1176 err = -EINVAL;
1177 goto done;
1178 }
1179
1180 switch (chan->mode) {
1181 case L2CAP_MODE_BASIC:
1182 break;
1183 case L2CAP_MODE_ERTM:
1184 case L2CAP_MODE_STREAMING:
1185 if (!disable_ertm)
1186 break;
1187 /* fall through */
1188 default:
1189 err = -ENOTSUPP;
1190 goto done;
1191 }
1192
1193 switch (sk->sk_state) {
1194 case BT_CONNECT:
1195 case BT_CONNECT2:
1196 case BT_CONFIG:
1197 /* Already connecting */
1198 err = 0;
1199 goto done;
1200
1201 case BT_CONNECTED:
1202 /* Already connected */
1203 err = -EISCONN;
1204 goto done;
1205
1206 case BT_OPEN:
1207 case BT_BOUND:
1208 /* Can connect */
1209 break;
1210
1211 default:
1212 err = -EBADFD;
1213 goto done;
1214 }
1215
1216 /* Set destination address and psm */
1217 bacpy(&bt_sk(sk)->dst, src);
1218 chan->psm = psm;
1219 chan->dcid = cid;
1220
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001221 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001222
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001223 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001224 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001225 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001226 else
1227 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001228 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001229
Ville Tervo30e76272011-02-22 16:10:53 -03001230 if (IS_ERR(hcon)) {
1231 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001232 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001233 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234
1235 conn = l2cap_conn_add(hcon, 0);
1236 if (!conn) {
1237 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001238 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 goto done;
1240 }
1241
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242 /* Update source addr of the socket */
1243 bacpy(src, conn->src);
1244
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001245 l2cap_chan_add(conn, chan);
1246
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001247 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001248 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001249
1250 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001251 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001252 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001253 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001254 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001255 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001256 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 }
1258
Ville Tervo30e76272011-02-22 16:10:53 -03001259 err = 0;
1260
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001262 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 hci_dev_put(hdev);
1264 return err;
1265}
1266
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001267int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001268{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001269 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001270 DECLARE_WAITQUEUE(wait, current);
1271 int err = 0;
1272 int timeo = HZ/5;
1273
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001274 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001275 set_current_state(TASK_INTERRUPTIBLE);
1276 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001277 if (!timeo)
1278 timeo = HZ/5;
1279
1280 if (signal_pending(current)) {
1281 err = sock_intr_errno(timeo);
1282 break;
1283 }
1284
1285 release_sock(sk);
1286 timeo = schedule_timeout(timeo);
1287 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001288 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001289
1290 err = sock_error(sk);
1291 if (err)
1292 break;
1293 }
1294 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001295 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001296 return err;
1297}
1298
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001299static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001300{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001301 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1302 monitor_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001303 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001304
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001305 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001306
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001307 lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001308 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001309 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001310 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001311 return;
1312 }
1313
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001314 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001315 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001316
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001317 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001318 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001319}
1320
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001321static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001322{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001323 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1324 retrans_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001325 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001326
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001327 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001328
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001329 lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001330 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001331 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001332
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001333 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001334
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001335 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001336 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001337}
1338
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001339static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001340{
1341 struct sk_buff *skb;
1342
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001343 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001344 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001345 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001346 break;
1347
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001348 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001349 kfree_skb(skb);
1350
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001351 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001352 }
1353
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001354 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001355 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001356}
1357
Szymon Janc67c9e842011-07-28 16:24:33 +02001358static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001359{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001360 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001361 u32 control;
1362 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001363
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001364 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001365 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001366 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001367 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001368
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001369 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001370 fcs = crc16(0, (u8 *)skb->data,
1371 skb->len - L2CAP_FCS_SIZE);
1372 put_unaligned_le16(fcs,
1373 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001374 }
1375
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001376 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001377
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001378 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001379 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001380}
1381
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001382static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001383{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001384 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001385 u16 fcs;
1386 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001387
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001388 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001389 if (!skb)
1390 return;
1391
Szymon Jancd1726b62011-11-16 09:32:20 +01001392 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001393 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001394 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001395
Szymon Jancd1726b62011-11-16 09:32:20 +01001396 skb = skb_queue_next(&chan->tx_q, skb);
1397 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001398
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001399 if (chan->remote_max_tx &&
1400 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001401 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001402 return;
1403 }
1404
1405 tx_skb = skb_clone(skb, GFP_ATOMIC);
1406 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001407
1408 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001409 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001410
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001411 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001412 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001413
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001414 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001415 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001416
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001417 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001418
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001419 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001420 fcs = crc16(0, (u8 *)tx_skb->data,
1421 tx_skb->len - L2CAP_FCS_SIZE);
1422 put_unaligned_le16(fcs,
1423 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001424 }
1425
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001426 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001427}
1428
Szymon Janc67c9e842011-07-28 16:24:33 +02001429static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001430{
1431 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001432 u16 fcs;
1433 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001434 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001435
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001436 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001437 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001438
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001439 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001440
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001441 if (chan->remote_max_tx &&
1442 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001443 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001444 break;
1445 }
1446
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001447 tx_skb = skb_clone(skb, GFP_ATOMIC);
1448
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001449 bt_cb(skb)->retries++;
1450
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001451 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001452 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001453
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001454 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001455 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001456
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001457 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001458 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001459
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001460 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001461
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001462 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001463 fcs = crc16(0, (u8 *)skb->data,
1464 tx_skb->len - L2CAP_FCS_SIZE);
1465 put_unaligned_le16(fcs, skb->data +
1466 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001467 }
1468
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001469 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001470
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001471 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001472
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001473 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001474
1475 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001476
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301477 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001478 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301479
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001480 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001481
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001482 if (skb_queue_is_last(&chan->tx_q, skb))
1483 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001484 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001485 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001486
1487 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001488 }
1489
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001490 return nsent;
1491}
1492
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001493static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001494{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001495 int ret;
1496
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001497 if (!skb_queue_empty(&chan->tx_q))
1498 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001499
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001500 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001501 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001502 return ret;
1503}
1504
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001505static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001506{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001507 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001508
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001509 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001510
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001511 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001512 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001513 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001514 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001515 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001516 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001517
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001518 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001519 return;
1520
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001521 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001522 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001523}
1524
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001525static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001526{
1527 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001528 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001529
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001530 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001531 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001532
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001533 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001534 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001535
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001536 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001537}
1538
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001539static 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 -07001540{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001541 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001542 struct sk_buff **frag;
1543 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001545 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001546 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547
1548 sent += count;
1549 len -= count;
1550
1551 /* Continuation fragments (no L2CAP header) */
1552 frag = &skb_shinfo(skb)->frag_list;
1553 while (len) {
1554 count = min_t(unsigned int, conn->mtu, len);
1555
1556 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1557 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001558 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001559 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1560 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001561
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001562 (*frag)->priority = skb->priority;
1563
Linus Torvalds1da177e2005-04-16 15:20:36 -07001564 sent += count;
1565 len -= count;
1566
1567 frag = &(*frag)->next;
1568 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569
1570 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001571}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001573static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1574 struct msghdr *msg, size_t len,
1575 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001576{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001577 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001578 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001579 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001580 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001581 struct l2cap_hdr *lh;
1582
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001583 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001584
1585 count = min_t(unsigned int, (conn->mtu - hlen), len);
1586 skb = bt_skb_send_alloc(sk, count + hlen,
1587 msg->msg_flags & MSG_DONTWAIT, &err);
1588 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001589 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001590
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001591 skb->priority = priority;
1592
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001593 /* Create L2CAP header */
1594 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001595 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001597 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001598
1599 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1600 if (unlikely(err < 0)) {
1601 kfree_skb(skb);
1602 return ERR_PTR(err);
1603 }
1604 return skb;
1605}
1606
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001607static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1608 struct msghdr *msg, size_t len,
1609 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001610{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001611 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001612 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001613 struct sk_buff *skb;
1614 int err, count, hlen = L2CAP_HDR_SIZE;
1615 struct l2cap_hdr *lh;
1616
1617 BT_DBG("sk %p len %d", sk, (int)len);
1618
1619 count = min_t(unsigned int, (conn->mtu - hlen), len);
1620 skb = bt_skb_send_alloc(sk, count + hlen,
1621 msg->msg_flags & MSG_DONTWAIT, &err);
1622 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001623 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001624
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001625 skb->priority = priority;
1626
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001627 /* Create L2CAP header */
1628 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001629 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001630 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1631
1632 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1633 if (unlikely(err < 0)) {
1634 kfree_skb(skb);
1635 return ERR_PTR(err);
1636 }
1637 return skb;
1638}
1639
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001640static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1641 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001642 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001643{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001644 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001645 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001646 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001647 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001648 struct l2cap_hdr *lh;
1649
1650 BT_DBG("sk %p len %d", sk, (int)len);
1651
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001652 if (!conn)
1653 return ERR_PTR(-ENOTCONN);
1654
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001655 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1656 hlen = L2CAP_EXT_HDR_SIZE;
1657 else
1658 hlen = L2CAP_ENH_HDR_SIZE;
1659
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001660 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001661 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001662
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001663 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001664 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001665
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001666 count = min_t(unsigned int, (conn->mtu - hlen), len);
1667 skb = bt_skb_send_alloc(sk, count + hlen,
1668 msg->msg_flags & MSG_DONTWAIT, &err);
1669 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001670 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001671
1672 /* Create L2CAP header */
1673 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001674 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001675 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001676
1677 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1678
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001679 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001680 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001681
1682 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1683 if (unlikely(err < 0)) {
1684 kfree_skb(skb);
1685 return ERR_PTR(err);
1686 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001687
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001688 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001689 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001690
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001691 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001692 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693}
1694
Szymon Janc67c9e842011-07-28 16:24:33 +02001695static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001696{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001697 struct sk_buff *skb;
1698 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001699 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001700 size_t size = 0;
1701
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001702 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001703 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001704 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001705 if (IS_ERR(skb))
1706 return PTR_ERR(skb);
1707
1708 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001709 len -= chan->remote_mps;
1710 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001711
1712 while (len > 0) {
1713 size_t buflen;
1714
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001715 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001716 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001717 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001718 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001719 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001720 buflen = len;
1721 }
1722
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001723 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001724 if (IS_ERR(skb)) {
1725 skb_queue_purge(&sar_queue);
1726 return PTR_ERR(skb);
1727 }
1728
1729 __skb_queue_tail(&sar_queue, skb);
1730 len -= buflen;
1731 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001732 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001733 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1734 if (chan->tx_send_head == NULL)
1735 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001736
1737 return size;
1738}
1739
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001740int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1741 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001742{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001743 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001744 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001745 int err;
1746
1747 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001748 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001749 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001750 if (IS_ERR(skb))
1751 return PTR_ERR(skb);
1752
1753 l2cap_do_send(chan, skb);
1754 return len;
1755 }
1756
1757 switch (chan->mode) {
1758 case L2CAP_MODE_BASIC:
1759 /* Check outgoing MTU */
1760 if (len > chan->omtu)
1761 return -EMSGSIZE;
1762
1763 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001764 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001765 if (IS_ERR(skb))
1766 return PTR_ERR(skb);
1767
1768 l2cap_do_send(chan, skb);
1769 err = len;
1770 break;
1771
1772 case L2CAP_MODE_ERTM:
1773 case L2CAP_MODE_STREAMING:
1774 /* Entire SDU fits into one PDU */
1775 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001776 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001777 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1778 0);
1779 if (IS_ERR(skb))
1780 return PTR_ERR(skb);
1781
1782 __skb_queue_tail(&chan->tx_q, skb);
1783
1784 if (chan->tx_send_head == NULL)
1785 chan->tx_send_head = skb;
1786
1787 } else {
1788 /* Segment SDU into multiples PDUs */
1789 err = l2cap_sar_segment_sdu(chan, msg, len);
1790 if (err < 0)
1791 return err;
1792 }
1793
1794 if (chan->mode == L2CAP_MODE_STREAMING) {
1795 l2cap_streaming_send(chan);
1796 err = len;
1797 break;
1798 }
1799
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001800 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1801 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001802 err = len;
1803 break;
1804 }
1805
1806 err = l2cap_ertm_send(chan);
1807 if (err >= 0)
1808 err = len;
1809
1810 break;
1811
1812 default:
1813 BT_DBG("bad state %1.1x", chan->mode);
1814 err = -EBADFD;
1815 }
1816
1817 return err;
1818}
1819
Linus Torvalds1da177e2005-04-16 15:20:36 -07001820/* Copy frame to all raw sockets on that connection */
1821static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1822{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001824 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825
1826 BT_DBG("conn %p", conn);
1827
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02001828 mutex_lock(&conn->chan_lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001829 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001830 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001831 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001832 continue;
1833
1834 /* Don't send frame to the socket it came from */
1835 if (skb->sk == sk)
1836 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001837 nskb = skb_clone(skb, GFP_ATOMIC);
1838 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 continue;
1840
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001841 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842 kfree_skb(nskb);
1843 }
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02001844 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001845}
1846
1847/* ---- L2CAP signalling commands ---- */
1848static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1849 u8 code, u8 ident, u16 dlen, void *data)
1850{
1851 struct sk_buff *skb, **frag;
1852 struct l2cap_cmd_hdr *cmd;
1853 struct l2cap_hdr *lh;
1854 int len, count;
1855
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001856 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1857 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1860 count = min_t(unsigned int, conn->mtu, len);
1861
1862 skb = bt_skb_alloc(count, GFP_ATOMIC);
1863 if (!skb)
1864 return NULL;
1865
1866 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001867 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001868
1869 if (conn->hcon->type == LE_LINK)
1870 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1871 else
1872 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001873
1874 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1875 cmd->code = code;
1876 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001877 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878
1879 if (dlen) {
1880 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1881 memcpy(skb_put(skb, count), data, count);
1882 data += count;
1883 }
1884
1885 len -= skb->len;
1886
1887 /* Continuation fragments (no L2CAP header) */
1888 frag = &skb_shinfo(skb)->frag_list;
1889 while (len) {
1890 count = min_t(unsigned int, conn->mtu, len);
1891
1892 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1893 if (!*frag)
1894 goto fail;
1895
1896 memcpy(skb_put(*frag, count), data, count);
1897
1898 len -= count;
1899 data += count;
1900
1901 frag = &(*frag)->next;
1902 }
1903
1904 return skb;
1905
1906fail:
1907 kfree_skb(skb);
1908 return NULL;
1909}
1910
1911static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1912{
1913 struct l2cap_conf_opt *opt = *ptr;
1914 int len;
1915
1916 len = L2CAP_CONF_OPT_SIZE + opt->len;
1917 *ptr += len;
1918
1919 *type = opt->type;
1920 *olen = opt->len;
1921
1922 switch (opt->len) {
1923 case 1:
1924 *val = *((u8 *) opt->val);
1925 break;
1926
1927 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001928 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929 break;
1930
1931 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001932 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 break;
1934
1935 default:
1936 *val = (unsigned long) opt->val;
1937 break;
1938 }
1939
1940 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1941 return len;
1942}
1943
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1945{
1946 struct l2cap_conf_opt *opt = *ptr;
1947
1948 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1949
1950 opt->type = type;
1951 opt->len = len;
1952
1953 switch (len) {
1954 case 1:
1955 *((u8 *) opt->val) = val;
1956 break;
1957
1958 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001959 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 break;
1961
1962 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001963 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 break;
1965
1966 default:
1967 memcpy(opt->val, (void *) val, len);
1968 break;
1969 }
1970
1971 *ptr += L2CAP_CONF_OPT_SIZE + len;
1972}
1973
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001974static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1975{
1976 struct l2cap_conf_efs efs;
1977
Szymon Janc1ec918c2011-11-16 09:32:21 +01001978 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001979 case L2CAP_MODE_ERTM:
1980 efs.id = chan->local_id;
1981 efs.stype = chan->local_stype;
1982 efs.msdu = cpu_to_le16(chan->local_msdu);
1983 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1984 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1985 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1986 break;
1987
1988 case L2CAP_MODE_STREAMING:
1989 efs.id = 1;
1990 efs.stype = L2CAP_SERV_BESTEFFORT;
1991 efs.msdu = cpu_to_le16(chan->local_msdu);
1992 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1993 efs.acc_lat = 0;
1994 efs.flush_to = 0;
1995 break;
1996
1997 default:
1998 return;
1999 }
2000
2001 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
2002 (unsigned long) &efs);
2003}
2004
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002005static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002006{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002007 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
2008 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002009
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002010 lock_sock(chan->sk);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002011 l2cap_send_ack(chan);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002012 release_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002013}
2014
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002015static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002016{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002017 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002018 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002019 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002020 chan->num_acked = 0;
2021 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002022
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002023 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2024 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2025 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002026
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002027 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002028
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002029 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002030}
2031
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002032static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2033{
2034 switch (mode) {
2035 case L2CAP_MODE_STREAMING:
2036 case L2CAP_MODE_ERTM:
2037 if (l2cap_mode_supported(mode, remote_feat_mask))
2038 return mode;
2039 /* fall through */
2040 default:
2041 return L2CAP_MODE_BASIC;
2042 }
2043}
2044
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002045static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2046{
2047 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2048}
2049
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002050static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2051{
2052 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2053}
2054
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002055static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2056{
2057 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002058 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002059 /* use extended control field */
2060 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002061 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2062 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002063 chan->tx_win = min_t(u16, chan->tx_win,
2064 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002065 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2066 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002067}
2068
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002069static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002070{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002072 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002073 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002074 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002075
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002076 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002077
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002078 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002079 goto done;
2080
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002081 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002082 case L2CAP_MODE_STREAMING:
2083 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002084 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002085 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002086
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002087 if (__l2cap_efs_supported(chan))
2088 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2089
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002090 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002091 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002092 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002093 break;
2094 }
2095
2096done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002097 if (chan->imtu != L2CAP_DEFAULT_MTU)
2098 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002099
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002100 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002101 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002102 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2103 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002104 break;
2105
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002106 rfc.mode = L2CAP_MODE_BASIC;
2107 rfc.txwin_size = 0;
2108 rfc.max_transmit = 0;
2109 rfc.retrans_timeout = 0;
2110 rfc.monitor_timeout = 0;
2111 rfc.max_pdu_size = 0;
2112
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002113 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2114 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002115 break;
2116
2117 case L2CAP_MODE_ERTM:
2118 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002119 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002120 rfc.retrans_timeout = 0;
2121 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002122
2123 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2124 L2CAP_EXT_HDR_SIZE -
2125 L2CAP_SDULEN_SIZE -
2126 L2CAP_FCS_SIZE);
2127 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002128
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002129 l2cap_txwin_setup(chan);
2130
2131 rfc.txwin_size = min_t(u16, chan->tx_win,
2132 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002133
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002134 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2135 (unsigned long) &rfc);
2136
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002137 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2138 l2cap_add_opt_efs(&ptr, chan);
2139
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002140 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002141 break;
2142
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002143 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002144 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002145 chan->fcs = L2CAP_FCS_NONE;
2146 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002147 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002148
2149 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2150 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2151 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002152 break;
2153
2154 case L2CAP_MODE_STREAMING:
2155 rfc.mode = L2CAP_MODE_STREAMING;
2156 rfc.txwin_size = 0;
2157 rfc.max_transmit = 0;
2158 rfc.retrans_timeout = 0;
2159 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002160
2161 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2162 L2CAP_EXT_HDR_SIZE -
2163 L2CAP_SDULEN_SIZE -
2164 L2CAP_FCS_SIZE);
2165 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002166
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002167 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2168 (unsigned long) &rfc);
2169
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002170 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2171 l2cap_add_opt_efs(&ptr, chan);
2172
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002173 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002174 break;
2175
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002176 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002177 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002178 chan->fcs = L2CAP_FCS_NONE;
2179 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002180 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002181 break;
2182 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002184 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002185 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186
2187 return ptr - data;
2188}
2189
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002190static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002191{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002192 struct l2cap_conf_rsp *rsp = data;
2193 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002194 void *req = chan->conf_req;
2195 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002196 int type, hint, olen;
2197 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002198 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002199 struct l2cap_conf_efs efs;
2200 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002201 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002202 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002203 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002205 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002206
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002207 while (len >= L2CAP_CONF_OPT_SIZE) {
2208 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002210 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002211 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002212
2213 switch (type) {
2214 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002215 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002216 break;
2217
2218 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002219 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002220 break;
2221
2222 case L2CAP_CONF_QOS:
2223 break;
2224
Marcel Holtmann6464f352007-10-20 13:39:51 +02002225 case L2CAP_CONF_RFC:
2226 if (olen == sizeof(rfc))
2227 memcpy(&rfc, (void *) val, olen);
2228 break;
2229
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002230 case L2CAP_CONF_FCS:
2231 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002232 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002233 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002234
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002235 case L2CAP_CONF_EFS:
2236 remote_efs = 1;
2237 if (olen == sizeof(efs))
2238 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002239 break;
2240
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002241 case L2CAP_CONF_EWS:
2242 if (!enable_hs)
2243 return -ECONNREFUSED;
2244
2245 set_bit(FLAG_EXT_CTRL, &chan->flags);
2246 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002247 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002248 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002249 break;
2250
2251 default:
2252 if (hint)
2253 break;
2254
2255 result = L2CAP_CONF_UNKNOWN;
2256 *((u8 *) ptr++) = type;
2257 break;
2258 }
2259 }
2260
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002261 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002262 goto done;
2263
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002264 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002265 case L2CAP_MODE_STREAMING:
2266 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002267 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002268 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002269 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002270 break;
2271 }
2272
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002273 if (remote_efs) {
2274 if (__l2cap_efs_supported(chan))
2275 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2276 else
2277 return -ECONNREFUSED;
2278 }
2279
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002280 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002281 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002282
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002283 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002284 }
2285
2286done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002287 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002289 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002290
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002291 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002292 return -ECONNREFUSED;
2293
2294 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2295 sizeof(rfc), (unsigned long) &rfc);
2296 }
2297
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002298 if (result == L2CAP_CONF_SUCCESS) {
2299 /* Configure output options and let the other side know
2300 * which ones we don't like. */
2301
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002302 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2303 result = L2CAP_CONF_UNACCEPT;
2304 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002305 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002306 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002308 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002309
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002310 if (remote_efs) {
2311 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2312 efs.stype != L2CAP_SERV_NOTRAFIC &&
2313 efs.stype != chan->local_stype) {
2314
2315 result = L2CAP_CONF_UNACCEPT;
2316
2317 if (chan->num_conf_req >= 1)
2318 return -ECONNREFUSED;
2319
2320 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002321 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002322 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002323 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002324 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002325 result = L2CAP_CONF_PENDING;
2326 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002327 }
2328 }
2329
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002330 switch (rfc.mode) {
2331 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002332 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002333 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002334 break;
2335
2336 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002337 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2338 chan->remote_tx_win = rfc.txwin_size;
2339 else
2340 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2341
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002342 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002343
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002344 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2345 chan->conn->mtu -
2346 L2CAP_EXT_HDR_SIZE -
2347 L2CAP_SDULEN_SIZE -
2348 L2CAP_FCS_SIZE);
2349 rfc.max_pdu_size = cpu_to_le16(size);
2350 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002351
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002352 rfc.retrans_timeout =
2353 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2354 rfc.monitor_timeout =
2355 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002356
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002357 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002358
2359 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2360 sizeof(rfc), (unsigned long) &rfc);
2361
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002362 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2363 chan->remote_id = efs.id;
2364 chan->remote_stype = efs.stype;
2365 chan->remote_msdu = le16_to_cpu(efs.msdu);
2366 chan->remote_flush_to =
2367 le32_to_cpu(efs.flush_to);
2368 chan->remote_acc_lat =
2369 le32_to_cpu(efs.acc_lat);
2370 chan->remote_sdu_itime =
2371 le32_to_cpu(efs.sdu_itime);
2372 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2373 sizeof(efs), (unsigned long) &efs);
2374 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002375 break;
2376
2377 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002378 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2379 chan->conn->mtu -
2380 L2CAP_EXT_HDR_SIZE -
2381 L2CAP_SDULEN_SIZE -
2382 L2CAP_FCS_SIZE);
2383 rfc.max_pdu_size = cpu_to_le16(size);
2384 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002385
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002386 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002387
2388 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2389 sizeof(rfc), (unsigned long) &rfc);
2390
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002391 break;
2392
2393 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002394 result = L2CAP_CONF_UNACCEPT;
2395
2396 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002397 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002398 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002399
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002400 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002401 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002402 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002403 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002404 rsp->result = cpu_to_le16(result);
2405 rsp->flags = cpu_to_le16(0x0000);
2406
2407 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002408}
2409
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002410static 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 -03002411{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002412 struct l2cap_conf_req *req = data;
2413 void *ptr = req->data;
2414 int type, olen;
2415 unsigned long val;
2416 struct l2cap_conf_rfc rfc;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002417 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002418
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002419 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002420
2421 while (len >= L2CAP_CONF_OPT_SIZE) {
2422 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2423
2424 switch (type) {
2425 case L2CAP_CONF_MTU:
2426 if (val < L2CAP_DEFAULT_MIN_MTU) {
2427 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002428 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002429 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002430 chan->imtu = val;
2431 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002432 break;
2433
2434 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002435 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002436 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002437 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002438 break;
2439
2440 case L2CAP_CONF_RFC:
2441 if (olen == sizeof(rfc))
2442 memcpy(&rfc, (void *)val, olen);
2443
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002444 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002445 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002446 return -ECONNREFUSED;
2447
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002448 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002449
2450 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2451 sizeof(rfc), (unsigned long) &rfc);
2452 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002453
2454 case L2CAP_CONF_EWS:
2455 chan->tx_win = min_t(u16, val,
2456 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002457 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2458 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002459 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002460
2461 case L2CAP_CONF_EFS:
2462 if (olen == sizeof(efs))
2463 memcpy(&efs, (void *)val, olen);
2464
2465 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2466 efs.stype != L2CAP_SERV_NOTRAFIC &&
2467 efs.stype != chan->local_stype)
2468 return -ECONNREFUSED;
2469
2470 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2471 sizeof(efs), (unsigned long) &efs);
2472 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002473 }
2474 }
2475
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002476 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002477 return -ECONNREFUSED;
2478
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002479 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002480
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002481 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002482 switch (rfc.mode) {
2483 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002484 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2485 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2486 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002487
2488 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2489 chan->local_msdu = le16_to_cpu(efs.msdu);
2490 chan->local_sdu_itime =
2491 le32_to_cpu(efs.sdu_itime);
2492 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2493 chan->local_flush_to =
2494 le32_to_cpu(efs.flush_to);
2495 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002496 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002497
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002498 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002499 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002500 }
2501 }
2502
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002503 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002504 req->flags = cpu_to_le16(0x0000);
2505
2506 return ptr - data;
2507}
2508
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002509static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002510{
2511 struct l2cap_conf_rsp *rsp = data;
2512 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002514 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002515
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002516 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002517 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002518 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519
2520 return ptr - data;
2521}
2522
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002523void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002524{
2525 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002526 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002527 u8 buf[128];
2528
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002529 rsp.scid = cpu_to_le16(chan->dcid);
2530 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002531 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2532 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2533 l2cap_send_cmd(conn, chan->ident,
2534 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2535
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002536 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002537 return;
2538
Gustavo F. Padovan710f9b0a2011-03-25 14:30:37 -03002539 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2540 l2cap_build_conf_req(chan, buf), buf);
2541 chan->num_conf_req++;
2542}
2543
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002544static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002545{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002546 int type, olen;
2547 unsigned long val;
2548 struct l2cap_conf_rfc rfc;
2549
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002550 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002551
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002552 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002553 return;
2554
2555 while (len >= L2CAP_CONF_OPT_SIZE) {
2556 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2557
2558 switch (type) {
2559 case L2CAP_CONF_RFC:
2560 if (olen == sizeof(rfc))
2561 memcpy(&rfc, (void *)val, olen);
2562 goto done;
2563 }
2564 }
2565
2566done:
2567 switch (rfc.mode) {
2568 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002569 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2570 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2571 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002572 break;
2573 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002574 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002575 }
2576}
2577
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002578static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2579{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002580 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002581
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002582 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002583 return 0;
2584
2585 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2586 cmd->ident == conn->info_ident) {
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02002587 cancel_delayed_work_sync(&conn->info_work);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002588
2589 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002590 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002591
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002592 l2cap_conn_start(conn);
2593 }
2594
2595 return 0;
2596}
2597
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2599{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2601 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002602 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002603 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002604 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002605
2606 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002607 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002608
2609 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2610
2611 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002612 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2613 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002614 result = L2CAP_CR_BAD_PSM;
2615 goto sendresp;
2616 }
2617
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002618 parent = pchan->sk;
2619
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002620 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002621
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002622 /* Check if the ACL is secure enough (if not SDP) */
2623 if (psm != cpu_to_le16(0x0001) &&
2624 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002625 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002626 result = L2CAP_CR_SEC_BLOCK;
2627 goto response;
2628 }
2629
Linus Torvalds1da177e2005-04-16 15:20:36 -07002630 result = L2CAP_CR_NO_MEM;
2631
2632 /* Check for backlog size */
2633 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002634 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 goto response;
2636 }
2637
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002638 chan = pchan->ops->new_connection(pchan->data);
2639 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640 goto response;
2641
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002642 sk = chan->sk;
2643
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02002644 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645
2646 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002647 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02002648 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002649 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002650 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 goto response;
2652 }
2653
2654 hci_conn_hold(conn->hcon);
2655
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656 bacpy(&bt_sk(sk)->src, conn->src);
2657 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002658 chan->psm = psm;
2659 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002661 bt_accept_enqueue(parent, sk);
2662
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002663 __l2cap_chan_add(conn, chan);
2664
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002665 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002667 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002669 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670
Marcel Holtmann984947d2009-02-06 23:35:19 +01002671 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002672 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002673 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002674 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002675 result = L2CAP_CR_PEND;
2676 status = L2CAP_CS_AUTHOR_PEND;
2677 parent->sk_data_ready(parent, 0);
2678 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002679 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002680 result = L2CAP_CR_SUCCESS;
2681 status = L2CAP_CS_NO_INFO;
2682 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002683 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002684 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002685 result = L2CAP_CR_PEND;
2686 status = L2CAP_CS_AUTHEN_PEND;
2687 }
2688 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002689 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002690 result = L2CAP_CR_PEND;
2691 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692 }
2693
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02002694 mutex_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695
2696response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002697 release_sock(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698
2699sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002700 rsp.scid = cpu_to_le16(scid);
2701 rsp.dcid = cpu_to_le16(dcid);
2702 rsp.result = cpu_to_le16(result);
2703 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002705
2706 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2707 struct l2cap_info_req info;
2708 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2709
2710 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2711 conn->info_ident = l2cap_get_ident(conn);
2712
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02002713 schedule_delayed_work(&conn->info_work,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002714 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2715
2716 l2cap_send_cmd(conn, conn->info_ident,
2717 L2CAP_INFO_REQ, sizeof(info), &info);
2718 }
2719
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002720 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002721 result == L2CAP_CR_SUCCESS) {
2722 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002723 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002724 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002725 l2cap_build_conf_req(chan, buf), buf);
2726 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002727 }
2728
Linus Torvalds1da177e2005-04-16 15:20:36 -07002729 return 0;
2730}
2731
2732static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2733{
2734 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2735 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002736 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002737 struct sock *sk;
2738 u8 req[128];
2739
2740 scid = __le16_to_cpu(rsp->scid);
2741 dcid = __le16_to_cpu(rsp->dcid);
2742 result = __le16_to_cpu(rsp->result);
2743 status = __le16_to_cpu(rsp->status);
2744
2745 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2746
2747 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002748 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002749 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002750 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002752 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002753 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002754 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755 }
2756
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002757 sk = chan->sk;
2758
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759 switch (result) {
2760 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002761 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002762 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002763 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002764 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002765
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002766 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002767 break;
2768
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002770 l2cap_build_conf_req(chan, req), req);
2771 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772 break;
2773
2774 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002775 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002776 break;
2777
2778 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002779 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002780 break;
2781 }
2782
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002783 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002784 return 0;
2785}
2786
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002787static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002788{
2789 /* FCS is enabled only in ERTM or streaming mode, if one or both
2790 * sides request it.
2791 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002792 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002793 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002794 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002795 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002796}
2797
Al Viro88219a02007-07-29 00:17:25 -07002798static 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 -07002799{
2800 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2801 u16 dcid, flags;
2802 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002803 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002804 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002805 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806
2807 dcid = __le16_to_cpu(req->dcid);
2808 flags = __le16_to_cpu(req->flags);
2809
2810 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2811
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002812 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002813 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002814 return -ENOENT;
2815
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002816 sk = chan->sk;
2817
David S. Miller033b1142011-07-21 13:38:42 -07002818 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002819 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002820
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002821 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2822 rej.scid = cpu_to_le16(chan->scid);
2823 rej.dcid = cpu_to_le16(chan->dcid);
2824
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002825 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2826 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002827 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002828 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002829
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002830 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002831 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002832 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002833 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002834 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002835 L2CAP_CONF_REJECT, flags), rsp);
2836 goto unlock;
2837 }
2838
2839 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002840 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2841 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842
2843 if (flags & 0x0001) {
2844 /* Incomplete config. Send empty response. */
2845 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002846 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002847 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 goto unlock;
2849 }
2850
2851 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002852 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002853 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002854 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002856 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002858 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002859 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002860
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002861 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002862 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002863
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002864 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002865 goto unlock;
2866
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002867 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002868 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002869
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002870 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002871
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002872 chan->next_tx_seq = 0;
2873 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002874 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002875 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002876 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002877
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002879 goto unlock;
2880 }
2881
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002882 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002883 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002884 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002885 l2cap_build_conf_req(chan, buf), buf);
2886 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 }
2888
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002889 /* Got Conf Rsp PENDING from remote side and asume we sent
2890 Conf Rsp PENDING in the code above */
2891 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2892 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2893
2894 /* check compatibility */
2895
2896 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2897 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2898
2899 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002900 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002901 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2902 }
2903
Linus Torvalds1da177e2005-04-16 15:20:36 -07002904unlock:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002905 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 return 0;
2907}
2908
2909static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2910{
2911 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2912 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002913 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002915 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
2917 scid = __le16_to_cpu(rsp->scid);
2918 flags = __le16_to_cpu(rsp->flags);
2919 result = __le16_to_cpu(rsp->result);
2920
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002921 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2922 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002924 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002925 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926 return 0;
2927
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002928 sk = chan->sk;
2929
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 switch (result) {
2931 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002932 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002933 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002934 break;
2935
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002936 case L2CAP_CONF_PENDING:
2937 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2938
2939 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2940 char buf[64];
2941
2942 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2943 buf, &result);
2944 if (len < 0) {
2945 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2946 goto done;
2947 }
2948
2949 /* check compatibility */
2950
2951 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2952 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2953
2954 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002955 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002956 L2CAP_CONF_SUCCESS, 0x0000), buf);
2957 }
2958 goto done;
2959
Linus Torvalds1da177e2005-04-16 15:20:36 -07002960 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002961 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002962 char req[64];
2963
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002964 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002965 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002966 goto done;
2967 }
2968
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002969 /* throw out any old stored conf requests */
2970 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002971 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2972 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002973 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002974 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002975 goto done;
2976 }
2977
2978 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2979 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002980 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002981 if (result != L2CAP_CONF_SUCCESS)
2982 goto done;
2983 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 }
2985
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002986 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002987 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002988 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002989 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 goto done;
2991 }
2992
2993 if (flags & 0x01)
2994 goto done;
2995
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002996 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002997
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002998 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002999 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003000
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03003001 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003002 chan->next_tx_seq = 0;
3003 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03003004 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003005 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003006 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003007
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 l2cap_chan_ready(sk);
3009 }
3010
3011done:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003012 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003013 return 0;
3014}
3015
3016static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3017{
3018 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3019 struct l2cap_disconn_rsp rsp;
3020 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003021 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003022 struct sock *sk;
3023
3024 scid = __le16_to_cpu(req->scid);
3025 dcid = __le16_to_cpu(req->dcid);
3026
3027 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3028
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003029 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003030 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 return 0;
3032
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003033 sk = chan->sk;
3034
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003035 rsp.dcid = cpu_to_le16(chan->scid);
3036 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3038
3039 sk->sk_shutdown = SHUTDOWN_MASK;
3040
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003041 l2cap_chan_del(chan, ECONNRESET);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003042 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003043
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003044 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003045 return 0;
3046}
3047
3048static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3049{
3050 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3051 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003052 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003053 struct sock *sk;
3054
3055 scid = __le16_to_cpu(rsp->scid);
3056 dcid = __le16_to_cpu(rsp->dcid);
3057
3058 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3059
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003060 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003061 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062 return 0;
3063
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003064 sk = chan->sk;
3065
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003066 l2cap_chan_del(chan, 0);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003067 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003068
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003069 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 return 0;
3071}
3072
3073static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3074{
3075 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076 u16 type;
3077
3078 type = __le16_to_cpu(req->type);
3079
3080 BT_DBG("type 0x%4.4x", type);
3081
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003082 if (type == L2CAP_IT_FEAT_MASK) {
3083 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003084 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003085 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3086 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3087 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003088 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003089 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3090 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003091 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003092 feat_mask |= L2CAP_FEAT_EXT_FLOW
3093 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003094
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003095 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003096 l2cap_send_cmd(conn, cmd->ident,
3097 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003098 } else if (type == L2CAP_IT_FIXED_CHAN) {
3099 u8 buf[12];
3100 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003101
3102 if (enable_hs)
3103 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3104 else
3105 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3106
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003107 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3108 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003109 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003110 l2cap_send_cmd(conn, cmd->ident,
3111 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003112 } else {
3113 struct l2cap_info_rsp rsp;
3114 rsp.type = cpu_to_le16(type);
3115 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3116 l2cap_send_cmd(conn, cmd->ident,
3117 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3118 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003119
3120 return 0;
3121}
3122
3123static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3124{
3125 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3126 u16 type, result;
3127
3128 type = __le16_to_cpu(rsp->type);
3129 result = __le16_to_cpu(rsp->result);
3130
3131 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3132
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003133 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3134 if (cmd->ident != conn->info_ident ||
3135 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3136 return 0;
3137
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -02003138 cancel_delayed_work_sync(&conn->info_work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003139
Ville Tervoadb08ed2010-08-04 09:43:33 +03003140 if (result != L2CAP_IR_SUCCESS) {
3141 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3142 conn->info_ident = 0;
3143
3144 l2cap_conn_start(conn);
3145
3146 return 0;
3147 }
3148
Marcel Holtmann984947d2009-02-06 23:35:19 +01003149 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003150 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003151
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003152 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003153 struct l2cap_info_req req;
3154 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3155
3156 conn->info_ident = l2cap_get_ident(conn);
3157
3158 l2cap_send_cmd(conn, conn->info_ident,
3159 L2CAP_INFO_REQ, sizeof(req), &req);
3160 } else {
3161 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3162 conn->info_ident = 0;
3163
3164 l2cap_conn_start(conn);
3165 }
3166 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003167 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003168 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003169
3170 l2cap_conn_start(conn);
3171 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003172
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173 return 0;
3174}
3175
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003176static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3177 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3178 void *data)
3179{
3180 struct l2cap_create_chan_req *req = data;
3181 struct l2cap_create_chan_rsp rsp;
3182 u16 psm, scid;
3183
3184 if (cmd_len != sizeof(*req))
3185 return -EPROTO;
3186
3187 if (!enable_hs)
3188 return -EINVAL;
3189
3190 psm = le16_to_cpu(req->psm);
3191 scid = le16_to_cpu(req->scid);
3192
3193 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3194
3195 /* Placeholder: Always reject */
3196 rsp.dcid = 0;
3197 rsp.scid = cpu_to_le16(scid);
3198 rsp.result = L2CAP_CR_NO_MEM;
3199 rsp.status = L2CAP_CS_NO_INFO;
3200
3201 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3202 sizeof(rsp), &rsp);
3203
3204 return 0;
3205}
3206
3207static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3208 struct l2cap_cmd_hdr *cmd, void *data)
3209{
3210 BT_DBG("conn %p", conn);
3211
3212 return l2cap_connect_rsp(conn, cmd, data);
3213}
3214
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003215static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3216 u16 icid, u16 result)
3217{
3218 struct l2cap_move_chan_rsp rsp;
3219
3220 BT_DBG("icid %d, result %d", icid, result);
3221
3222 rsp.icid = cpu_to_le16(icid);
3223 rsp.result = cpu_to_le16(result);
3224
3225 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3226}
3227
3228static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3229 struct l2cap_chan *chan, u16 icid, u16 result)
3230{
3231 struct l2cap_move_chan_cfm cfm;
3232 u8 ident;
3233
3234 BT_DBG("icid %d, result %d", icid, result);
3235
3236 ident = l2cap_get_ident(conn);
3237 if (chan)
3238 chan->ident = ident;
3239
3240 cfm.icid = cpu_to_le16(icid);
3241 cfm.result = cpu_to_le16(result);
3242
3243 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3244}
3245
3246static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3247 u16 icid)
3248{
3249 struct l2cap_move_chan_cfm_rsp rsp;
3250
3251 BT_DBG("icid %d", icid);
3252
3253 rsp.icid = cpu_to_le16(icid);
3254 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3255}
3256
3257static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3258 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3259{
3260 struct l2cap_move_chan_req *req = data;
3261 u16 icid = 0;
3262 u16 result = L2CAP_MR_NOT_ALLOWED;
3263
3264 if (cmd_len != sizeof(*req))
3265 return -EPROTO;
3266
3267 icid = le16_to_cpu(req->icid);
3268
3269 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3270
3271 if (!enable_hs)
3272 return -EINVAL;
3273
3274 /* Placeholder: Always refuse */
3275 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3276
3277 return 0;
3278}
3279
3280static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3281 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3282{
3283 struct l2cap_move_chan_rsp *rsp = data;
3284 u16 icid, result;
3285
3286 if (cmd_len != sizeof(*rsp))
3287 return -EPROTO;
3288
3289 icid = le16_to_cpu(rsp->icid);
3290 result = le16_to_cpu(rsp->result);
3291
3292 BT_DBG("icid %d, result %d", icid, result);
3293
3294 /* Placeholder: Always unconfirmed */
3295 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3296
3297 return 0;
3298}
3299
3300static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3301 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3302{
3303 struct l2cap_move_chan_cfm *cfm = data;
3304 u16 icid, result;
3305
3306 if (cmd_len != sizeof(*cfm))
3307 return -EPROTO;
3308
3309 icid = le16_to_cpu(cfm->icid);
3310 result = le16_to_cpu(cfm->result);
3311
3312 BT_DBG("icid %d, result %d", icid, result);
3313
3314 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3315
3316 return 0;
3317}
3318
3319static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3320 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3321{
3322 struct l2cap_move_chan_cfm_rsp *rsp = data;
3323 u16 icid;
3324
3325 if (cmd_len != sizeof(*rsp))
3326 return -EPROTO;
3327
3328 icid = le16_to_cpu(rsp->icid);
3329
3330 BT_DBG("icid %d", icid);
3331
3332 return 0;
3333}
3334
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003335static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003336 u16 to_multiplier)
3337{
3338 u16 max_latency;
3339
3340 if (min > max || min < 6 || max > 3200)
3341 return -EINVAL;
3342
3343 if (to_multiplier < 10 || to_multiplier > 3200)
3344 return -EINVAL;
3345
3346 if (max >= to_multiplier * 8)
3347 return -EINVAL;
3348
3349 max_latency = (to_multiplier * 8 / max) - 1;
3350 if (latency > 499 || latency > max_latency)
3351 return -EINVAL;
3352
3353 return 0;
3354}
3355
3356static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3357 struct l2cap_cmd_hdr *cmd, u8 *data)
3358{
3359 struct hci_conn *hcon = conn->hcon;
3360 struct l2cap_conn_param_update_req *req;
3361 struct l2cap_conn_param_update_rsp rsp;
3362 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003363 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003364
3365 if (!(hcon->link_mode & HCI_LM_MASTER))
3366 return -EINVAL;
3367
3368 cmd_len = __le16_to_cpu(cmd->len);
3369 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3370 return -EPROTO;
3371
3372 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003373 min = __le16_to_cpu(req->min);
3374 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003375 latency = __le16_to_cpu(req->latency);
3376 to_multiplier = __le16_to_cpu(req->to_multiplier);
3377
3378 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3379 min, max, latency, to_multiplier);
3380
3381 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003382
3383 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3384 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003385 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3386 else
3387 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3388
3389 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3390 sizeof(rsp), &rsp);
3391
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003392 if (!err)
3393 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3394
Claudio Takahaside731152011-02-11 19:28:55 -02003395 return 0;
3396}
3397
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003398static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3399 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3400{
3401 int err = 0;
3402
3403 switch (cmd->code) {
3404 case L2CAP_COMMAND_REJ:
3405 l2cap_command_rej(conn, cmd, data);
3406 break;
3407
3408 case L2CAP_CONN_REQ:
3409 err = l2cap_connect_req(conn, cmd, data);
3410 break;
3411
3412 case L2CAP_CONN_RSP:
3413 err = l2cap_connect_rsp(conn, cmd, data);
3414 break;
3415
3416 case L2CAP_CONF_REQ:
3417 err = l2cap_config_req(conn, cmd, cmd_len, data);
3418 break;
3419
3420 case L2CAP_CONF_RSP:
3421 err = l2cap_config_rsp(conn, cmd, data);
3422 break;
3423
3424 case L2CAP_DISCONN_REQ:
3425 err = l2cap_disconnect_req(conn, cmd, data);
3426 break;
3427
3428 case L2CAP_DISCONN_RSP:
3429 err = l2cap_disconnect_rsp(conn, cmd, data);
3430 break;
3431
3432 case L2CAP_ECHO_REQ:
3433 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3434 break;
3435
3436 case L2CAP_ECHO_RSP:
3437 break;
3438
3439 case L2CAP_INFO_REQ:
3440 err = l2cap_information_req(conn, cmd, data);
3441 break;
3442
3443 case L2CAP_INFO_RSP:
3444 err = l2cap_information_rsp(conn, cmd, data);
3445 break;
3446
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003447 case L2CAP_CREATE_CHAN_REQ:
3448 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3449 break;
3450
3451 case L2CAP_CREATE_CHAN_RSP:
3452 err = l2cap_create_channel_rsp(conn, cmd, data);
3453 break;
3454
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003455 case L2CAP_MOVE_CHAN_REQ:
3456 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3457 break;
3458
3459 case L2CAP_MOVE_CHAN_RSP:
3460 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3461 break;
3462
3463 case L2CAP_MOVE_CHAN_CFM:
3464 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3465 break;
3466
3467 case L2CAP_MOVE_CHAN_CFM_RSP:
3468 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3469 break;
3470
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003471 default:
3472 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3473 err = -EINVAL;
3474 break;
3475 }
3476
3477 return err;
3478}
3479
3480static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3481 struct l2cap_cmd_hdr *cmd, u8 *data)
3482{
3483 switch (cmd->code) {
3484 case L2CAP_COMMAND_REJ:
3485 return 0;
3486
3487 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003488 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003489
3490 case L2CAP_CONN_PARAM_UPDATE_RSP:
3491 return 0;
3492
3493 default:
3494 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3495 return -EINVAL;
3496 }
3497}
3498
3499static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3500 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501{
3502 u8 *data = skb->data;
3503 int len = skb->len;
3504 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003505 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506
3507 l2cap_raw_recv(conn, skb);
3508
3509 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003510 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3512 data += L2CAP_CMD_HDR_SIZE;
3513 len -= L2CAP_CMD_HDR_SIZE;
3514
Al Viro88219a02007-07-29 00:17:25 -07003515 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003516
Al Viro88219a02007-07-29 00:17:25 -07003517 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 -07003518
Al Viro88219a02007-07-29 00:17:25 -07003519 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003520 BT_DBG("corrupted command");
3521 break;
3522 }
3523
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003524 if (conn->hcon->type == LE_LINK)
3525 err = l2cap_le_sig_cmd(conn, &cmd, data);
3526 else
3527 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
3529 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003530 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003531
3532 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003533
3534 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003535 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3537 }
3538
Al Viro88219a02007-07-29 00:17:25 -07003539 data += cmd_len;
3540 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003541 }
3542
3543 kfree_skb(skb);
3544}
3545
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003546static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003547{
3548 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003549 int hdr_size;
3550
3551 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3552 hdr_size = L2CAP_EXT_HDR_SIZE;
3553 else
3554 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003555
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003556 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003557 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003558 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3559 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3560
3561 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003562 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003563 }
3564 return 0;
3565}
3566
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003567static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003568{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003569 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003570
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003571 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003572
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003573 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003574
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003575 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003576 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003577 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003578 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003579 }
3580
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003581 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003582 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003583
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003584 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003585
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003586 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003587 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003588 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003589 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003590 }
3591}
3592
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003593static 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 -03003594{
3595 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003596 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003597
3598 bt_cb(skb)->tx_seq = tx_seq;
3599 bt_cb(skb)->sar = sar;
3600
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003601 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003602
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003603 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003604
Szymon Janc039d9572011-11-16 09:32:19 +01003605 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003606 if (bt_cb(next_skb)->tx_seq == tx_seq)
3607 return -EINVAL;
3608
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003609 next_tx_seq_offset = __seq_offset(chan,
3610 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003611
3612 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003613 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003614 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003615 }
3616
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003617 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003618 next_skb = NULL;
3619 else
3620 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3621 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003622
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003623 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003624
3625 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003626}
3627
Mat Martineau84084a32011-07-22 14:54:00 -07003628static void append_skb_frag(struct sk_buff *skb,
3629 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003630{
Mat Martineau84084a32011-07-22 14:54:00 -07003631 /* skb->len reflects data in skb as well as all fragments
3632 * skb->data_len reflects only data in fragments
3633 */
3634 if (!skb_has_frag_list(skb))
3635 skb_shinfo(skb)->frag_list = new_frag;
3636
3637 new_frag->next = NULL;
3638
3639 (*last_frag)->next = new_frag;
3640 *last_frag = new_frag;
3641
3642 skb->len += new_frag->len;
3643 skb->data_len += new_frag->len;
3644 skb->truesize += new_frag->truesize;
3645}
3646
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003647static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003648{
3649 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003650
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003651 switch (__get_ctrl_sar(chan, control)) {
3652 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003653 if (chan->sdu)
3654 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003655
Mat Martineau84084a32011-07-22 14:54:00 -07003656 err = chan->ops->recv(chan->data, skb);
3657 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003658
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003659 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003660 if (chan->sdu)
3661 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003662
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003663 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003664 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003665
Mat Martineau84084a32011-07-22 14:54:00 -07003666 if (chan->sdu_len > chan->imtu) {
3667 err = -EMSGSIZE;
3668 break;
3669 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003670
Mat Martineau84084a32011-07-22 14:54:00 -07003671 if (skb->len >= chan->sdu_len)
3672 break;
3673
3674 chan->sdu = skb;
3675 chan->sdu_last_frag = skb;
3676
3677 skb = NULL;
3678 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003679 break;
3680
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003681 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003682 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003683 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003684
Mat Martineau84084a32011-07-22 14:54:00 -07003685 append_skb_frag(chan->sdu, skb,
3686 &chan->sdu_last_frag);
3687 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003688
Mat Martineau84084a32011-07-22 14:54:00 -07003689 if (chan->sdu->len >= chan->sdu_len)
3690 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003691
Mat Martineau84084a32011-07-22 14:54:00 -07003692 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003693 break;
3694
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003695 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003696 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003697 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003698
Mat Martineau84084a32011-07-22 14:54:00 -07003699 append_skb_frag(chan->sdu, skb,
3700 &chan->sdu_last_frag);
3701 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003702
Mat Martineau84084a32011-07-22 14:54:00 -07003703 if (chan->sdu->len != chan->sdu_len)
3704 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003705
Mat Martineau84084a32011-07-22 14:54:00 -07003706 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003707
Mat Martineau84084a32011-07-22 14:54:00 -07003708 if (!err) {
3709 /* Reassembly complete */
3710 chan->sdu = NULL;
3711 chan->sdu_last_frag = NULL;
3712 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003713 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003714 break;
3715 }
3716
Mat Martineau84084a32011-07-22 14:54:00 -07003717 if (err) {
3718 kfree_skb(skb);
3719 kfree_skb(chan->sdu);
3720 chan->sdu = NULL;
3721 chan->sdu_last_frag = NULL;
3722 chan->sdu_len = 0;
3723 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003724
Mat Martineau84084a32011-07-22 14:54:00 -07003725 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003726}
3727
Mat Martineau26f880d2011-07-07 09:39:01 -07003728static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003729{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003730 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003731
Mat Martineau26f880d2011-07-07 09:39:01 -07003732 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003733
Mat Martineau26f880d2011-07-07 09:39:01 -07003734 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3735
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003736 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003737 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003738 l2cap_send_sframe(chan, control);
3739
3740 set_bit(CONN_RNR_SENT, &chan->conn_state);
3741
3742 __clear_ack_timer(chan);
3743}
3744
3745static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3746{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003747 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003748
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003749 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003750 goto done;
3751
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003752 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003753 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003754 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003755 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003756 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003757
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003758 __clear_retrans_timer(chan);
3759 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003760
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003761 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003762
3763done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003764 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3765 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003766
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003767 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003768}
3769
Mat Martineaue3281402011-07-07 09:39:02 -07003770void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003771{
Mat Martineaue3281402011-07-07 09:39:02 -07003772 if (chan->mode == L2CAP_MODE_ERTM) {
3773 if (busy)
3774 l2cap_ertm_enter_local_busy(chan);
3775 else
3776 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003777 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003778}
3779
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003780static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003781{
3782 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003783 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003784
Mat Martineaue3281402011-07-07 09:39:02 -07003785 while ((skb = skb_peek(&chan->srej_q)) &&
3786 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3787 int err;
3788
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003789 if (bt_cb(skb)->tx_seq != tx_seq)
3790 break;
3791
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003792 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003793 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003794 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003795
3796 if (err < 0) {
3797 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3798 break;
3799 }
3800
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003801 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3802 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003803 }
3804}
3805
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003806static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003807{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003808 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003809 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003810
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003811 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003812 if (l->tx_seq == tx_seq) {
3813 list_del(&l->list);
3814 kfree(l);
3815 return;
3816 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003817 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003818 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003819 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003820 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003821 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003822 }
3823}
3824
Szymon Jancaef89f22011-11-16 09:32:18 +01003825static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003826{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003827 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003828 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003829
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003830 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003831 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003832 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003833 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003834
3835 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003836 if (!new)
3837 return -ENOMEM;
3838
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003839 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003840
3841 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3842
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003843 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003844 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003845
3846 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003847
3848 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003849}
3850
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003851static 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 -03003852{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003853 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003854 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003855 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003856 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003857 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003858 int err = 0;
3859
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003860 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 -03003861 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003862
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003863 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003864 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003865 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003866 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003867 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003868 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003869 }
3870
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003871 chan->expected_ack_seq = req_seq;
3872 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003873
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003874 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003875
3876 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003877 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003878 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003879 goto drop;
3880 }
3881
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003882 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003883 goto drop;
3884
Mat Martineau02f1b642011-06-29 14:35:19 -07003885 if (tx_seq == chan->expected_tx_seq)
3886 goto expected;
3887
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003888 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003889 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003890
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003891 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003892 struct srej_list, list);
3893 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003894 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003895 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003896
3897 list_del(&first->list);
3898 kfree(first);
3899
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003900 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003901 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003902 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003903 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003904 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003905 }
3906 } else {
3907 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003908
3909 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003910 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003911 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003912
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003913 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003914 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003915 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003916 return 0;
3917 }
3918 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003919
3920 err = l2cap_send_srejframe(chan, tx_seq);
3921 if (err < 0) {
3922 l2cap_send_disconn_req(chan->conn, chan, -err);
3923 return err;
3924 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003925 }
3926 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003927 expected_tx_seq_offset = __seq_offset(chan,
3928 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003929
3930 /* duplicated tx_seq */
3931 if (tx_seq_offset < expected_tx_seq_offset)
3932 goto drop;
3933
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003934 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003935
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003936 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003937
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003938 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003939 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003940
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003941 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003942 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003943
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003944 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003945
Szymon Jancaef89f22011-11-16 09:32:18 +01003946 err = l2cap_send_srejframe(chan, tx_seq);
3947 if (err < 0) {
3948 l2cap_send_disconn_req(chan->conn, chan, -err);
3949 return err;
3950 }
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003951
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003952 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003953 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003954 return 0;
3955
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003956expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003957 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003958
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003959 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003960 bt_cb(skb)->tx_seq = tx_seq;
3961 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003962 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003963 return 0;
3964 }
3965
Mat Martineau84084a32011-07-22 14:54:00 -07003966 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003967 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3968
Mat Martineaue3281402011-07-07 09:39:02 -07003969 if (err < 0) {
3970 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3971 return err;
3972 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003973
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003974 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003975 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003976 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003977 }
3978
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003979
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003980 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3981 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003982 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003983 else
3984 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003985
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003986 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003987
3988drop:
3989 kfree_skb(skb);
3990 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003991}
3992
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003993static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003994{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003995 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003996 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003997
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003998 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003999 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004000
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004001 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004002 set_bit(CONN_SEND_FBIT, &chan->conn_state);
4003 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
4004 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004005 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004006 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004007
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004008 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004009 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004010 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004011 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004012 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004013
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004014 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004015 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004016
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004017 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004018 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004019
4020 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004021 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004022 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004023 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004024
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004025 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4026 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004027 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004028 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004029 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004030 }
4031}
4032
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004033static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004034{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004035 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004036
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004037 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004038
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004039 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004040
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004041 chan->expected_ack_seq = tx_seq;
4042 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004043
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004044 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004045 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004046 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004047 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004048 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004049
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004050 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4051 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004052 }
4053}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004054static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004055{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004056 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004057
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004058 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004059
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004060 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004061
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004062 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004063 chan->expected_ack_seq = tx_seq;
4064 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004065
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004066 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004067 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004068
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004069 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004070
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004071 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004072 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004073 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004074 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004075 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004076 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004077 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004078 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004079 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004080 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004081 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004082 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004083 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004084 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004085 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004086 }
4087 }
4088}
4089
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004090static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004091{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004092 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004093
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004094 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004095
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004096 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004097 chan->expected_ack_seq = tx_seq;
4098 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004099
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004100 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004101 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004102
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004103 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004104 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004105 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004106 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004107 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004108 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004109
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004110 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004111 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004112 } else {
4113 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4114 l2cap_send_sframe(chan, rx_control);
4115 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004116}
4117
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004118static 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 -03004119{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004120 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004121
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004122 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004123 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004124 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004125 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004126 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004127 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004128 }
4129
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004130 switch (__get_ctrl_super(chan, rx_control)) {
4131 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004132 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004133 break;
4134
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004135 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004136 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004137 break;
4138
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004139 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004140 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004141 break;
4142
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004143 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004144 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004145 break;
4146 }
4147
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004148 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004149 return 0;
4150}
4151
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004152static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4153{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004154 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004155 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004156 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004157 int len, next_tx_seq_offset, req_seq_offset;
4158
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004159 control = __get_control(chan, skb->data);
4160 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004161 len = skb->len;
4162
4163 /*
4164 * We can just drop the corrupted I-frame here.
4165 * Receiver will miss it and start proper recovery
4166 * procedures and ask retransmission.
4167 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004168 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004169 goto drop;
4170
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004171 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004172 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004173
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004174 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004175 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004176
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004177 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004178 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004179 goto drop;
4180 }
4181
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004182 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004183
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004184 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4185
4186 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4187 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004188
4189 /* check for invalid req-seq */
4190 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004191 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004192 goto drop;
4193 }
4194
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004195 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004196 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004197 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004198 goto drop;
4199 }
4200
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004201 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004202 } else {
4203 if (len != 0) {
4204 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004205 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004206 goto drop;
4207 }
4208
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004209 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004210 }
4211
4212 return 0;
4213
4214drop:
4215 kfree_skb(skb);
4216 return 0;
4217}
4218
Linus Torvalds1da177e2005-04-16 15:20:36 -07004219static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4220{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004221 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004222 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004223 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004224 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004225 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004227 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004228 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004229 BT_DBG("unknown cid 0x%4.4x", cid);
4230 goto drop;
4231 }
4232
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004233 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004234
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004235 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004236
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004237 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238 goto drop;
4239
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004240 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004241 case L2CAP_MODE_BASIC:
4242 /* If socket recv buffers overflows we drop data here
4243 * which is *bad* because L2CAP has to be reliable.
4244 * But we don't have any other choice. L2CAP doesn't
4245 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004246
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004247 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004248 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004249
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004250 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004251 goto done;
4252 break;
4253
4254 case L2CAP_MODE_ERTM:
Gustavo F. Padovaneb403a12011-06-24 01:54:50 -03004255 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004256
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004257 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004258
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004259 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004260 control = __get_control(chan, skb->data);
4261 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004262 len = skb->len;
4263
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004264 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004265 goto drop;
4266
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004267 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004268 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004269
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004270 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004271 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004272
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004273 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004274 goto drop;
4275
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004276 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004277
Mat Martineau84084a32011-07-22 14:54:00 -07004278 if (chan->expected_tx_seq != tx_seq) {
4279 /* Frame(s) missing - must discard partial SDU */
4280 kfree_skb(chan->sdu);
4281 chan->sdu = NULL;
4282 chan->sdu_last_frag = NULL;
4283 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004284
Mat Martineau84084a32011-07-22 14:54:00 -07004285 /* TODO: Notify userland of missing data */
4286 }
4287
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004288 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004289
4290 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4291 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004292
4293 goto done;
4294
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004295 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004296 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004297 break;
4298 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299
4300drop:
4301 kfree_skb(skb);
4302
4303done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004304 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004305 release_sock(sk);
Marcel Holtmann01394182006-07-03 10:02:46 +02004306
Linus Torvalds1da177e2005-04-16 15:20:36 -07004307 return 0;
4308}
4309
Al Viro8e036fc2007-07-29 00:16:36 -07004310static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004312 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004313 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004315 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4316 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 goto drop;
4318
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004319 sk = chan->sk;
4320
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004321 lock_sock(sk);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004322
Linus Torvalds1da177e2005-04-16 15:20:36 -07004323 BT_DBG("sk %p, len %d", sk, skb->len);
4324
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004325 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004326 goto drop;
4327
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004328 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 goto drop;
4330
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004331 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004332 goto done;
4333
4334drop:
4335 kfree_skb(skb);
4336
4337done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004338 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004339 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004340 return 0;
4341}
4342
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004343static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4344{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004345 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004346 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004347
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004348 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4349 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004350 goto drop;
4351
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004352 sk = chan->sk;
4353
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004354 lock_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004355
4356 BT_DBG("sk %p, len %d", sk, skb->len);
4357
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004358 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004359 goto drop;
4360
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004361 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004362 goto drop;
4363
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004364 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004365 goto done;
4366
4367drop:
4368 kfree_skb(skb);
4369
4370done:
4371 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004372 release_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004373 return 0;
4374}
4375
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4377{
4378 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004379 u16 cid, len;
4380 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004381
4382 skb_pull(skb, L2CAP_HDR_SIZE);
4383 cid = __le16_to_cpu(lh->cid);
4384 len = __le16_to_cpu(lh->len);
4385
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004386 if (len != skb->len) {
4387 kfree_skb(skb);
4388 return;
4389 }
4390
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4392
4393 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004394 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004395 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004396 l2cap_sig_channel(conn, skb);
4397 break;
4398
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004399 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004400 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 skb_pull(skb, 2);
4402 l2cap_conless_channel(conn, psm, skb);
4403 break;
4404
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004405 case L2CAP_CID_LE_DATA:
4406 l2cap_att_channel(conn, cid, skb);
4407 break;
4408
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004409 case L2CAP_CID_SMP:
4410 if (smp_sig_channel(conn, skb))
4411 l2cap_conn_del(conn->hcon, EACCES);
4412 break;
4413
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414 default:
4415 l2cap_data_channel(conn, cid, skb);
4416 break;
4417 }
4418}
4419
4420/* ---- L2CAP interface with lower layer (HCI) ---- */
4421
4422static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4423{
4424 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004425 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
4427 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004428 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429
4430 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4431
4432 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004433 read_lock(&chan_list_lock);
4434 list_for_each_entry(c, &chan_list, global_l) {
4435 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004436
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004437 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438 continue;
4439
4440 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004441 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004442 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004443 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004444 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004445 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4446 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004447 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004448 lm2 |= HCI_LM_MASTER;
4449 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004451 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004452
4453 return exact ? lm1 : lm2;
4454}
4455
4456static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4457{
Marcel Holtmann01394182006-07-03 10:02:46 +02004458 struct l2cap_conn *conn;
4459
Linus Torvalds1da177e2005-04-16 15:20:36 -07004460 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4461
Ville Tervoacd7d372011-02-10 22:38:49 -03004462 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004463 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004464
4465 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004466 conn = l2cap_conn_add(hcon, status);
4467 if (conn)
4468 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004469 } else
Joe Perchese1750722011-06-29 18:18:29 -07004470 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471
4472 return 0;
4473}
4474
Marcel Holtmann2950f212009-02-12 14:02:50 +01004475static int l2cap_disconn_ind(struct hci_conn *hcon)
4476{
4477 struct l2cap_conn *conn = hcon->l2cap_data;
4478
4479 BT_DBG("hcon %p", hcon);
4480
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004481 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004482 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004483
4484 return conn->disc_reason;
4485}
4486
4487static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004488{
4489 BT_DBG("hcon %p reason %d", hcon, reason);
4490
Ville Tervoacd7d372011-02-10 22:38:49 -03004491 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004492 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004493
Joe Perchese1750722011-06-29 18:18:29 -07004494 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004495
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496 return 0;
4497}
4498
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004499static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004500{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004501 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004502 return;
4503
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004504 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004505 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004506 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004507 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004508 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004509 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004510 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004511 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004512 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004513 }
4514}
4515
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004516static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004517{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004518 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004519 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004520
Marcel Holtmann01394182006-07-03 10:02:46 +02004521 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004522 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004523
Linus Torvalds1da177e2005-04-16 15:20:36 -07004524 BT_DBG("conn %p", conn);
4525
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004526 if (hcon->type == LE_LINK) {
4527 smp_distribute_keys(conn, 0);
4528 del_timer(&conn->security_timer);
4529 }
4530
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02004531 mutex_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004533 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004534 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004535
Linus Torvalds1da177e2005-04-16 15:20:36 -07004536 bh_lock_sock(sk);
4537
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004538 BT_DBG("chan->scid %d", chan->scid);
4539
4540 if (chan->scid == L2CAP_CID_LE_DATA) {
4541 if (!status && encrypt) {
4542 chan->sec_level = hcon->sec_level;
4543 l2cap_chan_ready(sk);
4544 }
4545
4546 bh_unlock_sock(sk);
4547 continue;
4548 }
4549
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004550 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004551 bh_unlock_sock(sk);
4552 continue;
4553 }
4554
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004555 if (!status && (chan->state == BT_CONNECTED ||
4556 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004557 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004558 bh_unlock_sock(sk);
4559 continue;
4560 }
4561
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004562 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004563 if (!status) {
4564 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004565 req.scid = cpu_to_le16(chan->scid);
4566 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004567
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004568 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004569 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004570
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004571 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004572 L2CAP_CONN_REQ, sizeof(req), &req);
4573 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004574 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004575 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004576 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004577 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004578 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004579 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004580
4581 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004582 if (bt_sk(sk)->defer_setup) {
4583 struct sock *parent = bt_sk(sk)->parent;
4584 res = L2CAP_CR_PEND;
4585 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004586 if (parent)
4587 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004588 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004589 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004590 res = L2CAP_CR_SUCCESS;
4591 stat = L2CAP_CS_NO_INFO;
4592 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004593 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004594 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004595 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004596 res = L2CAP_CR_SEC_BLOCK;
4597 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004598 }
4599
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004600 rsp.scid = cpu_to_le16(chan->dcid);
4601 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004602 rsp.result = cpu_to_le16(res);
4603 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004604 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4605 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 }
4607
Linus Torvalds1da177e2005-04-16 15:20:36 -07004608 bh_unlock_sock(sk);
4609 }
4610
Gustavo F. Padovand01b2ff2011-12-09 04:45:12 -02004611 mutex_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004612
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 return 0;
4614}
4615
4616static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4617{
4618 struct l2cap_conn *conn = hcon->l2cap_data;
4619
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004620 if (!conn)
4621 conn = l2cap_conn_add(hcon, 0);
4622
4623 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 goto drop;
4625
4626 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4627
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004628 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004629 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004630 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004631 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632 int len;
4633
4634 if (conn->rx_len) {
4635 BT_ERR("Unexpected start frame (len %d)", skb->len);
4636 kfree_skb(conn->rx_skb);
4637 conn->rx_skb = NULL;
4638 conn->rx_len = 0;
4639 l2cap_conn_unreliable(conn, ECOMM);
4640 }
4641
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004642 /* Start fragment always begin with Basic L2CAP header */
4643 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004644 BT_ERR("Frame is too short (len %d)", skb->len);
4645 l2cap_conn_unreliable(conn, ECOMM);
4646 goto drop;
4647 }
4648
4649 hdr = (struct l2cap_hdr *) skb->data;
4650 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004651 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004652
4653 if (len == skb->len) {
4654 /* Complete frame received */
4655 l2cap_recv_frame(conn, skb);
4656 return 0;
4657 }
4658
4659 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4660
4661 if (skb->len > len) {
4662 BT_ERR("Frame is too long (len %d, expected len %d)",
4663 skb->len, len);
4664 l2cap_conn_unreliable(conn, ECOMM);
4665 goto drop;
4666 }
4667
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004668 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004669
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004670 if (chan && chan->sk) {
4671 struct sock *sk = chan->sk;
4672
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004673 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004674 BT_ERR("Frame exceeding recv MTU (len %d, "
4675 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004676 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004677 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004678 l2cap_conn_unreliable(conn, ECOMM);
4679 goto drop;
4680 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004681 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004682 }
4683
Linus Torvalds1da177e2005-04-16 15:20:36 -07004684 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004685 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4686 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004687 goto drop;
4688
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004689 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004690 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691 conn->rx_len = len - skb->len;
4692 } else {
4693 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4694
4695 if (!conn->rx_len) {
4696 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4697 l2cap_conn_unreliable(conn, ECOMM);
4698 goto drop;
4699 }
4700
4701 if (skb->len > conn->rx_len) {
4702 BT_ERR("Fragment is too long (len %d, expected %d)",
4703 skb->len, conn->rx_len);
4704 kfree_skb(conn->rx_skb);
4705 conn->rx_skb = NULL;
4706 conn->rx_len = 0;
4707 l2cap_conn_unreliable(conn, ECOMM);
4708 goto drop;
4709 }
4710
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004711 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004712 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713 conn->rx_len -= skb->len;
4714
4715 if (!conn->rx_len) {
4716 /* Complete frame received */
4717 l2cap_recv_frame(conn, conn->rx_skb);
4718 conn->rx_skb = NULL;
4719 }
4720 }
4721
4722drop:
4723 kfree_skb(skb);
4724 return 0;
4725}
4726
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004727static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004729 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004731 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004733 list_for_each_entry(c, &chan_list, global_l) {
4734 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004736 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 +01004737 batostr(&bt_sk(sk)->src),
4738 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004739 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004740 c->scid, c->dcid, c->imtu, c->omtu,
4741 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004742}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004744 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004745
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004746 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747}
4748
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004749static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4750{
4751 return single_open(file, l2cap_debugfs_show, inode->i_private);
4752}
4753
4754static const struct file_operations l2cap_debugfs_fops = {
4755 .open = l2cap_debugfs_open,
4756 .read = seq_read,
4757 .llseek = seq_lseek,
4758 .release = single_release,
4759};
4760
4761static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763static struct hci_proto l2cap_hci_proto = {
4764 .name = "L2CAP",
4765 .id = HCI_PROTO_L2CAP,
4766 .connect_ind = l2cap_connect_ind,
4767 .connect_cfm = l2cap_connect_cfm,
4768 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004769 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004770 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004771 .recv_acldata = l2cap_recv_acldata
4772};
4773
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004774int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004775{
4776 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004777
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004778 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004779 if (err < 0)
4780 return err;
4781
Linus Torvalds1da177e2005-04-16 15:20:36 -07004782 err = hci_register_proto(&l2cap_hci_proto);
4783 if (err < 0) {
4784 BT_ERR("L2CAP protocol registration failed");
4785 bt_sock_unregister(BTPROTO_L2CAP);
4786 goto error;
4787 }
4788
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004789 if (bt_debugfs) {
4790 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4791 bt_debugfs, NULL, &l2cap_debugfs_fops);
4792 if (!l2cap_debugfs)
4793 BT_ERR("Failed to create L2CAP debug file");
4794 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004795
Linus Torvalds1da177e2005-04-16 15:20:36 -07004796 return 0;
4797
4798error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004799 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004800 return err;
4801}
4802
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004803void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004804{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004805 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004806
Linus Torvalds1da177e2005-04-16 15:20:36 -07004807 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4808 BT_ERR("L2CAP protocol unregistration failed");
4809
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004810 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811}
4812
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004813module_param(disable_ertm, bool, 0644);
4814MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");