blob: cba1f683b6498df6848802851dbbd19700183b0b [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.
Gustavo F. Padovan590051d2011-12-18 13:39:33 -02006 Copyright (C) 2011 ProFUSION Embedded Systems
Linus Torvalds1da177e2005-04-16 15:20:36 -07007
8 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation;
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090018 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070021 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090023 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070025 SOFTWARE IS DISCLAIMED.
26*/
27
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020028/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31
32#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080033#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/poll.h>
39#include <linux/fcntl.h>
40#include <linux/init.h>
41#include <linux/interrupt.h>
42#include <linux/socket.h>
43#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080045#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010046#include <linux/debugfs.h>
47#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030048#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030049#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070050#include <net/sock.h>
51
52#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#include <asm/unaligned.h>
54
55#include <net/bluetooth/bluetooth.h>
56#include <net/bluetooth/hci_core.h>
57#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030058#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Rusty Russelleb939922011-12-19 14:08:01 +000060bool disable_ertm;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +020076static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030077
Marcel Holtmann01394182006-07-03 10:02:46 +020078/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030079
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030080static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020081{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020082 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030083
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020084 rcu_read_lock();
85
86 list_for_each_entry_rcu(c, &conn->chan_l, list) {
87 if (c->dcid == cid) {
88 r = c;
89 break;
90 }
Marcel Holtmann01394182006-07-03 10:02:46 +020091 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020092
93 rcu_read_unlock();
94 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +020095}
96
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020098{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -020099 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300100
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200101 rcu_read_lock();
102
103 list_for_each_entry_rcu(c, &conn->chan_l, list) {
104 if (c->scid == cid) {
105 r = c;
106 break;
107 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200108 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200109
110 rcu_read_unlock();
111 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200112}
113
114/* Find channel with given SCID.
115 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200117{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300118 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300120 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300121 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300122 lock_sock(c->sk);
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. Padovan3d57dc62011-12-17 10:56:45 -0200128 struct l2cap_chan *c, *r = NULL;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300129
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200130 rcu_read_lock();
131
132 list_for_each_entry_rcu(c, &conn->chan_l, list) {
133 if (c->ident == ident) {
134 r = c;
135 break;
136 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200137 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200138
139 rcu_read_unlock();
140 return r;
Marcel Holtmann01394182006-07-03 10:02:46 +0200141}
142
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300143static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200144{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300145 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300146
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300147 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 if (c)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300149 lock_sock(c->sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300150 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200151}
152
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300156
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300157 list_for_each_entry(c, &chan_list, global_l) {
158 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100159 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160 }
Szymon Janc250938c2011-11-16 09:32:22 +0100161 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300162}
163
164int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
165{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300166 int err;
167
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200168 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300169
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300170 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300171 err = -EADDRINUSE;
172 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300173 }
174
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300175 if (psm) {
176 chan->psm = psm;
177 chan->sport = psm;
178 err = 0;
179 } else {
180 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300181
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300182 err = -EINVAL;
183 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300184 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300185 chan->psm = cpu_to_le16(p);
186 chan->sport = cpu_to_le16(p);
187 err = 0;
188 break;
189 }
190 }
191
192done:
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200193 write_unlock(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300194 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300195}
196
197int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
198{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200199 write_lock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300200
201 chan->scid = scid;
202
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200203 write_unlock(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300204
205 return 0;
206}
207
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300208static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200209{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300210 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200211
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300212 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300213 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200214 return cid;
215 }
216
217 return 0;
218}
219
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200220static char *state_to_string(int state)
221{
222 switch(state) {
223 case BT_CONNECTED:
224 return "BT_CONNECTED";
225 case BT_OPEN:
226 return "BT_OPEN";
227 case BT_BOUND:
228 return "BT_BOUND";
229 case BT_LISTEN:
230 return "BT_LISTEN";
231 case BT_CONNECT:
232 return "BT_CONNECT";
233 case BT_CONNECT2:
234 return "BT_CONNECT2";
235 case BT_CONFIG:
236 return "BT_CONFIG";
237 case BT_DISCONN:
238 return "BT_DISCONN";
239 case BT_CLOSED:
240 return "BT_CLOSED";
241 }
242
243 return "invalid state";
244}
245
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300246static void l2cap_state_change(struct l2cap_chan *chan, int state)
247{
Gustavo F. Padovanbadaaa02011-11-23 20:11:46 -0200248 BT_DBG("%p %s -> %s", chan, state_to_string(chan->state),
249 state_to_string(state));
250
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300251 chan->state = state;
252 chan->ops->state_change(chan->data, state);
253}
254
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300255static void l2cap_chan_timeout(struct work_struct *work)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300256{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300257 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
258 chan_timer.work);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259 struct sock *sk = chan->sk;
260 int reason;
261
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300262 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300263
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300264 lock_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300265
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300266 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300267 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300268 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300269 chan->sec_level != BT_SECURITY_SDP)
270 reason = ECONNREFUSED;
271 else
272 reason = ETIMEDOUT;
273
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300274 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300275
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300276 release_sock(sk);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300277
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300278 chan->ops->close(chan->data);
Ulisses Furquim371fd832011-12-21 20:02:36 -0200279 l2cap_chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300280}
281
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300282struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200283{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300284 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200285
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300286 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
287 if (!chan)
288 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200289
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300290 chan->sk = sk;
291
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200292 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300293 list_add(&chan->global_l, &chan_list);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200294 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300295
Gustavo F. Padovan721c4182011-06-23 19:29:58 -0300296 INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300297
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300298 chan->state = BT_OPEN;
299
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300300 atomic_set(&chan->refcnt, 1);
301
Szymon Jancabc545b2011-11-03 16:05:44 +0100302 BT_DBG("sk %p chan %p", sk, chan);
303
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300304 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200305}
306
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300307void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300308{
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200309 write_lock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300310 list_del(&chan->global_l);
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200311 write_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300312
Ulisses Furquim371fd832011-12-21 20:02:36 -0200313 l2cap_chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300314}
315
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200316static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200317{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300318 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300319 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200320
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200321 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100322
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300323 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200324
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300325 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300326 if (conn->hcon->type == LE_LINK) {
327 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300328 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300329 chan->scid = L2CAP_CID_LE_DATA;
330 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300331 } else {
332 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300333 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300334 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300335 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300336 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300338 chan->scid = L2CAP_CID_CONN_LESS;
339 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300340 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200341 } else {
342 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300343 chan->scid = L2CAP_CID_SIGNALING;
344 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300345 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200346 }
347
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300348 chan->local_id = L2CAP_BESTEFFORT_ID;
349 chan->local_stype = L2CAP_SERV_BESTEFFORT;
350 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
351 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
352 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
353 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
354
Ulisses Furquim371fd832011-12-21 20:02:36 -0200355 l2cap_chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300356
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200357 list_add_rcu(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200358}
359
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900360/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200361 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300362static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200363{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300364 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300365 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200366 struct sock *parent = bt_sk(sk)->parent;
367
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300368 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200369
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300370 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200371
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900372 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300373 /* Delete from channel list */
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200374 list_del_rcu(&chan->list);
375 synchronize_rcu();
376
Ulisses Furquim371fd832011-12-21 20:02:36 -0200377 l2cap_chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300378
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300379 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200380 hci_conn_put(conn->hcon);
381 }
382
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300383 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200384 sock_set_flag(sk, SOCK_ZAPPED);
385
386 if (err)
387 sk->sk_err = err;
388
389 if (parent) {
390 bt_accept_unlink(sk);
391 parent->sk_data_ready(parent, 0);
392 } else
393 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300394
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300395 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
396 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300397 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300398
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300399 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300400
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300401 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300402 struct srej_list *l, *tmp;
403
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300404 __clear_retrans_timer(chan);
405 __clear_monitor_timer(chan);
406 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300407
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300408 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300409
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300410 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300411 list_del(&l->list);
412 kfree(l);
413 }
414 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200415}
416
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300417static void l2cap_chan_cleanup_listen(struct sock *parent)
418{
419 struct sock *sk;
420
421 BT_DBG("parent %p", parent);
422
423 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300424 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300425 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300426 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300427 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300428 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300429 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300430 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300431 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300432}
433
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300434void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300435{
436 struct l2cap_conn *conn = chan->conn;
437 struct sock *sk = chan->sk;
438
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300439 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300440
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300441 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300442 case BT_LISTEN:
443 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300444
445 l2cap_state_change(chan, BT_CLOSED);
446 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300447 break;
448
449 case BT_CONNECTED:
450 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300451 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300452 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300453 __clear_chan_timer(chan);
454 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300455 l2cap_send_disconn_req(conn, chan, reason);
456 } else
457 l2cap_chan_del(chan, reason);
458 break;
459
460 case BT_CONNECT2:
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) {
463 struct l2cap_conn_rsp rsp;
464 __u16 result;
465
466 if (bt_sk(sk)->defer_setup)
467 result = L2CAP_CR_SEC_BLOCK;
468 else
469 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300470 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300471
472 rsp.scid = cpu_to_le16(chan->dcid);
473 rsp.dcid = cpu_to_le16(chan->scid);
474 rsp.result = cpu_to_le16(result);
475 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
476 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
477 sizeof(rsp), &rsp);
478 }
479
480 l2cap_chan_del(chan, reason);
481 break;
482
483 case BT_CONNECT:
484 case BT_DISCONN:
485 l2cap_chan_del(chan, reason);
486 break;
487
488 default:
489 sock_set_flag(sk, SOCK_ZAPPED);
490 break;
491 }
492}
493
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300494static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530495{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300496 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300497 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530498 case BT_SECURITY_HIGH:
499 return HCI_AT_DEDICATED_BONDING_MITM;
500 case BT_SECURITY_MEDIUM:
501 return HCI_AT_DEDICATED_BONDING;
502 default:
503 return HCI_AT_NO_BONDING;
504 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300505 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300506 if (chan->sec_level == BT_SECURITY_LOW)
507 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530508
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300509 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530510 return HCI_AT_NO_BONDING_MITM;
511 else
512 return HCI_AT_NO_BONDING;
513 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300514 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530515 case BT_SECURITY_HIGH:
516 return HCI_AT_GENERAL_BONDING_MITM;
517 case BT_SECURITY_MEDIUM:
518 return HCI_AT_GENERAL_BONDING;
519 default:
520 return HCI_AT_NO_BONDING;
521 }
522 }
523}
524
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200525/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200526int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200527{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300528 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100529 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200530
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300531 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100532
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300533 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200534}
535
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200536static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200537{
538 u8 id;
539
540 /* Get next available identificator.
541 * 1 - 128 are used by kernel.
542 * 129 - 199 are reserved.
543 * 200 - 254 are used by utilities like l2ping, etc.
544 */
545
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200546 spin_lock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200547
548 if (++conn->tx_ident > 128)
549 conn->tx_ident = 1;
550
551 id = conn->tx_ident;
552
Gustavo F. Padovan333055f2011-12-22 15:14:39 -0200553 spin_unlock(&conn->lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200554
555 return id;
556}
557
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300558static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200559{
560 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200561 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200562
563 BT_DBG("code 0x%2.2x", code);
564
565 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300566 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200567
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200568 if (lmp_no_flush_capable(conn->hcon->hdev))
569 flags = ACL_START_NO_FLUSH;
570 else
571 flags = ACL_START;
572
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700573 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200574 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700575
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200576 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200577}
578
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200579static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
580{
581 struct hci_conn *hcon = chan->conn->hcon;
582 u16 flags;
583
584 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
585 skb->priority);
586
587 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
588 lmp_no_flush_capable(hcon->hdev))
589 flags = ACL_START_NO_FLUSH;
590 else
591 flags = ACL_START;
592
593 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
594 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595}
596
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300597static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300598{
599 struct sk_buff *skb;
600 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300601 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300602 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300603
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300604 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300605 return;
606
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300607 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
608 hlen = L2CAP_EXT_HDR_SIZE;
609 else
610 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300611
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300612 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300613 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300614
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300615 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300616
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300617 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300618
619 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300620
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300621 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300622 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300623
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300624 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300625 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300626
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300627 skb = bt_skb_alloc(count, GFP_ATOMIC);
628 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300629 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300630
631 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300632 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300633 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300634
635 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300636
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300637 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300638 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
639 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300640 }
641
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200642 skb->priority = HCI_PRIO_MAX;
643 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300644}
645
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300646static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300647{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300648 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300649 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300650 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300651 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300652 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300653
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300654 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300655
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300656 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300657}
658
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300659static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300660{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300661 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300662}
663
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300664static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200665{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300666 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200667
668 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100669 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
670 return;
671
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200672 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300673 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200674 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300675 req.scid = cpu_to_le16(chan->scid);
676 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200677
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300678 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300679 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200680
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300681 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
682 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200683 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200684 } else {
685 struct l2cap_info_req req;
686 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
687
688 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
689 conn->info_ident = l2cap_get_ident(conn);
690
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200691 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200692 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
693
694 l2cap_send_cmd(conn, conn->info_ident,
695 L2CAP_INFO_REQ, sizeof(req), &req);
696 }
697}
698
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300699static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
700{
701 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300702 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300703 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
704
705 switch (mode) {
706 case L2CAP_MODE_ERTM:
707 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
708 case L2CAP_MODE_STREAMING:
709 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
710 default:
711 return 0x00;
712 }
713}
714
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300715static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300716{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300717 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300718 struct l2cap_disconn_req req;
719
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300720 if (!conn)
721 return;
722
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300723 sk = chan->sk;
724
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300725 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300726 __clear_retrans_timer(chan);
727 __clear_monitor_timer(chan);
728 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300729 }
730
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300731 req.dcid = cpu_to_le16(chan->dcid);
732 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300733 l2cap_send_cmd(conn, l2cap_get_ident(conn),
734 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300735
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300736 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300737 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300738}
739
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200741static void l2cap_conn_start(struct l2cap_conn *conn)
742{
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200743 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200744
745 BT_DBG("conn %p", conn);
746
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200747 rcu_read_lock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200748
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200749 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300750 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300751
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200752 bh_lock_sock(sk);
753
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300754 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200755 bh_unlock_sock(sk);
756 continue;
757 }
758
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300759 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300760 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300761
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200762 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300763 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300764 bh_unlock_sock(sk);
765 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200766 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300767
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300768 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
769 && test_bit(CONF_STATE2_DEVICE,
770 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300771 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300772 * so release the lock */
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300773 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300774 bh_unlock_sock(sk);
775 continue;
776 }
777
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300778 req.scid = cpu_to_le16(chan->scid);
779 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300780
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300781 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300782 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300783
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300784 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
785 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300786
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300787 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200788 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300789 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300790 rsp.scid = cpu_to_le16(chan->dcid);
791 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200792
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200793 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100794 if (bt_sk(sk)->defer_setup) {
795 struct sock *parent = bt_sk(sk)->parent;
796 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
797 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000798 if (parent)
799 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100800
801 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300802 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100803 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
804 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
805 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200806 } else {
807 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
808 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
809 }
810
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300811 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
812 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300813
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300814 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300815 rsp.result != L2CAP_CR_SUCCESS) {
816 bh_unlock_sock(sk);
817 continue;
818 }
819
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300820 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300821 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300822 l2cap_build_conf_req(chan, buf), buf);
823 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200824 }
825
826 bh_unlock_sock(sk);
827 }
828
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200829 rcu_read_unlock();
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200830}
831
Ville Tervob62f3282011-02-10 22:38:50 -0300832/* Find socket with cid and source bdaddr.
833 * Returns closest match, locked.
834 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300835static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300836{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300837 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300838
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300839 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300840
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300841 list_for_each_entry(c, &chan_list, global_l) {
842 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300843
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300844 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300845 continue;
846
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300847 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300848 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 if (!bacmp(&bt_sk(sk)->src, src)) {
850 read_unlock(&chan_list_lock);
851 return c;
852 }
Ville Tervob62f3282011-02-10 22:38:50 -0300853
854 /* Closest match */
855 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300856 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300857 }
858 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300859
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300860 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300861
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300863}
864
865static void l2cap_le_conn_ready(struct l2cap_conn *conn)
866{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300867 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300868 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300869
870 BT_DBG("");
871
872 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300873 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300874 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300875 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300876 return;
877
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300878 parent = pchan->sk;
879
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300880 lock_sock(parent);
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300881
Ville Tervob62f3282011-02-10 22:38:50 -0300882 /* Check for backlog size */
883 if (sk_acceptq_is_full(parent)) {
884 BT_DBG("backlog full %d", parent->sk_ack_backlog);
885 goto clean;
886 }
887
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300888 chan = pchan->ops->new_connection(pchan->data);
889 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300890 goto clean;
891
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300892 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300893
Ville Tervob62f3282011-02-10 22:38:50 -0300894 hci_conn_hold(conn->hcon);
895
Ville Tervob62f3282011-02-10 22:38:50 -0300896 bacpy(&bt_sk(sk)->src, conn->src);
897 bacpy(&bt_sk(sk)->dst, conn->dst);
898
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300899 bt_accept_enqueue(parent, sk);
900
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200901 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300902
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300903 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300904
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300905 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300906 parent->sk_data_ready(parent, 0);
907
Ville Tervob62f3282011-02-10 22:38:50 -0300908clean:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -0300909 release_sock(parent);
Ville Tervob62f3282011-02-10 22:38:50 -0300910}
911
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300912static void l2cap_chan_ready(struct sock *sk)
913{
914 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
915 struct sock *parent = bt_sk(sk)->parent;
916
917 BT_DBG("sk %p, parent %p", sk, parent);
918
919 chan->conf_state = 0;
920 __clear_chan_timer(chan);
921
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300922 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300923 sk->sk_state_change(sk);
924
925 if (parent)
926 parent->sk_data_ready(parent, 0);
927}
928
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200929static void l2cap_conn_ready(struct l2cap_conn *conn)
930{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300931 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200932
933 BT_DBG("conn %p", conn);
934
Ville Tervob62f3282011-02-10 22:38:50 -0300935 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
936 l2cap_le_conn_ready(conn);
937
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300938 if (conn->hcon->out && conn->hcon->type == LE_LINK)
939 smp_conn_security(conn, conn->hcon->pending_sec_level);
940
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200941 rcu_read_lock();
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200942
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200943 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300944 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300945
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200946 bh_lock_sock(sk);
947
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300948 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300949 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300950 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300951
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300952 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300953 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300954 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200955 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300956
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300957 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300958 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200959
960 bh_unlock_sock(sk);
961 }
962
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200963 rcu_read_unlock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200964}
965
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200966/* Notify sockets that we cannot guaranty reliability anymore */
967static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
968{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300969 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200970
971 BT_DBG("conn %p", conn);
972
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200973 rcu_read_lock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200974
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200975 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300976 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300977
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300978 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200979 sk->sk_err = err;
980 }
981
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -0200982 rcu_read_unlock();
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200983}
984
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200985static void l2cap_info_timeout(struct work_struct *work)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200986{
Gustavo F. Padovanf878fca2011-12-15 01:16:14 -0200987 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
Gustavo F. Padovan030013d2011-12-20 10:57:28 -0200988 info_timer.work);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200989
Marcel Holtmann984947d2009-02-06 23:35:19 +0100990 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100991 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100992
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200993 l2cap_conn_start(conn);
994}
995
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300996static void l2cap_conn_del(struct hci_conn *hcon, int err)
997{
998 struct l2cap_conn *conn = hcon->l2cap_data;
999 struct l2cap_chan *chan, *l;
1000 struct sock *sk;
1001
1002 if (!conn)
1003 return;
1004
1005 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1006
1007 kfree_skb(conn->rx_skb);
1008
1009 /* Kill channels */
1010 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1011 sk = chan->sk;
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001012 lock_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001013 l2cap_chan_del(chan, err);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03001014 release_sock(sk);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001015 chan->ops->close(chan->data);
1016 }
1017
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001018 hci_chan_del(conn->hchan);
1019
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001020 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
Ulisses Furquim371fd832011-12-21 20:02:36 -02001021 __cancel_delayed_work(&conn->info_timer);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001022
Johan Hedberg51a8efd2012-01-16 06:10:31 +02001023 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) {
Ulisses Furquim371fd832011-12-21 20:02:36 -02001024 __cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001025 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001026 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001027
1028 hcon->l2cap_data = NULL;
1029 kfree(conn);
1030}
1031
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001032static void security_timeout(struct work_struct *work)
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001033{
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001034 struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
1035 security_timer.work);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001036
1037 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1038}
1039
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1041{
Marcel Holtmann01394182006-07-03 10:02:46 +02001042 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001043 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044
Marcel Holtmann01394182006-07-03 10:02:46 +02001045 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return conn;
1047
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001048 hchan = hci_chan_create(hcon);
1049 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001052 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1053 if (!conn) {
1054 hci_chan_del(hchan);
1055 return NULL;
1056 }
1057
Linus Torvalds1da177e2005-04-16 15:20:36 -07001058 hcon->l2cap_data = conn;
1059 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001060 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001062 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001063
Ville Tervoacd7d372011-02-10 22:38:49 -03001064 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1065 conn->mtu = hcon->hdev->le_mtu;
1066 else
1067 conn->mtu = hcon->hdev->acl_mtu;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 conn->src = &hcon->hdev->bdaddr;
1070 conn->dst = &hcon->dst;
1071
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001072 conn->feat_mask = 0;
1073
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001075
1076 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001078 if (hcon->type == LE_LINK)
Gustavo F. Padovan6c9d42a2011-12-20 10:57:27 -02001079 INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001080 else
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02001081 INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
Dave Young45054dc2009-10-18 20:28:30 +00001082
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001083 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001084
Linus Torvalds1da177e2005-04-16 15:20:36 -07001085 return conn;
1086}
1087
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089
1090/* Find socket with psm and source bdaddr.
1091 * Returns closest match.
1092 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001093static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001095 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001096
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001097 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001098
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001099 list_for_each_entry(c, &chan_list, global_l) {
1100 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001101
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001102 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 continue;
1104
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001105 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001107 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001108 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001109 return c;
1110 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
1112 /* Closest match */
1113 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001114 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 }
1116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001118 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001119
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001120 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121}
1122
Johan Hedbergcbe8fed2012-01-08 22:51:16 +02001123int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001125 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127 struct l2cap_conn *conn;
1128 struct hci_conn *hcon;
1129 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001130 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001131 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001133 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001134 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001136 hdev = hci_get_route(dst, src);
1137 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138 return -EHOSTUNREACH;
1139
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001140 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001142 lock_sock(sk);
1143
1144 /* PSM must be odd and lsb of upper byte must be 0 */
1145 if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
1146 chan->chan_type != L2CAP_CHAN_RAW) {
1147 err = -EINVAL;
1148 goto done;
1149 }
1150
1151 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
1152 err = -EINVAL;
1153 goto done;
1154 }
1155
1156 switch (chan->mode) {
1157 case L2CAP_MODE_BASIC:
1158 break;
1159 case L2CAP_MODE_ERTM:
1160 case L2CAP_MODE_STREAMING:
1161 if (!disable_ertm)
1162 break;
1163 /* fall through */
1164 default:
1165 err = -ENOTSUPP;
1166 goto done;
1167 }
1168
1169 switch (sk->sk_state) {
1170 case BT_CONNECT:
1171 case BT_CONNECT2:
1172 case BT_CONFIG:
1173 /* Already connecting */
1174 err = 0;
1175 goto done;
1176
1177 case BT_CONNECTED:
1178 /* Already connected */
1179 err = -EISCONN;
1180 goto done;
1181
1182 case BT_OPEN:
1183 case BT_BOUND:
1184 /* Can connect */
1185 break;
1186
1187 default:
1188 err = -EBADFD;
1189 goto done;
1190 }
1191
1192 /* Set destination address and psm */
Gustavo F. Padovan9219b2a2012-01-02 20:08:04 -02001193 bacpy(&bt_sk(sk)->dst, dst);
Gustavo F. Padovan03a00192011-12-09 04:48:17 -02001194 chan->psm = psm;
1195 chan->dcid = cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001197 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001198
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001199 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001200 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001201 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001202 else
1203 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001204 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001205
Ville Tervo30e76272011-02-22 16:10:53 -03001206 if (IS_ERR(hcon)) {
1207 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001209 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211 conn = l2cap_conn_add(hcon, 0);
1212 if (!conn) {
1213 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001214 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215 goto done;
1216 }
1217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 /* Update source addr of the socket */
1219 bacpy(src, conn->src);
1220
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001221 l2cap_chan_add(conn, chan);
1222
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001223 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001224 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001225
1226 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001227 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001228 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001229 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001230 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001231 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001232 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233 }
1234
Ville Tervo30e76272011-02-22 16:10:53 -03001235 err = 0;
1236
Linus Torvalds1da177e2005-04-16 15:20:36 -07001237done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001238 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 hci_dev_put(hdev);
1240 return err;
1241}
1242
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001243int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001244{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001245 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001246 DECLARE_WAITQUEUE(wait, current);
1247 int err = 0;
1248 int timeo = HZ/5;
1249
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001250 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001251 set_current_state(TASK_INTERRUPTIBLE);
1252 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001253 if (!timeo)
1254 timeo = HZ/5;
1255
1256 if (signal_pending(current)) {
1257 err = sock_intr_errno(timeo);
1258 break;
1259 }
1260
1261 release_sock(sk);
1262 timeo = schedule_timeout(timeo);
1263 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001264 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001265
1266 err = sock_error(sk);
1267 if (err)
1268 break;
1269 }
1270 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001271 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001272 return err;
1273}
1274
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001275static void l2cap_monitor_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001276{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001277 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1278 monitor_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001279 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001280
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001281 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001282
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001283 lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001284 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001285 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001286 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001287 return;
1288 }
1289
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001290 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001291 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001292
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001293 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001294 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001295}
1296
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001297static void l2cap_retrans_timeout(struct work_struct *work)
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001298{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001299 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1300 retrans_timer.work);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001301 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001302
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001303 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001304
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001305 lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001306 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001307 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001308
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001309 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001310
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001311 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001312 release_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001313}
1314
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001315static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001316{
1317 struct sk_buff *skb;
1318
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001319 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001320 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001321 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001322 break;
1323
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001324 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001325 kfree_skb(skb);
1326
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001327 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001328 }
1329
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001330 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001331 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001332}
1333
Szymon Janc67c9e842011-07-28 16:24:33 +02001334static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001335{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001336 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001337 u32 control;
1338 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001339
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001340 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001341 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001342 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001343 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001344
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001345 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001346 fcs = crc16(0, (u8 *)skb->data,
1347 skb->len - L2CAP_FCS_SIZE);
1348 put_unaligned_le16(fcs,
1349 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001350 }
1351
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001352 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001353
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001354 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001355 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001356}
1357
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001358static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001359{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001360 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001361 u16 fcs;
1362 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001363
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001364 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001365 if (!skb)
1366 return;
1367
Szymon Jancd1726b62011-11-16 09:32:20 +01001368 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001369 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001370 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001371
Szymon Jancd1726b62011-11-16 09:32:20 +01001372 skb = skb_queue_next(&chan->tx_q, skb);
1373 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001374
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001375 if (chan->remote_max_tx &&
1376 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001377 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001378 return;
1379 }
1380
1381 tx_skb = skb_clone(skb, GFP_ATOMIC);
1382 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001383
1384 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001385 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001386
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001387 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001388 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001389
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001390 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001391 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001392
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001393 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001394
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001395 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001396 fcs = crc16(0, (u8 *)tx_skb->data,
1397 tx_skb->len - L2CAP_FCS_SIZE);
1398 put_unaligned_le16(fcs,
1399 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001400 }
1401
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001402 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001403}
1404
Szymon Janc67c9e842011-07-28 16:24:33 +02001405static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001406{
1407 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001408 u16 fcs;
1409 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001410 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001411
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001412 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001413 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001414
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001415 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001416
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001417 if (chan->remote_max_tx &&
1418 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001419 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001420 break;
1421 }
1422
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001423 tx_skb = skb_clone(skb, GFP_ATOMIC);
1424
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001425 bt_cb(skb)->retries++;
1426
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001427 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001428 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001429
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001430 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001431 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001432
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001433 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001434 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001435
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001436 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001437
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001438 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001439 fcs = crc16(0, (u8 *)skb->data,
1440 tx_skb->len - L2CAP_FCS_SIZE);
1441 put_unaligned_le16(fcs, skb->data +
1442 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001443 }
1444
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001445 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001446
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001447 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001448
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001449 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001450
1451 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001452
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301453 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001454 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301455
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001456 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001457
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001458 if (skb_queue_is_last(&chan->tx_q, skb))
1459 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001460 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001461 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001462
1463 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464 }
1465
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001466 return nsent;
1467}
1468
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001469static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001470{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001471 int ret;
1472
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001473 if (!skb_queue_empty(&chan->tx_q))
1474 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001475
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001476 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001477 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001478 return ret;
1479}
1480
Szymon Jancb17e73b2012-01-11 10:59:47 +01001481static void __l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001482{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001483 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001484
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001485 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001486
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001487 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001488 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001489 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001490 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001491 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001492 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001493
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001494 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001495 return;
1496
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001497 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001498 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001499}
1500
Szymon Jancb17e73b2012-01-11 10:59:47 +01001501static void l2cap_send_ack(struct l2cap_chan *chan)
1502{
1503 __clear_ack_timer(chan);
1504 __l2cap_send_ack(chan);
1505}
1506
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001507static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001508{
1509 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001510 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001511
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001512 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001513 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001514
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001515 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001516 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001517
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001518 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001519}
1520
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001521static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001523 struct sock *sk = chan->sk;
1524 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001525 struct sk_buff **frag;
1526 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001527
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001528 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001529 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530
1531 sent += count;
1532 len -= count;
1533
1534 /* Continuation fragments (no L2CAP header) */
1535 frag = &skb_shinfo(skb)->frag_list;
1536 while (len) {
1537 count = min_t(unsigned int, conn->mtu, len);
1538
1539 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1540 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001541 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001542 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1543 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001545 (*frag)->priority = skb->priority;
1546
Linus Torvalds1da177e2005-04-16 15:20:36 -07001547 sent += count;
1548 len -= count;
1549
1550 frag = &(*frag)->next;
1551 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552
1553 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001554}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001556static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1557 struct msghdr *msg, size_t len,
1558 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001559{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001560 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001561 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001562 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001563 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001564 struct l2cap_hdr *lh;
1565
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001566 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001567
1568 count = min_t(unsigned int, (conn->mtu - hlen), len);
1569 skb = bt_skb_send_alloc(sk, count + hlen,
1570 msg->msg_flags & MSG_DONTWAIT, &err);
1571 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001572 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001573
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001574 skb->priority = priority;
1575
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001576 /* Create L2CAP header */
1577 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001578 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001579 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001580 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001581
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001582 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001583 if (unlikely(err < 0)) {
1584 kfree_skb(skb);
1585 return ERR_PTR(err);
1586 }
1587 return skb;
1588}
1589
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001590static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1591 struct msghdr *msg, size_t len,
1592 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001593{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001594 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001595 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596 struct sk_buff *skb;
1597 int err, count, hlen = L2CAP_HDR_SIZE;
1598 struct l2cap_hdr *lh;
1599
1600 BT_DBG("sk %p len %d", sk, (int)len);
1601
1602 count = min_t(unsigned int, (conn->mtu - hlen), len);
1603 skb = bt_skb_send_alloc(sk, count + hlen,
1604 msg->msg_flags & MSG_DONTWAIT, &err);
1605 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001606 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001607
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001608 skb->priority = priority;
1609
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001610 /* Create L2CAP header */
1611 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001612 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001613 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1614
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001615 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001616 if (unlikely(err < 0)) {
1617 kfree_skb(skb);
1618 return ERR_PTR(err);
1619 }
1620 return skb;
1621}
1622
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001623static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1624 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001625 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001626{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001627 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001628 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001629 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001630 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001631 struct l2cap_hdr *lh;
1632
1633 BT_DBG("sk %p len %d", sk, (int)len);
1634
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001635 if (!conn)
1636 return ERR_PTR(-ENOTCONN);
1637
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001638 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1639 hlen = L2CAP_EXT_HDR_SIZE;
1640 else
1641 hlen = L2CAP_ENH_HDR_SIZE;
1642
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001643 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001644 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001645
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001646 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001647 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001648
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001649 count = min_t(unsigned int, (conn->mtu - hlen), len);
1650 skb = bt_skb_send_alloc(sk, count + hlen,
1651 msg->msg_flags & MSG_DONTWAIT, &err);
1652 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001653 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001654
1655 /* Create L2CAP header */
1656 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001657 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001658 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001659
1660 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1661
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001662 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001663 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001664
Andrei Emeltchenko0952a572012-01-13 17:21:43 +02001665 err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001666 if (unlikely(err < 0)) {
1667 kfree_skb(skb);
1668 return ERR_PTR(err);
1669 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001670
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001671 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001672 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001673
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001674 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001675 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676}
1677
Szymon Janc67c9e842011-07-28 16:24:33 +02001678static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001679{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001680 struct sk_buff *skb;
1681 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001682 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001683 size_t size = 0;
1684
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001685 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001686 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001687 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001688 if (IS_ERR(skb))
1689 return PTR_ERR(skb);
1690
1691 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001692 len -= chan->remote_mps;
1693 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001694
1695 while (len > 0) {
1696 size_t buflen;
1697
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001698 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001699 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001700 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001701 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001702 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001703 buflen = len;
1704 }
1705
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001706 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001707 if (IS_ERR(skb)) {
1708 skb_queue_purge(&sar_queue);
1709 return PTR_ERR(skb);
1710 }
1711
1712 __skb_queue_tail(&sar_queue, skb);
1713 len -= buflen;
1714 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001715 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001716 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1717 if (chan->tx_send_head == NULL)
1718 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001719
1720 return size;
1721}
1722
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001723int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1724 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001725{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001726 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001727 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001728 int err;
1729
1730 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001731 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001732 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001733 if (IS_ERR(skb))
1734 return PTR_ERR(skb);
1735
1736 l2cap_do_send(chan, skb);
1737 return len;
1738 }
1739
1740 switch (chan->mode) {
1741 case L2CAP_MODE_BASIC:
1742 /* Check outgoing MTU */
1743 if (len > chan->omtu)
1744 return -EMSGSIZE;
1745
1746 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001747 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001748 if (IS_ERR(skb))
1749 return PTR_ERR(skb);
1750
1751 l2cap_do_send(chan, skb);
1752 err = len;
1753 break;
1754
1755 case L2CAP_MODE_ERTM:
1756 case L2CAP_MODE_STREAMING:
1757 /* Entire SDU fits into one PDU */
1758 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001759 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001760 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1761 0);
1762 if (IS_ERR(skb))
1763 return PTR_ERR(skb);
1764
1765 __skb_queue_tail(&chan->tx_q, skb);
1766
1767 if (chan->tx_send_head == NULL)
1768 chan->tx_send_head = skb;
1769
1770 } else {
1771 /* Segment SDU into multiples PDUs */
1772 err = l2cap_sar_segment_sdu(chan, msg, len);
1773 if (err < 0)
1774 return err;
1775 }
1776
1777 if (chan->mode == L2CAP_MODE_STREAMING) {
1778 l2cap_streaming_send(chan);
1779 err = len;
1780 break;
1781 }
1782
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001783 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1784 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001785 err = len;
1786 break;
1787 }
1788
1789 err = l2cap_ertm_send(chan);
1790 if (err >= 0)
1791 err = len;
1792
1793 break;
1794
1795 default:
1796 BT_DBG("bad state %1.1x", chan->mode);
1797 err = -EBADFD;
1798 }
1799
1800 return err;
1801}
1802
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803/* Copy frame to all raw sockets on that connection */
1804static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1805{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001806 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001807 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808
1809 BT_DBG("conn %p", conn);
1810
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001811 rcu_read_lock();
1812
1813 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001814 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001815 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001816 continue;
1817
1818 /* Don't send frame to the socket it came from */
1819 if (skb->sk == sk)
1820 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001821 nskb = skb_clone(skb, GFP_ATOMIC);
1822 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823 continue;
1824
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001825 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001826 kfree_skb(nskb);
1827 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001828
1829 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830}
1831
1832/* ---- L2CAP signalling commands ---- */
1833static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1834 u8 code, u8 ident, u16 dlen, void *data)
1835{
1836 struct sk_buff *skb, **frag;
1837 struct l2cap_cmd_hdr *cmd;
1838 struct l2cap_hdr *lh;
1839 int len, count;
1840
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001841 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1842 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001843
1844 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1845 count = min_t(unsigned int, conn->mtu, len);
1846
1847 skb = bt_skb_alloc(count, GFP_ATOMIC);
1848 if (!skb)
1849 return NULL;
1850
1851 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001852 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001853
1854 if (conn->hcon->type == LE_LINK)
1855 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1856 else
1857 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858
1859 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1860 cmd->code = code;
1861 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001862 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001863
1864 if (dlen) {
1865 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1866 memcpy(skb_put(skb, count), data, count);
1867 data += count;
1868 }
1869
1870 len -= skb->len;
1871
1872 /* Continuation fragments (no L2CAP header) */
1873 frag = &skb_shinfo(skb)->frag_list;
1874 while (len) {
1875 count = min_t(unsigned int, conn->mtu, len);
1876
1877 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1878 if (!*frag)
1879 goto fail;
1880
1881 memcpy(skb_put(*frag, count), data, count);
1882
1883 len -= count;
1884 data += count;
1885
1886 frag = &(*frag)->next;
1887 }
1888
1889 return skb;
1890
1891fail:
1892 kfree_skb(skb);
1893 return NULL;
1894}
1895
1896static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1897{
1898 struct l2cap_conf_opt *opt = *ptr;
1899 int len;
1900
1901 len = L2CAP_CONF_OPT_SIZE + opt->len;
1902 *ptr += len;
1903
1904 *type = opt->type;
1905 *olen = opt->len;
1906
1907 switch (opt->len) {
1908 case 1:
1909 *val = *((u8 *) opt->val);
1910 break;
1911
1912 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001913 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914 break;
1915
1916 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001917 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918 break;
1919
1920 default:
1921 *val = (unsigned long) opt->val;
1922 break;
1923 }
1924
1925 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1926 return len;
1927}
1928
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1930{
1931 struct l2cap_conf_opt *opt = *ptr;
1932
1933 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1934
1935 opt->type = type;
1936 opt->len = len;
1937
1938 switch (len) {
1939 case 1:
1940 *((u8 *) opt->val) = val;
1941 break;
1942
1943 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001944 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001945 break;
1946
1947 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001948 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 break;
1950
1951 default:
1952 memcpy(opt->val, (void *) val, len);
1953 break;
1954 }
1955
1956 *ptr += L2CAP_CONF_OPT_SIZE + len;
1957}
1958
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001959static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1960{
1961 struct l2cap_conf_efs efs;
1962
Szymon Janc1ec918c2011-11-16 09:32:21 +01001963 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001964 case L2CAP_MODE_ERTM:
1965 efs.id = chan->local_id;
1966 efs.stype = chan->local_stype;
1967 efs.msdu = cpu_to_le16(chan->local_msdu);
1968 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1969 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1970 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1971 break;
1972
1973 case L2CAP_MODE_STREAMING:
1974 efs.id = 1;
1975 efs.stype = L2CAP_SERV_BESTEFFORT;
1976 efs.msdu = cpu_to_le16(chan->local_msdu);
1977 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1978 efs.acc_lat = 0;
1979 efs.flush_to = 0;
1980 break;
1981
1982 default:
1983 return;
1984 }
1985
1986 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1987 (unsigned long) &efs);
1988}
1989
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001990static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001991{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001992 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1993 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001994
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02001995 BT_DBG("chan %p", chan);
1996
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001997 lock_sock(chan->sk);
Szymon Jancb17e73b2012-01-11 10:59:47 +01001998 __l2cap_send_ack(chan);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001999 release_sock(chan->sk);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01002000
2001 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002002}
2003
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002004static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002005{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002006 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002007 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002008 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002009 chan->num_acked = 0;
2010 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002011
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002012 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2013 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2014 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002015
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002016 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002017
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002018 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002019}
2020
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002021static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2022{
2023 switch (mode) {
2024 case L2CAP_MODE_STREAMING:
2025 case L2CAP_MODE_ERTM:
2026 if (l2cap_mode_supported(mode, remote_feat_mask))
2027 return mode;
2028 /* fall through */
2029 default:
2030 return L2CAP_MODE_BASIC;
2031 }
2032}
2033
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002034static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2035{
2036 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2037}
2038
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002039static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2040{
2041 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2042}
2043
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002044static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2045{
2046 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002047 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002048 /* use extended control field */
2049 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002050 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2051 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002052 chan->tx_win = min_t(u16, chan->tx_win,
2053 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002054 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2055 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002056}
2057
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002058static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002060 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002061 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002062 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002063 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002065 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002067 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002068 goto done;
2069
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002070 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002071 case L2CAP_MODE_STREAMING:
2072 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002073 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002074 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002075
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002076 if (__l2cap_efs_supported(chan))
2077 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2078
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002079 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002080 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002081 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002082 break;
2083 }
2084
2085done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002086 if (chan->imtu != L2CAP_DEFAULT_MTU)
2087 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002088
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002089 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002090 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002091 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2092 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002093 break;
2094
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002095 rfc.mode = L2CAP_MODE_BASIC;
2096 rfc.txwin_size = 0;
2097 rfc.max_transmit = 0;
2098 rfc.retrans_timeout = 0;
2099 rfc.monitor_timeout = 0;
2100 rfc.max_pdu_size = 0;
2101
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002102 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2103 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002104 break;
2105
2106 case L2CAP_MODE_ERTM:
2107 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002108 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002109 rfc.retrans_timeout = 0;
2110 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002111
2112 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2113 L2CAP_EXT_HDR_SIZE -
2114 L2CAP_SDULEN_SIZE -
2115 L2CAP_FCS_SIZE);
2116 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002117
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002118 l2cap_txwin_setup(chan);
2119
2120 rfc.txwin_size = min_t(u16, chan->tx_win,
2121 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002122
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002123 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2124 (unsigned long) &rfc);
2125
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002126 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2127 l2cap_add_opt_efs(&ptr, chan);
2128
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002129 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002130 break;
2131
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002132 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002133 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002134 chan->fcs = L2CAP_FCS_NONE;
2135 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002136 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002137
2138 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2139 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2140 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002141 break;
2142
2143 case L2CAP_MODE_STREAMING:
2144 rfc.mode = L2CAP_MODE_STREAMING;
2145 rfc.txwin_size = 0;
2146 rfc.max_transmit = 0;
2147 rfc.retrans_timeout = 0;
2148 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002149
2150 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2151 L2CAP_EXT_HDR_SIZE -
2152 L2CAP_SDULEN_SIZE -
2153 L2CAP_FCS_SIZE);
2154 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002155
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002156 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2157 (unsigned long) &rfc);
2158
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002159 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2160 l2cap_add_opt_efs(&ptr, chan);
2161
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002162 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002163 break;
2164
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002165 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002166 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002167 chan->fcs = L2CAP_FCS_NONE;
2168 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002169 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002170 break;
2171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002173 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002174 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002175
2176 return ptr - data;
2177}
2178
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002179static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002180{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002181 struct l2cap_conf_rsp *rsp = data;
2182 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002183 void *req = chan->conf_req;
2184 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002185 int type, hint, olen;
2186 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002187 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002188 struct l2cap_conf_efs efs;
2189 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002190 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002191 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002192 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002194 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002195
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002196 while (len >= L2CAP_CONF_OPT_SIZE) {
2197 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002199 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002200 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002201
2202 switch (type) {
2203 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002204 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002205 break;
2206
2207 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002208 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002209 break;
2210
2211 case L2CAP_CONF_QOS:
2212 break;
2213
Marcel Holtmann6464f352007-10-20 13:39:51 +02002214 case L2CAP_CONF_RFC:
2215 if (olen == sizeof(rfc))
2216 memcpy(&rfc, (void *) val, olen);
2217 break;
2218
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002219 case L2CAP_CONF_FCS:
2220 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002221 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002222 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002223
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002224 case L2CAP_CONF_EFS:
2225 remote_efs = 1;
2226 if (olen == sizeof(efs))
2227 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002228 break;
2229
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002230 case L2CAP_CONF_EWS:
2231 if (!enable_hs)
2232 return -ECONNREFUSED;
2233
2234 set_bit(FLAG_EXT_CTRL, &chan->flags);
2235 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002236 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002237 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002238 break;
2239
2240 default:
2241 if (hint)
2242 break;
2243
2244 result = L2CAP_CONF_UNKNOWN;
2245 *((u8 *) ptr++) = type;
2246 break;
2247 }
2248 }
2249
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002250 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002251 goto done;
2252
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002253 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002254 case L2CAP_MODE_STREAMING:
2255 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002256 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002257 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002258 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002259 break;
2260 }
2261
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002262 if (remote_efs) {
2263 if (__l2cap_efs_supported(chan))
2264 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2265 else
2266 return -ECONNREFUSED;
2267 }
2268
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002269 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002270 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002271
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002272 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002273 }
2274
2275done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002276 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002277 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002278 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002279
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002280 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002281 return -ECONNREFUSED;
2282
2283 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2284 sizeof(rfc), (unsigned long) &rfc);
2285 }
2286
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002287 if (result == L2CAP_CONF_SUCCESS) {
2288 /* Configure output options and let the other side know
2289 * which ones we don't like. */
2290
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002291 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2292 result = L2CAP_CONF_UNACCEPT;
2293 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002294 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002295 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002296 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002297 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002298
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002299 if (remote_efs) {
2300 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2301 efs.stype != L2CAP_SERV_NOTRAFIC &&
2302 efs.stype != chan->local_stype) {
2303
2304 result = L2CAP_CONF_UNACCEPT;
2305
2306 if (chan->num_conf_req >= 1)
2307 return -ECONNREFUSED;
2308
2309 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002310 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002311 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002312 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002313 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002314 result = L2CAP_CONF_PENDING;
2315 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002316 }
2317 }
2318
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002319 switch (rfc.mode) {
2320 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002321 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002322 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002323 break;
2324
2325 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002326 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2327 chan->remote_tx_win = rfc.txwin_size;
2328 else
2329 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2330
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002331 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002332
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002333 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2334 chan->conn->mtu -
2335 L2CAP_EXT_HDR_SIZE -
2336 L2CAP_SDULEN_SIZE -
2337 L2CAP_FCS_SIZE);
2338 rfc.max_pdu_size = cpu_to_le16(size);
2339 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002340
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002341 rfc.retrans_timeout =
2342 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2343 rfc.monitor_timeout =
2344 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002345
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002346 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002347
2348 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2349 sizeof(rfc), (unsigned long) &rfc);
2350
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002351 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2352 chan->remote_id = efs.id;
2353 chan->remote_stype = efs.stype;
2354 chan->remote_msdu = le16_to_cpu(efs.msdu);
2355 chan->remote_flush_to =
2356 le32_to_cpu(efs.flush_to);
2357 chan->remote_acc_lat =
2358 le32_to_cpu(efs.acc_lat);
2359 chan->remote_sdu_itime =
2360 le32_to_cpu(efs.sdu_itime);
2361 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2362 sizeof(efs), (unsigned long) &efs);
2363 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002364 break;
2365
2366 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002367 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2368 chan->conn->mtu -
2369 L2CAP_EXT_HDR_SIZE -
2370 L2CAP_SDULEN_SIZE -
2371 L2CAP_FCS_SIZE);
2372 rfc.max_pdu_size = cpu_to_le16(size);
2373 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002374
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002375 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002376
2377 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2378 sizeof(rfc), (unsigned long) &rfc);
2379
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002380 break;
2381
2382 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002383 result = L2CAP_CONF_UNACCEPT;
2384
2385 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002386 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002387 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002388
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002389 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002390 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002391 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002392 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002393 rsp->result = cpu_to_le16(result);
2394 rsp->flags = cpu_to_le16(0x0000);
2395
2396 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002397}
2398
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002399static 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 -03002400{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002401 struct l2cap_conf_req *req = data;
2402 void *ptr = req->data;
2403 int type, olen;
2404 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002405 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002406 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002407
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002408 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002409
2410 while (len >= L2CAP_CONF_OPT_SIZE) {
2411 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2412
2413 switch (type) {
2414 case L2CAP_CONF_MTU:
2415 if (val < L2CAP_DEFAULT_MIN_MTU) {
2416 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002417 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002418 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002419 chan->imtu = val;
2420 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002421 break;
2422
2423 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002424 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002425 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002426 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002427 break;
2428
2429 case L2CAP_CONF_RFC:
2430 if (olen == sizeof(rfc))
2431 memcpy(&rfc, (void *)val, olen);
2432
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002433 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002434 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002435 return -ECONNREFUSED;
2436
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002437 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002438
2439 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2440 sizeof(rfc), (unsigned long) &rfc);
2441 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002442
2443 case L2CAP_CONF_EWS:
2444 chan->tx_win = min_t(u16, val,
2445 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002446 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2447 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002448 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002449
2450 case L2CAP_CONF_EFS:
2451 if (olen == sizeof(efs))
2452 memcpy(&efs, (void *)val, olen);
2453
2454 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2455 efs.stype != L2CAP_SERV_NOTRAFIC &&
2456 efs.stype != chan->local_stype)
2457 return -ECONNREFUSED;
2458
2459 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2460 sizeof(efs), (unsigned long) &efs);
2461 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002462 }
2463 }
2464
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002465 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002466 return -ECONNREFUSED;
2467
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002468 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002469
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002470 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002471 switch (rfc.mode) {
2472 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002473 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2474 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2475 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002476
2477 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2478 chan->local_msdu = le16_to_cpu(efs.msdu);
2479 chan->local_sdu_itime =
2480 le32_to_cpu(efs.sdu_itime);
2481 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2482 chan->local_flush_to =
2483 le32_to_cpu(efs.flush_to);
2484 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002485 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002486
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002487 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002488 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002489 }
2490 }
2491
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002492 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002493 req->flags = cpu_to_le16(0x0000);
2494
2495 return ptr - data;
2496}
2497
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002498static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499{
2500 struct l2cap_conf_rsp *rsp = data;
2501 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002502
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002503 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002504
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002505 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002506 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002507 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
2509 return ptr - data;
2510}
2511
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002512void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002513{
2514 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002515 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002516 u8 buf[128];
2517
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002518 rsp.scid = cpu_to_le16(chan->dcid);
2519 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002520 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2521 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2522 l2cap_send_cmd(conn, chan->ident,
2523 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2524
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002525 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002526 return;
2527
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002528 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2529 l2cap_build_conf_req(chan, buf), buf);
2530 chan->num_conf_req++;
2531}
2532
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002533static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002534{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002535 int type, olen;
2536 unsigned long val;
2537 struct l2cap_conf_rfc rfc;
2538
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002539 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002540
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002541 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002542 return;
2543
2544 while (len >= L2CAP_CONF_OPT_SIZE) {
2545 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2546
2547 switch (type) {
2548 case L2CAP_CONF_RFC:
2549 if (olen == sizeof(rfc))
2550 memcpy(&rfc, (void *)val, olen);
2551 goto done;
2552 }
2553 }
2554
Mat Martineau36e999a2011-12-08 17:23:21 -08002555 /* Use sane default values in case a misbehaving remote device
2556 * did not send an RFC option.
2557 */
2558 rfc.mode = chan->mode;
2559 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2560 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2561 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2562
2563 BT_ERR("Expected RFC option was not found, using defaults");
2564
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002565done:
2566 switch (rfc.mode) {
2567 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002568 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2569 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2570 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002571 break;
2572 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002573 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002574 }
2575}
2576
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002577static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2578{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002579 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002580
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002581 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002582 return 0;
2583
2584 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2585 cmd->ident == conn->info_ident) {
Ulisses Furquim371fd832011-12-21 20:02:36 -02002586 __cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002587
2588 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002589 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002590
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002591 l2cap_conn_start(conn);
2592 }
2593
2594 return 0;
2595}
2596
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2598{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2600 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002601 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002602 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002603 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002604
2605 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002606 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002607
2608 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2609
2610 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002611 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2612 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613 result = L2CAP_CR_BAD_PSM;
2614 goto sendresp;
2615 }
2616
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002617 parent = pchan->sk;
2618
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002619 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002620
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002621 /* Check if the ACL is secure enough (if not SDP) */
2622 if (psm != cpu_to_le16(0x0001) &&
2623 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002624 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002625 result = L2CAP_CR_SEC_BLOCK;
2626 goto response;
2627 }
2628
Linus Torvalds1da177e2005-04-16 15:20:36 -07002629 result = L2CAP_CR_NO_MEM;
2630
2631 /* Check for backlog size */
2632 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002633 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002634 goto response;
2635 }
2636
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002637 chan = pchan->ops->new_connection(pchan->data);
2638 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002639 goto response;
2640
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002641 sk = chan->sk;
2642
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002644 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002645 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002646 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002647 goto response;
2648 }
2649
2650 hci_conn_hold(conn->hcon);
2651
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 bacpy(&bt_sk(sk)->src, conn->src);
2653 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002654 chan->psm = psm;
2655 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002656
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002657 bt_accept_enqueue(parent, sk);
2658
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02002659 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002660
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002661 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002663 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002664
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002665 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002666
Marcel Holtmann984947d2009-02-06 23:35:19 +01002667 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002668 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002669 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002670 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002671 result = L2CAP_CR_PEND;
2672 status = L2CAP_CS_AUTHOR_PEND;
2673 parent->sk_data_ready(parent, 0);
2674 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002675 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002676 result = L2CAP_CR_SUCCESS;
2677 status = L2CAP_CS_NO_INFO;
2678 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002679 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002680 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002681 result = L2CAP_CR_PEND;
2682 status = L2CAP_CS_AUTHEN_PEND;
2683 }
2684 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002685 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002686 result = L2CAP_CR_PEND;
2687 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002688 }
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002691 release_sock(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002692
2693sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002694 rsp.scid = cpu_to_le16(scid);
2695 rsp.dcid = cpu_to_le16(dcid);
2696 rsp.result = cpu_to_le16(result);
2697 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002698 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002699
2700 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2701 struct l2cap_info_req info;
2702 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2703
2704 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2705 conn->info_ident = l2cap_get_ident(conn);
2706
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002707 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002708 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2709
2710 l2cap_send_cmd(conn, conn->info_ident,
2711 L2CAP_INFO_REQ, sizeof(info), &info);
2712 }
2713
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002714 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002715 result == L2CAP_CR_SUCCESS) {
2716 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002717 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002718 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002719 l2cap_build_conf_req(chan, buf), buf);
2720 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002721 }
2722
Linus Torvalds1da177e2005-04-16 15:20:36 -07002723 return 0;
2724}
2725
2726static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2727{
2728 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2729 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002730 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002731 struct sock *sk;
2732 u8 req[128];
2733
2734 scid = __le16_to_cpu(rsp->scid);
2735 dcid = __le16_to_cpu(rsp->dcid);
2736 result = __le16_to_cpu(rsp->result);
2737 status = __le16_to_cpu(rsp->status);
2738
2739 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2740
2741 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002742 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002743 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002744 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002746 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002747 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002748 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 }
2750
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002751 sk = chan->sk;
2752
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 switch (result) {
2754 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002755 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002756 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002757 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002758 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002759
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002760 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002761 break;
2762
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002764 l2cap_build_conf_req(chan, req), req);
2765 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 break;
2767
2768 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002769 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002770 break;
2771
2772 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002773 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002774 break;
2775 }
2776
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002777 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002778 return 0;
2779}
2780
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002781static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002782{
2783 /* FCS is enabled only in ERTM or streaming mode, if one or both
2784 * sides request it.
2785 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002786 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002787 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002788 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002789 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002790}
2791
Al Viro88219a02007-07-29 00:17:25 -07002792static 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 -07002793{
2794 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2795 u16 dcid, flags;
2796 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002797 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002798 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002799 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002800
2801 dcid = __le16_to_cpu(req->dcid);
2802 flags = __le16_to_cpu(req->flags);
2803
2804 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2805
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002806 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002807 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002808 return -ENOENT;
2809
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002810 sk = chan->sk;
2811
David S. Miller033b1142011-07-21 13:38:42 -07002812 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002813 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002814
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002815 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2816 rej.scid = cpu_to_le16(chan->scid);
2817 rej.dcid = cpu_to_le16(chan->dcid);
2818
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002819 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2820 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002821 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002822 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002823
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002824 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002825 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002826 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002827 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002828 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002829 L2CAP_CONF_REJECT, flags), rsp);
2830 goto unlock;
2831 }
2832
2833 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002834 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2835 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836
2837 if (flags & 0x0001) {
2838 /* Incomplete config. Send empty response. */
2839 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002840 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002841 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002842 goto unlock;
2843 }
2844
2845 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002846 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002847 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002848 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002850 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002851
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002852 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002853 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002854
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002855 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002856 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002857
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002858 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002859 goto unlock;
2860
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002861 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002862 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002863
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002864 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002865
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002866 chan->next_tx_seq = 0;
2867 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002868 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002869 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002870 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002871
Linus Torvalds1da177e2005-04-16 15:20:36 -07002872 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002873 goto unlock;
2874 }
2875
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002876 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002877 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002879 l2cap_build_conf_req(chan, buf), buf);
2880 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002881 }
2882
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002883 /* Got Conf Rsp PENDING from remote side and asume we sent
2884 Conf Rsp PENDING in the code above */
2885 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2886 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2887
2888 /* check compatibility */
2889
2890 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2891 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2892
2893 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002894 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002895 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2896 }
2897
Linus Torvalds1da177e2005-04-16 15:20:36 -07002898unlock:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002899 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 return 0;
2901}
2902
2903static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2904{
2905 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2906 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002907 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002908 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002909 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910
2911 scid = __le16_to_cpu(rsp->scid);
2912 flags = __le16_to_cpu(rsp->flags);
2913 result = __le16_to_cpu(rsp->result);
2914
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002915 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2916 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002918 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002919 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002920 return 0;
2921
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002922 sk = chan->sk;
2923
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 switch (result) {
2925 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002926 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002927 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002928 break;
2929
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002930 case L2CAP_CONF_PENDING:
2931 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2932
2933 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2934 char buf[64];
2935
2936 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2937 buf, &result);
2938 if (len < 0) {
2939 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2940 goto done;
2941 }
2942
2943 /* check compatibility */
2944
2945 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2946 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2947
2948 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002949 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002950 L2CAP_CONF_SUCCESS, 0x0000), buf);
2951 }
2952 goto done;
2953
Linus Torvalds1da177e2005-04-16 15:20:36 -07002954 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002955 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002956 char req[64];
2957
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002958 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002959 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002960 goto done;
2961 }
2962
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002963 /* throw out any old stored conf requests */
2964 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002965 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2966 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002967 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002968 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002969 goto done;
2970 }
2971
2972 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2973 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002974 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002975 if (result != L2CAP_CONF_SUCCESS)
2976 goto done;
2977 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002978 }
2979
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002980 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002981 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01002982 __set_chan_timer(chan,
2983 msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002984 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985 goto done;
2986 }
2987
2988 if (flags & 0x01)
2989 goto done;
2990
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002991 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002992
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002993 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002994 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002995
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002996 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002997 chan->next_tx_seq = 0;
2998 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002999 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03003000 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003001 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003002
Linus Torvalds1da177e2005-04-16 15:20:36 -07003003 l2cap_chan_ready(sk);
3004 }
3005
3006done:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003007 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003008 return 0;
3009}
3010
3011static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3012{
3013 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3014 struct l2cap_disconn_rsp rsp;
3015 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003016 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003017 struct sock *sk;
3018
3019 scid = __le16_to_cpu(req->scid);
3020 dcid = __le16_to_cpu(req->dcid);
3021
3022 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3023
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003024 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003025 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003026 return 0;
3027
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003028 sk = chan->sk;
3029
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003030 rsp.dcid = cpu_to_le16(chan->scid);
3031 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003032 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3033
3034 sk->sk_shutdown = SHUTDOWN_MASK;
3035
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003036 l2cap_chan_del(chan, ECONNRESET);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003037 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003038
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003039 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003040 return 0;
3041}
3042
3043static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3044{
3045 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3046 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003047 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003048 struct sock *sk;
3049
3050 scid = __le16_to_cpu(rsp->scid);
3051 dcid = __le16_to_cpu(rsp->dcid);
3052
3053 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3054
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003055 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003056 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003057 return 0;
3058
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003059 sk = chan->sk;
3060
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003061 l2cap_chan_del(chan, 0);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003062 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003063
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003064 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003065 return 0;
3066}
3067
3068static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3069{
3070 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003071 u16 type;
3072
3073 type = __le16_to_cpu(req->type);
3074
3075 BT_DBG("type 0x%4.4x", type);
3076
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003077 if (type == L2CAP_IT_FEAT_MASK) {
3078 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003079 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003080 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3081 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3082 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003083 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003084 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3085 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003086 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003087 feat_mask |= L2CAP_FEAT_EXT_FLOW
3088 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003089
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003090 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003091 l2cap_send_cmd(conn, cmd->ident,
3092 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003093 } else if (type == L2CAP_IT_FIXED_CHAN) {
3094 u8 buf[12];
3095 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003096
3097 if (enable_hs)
3098 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3099 else
3100 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3101
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003102 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3103 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003104 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003105 l2cap_send_cmd(conn, cmd->ident,
3106 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003107 } else {
3108 struct l2cap_info_rsp rsp;
3109 rsp.type = cpu_to_le16(type);
3110 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3111 l2cap_send_cmd(conn, cmd->ident,
3112 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003114
3115 return 0;
3116}
3117
3118static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3119{
3120 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3121 u16 type, result;
3122
3123 type = __le16_to_cpu(rsp->type);
3124 result = __le16_to_cpu(rsp->result);
3125
3126 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3127
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003128 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3129 if (cmd->ident != conn->info_ident ||
3130 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3131 return 0;
3132
Ulisses Furquim371fd832011-12-21 20:02:36 -02003133 __cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003134
Ville Tervoadb08ed2010-08-04 09:43:33 +03003135 if (result != L2CAP_IR_SUCCESS) {
3136 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3137 conn->info_ident = 0;
3138
3139 l2cap_conn_start(conn);
3140
3141 return 0;
3142 }
3143
Marcel Holtmann984947d2009-02-06 23:35:19 +01003144 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003145 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003146
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003147 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003148 struct l2cap_info_req req;
3149 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3150
3151 conn->info_ident = l2cap_get_ident(conn);
3152
3153 l2cap_send_cmd(conn, conn->info_ident,
3154 L2CAP_INFO_REQ, sizeof(req), &req);
3155 } else {
3156 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3157 conn->info_ident = 0;
3158
3159 l2cap_conn_start(conn);
3160 }
3161 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003162 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003163 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003164
3165 l2cap_conn_start(conn);
3166 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003167
Linus Torvalds1da177e2005-04-16 15:20:36 -07003168 return 0;
3169}
3170
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003171static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3172 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3173 void *data)
3174{
3175 struct l2cap_create_chan_req *req = data;
3176 struct l2cap_create_chan_rsp rsp;
3177 u16 psm, scid;
3178
3179 if (cmd_len != sizeof(*req))
3180 return -EPROTO;
3181
3182 if (!enable_hs)
3183 return -EINVAL;
3184
3185 psm = le16_to_cpu(req->psm);
3186 scid = le16_to_cpu(req->scid);
3187
3188 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3189
3190 /* Placeholder: Always reject */
3191 rsp.dcid = 0;
3192 rsp.scid = cpu_to_le16(scid);
3193 rsp.result = L2CAP_CR_NO_MEM;
3194 rsp.status = L2CAP_CS_NO_INFO;
3195
3196 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3197 sizeof(rsp), &rsp);
3198
3199 return 0;
3200}
3201
3202static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3203 struct l2cap_cmd_hdr *cmd, void *data)
3204{
3205 BT_DBG("conn %p", conn);
3206
3207 return l2cap_connect_rsp(conn, cmd, data);
3208}
3209
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003210static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3211 u16 icid, u16 result)
3212{
3213 struct l2cap_move_chan_rsp rsp;
3214
3215 BT_DBG("icid %d, result %d", icid, result);
3216
3217 rsp.icid = cpu_to_le16(icid);
3218 rsp.result = cpu_to_le16(result);
3219
3220 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3221}
3222
3223static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3224 struct l2cap_chan *chan, u16 icid, u16 result)
3225{
3226 struct l2cap_move_chan_cfm cfm;
3227 u8 ident;
3228
3229 BT_DBG("icid %d, result %d", icid, result);
3230
3231 ident = l2cap_get_ident(conn);
3232 if (chan)
3233 chan->ident = ident;
3234
3235 cfm.icid = cpu_to_le16(icid);
3236 cfm.result = cpu_to_le16(result);
3237
3238 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3239}
3240
3241static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3242 u16 icid)
3243{
3244 struct l2cap_move_chan_cfm_rsp rsp;
3245
3246 BT_DBG("icid %d", icid);
3247
3248 rsp.icid = cpu_to_le16(icid);
3249 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3250}
3251
3252static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3253 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3254{
3255 struct l2cap_move_chan_req *req = data;
3256 u16 icid = 0;
3257 u16 result = L2CAP_MR_NOT_ALLOWED;
3258
3259 if (cmd_len != sizeof(*req))
3260 return -EPROTO;
3261
3262 icid = le16_to_cpu(req->icid);
3263
3264 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3265
3266 if (!enable_hs)
3267 return -EINVAL;
3268
3269 /* Placeholder: Always refuse */
3270 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3271
3272 return 0;
3273}
3274
3275static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3276 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3277{
3278 struct l2cap_move_chan_rsp *rsp = data;
3279 u16 icid, result;
3280
3281 if (cmd_len != sizeof(*rsp))
3282 return -EPROTO;
3283
3284 icid = le16_to_cpu(rsp->icid);
3285 result = le16_to_cpu(rsp->result);
3286
3287 BT_DBG("icid %d, result %d", icid, result);
3288
3289 /* Placeholder: Always unconfirmed */
3290 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3291
3292 return 0;
3293}
3294
3295static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3296 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3297{
3298 struct l2cap_move_chan_cfm *cfm = data;
3299 u16 icid, result;
3300
3301 if (cmd_len != sizeof(*cfm))
3302 return -EPROTO;
3303
3304 icid = le16_to_cpu(cfm->icid);
3305 result = le16_to_cpu(cfm->result);
3306
3307 BT_DBG("icid %d, result %d", icid, result);
3308
3309 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3310
3311 return 0;
3312}
3313
3314static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3315 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3316{
3317 struct l2cap_move_chan_cfm_rsp *rsp = data;
3318 u16 icid;
3319
3320 if (cmd_len != sizeof(*rsp))
3321 return -EPROTO;
3322
3323 icid = le16_to_cpu(rsp->icid);
3324
3325 BT_DBG("icid %d", icid);
3326
3327 return 0;
3328}
3329
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003330static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003331 u16 to_multiplier)
3332{
3333 u16 max_latency;
3334
3335 if (min > max || min < 6 || max > 3200)
3336 return -EINVAL;
3337
3338 if (to_multiplier < 10 || to_multiplier > 3200)
3339 return -EINVAL;
3340
3341 if (max >= to_multiplier * 8)
3342 return -EINVAL;
3343
3344 max_latency = (to_multiplier * 8 / max) - 1;
3345 if (latency > 499 || latency > max_latency)
3346 return -EINVAL;
3347
3348 return 0;
3349}
3350
3351static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3352 struct l2cap_cmd_hdr *cmd, u8 *data)
3353{
3354 struct hci_conn *hcon = conn->hcon;
3355 struct l2cap_conn_param_update_req *req;
3356 struct l2cap_conn_param_update_rsp rsp;
3357 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003358 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003359
3360 if (!(hcon->link_mode & HCI_LM_MASTER))
3361 return -EINVAL;
3362
3363 cmd_len = __le16_to_cpu(cmd->len);
3364 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3365 return -EPROTO;
3366
3367 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003368 min = __le16_to_cpu(req->min);
3369 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003370 latency = __le16_to_cpu(req->latency);
3371 to_multiplier = __le16_to_cpu(req->to_multiplier);
3372
3373 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3374 min, max, latency, to_multiplier);
3375
3376 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003377
3378 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3379 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003380 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3381 else
3382 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3383
3384 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3385 sizeof(rsp), &rsp);
3386
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003387 if (!err)
3388 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3389
Claudio Takahaside731152011-02-11 19:28:55 -02003390 return 0;
3391}
3392
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003393static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3394 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3395{
3396 int err = 0;
3397
3398 switch (cmd->code) {
3399 case L2CAP_COMMAND_REJ:
3400 l2cap_command_rej(conn, cmd, data);
3401 break;
3402
3403 case L2CAP_CONN_REQ:
3404 err = l2cap_connect_req(conn, cmd, data);
3405 break;
3406
3407 case L2CAP_CONN_RSP:
3408 err = l2cap_connect_rsp(conn, cmd, data);
3409 break;
3410
3411 case L2CAP_CONF_REQ:
3412 err = l2cap_config_req(conn, cmd, cmd_len, data);
3413 break;
3414
3415 case L2CAP_CONF_RSP:
3416 err = l2cap_config_rsp(conn, cmd, data);
3417 break;
3418
3419 case L2CAP_DISCONN_REQ:
3420 err = l2cap_disconnect_req(conn, cmd, data);
3421 break;
3422
3423 case L2CAP_DISCONN_RSP:
3424 err = l2cap_disconnect_rsp(conn, cmd, data);
3425 break;
3426
3427 case L2CAP_ECHO_REQ:
3428 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3429 break;
3430
3431 case L2CAP_ECHO_RSP:
3432 break;
3433
3434 case L2CAP_INFO_REQ:
3435 err = l2cap_information_req(conn, cmd, data);
3436 break;
3437
3438 case L2CAP_INFO_RSP:
3439 err = l2cap_information_rsp(conn, cmd, data);
3440 break;
3441
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003442 case L2CAP_CREATE_CHAN_REQ:
3443 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3444 break;
3445
3446 case L2CAP_CREATE_CHAN_RSP:
3447 err = l2cap_create_channel_rsp(conn, cmd, data);
3448 break;
3449
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003450 case L2CAP_MOVE_CHAN_REQ:
3451 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3452 break;
3453
3454 case L2CAP_MOVE_CHAN_RSP:
3455 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3456 break;
3457
3458 case L2CAP_MOVE_CHAN_CFM:
3459 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3460 break;
3461
3462 case L2CAP_MOVE_CHAN_CFM_RSP:
3463 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3464 break;
3465
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003466 default:
3467 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3468 err = -EINVAL;
3469 break;
3470 }
3471
3472 return err;
3473}
3474
3475static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3476 struct l2cap_cmd_hdr *cmd, u8 *data)
3477{
3478 switch (cmd->code) {
3479 case L2CAP_COMMAND_REJ:
3480 return 0;
3481
3482 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003483 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003484
3485 case L2CAP_CONN_PARAM_UPDATE_RSP:
3486 return 0;
3487
3488 default:
3489 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3490 return -EINVAL;
3491 }
3492}
3493
3494static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3495 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003496{
3497 u8 *data = skb->data;
3498 int len = skb->len;
3499 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003500 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003501
3502 l2cap_raw_recv(conn, skb);
3503
3504 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003505 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003506 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3507 data += L2CAP_CMD_HDR_SIZE;
3508 len -= L2CAP_CMD_HDR_SIZE;
3509
Al Viro88219a02007-07-29 00:17:25 -07003510 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003511
Al Viro88219a02007-07-29 00:17:25 -07003512 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 -07003513
Al Viro88219a02007-07-29 00:17:25 -07003514 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003515 BT_DBG("corrupted command");
3516 break;
3517 }
3518
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003519 if (conn->hcon->type == LE_LINK)
3520 err = l2cap_le_sig_cmd(conn, &cmd, data);
3521 else
3522 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003523
3524 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003525 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003526
3527 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003528
3529 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003530 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003531 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3532 }
3533
Al Viro88219a02007-07-29 00:17:25 -07003534 data += cmd_len;
3535 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003536 }
3537
3538 kfree_skb(skb);
3539}
3540
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003541static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003542{
3543 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003544 int hdr_size;
3545
3546 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3547 hdr_size = L2CAP_EXT_HDR_SIZE;
3548 else
3549 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003550
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003551 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003552 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003553 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3554 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3555
3556 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003557 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003558 }
3559 return 0;
3560}
3561
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003562static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003563{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003564 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003565
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003566 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003567
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003568 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003569
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003570 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003571 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003572 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003573 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003574 }
3575
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003576 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003577 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003578
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003579 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003580
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003581 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003582 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003583 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003584 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003585 }
3586}
3587
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003588static 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 -03003589{
3590 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003591 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003592
3593 bt_cb(skb)->tx_seq = tx_seq;
3594 bt_cb(skb)->sar = sar;
3595
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003596 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003597
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003598 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003599
Szymon Janc039d9572011-11-16 09:32:19 +01003600 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003601 if (bt_cb(next_skb)->tx_seq == tx_seq)
3602 return -EINVAL;
3603
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003604 next_tx_seq_offset = __seq_offset(chan,
3605 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003606
3607 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003608 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003609 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003610 }
3611
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003612 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003613 next_skb = NULL;
3614 else
3615 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3616 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003617
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003618 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003619
3620 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003621}
3622
Mat Martineau84084a32011-07-22 14:54:00 -07003623static void append_skb_frag(struct sk_buff *skb,
3624 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003625{
Mat Martineau84084a32011-07-22 14:54:00 -07003626 /* skb->len reflects data in skb as well as all fragments
3627 * skb->data_len reflects only data in fragments
3628 */
3629 if (!skb_has_frag_list(skb))
3630 skb_shinfo(skb)->frag_list = new_frag;
3631
3632 new_frag->next = NULL;
3633
3634 (*last_frag)->next = new_frag;
3635 *last_frag = new_frag;
3636
3637 skb->len += new_frag->len;
3638 skb->data_len += new_frag->len;
3639 skb->truesize += new_frag->truesize;
3640}
3641
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003642static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003643{
3644 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003645
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003646 switch (__get_ctrl_sar(chan, control)) {
3647 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003648 if (chan->sdu)
3649 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003650
Mat Martineau84084a32011-07-22 14:54:00 -07003651 err = chan->ops->recv(chan->data, skb);
3652 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003653
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003654 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003655 if (chan->sdu)
3656 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003657
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003658 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003659 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003660
Mat Martineau84084a32011-07-22 14:54:00 -07003661 if (chan->sdu_len > chan->imtu) {
3662 err = -EMSGSIZE;
3663 break;
3664 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003665
Mat Martineau84084a32011-07-22 14:54:00 -07003666 if (skb->len >= chan->sdu_len)
3667 break;
3668
3669 chan->sdu = skb;
3670 chan->sdu_last_frag = skb;
3671
3672 skb = NULL;
3673 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003674 break;
3675
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003676 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003677 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003678 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003679
Mat Martineau84084a32011-07-22 14:54:00 -07003680 append_skb_frag(chan->sdu, skb,
3681 &chan->sdu_last_frag);
3682 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003683
Mat Martineau84084a32011-07-22 14:54:00 -07003684 if (chan->sdu->len >= chan->sdu_len)
3685 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003686
Mat Martineau84084a32011-07-22 14:54:00 -07003687 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003688 break;
3689
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003690 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003691 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003692 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003693
Mat Martineau84084a32011-07-22 14:54:00 -07003694 append_skb_frag(chan->sdu, skb,
3695 &chan->sdu_last_frag);
3696 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003697
Mat Martineau84084a32011-07-22 14:54:00 -07003698 if (chan->sdu->len != chan->sdu_len)
3699 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003700
Mat Martineau84084a32011-07-22 14:54:00 -07003701 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003702
Mat Martineau84084a32011-07-22 14:54:00 -07003703 if (!err) {
3704 /* Reassembly complete */
3705 chan->sdu = NULL;
3706 chan->sdu_last_frag = NULL;
3707 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003708 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003709 break;
3710 }
3711
Mat Martineau84084a32011-07-22 14:54:00 -07003712 if (err) {
3713 kfree_skb(skb);
3714 kfree_skb(chan->sdu);
3715 chan->sdu = NULL;
3716 chan->sdu_last_frag = NULL;
3717 chan->sdu_len = 0;
3718 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003719
Mat Martineau84084a32011-07-22 14:54:00 -07003720 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003721}
3722
Mat Martineau26f880d2011-07-07 09:39:01 -07003723static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003724{
Mat Martineau26f880d2011-07-07 09:39:01 -07003725 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003726
Mat Martineau26f880d2011-07-07 09:39:01 -07003727 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3728
Szymon Janc77f918b2012-01-11 10:59:48 +01003729 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003730}
3731
3732static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3733{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003734 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003735
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003736 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003737 goto done;
3738
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003739 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003740 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003741 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003742 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003743 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003744
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003745 __clear_retrans_timer(chan);
3746 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003747
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003748 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003749
3750done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003751 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3752 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003753
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003754 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003755}
3756
Mat Martineaue3281402011-07-07 09:39:02 -07003757void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003758{
Mat Martineaue3281402011-07-07 09:39:02 -07003759 if (chan->mode == L2CAP_MODE_ERTM) {
3760 if (busy)
3761 l2cap_ertm_enter_local_busy(chan);
3762 else
3763 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003764 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003765}
3766
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003767static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003768{
3769 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003770 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003771
Mat Martineaue3281402011-07-07 09:39:02 -07003772 while ((skb = skb_peek(&chan->srej_q)) &&
3773 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3774 int err;
3775
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003776 if (bt_cb(skb)->tx_seq != tx_seq)
3777 break;
3778
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003779 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003780 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003781 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003782
3783 if (err < 0) {
3784 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3785 break;
3786 }
3787
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003788 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3789 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003790 }
3791}
3792
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003793static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003794{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003795 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003796 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003797
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003798 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003799 if (l->tx_seq == tx_seq) {
3800 list_del(&l->list);
3801 kfree(l);
3802 return;
3803 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003804 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003805 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003806 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003807 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003808 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003809 }
3810}
3811
Szymon Jancaef89f22011-11-16 09:32:18 +01003812static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003813{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003814 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003815 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003816
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003817 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003818 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003819 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003820 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003821
3822 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003823 if (!new)
3824 return -ENOMEM;
3825
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003826 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003827
3828 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3829
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003830 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003831 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003832
3833 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003834
3835 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003836}
3837
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003838static 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 -03003839{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003840 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003841 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003842 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003843 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003844 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003845 int err = 0;
3846
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003847 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 -03003848 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003849
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003850 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003851 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003852 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003853 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003854 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003855 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003856 }
3857
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003858 chan->expected_ack_seq = req_seq;
3859 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003860
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003861 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003862
3863 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003864 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003865 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003866 goto drop;
3867 }
3868
Szymon Janc77f918b2012-01-11 10:59:48 +01003869 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3870 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3871 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003872 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003873 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003874
Mat Martineau02f1b642011-06-29 14:35:19 -07003875 if (tx_seq == chan->expected_tx_seq)
3876 goto expected;
3877
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003878 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003879 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003880
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003881 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003882 struct srej_list, list);
3883 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003884 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003885 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003886
3887 list_del(&first->list);
3888 kfree(first);
3889
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003890 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003891 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003892 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003893 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003894 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003895 }
3896 } else {
3897 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003898
3899 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003900 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003901 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003902
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003903 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003904 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003905 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003906 return 0;
3907 }
3908 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003909
3910 err = l2cap_send_srejframe(chan, tx_seq);
3911 if (err < 0) {
3912 l2cap_send_disconn_req(chan->conn, chan, -err);
3913 return err;
3914 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003915 }
3916 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003917 expected_tx_seq_offset = __seq_offset(chan,
3918 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003919
3920 /* duplicated tx_seq */
3921 if (tx_seq_offset < expected_tx_seq_offset)
3922 goto drop;
3923
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003924 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003925
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003926 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003927
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003928 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003929 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003930
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003931 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003932 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003933
Szymon Janc0ef3ef02012-01-11 10:59:46 +01003934 /* Set P-bit only if there are some I-frames to ack. */
3935 if (__clear_ack_timer(chan))
3936 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003937
Szymon Jancaef89f22011-11-16 09:32:18 +01003938 err = l2cap_send_srejframe(chan, tx_seq);
3939 if (err < 0) {
3940 l2cap_send_disconn_req(chan->conn, chan, -err);
3941 return err;
3942 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003943 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003944 return 0;
3945
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003946expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003947 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003948
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003949 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003950 bt_cb(skb)->tx_seq = tx_seq;
3951 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003952 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003953 return 0;
3954 }
3955
Mat Martineau84084a32011-07-22 14:54:00 -07003956 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003957 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3958
Mat Martineaue3281402011-07-07 09:39:02 -07003959 if (err < 0) {
3960 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3961 return err;
3962 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003963
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003964 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003965 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003966 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003967 }
3968
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003969
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003970 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3971 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003972 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003973 else
3974 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003975
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003976 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003977
3978drop:
3979 kfree_skb(skb);
3980 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003981}
3982
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003983static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003984{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003985 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003986 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003987
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003988 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003989 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003990
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003991 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003992 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3993 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3994 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003995 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003996 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003997
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003998 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003999 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004000 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004001 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004002 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004003
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004004 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004005 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004006
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004007 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004008 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004009
4010 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004011 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004012 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004013 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004014
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004015 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4016 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004017 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004018 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004019 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004020 }
4021}
4022
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004023static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004024{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004025 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004026
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004027 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004028
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004029 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004030
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004031 chan->expected_ack_seq = tx_seq;
4032 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004033
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004034 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004035 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004036 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004037 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004038 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004039
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004040 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4041 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004042 }
4043}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004044static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004045{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004046 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004047
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004048 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004049
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004050 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004051
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004052 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004053 chan->expected_ack_seq = tx_seq;
4054 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004055
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004056 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004057 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004058
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004059 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004060
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004061 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004062 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004063 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004064 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004065 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004066 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004067 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004068 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004069 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004070 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004071 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004072 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004073 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004074 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004075 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004076 }
4077 }
4078}
4079
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004080static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004081{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004082 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004083
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004084 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004085
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004086 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004087 chan->expected_ack_seq = tx_seq;
4088 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004089
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004090 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004091 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004092
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004093 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004094 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004095 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004096 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004097 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004098 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004099
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004100 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004101 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004102 } else {
4103 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4104 l2cap_send_sframe(chan, rx_control);
4105 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004106}
4107
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004108static 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 -03004109{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004110 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004111
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004112 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004113 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004114 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004115 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004116 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004117 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004118 }
4119
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004120 switch (__get_ctrl_super(chan, rx_control)) {
4121 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004122 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004123 break;
4124
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004125 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004126 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004127 break;
4128
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004129 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004130 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004131 break;
4132
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004133 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004134 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004135 break;
4136 }
4137
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004138 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004139 return 0;
4140}
4141
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004142int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004143{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004144 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004145 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004146 int len, next_tx_seq_offset, req_seq_offset;
4147
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004148 control = __get_control(chan, skb->data);
4149 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004150 len = skb->len;
4151
4152 /*
4153 * We can just drop the corrupted I-frame here.
4154 * Receiver will miss it and start proper recovery
4155 * procedures and ask retransmission.
4156 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004157 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004158 goto drop;
4159
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004160 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004161 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004162
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004163 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004164 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004165
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004166 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004167 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004168 goto drop;
4169 }
4170
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004171 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004172
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004173 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4174
4175 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4176 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004177
4178 /* check for invalid req-seq */
4179 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004180 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004181 goto drop;
4182 }
4183
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004184 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004185 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004186 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004187 goto drop;
4188 }
4189
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004190 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004191 } else {
4192 if (len != 0) {
4193 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004194 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004195 goto drop;
4196 }
4197
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004198 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004199 }
4200
4201 return 0;
4202
4203drop:
4204 kfree_skb(skb);
4205 return 0;
4206}
4207
Linus Torvalds1da177e2005-04-16 15:20:36 -07004208static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4209{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004210 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004211 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004212 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004213 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004214 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004215
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004216 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004217 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004218 BT_DBG("unknown cid 0x%4.4x", cid);
4219 goto drop;
4220 }
4221
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004222 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004223
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004224 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004225
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004226 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004227 goto drop;
4228
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004229 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004230 case L2CAP_MODE_BASIC:
4231 /* If socket recv buffers overflows we drop data here
4232 * which is *bad* because L2CAP has to be reliable.
4233 * But we don't have any other choice. L2CAP doesn't
4234 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004235
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004236 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004237 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004238
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004239 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004240 goto done;
4241 break;
4242
4243 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004244 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004245
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004246 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004247
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004248 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004249 control = __get_control(chan, skb->data);
4250 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004251 len = skb->len;
4252
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004253 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004254 goto drop;
4255
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004256 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004257 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004258
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004259 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004260 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004261
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004262 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004263 goto drop;
4264
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004265 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004266
Mat Martineau84084a32011-07-22 14:54:00 -07004267 if (chan->expected_tx_seq != tx_seq) {
4268 /* Frame(s) missing - must discard partial SDU */
4269 kfree_skb(chan->sdu);
4270 chan->sdu = NULL;
4271 chan->sdu_last_frag = NULL;
4272 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004273
Mat Martineau84084a32011-07-22 14:54:00 -07004274 /* TODO: Notify userland of missing data */
4275 }
4276
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004277 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004278
4279 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4280 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004281
4282 goto done;
4283
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004284 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004285 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004286 break;
4287 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288
4289drop:
4290 kfree_skb(skb);
4291
4292done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004293 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004294 release_sock(sk);
Marcel Holtmann01394182006-07-03 10:02:46 +02004295
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296 return 0;
4297}
4298
Al Viro8e036fc2007-07-29 00:16:36 -07004299static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004300{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004301 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004302 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004304 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4305 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004306 goto drop;
4307
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004308 sk = chan->sk;
4309
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004310 lock_sock(sk);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004311
Linus Torvalds1da177e2005-04-16 15:20:36 -07004312 BT_DBG("sk %p, len %d", sk, skb->len);
4313
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004314 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004315 goto drop;
4316
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004317 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004318 goto drop;
4319
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004320 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004321 goto done;
4322
4323drop:
4324 kfree_skb(skb);
4325
4326done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004327 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004328 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004329 return 0;
4330}
4331
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004332static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4333{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004334 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004335 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004336
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004337 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4338 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004339 goto drop;
4340
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004341 sk = chan->sk;
4342
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004343 lock_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004344
4345 BT_DBG("sk %p, len %d", sk, skb->len);
4346
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004347 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004348 goto drop;
4349
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004350 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004351 goto drop;
4352
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004353 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004354 goto done;
4355
4356drop:
4357 kfree_skb(skb);
4358
4359done:
4360 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004361 release_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004362 return 0;
4363}
4364
Linus Torvalds1da177e2005-04-16 15:20:36 -07004365static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4366{
4367 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004368 u16 cid, len;
4369 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004370
4371 skb_pull(skb, L2CAP_HDR_SIZE);
4372 cid = __le16_to_cpu(lh->cid);
4373 len = __le16_to_cpu(lh->len);
4374
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004375 if (len != skb->len) {
4376 kfree_skb(skb);
4377 return;
4378 }
4379
Linus Torvalds1da177e2005-04-16 15:20:36 -07004380 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4381
4382 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004383 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004384 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004385 l2cap_sig_channel(conn, skb);
4386 break;
4387
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004388 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004389 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004390 skb_pull(skb, 2);
4391 l2cap_conless_channel(conn, psm, skb);
4392 break;
4393
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004394 case L2CAP_CID_LE_DATA:
4395 l2cap_att_channel(conn, cid, skb);
4396 break;
4397
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004398 case L2CAP_CID_SMP:
4399 if (smp_sig_channel(conn, skb))
4400 l2cap_conn_del(conn->hcon, EACCES);
4401 break;
4402
Linus Torvalds1da177e2005-04-16 15:20:36 -07004403 default:
4404 l2cap_data_channel(conn, cid, skb);
4405 break;
4406 }
4407}
4408
4409/* ---- L2CAP interface with lower layer (HCI) ---- */
4410
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004411int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412{
4413 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004414 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
Linus Torvalds1da177e2005-04-16 15:20:36 -07004416 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4417
4418 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004419 read_lock(&chan_list_lock);
4420 list_for_each_entry(c, &chan_list, global_l) {
4421 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004422
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004423 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004424 continue;
4425
4426 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004427 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004428 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004429 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004430 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004431 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4432 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004433 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004434 lm2 |= HCI_LM_MASTER;
4435 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004436 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004437 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004438
4439 return exact ? lm1 : lm2;
4440}
4441
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004442int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004443{
Marcel Holtmann01394182006-07-03 10:02:46 +02004444 struct l2cap_conn *conn;
4445
Linus Torvalds1da177e2005-04-16 15:20:36 -07004446 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4447
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004449 conn = l2cap_conn_add(hcon, status);
4450 if (conn)
4451 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004452 } else
Joe Perchese1750722011-06-29 18:18:29 -07004453 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004454
4455 return 0;
4456}
4457
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004458int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004459{
4460 struct l2cap_conn *conn = hcon->l2cap_data;
4461
4462 BT_DBG("hcon %p", hcon);
4463
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004464 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004465 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004466 return conn->disc_reason;
4467}
4468
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004469int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004470{
4471 BT_DBG("hcon %p reason %d", hcon, reason);
4472
Joe Perchese1750722011-06-29 18:18:29 -07004473 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004474 return 0;
4475}
4476
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004477static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004478{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004479 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004480 return;
4481
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004482 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004483 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004484 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004485 __set_chan_timer(chan,
4486 msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004487 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004488 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004489 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004490 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004491 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004492 }
4493}
4494
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004495int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004496{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004497 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004498 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499
Marcel Holtmann01394182006-07-03 10:02:46 +02004500 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004501 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004502
Linus Torvalds1da177e2005-04-16 15:20:36 -07004503 BT_DBG("conn %p", conn);
4504
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004505 if (hcon->type == LE_LINK) {
4506 smp_distribute_keys(conn, 0);
Ulisses Furquim371fd832011-12-21 20:02:36 -02004507 __cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004508 }
4509
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004510 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004511
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004512 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004513 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004514
Linus Torvalds1da177e2005-04-16 15:20:36 -07004515 bh_lock_sock(sk);
4516
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004517 BT_DBG("chan->scid %d", chan->scid);
4518
4519 if (chan->scid == L2CAP_CID_LE_DATA) {
4520 if (!status && encrypt) {
4521 chan->sec_level = hcon->sec_level;
4522 l2cap_chan_ready(sk);
4523 }
4524
4525 bh_unlock_sock(sk);
4526 continue;
4527 }
4528
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004529 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004530 bh_unlock_sock(sk);
4531 continue;
4532 }
4533
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004534 if (!status && (chan->state == BT_CONNECTED ||
4535 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004536 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004537 bh_unlock_sock(sk);
4538 continue;
4539 }
4540
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004541 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004542 if (!status) {
4543 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004544 req.scid = cpu_to_le16(chan->scid);
4545 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004546
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004547 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004548 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004549
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004550 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004551 L2CAP_CONN_REQ, sizeof(req), &req);
4552 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004553 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004554 __set_chan_timer(chan,
4555 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004556 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004557 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004558 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004559 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004560
4561 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004562 if (bt_sk(sk)->defer_setup) {
4563 struct sock *parent = bt_sk(sk)->parent;
4564 res = L2CAP_CR_PEND;
4565 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004566 if (parent)
4567 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004568 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004569 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004570 res = L2CAP_CR_SUCCESS;
4571 stat = L2CAP_CS_NO_INFO;
4572 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004573 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004574 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004575 __set_chan_timer(chan,
4576 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004577 res = L2CAP_CR_SEC_BLOCK;
4578 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004579 }
4580
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004581 rsp.scid = cpu_to_le16(chan->dcid);
4582 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004583 rsp.result = cpu_to_le16(res);
4584 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004585 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4586 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 }
4588
Linus Torvalds1da177e2005-04-16 15:20:36 -07004589 bh_unlock_sock(sk);
4590 }
4591
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004592 rcu_read_unlock();
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004593
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 return 0;
4595}
4596
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004597int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004598{
4599 struct l2cap_conn *conn = hcon->l2cap_data;
4600
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004601 if (!conn)
4602 conn = l2cap_conn_add(hcon, 0);
4603
4604 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004605 goto drop;
4606
4607 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4608
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004609 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004610 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004611 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004612 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004613 int len;
4614
4615 if (conn->rx_len) {
4616 BT_ERR("Unexpected start frame (len %d)", skb->len);
4617 kfree_skb(conn->rx_skb);
4618 conn->rx_skb = NULL;
4619 conn->rx_len = 0;
4620 l2cap_conn_unreliable(conn, ECOMM);
4621 }
4622
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004623 /* Start fragment always begin with Basic L2CAP header */
4624 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625 BT_ERR("Frame is too short (len %d)", skb->len);
4626 l2cap_conn_unreliable(conn, ECOMM);
4627 goto drop;
4628 }
4629
4630 hdr = (struct l2cap_hdr *) skb->data;
4631 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004632 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004633
4634 if (len == skb->len) {
4635 /* Complete frame received */
4636 l2cap_recv_frame(conn, skb);
4637 return 0;
4638 }
4639
4640 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4641
4642 if (skb->len > len) {
4643 BT_ERR("Frame is too long (len %d, expected len %d)",
4644 skb->len, len);
4645 l2cap_conn_unreliable(conn, ECOMM);
4646 goto drop;
4647 }
4648
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004649 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004650
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004651 if (chan && chan->sk) {
4652 struct sock *sk = chan->sk;
4653
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004654 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004655 BT_ERR("Frame exceeding recv MTU (len %d, "
4656 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004657 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004658 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004659 l2cap_conn_unreliable(conn, ECOMM);
4660 goto drop;
4661 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004662 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004663 }
4664
Linus Torvalds1da177e2005-04-16 15:20:36 -07004665 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004666 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4667 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004668 goto drop;
4669
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004670 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004671 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004672 conn->rx_len = len - skb->len;
4673 } else {
4674 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4675
4676 if (!conn->rx_len) {
4677 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4678 l2cap_conn_unreliable(conn, ECOMM);
4679 goto drop;
4680 }
4681
4682 if (skb->len > conn->rx_len) {
4683 BT_ERR("Fragment is too long (len %d, expected %d)",
4684 skb->len, conn->rx_len);
4685 kfree_skb(conn->rx_skb);
4686 conn->rx_skb = NULL;
4687 conn->rx_len = 0;
4688 l2cap_conn_unreliable(conn, ECOMM);
4689 goto drop;
4690 }
4691
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004692 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004693 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694 conn->rx_len -= skb->len;
4695
4696 if (!conn->rx_len) {
4697 /* Complete frame received */
4698 l2cap_recv_frame(conn, conn->rx_skb);
4699 conn->rx_skb = NULL;
4700 }
4701 }
4702
4703drop:
4704 kfree_skb(skb);
4705 return 0;
4706}
4707
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004708static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004710 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004712 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004713
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004714 list_for_each_entry(c, &chan_list, global_l) {
4715 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004717 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 +01004718 batostr(&bt_sk(sk)->src),
4719 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004720 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004721 c->scid, c->dcid, c->imtu, c->omtu,
4722 c->sec_level, c->mode);
Andrei Emeltchenko61e1b4b2012-01-19 11:19:50 +02004723 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004725 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004726
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004727 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728}
4729
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004730static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4731{
4732 return single_open(file, l2cap_debugfs_show, inode->i_private);
4733}
4734
4735static const struct file_operations l2cap_debugfs_fops = {
4736 .open = l2cap_debugfs_open,
4737 .read = seq_read,
4738 .llseek = seq_lseek,
4739 .release = single_release,
4740};
4741
4742static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004744int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745{
4746 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004747
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004748 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004749 if (err < 0)
4750 return err;
4751
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004752 if (bt_debugfs) {
4753 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4754 bt_debugfs, NULL, &l2cap_debugfs_fops);
4755 if (!l2cap_debugfs)
4756 BT_ERR("Failed to create L2CAP debug file");
4757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760}
4761
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004762void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004764 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004765 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766}
4767
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004768module_param(disable_ertm, bool, 0644);
4769MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");