blob: 22319377eb202fe33987d0e77a7a2633ab9a434d [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
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001023 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
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
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001521static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001523 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001524 struct sk_buff **frag;
1525 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001526
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001527 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001528 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001529
1530 sent += count;
1531 len -= count;
1532
1533 /* Continuation fragments (no L2CAP header) */
1534 frag = &skb_shinfo(skb)->frag_list;
1535 while (len) {
1536 count = min_t(unsigned int, conn->mtu, len);
1537
1538 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1539 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001540 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001541 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1542 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001544 (*frag)->priority = skb->priority;
1545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546 sent += count;
1547 len -= count;
1548
1549 frag = &(*frag)->next;
1550 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001551
1552 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001553}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001555static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1556 struct msghdr *msg, size_t len,
1557 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001558{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001559 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001560 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001561 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001562 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001563 struct l2cap_hdr *lh;
1564
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001565 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001566
1567 count = min_t(unsigned int, (conn->mtu - hlen), len);
1568 skb = bt_skb_send_alloc(sk, count + hlen,
1569 msg->msg_flags & MSG_DONTWAIT, &err);
1570 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001571 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001572
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001573 skb->priority = priority;
1574
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001575 /* Create L2CAP header */
1576 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001577 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001578 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001579 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001580
1581 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1582 if (unlikely(err < 0)) {
1583 kfree_skb(skb);
1584 return ERR_PTR(err);
1585 }
1586 return skb;
1587}
1588
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001589static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1590 struct msghdr *msg, size_t len,
1591 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001592{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001593 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001594 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001595 struct sk_buff *skb;
1596 int err, count, hlen = L2CAP_HDR_SIZE;
1597 struct l2cap_hdr *lh;
1598
1599 BT_DBG("sk %p len %d", sk, (int)len);
1600
1601 count = min_t(unsigned int, (conn->mtu - hlen), len);
1602 skb = bt_skb_send_alloc(sk, count + hlen,
1603 msg->msg_flags & MSG_DONTWAIT, &err);
1604 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001605 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001607 skb->priority = priority;
1608
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001609 /* Create L2CAP header */
1610 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001611 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001612 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1613
1614 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1615 if (unlikely(err < 0)) {
1616 kfree_skb(skb);
1617 return ERR_PTR(err);
1618 }
1619 return skb;
1620}
1621
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001622static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1623 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001624 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001625{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001626 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001627 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001628 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001629 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001630 struct l2cap_hdr *lh;
1631
1632 BT_DBG("sk %p len %d", sk, (int)len);
1633
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001634 if (!conn)
1635 return ERR_PTR(-ENOTCONN);
1636
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001637 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1638 hlen = L2CAP_EXT_HDR_SIZE;
1639 else
1640 hlen = L2CAP_ENH_HDR_SIZE;
1641
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001642 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001643 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001644
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001645 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001646 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001647
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001648 count = min_t(unsigned int, (conn->mtu - hlen), len);
1649 skb = bt_skb_send_alloc(sk, count + hlen,
1650 msg->msg_flags & MSG_DONTWAIT, &err);
1651 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001652 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001653
1654 /* Create L2CAP header */
1655 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001656 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001657 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001658
1659 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1660
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001661 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001662 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001663
1664 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1665 if (unlikely(err < 0)) {
1666 kfree_skb(skb);
1667 return ERR_PTR(err);
1668 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001669
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001670 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001671 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001672
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001673 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001674 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001675}
1676
Szymon Janc67c9e842011-07-28 16:24:33 +02001677static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001678{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001679 struct sk_buff *skb;
1680 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001681 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001682 size_t size = 0;
1683
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001684 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001685 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001686 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001687 if (IS_ERR(skb))
1688 return PTR_ERR(skb);
1689
1690 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001691 len -= chan->remote_mps;
1692 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001693
1694 while (len > 0) {
1695 size_t buflen;
1696
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001697 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001698 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001699 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001700 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001701 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001702 buflen = len;
1703 }
1704
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001705 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001706 if (IS_ERR(skb)) {
1707 skb_queue_purge(&sar_queue);
1708 return PTR_ERR(skb);
1709 }
1710
1711 __skb_queue_tail(&sar_queue, skb);
1712 len -= buflen;
1713 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001714 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001715 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1716 if (chan->tx_send_head == NULL)
1717 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001718
1719 return size;
1720}
1721
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001722int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1723 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001724{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001725 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001726 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001727 int err;
1728
1729 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001730 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001731 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001732 if (IS_ERR(skb))
1733 return PTR_ERR(skb);
1734
1735 l2cap_do_send(chan, skb);
1736 return len;
1737 }
1738
1739 switch (chan->mode) {
1740 case L2CAP_MODE_BASIC:
1741 /* Check outgoing MTU */
1742 if (len > chan->omtu)
1743 return -EMSGSIZE;
1744
1745 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001746 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001747 if (IS_ERR(skb))
1748 return PTR_ERR(skb);
1749
1750 l2cap_do_send(chan, skb);
1751 err = len;
1752 break;
1753
1754 case L2CAP_MODE_ERTM:
1755 case L2CAP_MODE_STREAMING:
1756 /* Entire SDU fits into one PDU */
1757 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001758 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001759 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1760 0);
1761 if (IS_ERR(skb))
1762 return PTR_ERR(skb);
1763
1764 __skb_queue_tail(&chan->tx_q, skb);
1765
1766 if (chan->tx_send_head == NULL)
1767 chan->tx_send_head = skb;
1768
1769 } else {
1770 /* Segment SDU into multiples PDUs */
1771 err = l2cap_sar_segment_sdu(chan, msg, len);
1772 if (err < 0)
1773 return err;
1774 }
1775
1776 if (chan->mode == L2CAP_MODE_STREAMING) {
1777 l2cap_streaming_send(chan);
1778 err = len;
1779 break;
1780 }
1781
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001782 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1783 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001784 err = len;
1785 break;
1786 }
1787
1788 err = l2cap_ertm_send(chan);
1789 if (err >= 0)
1790 err = len;
1791
1792 break;
1793
1794 default:
1795 BT_DBG("bad state %1.1x", chan->mode);
1796 err = -EBADFD;
1797 }
1798
1799 return err;
1800}
1801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802/* Copy frame to all raw sockets on that connection */
1803static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1804{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001806 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807
1808 BT_DBG("conn %p", conn);
1809
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001810 rcu_read_lock();
1811
1812 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001813 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001814 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001815 continue;
1816
1817 /* Don't send frame to the socket it came from */
1818 if (skb->sk == sk)
1819 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001820 nskb = skb_clone(skb, GFP_ATOMIC);
1821 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001822 continue;
1823
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001824 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 kfree_skb(nskb);
1826 }
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02001827
1828 rcu_read_unlock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001829}
1830
1831/* ---- L2CAP signalling commands ---- */
1832static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1833 u8 code, u8 ident, u16 dlen, void *data)
1834{
1835 struct sk_buff *skb, **frag;
1836 struct l2cap_cmd_hdr *cmd;
1837 struct l2cap_hdr *lh;
1838 int len, count;
1839
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001840 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1841 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001842
1843 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1844 count = min_t(unsigned int, conn->mtu, len);
1845
1846 skb = bt_skb_alloc(count, GFP_ATOMIC);
1847 if (!skb)
1848 return NULL;
1849
1850 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001851 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001852
1853 if (conn->hcon->type == LE_LINK)
1854 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1855 else
1856 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001857
1858 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1859 cmd->code = code;
1860 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001861 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001862
1863 if (dlen) {
1864 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1865 memcpy(skb_put(skb, count), data, count);
1866 data += count;
1867 }
1868
1869 len -= skb->len;
1870
1871 /* Continuation fragments (no L2CAP header) */
1872 frag = &skb_shinfo(skb)->frag_list;
1873 while (len) {
1874 count = min_t(unsigned int, conn->mtu, len);
1875
1876 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1877 if (!*frag)
1878 goto fail;
1879
1880 memcpy(skb_put(*frag, count), data, count);
1881
1882 len -= count;
1883 data += count;
1884
1885 frag = &(*frag)->next;
1886 }
1887
1888 return skb;
1889
1890fail:
1891 kfree_skb(skb);
1892 return NULL;
1893}
1894
1895static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1896{
1897 struct l2cap_conf_opt *opt = *ptr;
1898 int len;
1899
1900 len = L2CAP_CONF_OPT_SIZE + opt->len;
1901 *ptr += len;
1902
1903 *type = opt->type;
1904 *olen = opt->len;
1905
1906 switch (opt->len) {
1907 case 1:
1908 *val = *((u8 *) opt->val);
1909 break;
1910
1911 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001912 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001913 break;
1914
1915 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001916 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001917 break;
1918
1919 default:
1920 *val = (unsigned long) opt->val;
1921 break;
1922 }
1923
1924 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1925 return len;
1926}
1927
Linus Torvalds1da177e2005-04-16 15:20:36 -07001928static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1929{
1930 struct l2cap_conf_opt *opt = *ptr;
1931
1932 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1933
1934 opt->type = type;
1935 opt->len = len;
1936
1937 switch (len) {
1938 case 1:
1939 *((u8 *) opt->val) = val;
1940 break;
1941
1942 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001943 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 break;
1945
1946 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001947 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 break;
1949
1950 default:
1951 memcpy(opt->val, (void *) val, len);
1952 break;
1953 }
1954
1955 *ptr += L2CAP_CONF_OPT_SIZE + len;
1956}
1957
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001958static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1959{
1960 struct l2cap_conf_efs efs;
1961
Szymon Janc1ec918c2011-11-16 09:32:21 +01001962 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001963 case L2CAP_MODE_ERTM:
1964 efs.id = chan->local_id;
1965 efs.stype = chan->local_stype;
1966 efs.msdu = cpu_to_le16(chan->local_msdu);
1967 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1968 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1969 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1970 break;
1971
1972 case L2CAP_MODE_STREAMING:
1973 efs.id = 1;
1974 efs.stype = L2CAP_SERV_BESTEFFORT;
1975 efs.msdu = cpu_to_le16(chan->local_msdu);
1976 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1977 efs.acc_lat = 0;
1978 efs.flush_to = 0;
1979 break;
1980
1981 default:
1982 return;
1983 }
1984
1985 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1986 (unsigned long) &efs);
1987}
1988
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001989static void l2cap_ack_timeout(struct work_struct *work)
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001990{
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001991 struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
1992 ack_timer.work);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001993
Gustavo F. Padovan2fb9b3d2011-12-22 16:56:05 -02001994 BT_DBG("chan %p", chan);
1995
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001996 lock_sock(chan->sk);
Szymon Jancb17e73b2012-01-11 10:59:47 +01001997 __l2cap_send_ack(chan);
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03001998 release_sock(chan->sk);
Szymon Janc09bfb2e2012-01-11 10:59:49 +01001999
2000 l2cap_chan_put(chan);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03002001}
2002
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002003static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002004{
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002005 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002006 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002007 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03002008 chan->num_acked = 0;
2009 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002010
Gustavo F. Padovan721c4182011-06-23 19:29:58 -03002011 INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
2012 INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
2013 INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002014
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03002015 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03002016
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03002017 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002018}
2019
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002020static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
2021{
2022 switch (mode) {
2023 case L2CAP_MODE_STREAMING:
2024 case L2CAP_MODE_ERTM:
2025 if (l2cap_mode_supported(mode, remote_feat_mask))
2026 return mode;
2027 /* fall through */
2028 default:
2029 return L2CAP_MODE_BASIC;
2030 }
2031}
2032
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002033static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
2034{
2035 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
2036}
2037
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002038static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
2039{
2040 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
2041}
2042
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002043static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
2044{
2045 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002046 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002047 /* use extended control field */
2048 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002049 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
2050 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002051 chan->tx_win = min_t(u16, chan->tx_win,
2052 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002053 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
2054 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002055}
2056
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002057static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002058{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002059 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002060 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002062 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002063
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002064 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002066 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002067 goto done;
2068
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002069 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002070 case L2CAP_MODE_STREAMING:
2071 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002072 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002073 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002074
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002075 if (__l2cap_efs_supported(chan))
2076 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2077
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002078 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002079 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002080 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002081 break;
2082 }
2083
2084done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002085 if (chan->imtu != L2CAP_DEFAULT_MTU)
2086 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002087
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002088 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002089 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002090 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2091 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002092 break;
2093
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002094 rfc.mode = L2CAP_MODE_BASIC;
2095 rfc.txwin_size = 0;
2096 rfc.max_transmit = 0;
2097 rfc.retrans_timeout = 0;
2098 rfc.monitor_timeout = 0;
2099 rfc.max_pdu_size = 0;
2100
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002101 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2102 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002103 break;
2104
2105 case L2CAP_MODE_ERTM:
2106 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002107 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002108 rfc.retrans_timeout = 0;
2109 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002110
2111 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2112 L2CAP_EXT_HDR_SIZE -
2113 L2CAP_SDULEN_SIZE -
2114 L2CAP_FCS_SIZE);
2115 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002116
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002117 l2cap_txwin_setup(chan);
2118
2119 rfc.txwin_size = min_t(u16, chan->tx_win,
2120 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002121
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002122 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2123 (unsigned long) &rfc);
2124
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002125 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2126 l2cap_add_opt_efs(&ptr, chan);
2127
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002128 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002129 break;
2130
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002131 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002132 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002133 chan->fcs = L2CAP_FCS_NONE;
2134 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002135 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002136
2137 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2138 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2139 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002140 break;
2141
2142 case L2CAP_MODE_STREAMING:
2143 rfc.mode = L2CAP_MODE_STREAMING;
2144 rfc.txwin_size = 0;
2145 rfc.max_transmit = 0;
2146 rfc.retrans_timeout = 0;
2147 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002148
2149 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2150 L2CAP_EXT_HDR_SIZE -
2151 L2CAP_SDULEN_SIZE -
2152 L2CAP_FCS_SIZE);
2153 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002154
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002155 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2156 (unsigned long) &rfc);
2157
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002158 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2159 l2cap_add_opt_efs(&ptr, chan);
2160
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002161 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002162 break;
2163
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002164 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002165 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002166 chan->fcs = L2CAP_FCS_NONE;
2167 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002168 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002169 break;
2170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002172 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002173 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174
2175 return ptr - data;
2176}
2177
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002178static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002180 struct l2cap_conf_rsp *rsp = data;
2181 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002182 void *req = chan->conf_req;
2183 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002184 int type, hint, olen;
2185 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002186 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002187 struct l2cap_conf_efs efs;
2188 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002189 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002190 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002191 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002192
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002193 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002194
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002195 while (len >= L2CAP_CONF_OPT_SIZE) {
2196 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002197
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002198 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002199 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002200
2201 switch (type) {
2202 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002203 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002204 break;
2205
2206 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002207 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002208 break;
2209
2210 case L2CAP_CONF_QOS:
2211 break;
2212
Marcel Holtmann6464f352007-10-20 13:39:51 +02002213 case L2CAP_CONF_RFC:
2214 if (olen == sizeof(rfc))
2215 memcpy(&rfc, (void *) val, olen);
2216 break;
2217
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002218 case L2CAP_CONF_FCS:
2219 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002220 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002221 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002222
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002223 case L2CAP_CONF_EFS:
2224 remote_efs = 1;
2225 if (olen == sizeof(efs))
2226 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002227 break;
2228
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002229 case L2CAP_CONF_EWS:
2230 if (!enable_hs)
2231 return -ECONNREFUSED;
2232
2233 set_bit(FLAG_EXT_CTRL, &chan->flags);
2234 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002235 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002236 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002237 break;
2238
2239 default:
2240 if (hint)
2241 break;
2242
2243 result = L2CAP_CONF_UNKNOWN;
2244 *((u8 *) ptr++) = type;
2245 break;
2246 }
2247 }
2248
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002249 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002250 goto done;
2251
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002252 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002253 case L2CAP_MODE_STREAMING:
2254 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002255 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002256 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002257 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002258 break;
2259 }
2260
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002261 if (remote_efs) {
2262 if (__l2cap_efs_supported(chan))
2263 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2264 else
2265 return -ECONNREFUSED;
2266 }
2267
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002268 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002269 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002270
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002271 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002272 }
2273
2274done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002275 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002276 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002277 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002278
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002279 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002280 return -ECONNREFUSED;
2281
2282 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2283 sizeof(rfc), (unsigned long) &rfc);
2284 }
2285
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002286 if (result == L2CAP_CONF_SUCCESS) {
2287 /* Configure output options and let the other side know
2288 * which ones we don't like. */
2289
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002290 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2291 result = L2CAP_CONF_UNACCEPT;
2292 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002293 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002294 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002295 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002296 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002297
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002298 if (remote_efs) {
2299 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2300 efs.stype != L2CAP_SERV_NOTRAFIC &&
2301 efs.stype != chan->local_stype) {
2302
2303 result = L2CAP_CONF_UNACCEPT;
2304
2305 if (chan->num_conf_req >= 1)
2306 return -ECONNREFUSED;
2307
2308 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002309 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002310 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002311 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002312 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002313 result = L2CAP_CONF_PENDING;
2314 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002315 }
2316 }
2317
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002318 switch (rfc.mode) {
2319 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002320 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002321 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002322 break;
2323
2324 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002325 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2326 chan->remote_tx_win = rfc.txwin_size;
2327 else
2328 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2329
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002330 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002331
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002332 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2333 chan->conn->mtu -
2334 L2CAP_EXT_HDR_SIZE -
2335 L2CAP_SDULEN_SIZE -
2336 L2CAP_FCS_SIZE);
2337 rfc.max_pdu_size = cpu_to_le16(size);
2338 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002339
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002340 rfc.retrans_timeout =
2341 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2342 rfc.monitor_timeout =
2343 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002344
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002345 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002346
2347 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2348 sizeof(rfc), (unsigned long) &rfc);
2349
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002350 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2351 chan->remote_id = efs.id;
2352 chan->remote_stype = efs.stype;
2353 chan->remote_msdu = le16_to_cpu(efs.msdu);
2354 chan->remote_flush_to =
2355 le32_to_cpu(efs.flush_to);
2356 chan->remote_acc_lat =
2357 le32_to_cpu(efs.acc_lat);
2358 chan->remote_sdu_itime =
2359 le32_to_cpu(efs.sdu_itime);
2360 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2361 sizeof(efs), (unsigned long) &efs);
2362 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002363 break;
2364
2365 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002366 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2367 chan->conn->mtu -
2368 L2CAP_EXT_HDR_SIZE -
2369 L2CAP_SDULEN_SIZE -
2370 L2CAP_FCS_SIZE);
2371 rfc.max_pdu_size = cpu_to_le16(size);
2372 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002373
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002374 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002375
2376 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2377 sizeof(rfc), (unsigned long) &rfc);
2378
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002379 break;
2380
2381 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002382 result = L2CAP_CONF_UNACCEPT;
2383
2384 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002385 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002386 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002387
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002388 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002389 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002390 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002391 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002392 rsp->result = cpu_to_le16(result);
2393 rsp->flags = cpu_to_le16(0x0000);
2394
2395 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002396}
2397
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002398static 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 -03002399{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002400 struct l2cap_conf_req *req = data;
2401 void *ptr = req->data;
2402 int type, olen;
2403 unsigned long val;
Mat Martineau36e999a2011-12-08 17:23:21 -08002404 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002405 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002406
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002407 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002408
2409 while (len >= L2CAP_CONF_OPT_SIZE) {
2410 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2411
2412 switch (type) {
2413 case L2CAP_CONF_MTU:
2414 if (val < L2CAP_DEFAULT_MIN_MTU) {
2415 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002416 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002417 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002418 chan->imtu = val;
2419 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002420 break;
2421
2422 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002423 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002424 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002425 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002426 break;
2427
2428 case L2CAP_CONF_RFC:
2429 if (olen == sizeof(rfc))
2430 memcpy(&rfc, (void *)val, olen);
2431
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002432 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002433 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002434 return -ECONNREFUSED;
2435
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002436 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002437
2438 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2439 sizeof(rfc), (unsigned long) &rfc);
2440 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002441
2442 case L2CAP_CONF_EWS:
2443 chan->tx_win = min_t(u16, val,
2444 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002445 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2446 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002447 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002448
2449 case L2CAP_CONF_EFS:
2450 if (olen == sizeof(efs))
2451 memcpy(&efs, (void *)val, olen);
2452
2453 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2454 efs.stype != L2CAP_SERV_NOTRAFIC &&
2455 efs.stype != chan->local_stype)
2456 return -ECONNREFUSED;
2457
2458 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2459 sizeof(efs), (unsigned long) &efs);
2460 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002461 }
2462 }
2463
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002464 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002465 return -ECONNREFUSED;
2466
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002467 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002468
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002469 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002470 switch (rfc.mode) {
2471 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002472 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2473 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2474 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002475
2476 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2477 chan->local_msdu = le16_to_cpu(efs.msdu);
2478 chan->local_sdu_itime =
2479 le32_to_cpu(efs.sdu_itime);
2480 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2481 chan->local_flush_to =
2482 le32_to_cpu(efs.flush_to);
2483 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002484 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002485
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002486 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002487 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002488 }
2489 }
2490
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002491 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002492 req->flags = cpu_to_le16(0x0000);
2493
2494 return ptr - data;
2495}
2496
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002497static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002498{
2499 struct l2cap_conf_rsp *rsp = data;
2500 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002501
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002502 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002503
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002504 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002505 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002506 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002507
2508 return ptr - data;
2509}
2510
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002511void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002512{
2513 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002514 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002515 u8 buf[128];
2516
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002517 rsp.scid = cpu_to_le16(chan->dcid);
2518 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002519 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2520 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2521 l2cap_send_cmd(conn, chan->ident,
2522 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2523
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002524 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002525 return;
2526
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002527 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2528 l2cap_build_conf_req(chan, buf), buf);
2529 chan->num_conf_req++;
2530}
2531
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002532static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002533{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002534 int type, olen;
2535 unsigned long val;
2536 struct l2cap_conf_rfc rfc;
2537
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002538 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002539
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002540 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002541 return;
2542
2543 while (len >= L2CAP_CONF_OPT_SIZE) {
2544 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2545
2546 switch (type) {
2547 case L2CAP_CONF_RFC:
2548 if (olen == sizeof(rfc))
2549 memcpy(&rfc, (void *)val, olen);
2550 goto done;
2551 }
2552 }
2553
Mat Martineau36e999a2011-12-08 17:23:21 -08002554 /* Use sane default values in case a misbehaving remote device
2555 * did not send an RFC option.
2556 */
2557 rfc.mode = chan->mode;
2558 rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
2559 rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
2560 rfc.max_pdu_size = cpu_to_le16(chan->imtu);
2561
2562 BT_ERR("Expected RFC option was not found, using defaults");
2563
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002564done:
2565 switch (rfc.mode) {
2566 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002567 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2568 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2569 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002570 break;
2571 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002572 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002573 }
2574}
2575
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002576static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2577{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002578 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002579
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002580 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002581 return 0;
2582
2583 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2584 cmd->ident == conn->info_ident) {
Ulisses Furquim371fd832011-12-21 20:02:36 -02002585 __cancel_delayed_work(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002586
2587 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002588 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002589
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002590 l2cap_conn_start(conn);
2591 }
2592
2593 return 0;
2594}
2595
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2597{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2599 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002600 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002601 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002602 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603
2604 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002605 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002606
2607 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2608
2609 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002610 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2611 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612 result = L2CAP_CR_BAD_PSM;
2613 goto sendresp;
2614 }
2615
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002616 parent = pchan->sk;
2617
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002618 lock_sock(parent);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002619
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002620 /* Check if the ACL is secure enough (if not SDP) */
2621 if (psm != cpu_to_le16(0x0001) &&
2622 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002623 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002624 result = L2CAP_CR_SEC_BLOCK;
2625 goto response;
2626 }
2627
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 result = L2CAP_CR_NO_MEM;
2629
2630 /* Check for backlog size */
2631 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002632 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 goto response;
2634 }
2635
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002636 chan = pchan->ops->new_connection(pchan->data);
2637 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002638 goto response;
2639
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002640 sk = chan->sk;
2641
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002643 if (__l2cap_get_chan_by_dcid(conn, scid)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002645 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002646 goto response;
2647 }
2648
2649 hci_conn_hold(conn->hcon);
2650
Linus Torvalds1da177e2005-04-16 15:20:36 -07002651 bacpy(&bt_sk(sk)->src, conn->src);
2652 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002653 chan->psm = psm;
2654 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002656 bt_accept_enqueue(parent, sk);
2657
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02002658 l2cap_chan_add(conn, chan);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002659
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002660 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002662 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002663
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002664 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665
Marcel Holtmann984947d2009-02-06 23:35:19 +01002666 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002667 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002668 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002669 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002670 result = L2CAP_CR_PEND;
2671 status = L2CAP_CS_AUTHOR_PEND;
2672 parent->sk_data_ready(parent, 0);
2673 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002674 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002675 result = L2CAP_CR_SUCCESS;
2676 status = L2CAP_CS_NO_INFO;
2677 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002678 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002679 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002680 result = L2CAP_CR_PEND;
2681 status = L2CAP_CS_AUTHEN_PEND;
2682 }
2683 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002684 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002685 result = L2CAP_CR_PEND;
2686 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 }
2688
Linus Torvalds1da177e2005-04-16 15:20:36 -07002689response:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002690 release_sock(parent);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
2692sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002693 rsp.scid = cpu_to_le16(scid);
2694 rsp.dcid = cpu_to_le16(dcid);
2695 rsp.result = cpu_to_le16(result);
2696 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002697 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002698
2699 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2700 struct l2cap_info_req info;
2701 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2702
2703 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2704 conn->info_ident = l2cap_get_ident(conn);
2705
Gustavo F. Padovan030013d2011-12-20 10:57:28 -02002706 schedule_delayed_work(&conn->info_timer,
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002707 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2708
2709 l2cap_send_cmd(conn, conn->info_ident,
2710 L2CAP_INFO_REQ, sizeof(info), &info);
2711 }
2712
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002713 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002714 result == L2CAP_CR_SUCCESS) {
2715 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002716 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002717 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002718 l2cap_build_conf_req(chan, buf), buf);
2719 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002720 }
2721
Linus Torvalds1da177e2005-04-16 15:20:36 -07002722 return 0;
2723}
2724
2725static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2726{
2727 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2728 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002729 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 struct sock *sk;
2731 u8 req[128];
2732
2733 scid = __le16_to_cpu(rsp->scid);
2734 dcid = __le16_to_cpu(rsp->dcid);
2735 result = __le16_to_cpu(rsp->result);
2736 status = __le16_to_cpu(rsp->status);
2737
2738 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2739
2740 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002741 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002742 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002743 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002745 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002746 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002747 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 }
2749
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002750 sk = chan->sk;
2751
Linus Torvalds1da177e2005-04-16 15:20:36 -07002752 switch (result) {
2753 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002754 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002755 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002756 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002757 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002758
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002759 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002760 break;
2761
Linus Torvalds1da177e2005-04-16 15:20:36 -07002762 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002763 l2cap_build_conf_req(chan, req), req);
2764 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002765 break;
2766
2767 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002768 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002769 break;
2770
2771 default:
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002772 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002773 break;
2774 }
2775
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002776 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002777 return 0;
2778}
2779
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002780static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002781{
2782 /* FCS is enabled only in ERTM or streaming mode, if one or both
2783 * sides request it.
2784 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002785 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002786 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002787 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002788 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002789}
2790
Al Viro88219a02007-07-29 00:17:25 -07002791static 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 -07002792{
2793 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2794 u16 dcid, flags;
2795 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002796 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002798 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799
2800 dcid = __le16_to_cpu(req->dcid);
2801 flags = __le16_to_cpu(req->flags);
2802
2803 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2804
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002805 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002806 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002807 return -ENOENT;
2808
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002809 sk = chan->sk;
2810
David S. Miller033b1142011-07-21 13:38:42 -07002811 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002812 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002813
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002814 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2815 rej.scid = cpu_to_le16(chan->scid);
2816 rej.dcid = cpu_to_le16(chan->dcid);
2817
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002818 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2819 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002820 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002821 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002822
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002823 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002824 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002825 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002826 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002827 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002828 L2CAP_CONF_REJECT, flags), rsp);
2829 goto unlock;
2830 }
2831
2832 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002833 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2834 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002835
2836 if (flags & 0x0001) {
2837 /* Incomplete config. Send empty response. */
2838 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002839 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002840 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002841 goto unlock;
2842 }
2843
2844 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002845 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002846 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002847 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002848 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002849 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002850
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002851 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002852 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002853
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002854 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002855 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002856
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002857 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002858 goto unlock;
2859
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002860 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002861 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002862
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002863 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002864
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002865 chan->next_tx_seq = 0;
2866 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002867 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002868 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002869 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002870
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002872 goto unlock;
2873 }
2874
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002875 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002876 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002878 l2cap_build_conf_req(chan, buf), buf);
2879 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002880 }
2881
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002882 /* Got Conf Rsp PENDING from remote side and asume we sent
2883 Conf Rsp PENDING in the code above */
2884 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2885 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2886
2887 /* check compatibility */
2888
2889 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2890 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2891
2892 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002893 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002894 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2895 }
2896
Linus Torvalds1da177e2005-04-16 15:20:36 -07002897unlock:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03002898 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 return 0;
2900}
2901
2902static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2903{
2904 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2905 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002906 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002907 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002908 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002909
2910 scid = __le16_to_cpu(rsp->scid);
2911 flags = __le16_to_cpu(rsp->flags);
2912 result = __le16_to_cpu(rsp->result);
2913
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002914 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2915 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002916
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002917 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002918 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919 return 0;
2920
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002921 sk = chan->sk;
2922
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 switch (result) {
2924 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002925 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002926 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002927 break;
2928
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002929 case L2CAP_CONF_PENDING:
2930 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2931
2932 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2933 char buf[64];
2934
2935 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2936 buf, &result);
2937 if (len < 0) {
2938 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2939 goto done;
2940 }
2941
2942 /* check compatibility */
2943
2944 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2945 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2946
2947 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002948 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002949 L2CAP_CONF_SUCCESS, 0x0000), buf);
2950 }
2951 goto done;
2952
Linus Torvalds1da177e2005-04-16 15:20:36 -07002953 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002954 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002955 char req[64];
2956
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002957 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002958 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002959 goto done;
2960 }
2961
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002962 /* throw out any old stored conf requests */
2963 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002964 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2965 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002966 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002967 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002968 goto done;
2969 }
2970
2971 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2972 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002973 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002974 if (result != L2CAP_CONF_SUCCESS)
2975 goto done;
2976 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 }
2978
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002979 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002980 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01002981 __set_chan_timer(chan,
2982 msecs_to_jiffies(L2CAP_DISC_REJ_TIMEOUT));
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002983 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002984 goto done;
2985 }
2986
2987 if (flags & 0x01)
2988 goto done;
2989
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002990 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002992 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002993 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002994
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002995 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002996 chan->next_tx_seq = 0;
2997 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002998 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002999 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003000 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03003001
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 l2cap_chan_ready(sk);
3003 }
3004
3005done:
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003006 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003007 return 0;
3008}
3009
3010static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3011{
3012 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
3013 struct l2cap_disconn_rsp rsp;
3014 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003015 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003016 struct sock *sk;
3017
3018 scid = __le16_to_cpu(req->scid);
3019 dcid = __le16_to_cpu(req->dcid);
3020
3021 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
3022
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003023 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003024 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 return 0;
3026
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003027 sk = chan->sk;
3028
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03003029 rsp.dcid = cpu_to_le16(chan->scid);
3030 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003031 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
3032
3033 sk->sk_shutdown = SHUTDOWN_MASK;
3034
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003035 l2cap_chan_del(chan, ECONNRESET);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003036 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003037
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003038 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003039 return 0;
3040}
3041
3042static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3043{
3044 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3045 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003046 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003047 struct sock *sk;
3048
3049 scid = __le16_to_cpu(rsp->scid);
3050 dcid = __le16_to_cpu(rsp->dcid);
3051
3052 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3053
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003054 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003055 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003056 return 0;
3057
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003058 sk = chan->sk;
3059
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003060 l2cap_chan_del(chan, 0);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03003061 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003062
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003063 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003064 return 0;
3065}
3066
3067static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3068{
3069 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070 u16 type;
3071
3072 type = __le16_to_cpu(req->type);
3073
3074 BT_DBG("type 0x%4.4x", type);
3075
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003076 if (type == L2CAP_IT_FEAT_MASK) {
3077 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003078 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003079 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3080 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3081 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003082 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003083 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3084 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003085 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003086 feat_mask |= L2CAP_FEAT_EXT_FLOW
3087 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003088
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003089 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003090 l2cap_send_cmd(conn, cmd->ident,
3091 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003092 } else if (type == L2CAP_IT_FIXED_CHAN) {
3093 u8 buf[12];
3094 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003095
3096 if (enable_hs)
3097 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3098 else
3099 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3100
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003101 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3102 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003103 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003104 l2cap_send_cmd(conn, cmd->ident,
3105 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003106 } else {
3107 struct l2cap_info_rsp rsp;
3108 rsp.type = cpu_to_le16(type);
3109 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3110 l2cap_send_cmd(conn, cmd->ident,
3111 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113
3114 return 0;
3115}
3116
3117static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3118{
3119 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3120 u16 type, result;
3121
3122 type = __le16_to_cpu(rsp->type);
3123 result = __le16_to_cpu(rsp->result);
3124
3125 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3126
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003127 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3128 if (cmd->ident != conn->info_ident ||
3129 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3130 return 0;
3131
Ulisses Furquim371fd832011-12-21 20:02:36 -02003132 __cancel_delayed_work(&conn->info_timer);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003133
Ville Tervoadb08ed2010-08-04 09:43:33 +03003134 if (result != L2CAP_IR_SUCCESS) {
3135 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3136 conn->info_ident = 0;
3137
3138 l2cap_conn_start(conn);
3139
3140 return 0;
3141 }
3142
Marcel Holtmann984947d2009-02-06 23:35:19 +01003143 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003144 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003145
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003146 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003147 struct l2cap_info_req req;
3148 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3149
3150 conn->info_ident = l2cap_get_ident(conn);
3151
3152 l2cap_send_cmd(conn, conn->info_ident,
3153 L2CAP_INFO_REQ, sizeof(req), &req);
3154 } else {
3155 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3156 conn->info_ident = 0;
3157
3158 l2cap_conn_start(conn);
3159 }
3160 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003161 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003162 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003163
3164 l2cap_conn_start(conn);
3165 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003166
Linus Torvalds1da177e2005-04-16 15:20:36 -07003167 return 0;
3168}
3169
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003170static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3171 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3172 void *data)
3173{
3174 struct l2cap_create_chan_req *req = data;
3175 struct l2cap_create_chan_rsp rsp;
3176 u16 psm, scid;
3177
3178 if (cmd_len != sizeof(*req))
3179 return -EPROTO;
3180
3181 if (!enable_hs)
3182 return -EINVAL;
3183
3184 psm = le16_to_cpu(req->psm);
3185 scid = le16_to_cpu(req->scid);
3186
3187 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3188
3189 /* Placeholder: Always reject */
3190 rsp.dcid = 0;
3191 rsp.scid = cpu_to_le16(scid);
3192 rsp.result = L2CAP_CR_NO_MEM;
3193 rsp.status = L2CAP_CS_NO_INFO;
3194
3195 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3196 sizeof(rsp), &rsp);
3197
3198 return 0;
3199}
3200
3201static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3202 struct l2cap_cmd_hdr *cmd, void *data)
3203{
3204 BT_DBG("conn %p", conn);
3205
3206 return l2cap_connect_rsp(conn, cmd, data);
3207}
3208
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003209static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3210 u16 icid, u16 result)
3211{
3212 struct l2cap_move_chan_rsp rsp;
3213
3214 BT_DBG("icid %d, result %d", icid, result);
3215
3216 rsp.icid = cpu_to_le16(icid);
3217 rsp.result = cpu_to_le16(result);
3218
3219 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3220}
3221
3222static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3223 struct l2cap_chan *chan, u16 icid, u16 result)
3224{
3225 struct l2cap_move_chan_cfm cfm;
3226 u8 ident;
3227
3228 BT_DBG("icid %d, result %d", icid, result);
3229
3230 ident = l2cap_get_ident(conn);
3231 if (chan)
3232 chan->ident = ident;
3233
3234 cfm.icid = cpu_to_le16(icid);
3235 cfm.result = cpu_to_le16(result);
3236
3237 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3238}
3239
3240static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3241 u16 icid)
3242{
3243 struct l2cap_move_chan_cfm_rsp rsp;
3244
3245 BT_DBG("icid %d", icid);
3246
3247 rsp.icid = cpu_to_le16(icid);
3248 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3249}
3250
3251static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3252 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3253{
3254 struct l2cap_move_chan_req *req = data;
3255 u16 icid = 0;
3256 u16 result = L2CAP_MR_NOT_ALLOWED;
3257
3258 if (cmd_len != sizeof(*req))
3259 return -EPROTO;
3260
3261 icid = le16_to_cpu(req->icid);
3262
3263 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3264
3265 if (!enable_hs)
3266 return -EINVAL;
3267
3268 /* Placeholder: Always refuse */
3269 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3270
3271 return 0;
3272}
3273
3274static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3275 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3276{
3277 struct l2cap_move_chan_rsp *rsp = data;
3278 u16 icid, result;
3279
3280 if (cmd_len != sizeof(*rsp))
3281 return -EPROTO;
3282
3283 icid = le16_to_cpu(rsp->icid);
3284 result = le16_to_cpu(rsp->result);
3285
3286 BT_DBG("icid %d, result %d", icid, result);
3287
3288 /* Placeholder: Always unconfirmed */
3289 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3290
3291 return 0;
3292}
3293
3294static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3295 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3296{
3297 struct l2cap_move_chan_cfm *cfm = data;
3298 u16 icid, result;
3299
3300 if (cmd_len != sizeof(*cfm))
3301 return -EPROTO;
3302
3303 icid = le16_to_cpu(cfm->icid);
3304 result = le16_to_cpu(cfm->result);
3305
3306 BT_DBG("icid %d, result %d", icid, result);
3307
3308 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3309
3310 return 0;
3311}
3312
3313static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3314 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3315{
3316 struct l2cap_move_chan_cfm_rsp *rsp = data;
3317 u16 icid;
3318
3319 if (cmd_len != sizeof(*rsp))
3320 return -EPROTO;
3321
3322 icid = le16_to_cpu(rsp->icid);
3323
3324 BT_DBG("icid %d", icid);
3325
3326 return 0;
3327}
3328
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003329static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003330 u16 to_multiplier)
3331{
3332 u16 max_latency;
3333
3334 if (min > max || min < 6 || max > 3200)
3335 return -EINVAL;
3336
3337 if (to_multiplier < 10 || to_multiplier > 3200)
3338 return -EINVAL;
3339
3340 if (max >= to_multiplier * 8)
3341 return -EINVAL;
3342
3343 max_latency = (to_multiplier * 8 / max) - 1;
3344 if (latency > 499 || latency > max_latency)
3345 return -EINVAL;
3346
3347 return 0;
3348}
3349
3350static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3351 struct l2cap_cmd_hdr *cmd, u8 *data)
3352{
3353 struct hci_conn *hcon = conn->hcon;
3354 struct l2cap_conn_param_update_req *req;
3355 struct l2cap_conn_param_update_rsp rsp;
3356 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003357 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003358
3359 if (!(hcon->link_mode & HCI_LM_MASTER))
3360 return -EINVAL;
3361
3362 cmd_len = __le16_to_cpu(cmd->len);
3363 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3364 return -EPROTO;
3365
3366 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003367 min = __le16_to_cpu(req->min);
3368 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003369 latency = __le16_to_cpu(req->latency);
3370 to_multiplier = __le16_to_cpu(req->to_multiplier);
3371
3372 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3373 min, max, latency, to_multiplier);
3374
3375 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003376
3377 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3378 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003379 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3380 else
3381 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3382
3383 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3384 sizeof(rsp), &rsp);
3385
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003386 if (!err)
3387 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3388
Claudio Takahaside731152011-02-11 19:28:55 -02003389 return 0;
3390}
3391
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003392static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3393 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3394{
3395 int err = 0;
3396
3397 switch (cmd->code) {
3398 case L2CAP_COMMAND_REJ:
3399 l2cap_command_rej(conn, cmd, data);
3400 break;
3401
3402 case L2CAP_CONN_REQ:
3403 err = l2cap_connect_req(conn, cmd, data);
3404 break;
3405
3406 case L2CAP_CONN_RSP:
3407 err = l2cap_connect_rsp(conn, cmd, data);
3408 break;
3409
3410 case L2CAP_CONF_REQ:
3411 err = l2cap_config_req(conn, cmd, cmd_len, data);
3412 break;
3413
3414 case L2CAP_CONF_RSP:
3415 err = l2cap_config_rsp(conn, cmd, data);
3416 break;
3417
3418 case L2CAP_DISCONN_REQ:
3419 err = l2cap_disconnect_req(conn, cmd, data);
3420 break;
3421
3422 case L2CAP_DISCONN_RSP:
3423 err = l2cap_disconnect_rsp(conn, cmd, data);
3424 break;
3425
3426 case L2CAP_ECHO_REQ:
3427 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3428 break;
3429
3430 case L2CAP_ECHO_RSP:
3431 break;
3432
3433 case L2CAP_INFO_REQ:
3434 err = l2cap_information_req(conn, cmd, data);
3435 break;
3436
3437 case L2CAP_INFO_RSP:
3438 err = l2cap_information_rsp(conn, cmd, data);
3439 break;
3440
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003441 case L2CAP_CREATE_CHAN_REQ:
3442 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3443 break;
3444
3445 case L2CAP_CREATE_CHAN_RSP:
3446 err = l2cap_create_channel_rsp(conn, cmd, data);
3447 break;
3448
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003449 case L2CAP_MOVE_CHAN_REQ:
3450 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3451 break;
3452
3453 case L2CAP_MOVE_CHAN_RSP:
3454 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3455 break;
3456
3457 case L2CAP_MOVE_CHAN_CFM:
3458 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3459 break;
3460
3461 case L2CAP_MOVE_CHAN_CFM_RSP:
3462 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3463 break;
3464
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003465 default:
3466 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3467 err = -EINVAL;
3468 break;
3469 }
3470
3471 return err;
3472}
3473
3474static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3475 struct l2cap_cmd_hdr *cmd, u8 *data)
3476{
3477 switch (cmd->code) {
3478 case L2CAP_COMMAND_REJ:
3479 return 0;
3480
3481 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003482 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003483
3484 case L2CAP_CONN_PARAM_UPDATE_RSP:
3485 return 0;
3486
3487 default:
3488 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3489 return -EINVAL;
3490 }
3491}
3492
3493static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3494 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003495{
3496 u8 *data = skb->data;
3497 int len = skb->len;
3498 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003499 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003500
3501 l2cap_raw_recv(conn, skb);
3502
3503 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003504 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003505 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3506 data += L2CAP_CMD_HDR_SIZE;
3507 len -= L2CAP_CMD_HDR_SIZE;
3508
Al Viro88219a02007-07-29 00:17:25 -07003509 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003510
Al Viro88219a02007-07-29 00:17:25 -07003511 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 -07003512
Al Viro88219a02007-07-29 00:17:25 -07003513 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003514 BT_DBG("corrupted command");
3515 break;
3516 }
3517
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003518 if (conn->hcon->type == LE_LINK)
3519 err = l2cap_le_sig_cmd(conn, &cmd, data);
3520 else
3521 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003522
3523 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003524 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003525
3526 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003527
3528 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003529 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003530 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3531 }
3532
Al Viro88219a02007-07-29 00:17:25 -07003533 data += cmd_len;
3534 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003535 }
3536
3537 kfree_skb(skb);
3538}
3539
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003540static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003541{
3542 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003543 int hdr_size;
3544
3545 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3546 hdr_size = L2CAP_EXT_HDR_SIZE;
3547 else
3548 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003549
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003550 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003551 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003552 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3553 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3554
3555 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003556 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003557 }
3558 return 0;
3559}
3560
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003561static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003562{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003563 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003564
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003565 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003566
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003567 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003568
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003569 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003570 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003571 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003572 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003573 }
3574
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003575 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003576 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003577
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003578 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003579
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003580 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003581 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003582 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003583 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003584 }
3585}
3586
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003587static 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 -03003588{
3589 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003590 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003591
3592 bt_cb(skb)->tx_seq = tx_seq;
3593 bt_cb(skb)->sar = sar;
3594
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003595 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003596
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003597 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003598
Szymon Janc039d9572011-11-16 09:32:19 +01003599 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003600 if (bt_cb(next_skb)->tx_seq == tx_seq)
3601 return -EINVAL;
3602
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003603 next_tx_seq_offset = __seq_offset(chan,
3604 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003605
3606 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003607 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003608 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003609 }
3610
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003611 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003612 next_skb = NULL;
3613 else
3614 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3615 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003616
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003617 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003618
3619 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003620}
3621
Mat Martineau84084a32011-07-22 14:54:00 -07003622static void append_skb_frag(struct sk_buff *skb,
3623 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003624{
Mat Martineau84084a32011-07-22 14:54:00 -07003625 /* skb->len reflects data in skb as well as all fragments
3626 * skb->data_len reflects only data in fragments
3627 */
3628 if (!skb_has_frag_list(skb))
3629 skb_shinfo(skb)->frag_list = new_frag;
3630
3631 new_frag->next = NULL;
3632
3633 (*last_frag)->next = new_frag;
3634 *last_frag = new_frag;
3635
3636 skb->len += new_frag->len;
3637 skb->data_len += new_frag->len;
3638 skb->truesize += new_frag->truesize;
3639}
3640
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003641static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003642{
3643 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003644
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003645 switch (__get_ctrl_sar(chan, control)) {
3646 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003647 if (chan->sdu)
3648 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003649
Mat Martineau84084a32011-07-22 14:54:00 -07003650 err = chan->ops->recv(chan->data, skb);
3651 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003652
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003653 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003654 if (chan->sdu)
3655 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003656
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003657 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003658 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003659
Mat Martineau84084a32011-07-22 14:54:00 -07003660 if (chan->sdu_len > chan->imtu) {
3661 err = -EMSGSIZE;
3662 break;
3663 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003664
Mat Martineau84084a32011-07-22 14:54:00 -07003665 if (skb->len >= chan->sdu_len)
3666 break;
3667
3668 chan->sdu = skb;
3669 chan->sdu_last_frag = skb;
3670
3671 skb = NULL;
3672 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003673 break;
3674
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003675 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003676 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003677 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003678
Mat Martineau84084a32011-07-22 14:54:00 -07003679 append_skb_frag(chan->sdu, skb,
3680 &chan->sdu_last_frag);
3681 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003682
Mat Martineau84084a32011-07-22 14:54:00 -07003683 if (chan->sdu->len >= chan->sdu_len)
3684 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003685
Mat Martineau84084a32011-07-22 14:54:00 -07003686 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003687 break;
3688
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003689 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003690 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003691 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003692
Mat Martineau84084a32011-07-22 14:54:00 -07003693 append_skb_frag(chan->sdu, skb,
3694 &chan->sdu_last_frag);
3695 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003696
Mat Martineau84084a32011-07-22 14:54:00 -07003697 if (chan->sdu->len != chan->sdu_len)
3698 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003699
Mat Martineau84084a32011-07-22 14:54:00 -07003700 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003701
Mat Martineau84084a32011-07-22 14:54:00 -07003702 if (!err) {
3703 /* Reassembly complete */
3704 chan->sdu = NULL;
3705 chan->sdu_last_frag = NULL;
3706 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003707 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003708 break;
3709 }
3710
Mat Martineau84084a32011-07-22 14:54:00 -07003711 if (err) {
3712 kfree_skb(skb);
3713 kfree_skb(chan->sdu);
3714 chan->sdu = NULL;
3715 chan->sdu_last_frag = NULL;
3716 chan->sdu_len = 0;
3717 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003718
Mat Martineau84084a32011-07-22 14:54:00 -07003719 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003720}
3721
Mat Martineau26f880d2011-07-07 09:39:01 -07003722static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003723{
Mat Martineau26f880d2011-07-07 09:39:01 -07003724 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003725
Mat Martineau26f880d2011-07-07 09:39:01 -07003726 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3727
Szymon Janc77f918b2012-01-11 10:59:48 +01003728 __set_ack_timer(chan);
Mat Martineau26f880d2011-07-07 09:39:01 -07003729}
3730
3731static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3732{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003733 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003734
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003735 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003736 goto done;
3737
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003738 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003739 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003740 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003741 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003742 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003743
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003744 __clear_retrans_timer(chan);
3745 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003746
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003747 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003748
3749done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003750 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3751 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003752
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003753 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003754}
3755
Mat Martineaue3281402011-07-07 09:39:02 -07003756void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003757{
Mat Martineaue3281402011-07-07 09:39:02 -07003758 if (chan->mode == L2CAP_MODE_ERTM) {
3759 if (busy)
3760 l2cap_ertm_enter_local_busy(chan);
3761 else
3762 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003763 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003764}
3765
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003766static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003767{
3768 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003769 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003770
Mat Martineaue3281402011-07-07 09:39:02 -07003771 while ((skb = skb_peek(&chan->srej_q)) &&
3772 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3773 int err;
3774
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003775 if (bt_cb(skb)->tx_seq != tx_seq)
3776 break;
3777
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003778 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003779 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003780 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003781
3782 if (err < 0) {
3783 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3784 break;
3785 }
3786
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003787 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3788 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003789 }
3790}
3791
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003792static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003793{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003794 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003795 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003796
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003797 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003798 if (l->tx_seq == tx_seq) {
3799 list_del(&l->list);
3800 kfree(l);
3801 return;
3802 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003803 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003804 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003805 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003806 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003807 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003808 }
3809}
3810
Szymon Jancaef89f22011-11-16 09:32:18 +01003811static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003812{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003813 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003814 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003815
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003816 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003817 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003818 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003819 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003820
3821 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003822 if (!new)
3823 return -ENOMEM;
3824
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003825 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003826
3827 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3828
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003829 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003830 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003831
3832 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003833
3834 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003835}
3836
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003837static 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 -03003838{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003839 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003840 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003841 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003842 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003843 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003844 int err = 0;
3845
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003846 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 -03003847 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003848
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003849 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003850 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003851 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003852 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003853 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003854 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003855 }
3856
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003857 chan->expected_ack_seq = req_seq;
3858 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003859
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003860 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003861
3862 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003863 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003864 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003865 goto drop;
3866 }
3867
Szymon Janc77f918b2012-01-11 10:59:48 +01003868 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3869 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
3870 l2cap_send_ack(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003871 goto drop;
Szymon Janc77f918b2012-01-11 10:59:48 +01003872 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003873
Mat Martineau02f1b642011-06-29 14:35:19 -07003874 if (tx_seq == chan->expected_tx_seq)
3875 goto expected;
3876
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003877 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003878 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003879
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003880 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003881 struct srej_list, list);
3882 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003883 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003884 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003885
3886 list_del(&first->list);
3887 kfree(first);
3888
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003889 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003890 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003891 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003892 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003893 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003894 }
3895 } else {
3896 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003897
3898 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003899 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003900 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003901
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003902 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003903 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003904 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003905 return 0;
3906 }
3907 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003908
3909 err = l2cap_send_srejframe(chan, tx_seq);
3910 if (err < 0) {
3911 l2cap_send_disconn_req(chan->conn, chan, -err);
3912 return err;
3913 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003914 }
3915 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003916 expected_tx_seq_offset = __seq_offset(chan,
3917 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003918
3919 /* duplicated tx_seq */
3920 if (tx_seq_offset < expected_tx_seq_offset)
3921 goto drop;
3922
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003923 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003924
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003925 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003926
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003927 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003928 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003929
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003930 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003931 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003932
Szymon Janc0ef3ef02012-01-11 10:59:46 +01003933 /* Set P-bit only if there are some I-frames to ack. */
3934 if (__clear_ack_timer(chan))
3935 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003936
Szymon Jancaef89f22011-11-16 09:32:18 +01003937 err = l2cap_send_srejframe(chan, tx_seq);
3938 if (err < 0) {
3939 l2cap_send_disconn_req(chan->conn, chan, -err);
3940 return err;
3941 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003942 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003943 return 0;
3944
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003945expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003946 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003947
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003948 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003949 bt_cb(skb)->tx_seq = tx_seq;
3950 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003951 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003952 return 0;
3953 }
3954
Mat Martineau84084a32011-07-22 14:54:00 -07003955 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003956 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3957
Mat Martineaue3281402011-07-07 09:39:02 -07003958 if (err < 0) {
3959 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3960 return err;
3961 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003962
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003963 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003964 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003965 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003966 }
3967
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003968
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003969 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3970 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003971 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003972 else
3973 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003974
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003975 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003976
3977drop:
3978 kfree_skb(skb);
3979 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003980}
3981
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003982static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003983{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003984 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003985 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003986
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003987 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003988 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003989
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003990 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003991 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3992 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3993 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003994 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003995 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003996
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003997 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003998 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003999 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004000 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03004001 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004002
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004003 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004004 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004005
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004006 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004007 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004008
4009 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004010 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004011 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004012 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004013
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004014 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
4015 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004016 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02004017 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004018 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004019 }
4020}
4021
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004022static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004023{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004024 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004025
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004026 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004027
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004028 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004029
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004030 chan->expected_ack_seq = tx_seq;
4031 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004032
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004033 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004034 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004035 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004036 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004037 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004038
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004039 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4040 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004041 }
4042}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004043static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004044{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004045 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004046
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004047 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004048
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004049 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004050
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004051 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004052 chan->expected_ack_seq = tx_seq;
4053 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004054
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004055 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004056 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004057
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004058 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004059
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004060 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004061 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004062 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004063 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004064 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004065 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004066 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004067 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004068 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004069 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004070 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004071 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004072 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004073 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004074 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004075 }
4076 }
4077}
4078
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004079static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004080{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004081 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004082
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004083 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004084
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004085 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004086 chan->expected_ack_seq = tx_seq;
4087 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004088
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004089 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004090 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004091
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004092 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004093 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004094 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004095 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004096 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004097 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004098
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004099 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004100 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004101 } else {
4102 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4103 l2cap_send_sframe(chan, rx_control);
4104 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004105}
4106
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004107static 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 -03004108{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004109 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004110
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004111 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004112 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004113 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004114 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004115 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004116 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004117 }
4118
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004119 switch (__get_ctrl_super(chan, rx_control)) {
4120 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004121 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004122 break;
4123
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004124 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004125 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004126 break;
4127
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004128 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004129 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004130 break;
4131
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004132 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004133 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004134 break;
4135 }
4136
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004137 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004138 return 0;
4139}
4140
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004141int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004142{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004143 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004144 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004145 int len, next_tx_seq_offset, req_seq_offset;
4146
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004147 control = __get_control(chan, skb->data);
4148 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004149 len = skb->len;
4150
4151 /*
4152 * We can just drop the corrupted I-frame here.
4153 * Receiver will miss it and start proper recovery
4154 * procedures and ask retransmission.
4155 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004156 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004157 goto drop;
4158
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004159 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004160 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004161
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004162 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004163 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004164
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004165 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004166 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004167 goto drop;
4168 }
4169
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004170 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004171
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004172 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4173
4174 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4175 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004176
4177 /* check for invalid req-seq */
4178 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004179 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004180 goto drop;
4181 }
4182
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004183 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004184 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004185 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004186 goto drop;
4187 }
4188
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004189 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004190 } else {
4191 if (len != 0) {
4192 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004193 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004194 goto drop;
4195 }
4196
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004197 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004198 }
4199
4200 return 0;
4201
4202drop:
4203 kfree_skb(skb);
4204 return 0;
4205}
4206
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4208{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004209 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004210 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004211 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004212 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004213 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004214
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004215 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004216 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004217 BT_DBG("unknown cid 0x%4.4x", cid);
4218 goto drop;
4219 }
4220
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004221 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004222
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004223 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004224
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004225 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004226 goto drop;
4227
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004228 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004229 case L2CAP_MODE_BASIC:
4230 /* If socket recv buffers overflows we drop data here
4231 * which is *bad* because L2CAP has to be reliable.
4232 * But we don't have any other choice. L2CAP doesn't
4233 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004234
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004235 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004236 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004237
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004238 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004239 goto done;
4240 break;
4241
4242 case L2CAP_MODE_ERTM:
Andrei Emeltchenko5ef8cb92012-01-13 17:21:42 +02004243 l2cap_ertm_data_rcv(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004244
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004245 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004246
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004247 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004248 control = __get_control(chan, skb->data);
4249 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004250 len = skb->len;
4251
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004252 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004253 goto drop;
4254
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004255 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004256 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004257
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004258 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004259 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004260
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004261 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004262 goto drop;
4263
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004264 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004265
Mat Martineau84084a32011-07-22 14:54:00 -07004266 if (chan->expected_tx_seq != tx_seq) {
4267 /* Frame(s) missing - must discard partial SDU */
4268 kfree_skb(chan->sdu);
4269 chan->sdu = NULL;
4270 chan->sdu_last_frag = NULL;
4271 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004272
Mat Martineau84084a32011-07-22 14:54:00 -07004273 /* TODO: Notify userland of missing data */
4274 }
4275
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004276 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004277
4278 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4279 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004280
4281 goto done;
4282
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004283 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004284 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004285 break;
4286 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004287
4288drop:
4289 kfree_skb(skb);
4290
4291done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004292 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004293 release_sock(sk);
Marcel Holtmann01394182006-07-03 10:02:46 +02004294
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 return 0;
4296}
4297
Al Viro8e036fc2007-07-29 00:16:36 -07004298static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004299{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004300 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004301 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004303 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4304 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004305 goto drop;
4306
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004307 sk = chan->sk;
4308
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004309 lock_sock(sk);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004310
Linus Torvalds1da177e2005-04-16 15:20:36 -07004311 BT_DBG("sk %p, len %d", sk, skb->len);
4312
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004313 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004314 goto drop;
4315
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004316 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004317 goto drop;
4318
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004319 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004320 goto done;
4321
4322drop:
4323 kfree_skb(skb);
4324
4325done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004326 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004327 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004328 return 0;
4329}
4330
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004331static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4332{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004333 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004334 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004335
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004336 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4337 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004338 goto drop;
4339
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004340 sk = chan->sk;
4341
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004342 lock_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004343
4344 BT_DBG("sk %p, len %d", sk, skb->len);
4345
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004346 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004347 goto drop;
4348
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004349 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004350 goto drop;
4351
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004352 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004353 goto done;
4354
4355drop:
4356 kfree_skb(skb);
4357
4358done:
4359 if (sk)
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004360 release_sock(sk);
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004361 return 0;
4362}
4363
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4365{
4366 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004367 u16 cid, len;
4368 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004369
4370 skb_pull(skb, L2CAP_HDR_SIZE);
4371 cid = __le16_to_cpu(lh->cid);
4372 len = __le16_to_cpu(lh->len);
4373
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004374 if (len != skb->len) {
4375 kfree_skb(skb);
4376 return;
4377 }
4378
Linus Torvalds1da177e2005-04-16 15:20:36 -07004379 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4380
4381 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004382 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004383 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004384 l2cap_sig_channel(conn, skb);
4385 break;
4386
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004387 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004388 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389 skb_pull(skb, 2);
4390 l2cap_conless_channel(conn, psm, skb);
4391 break;
4392
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004393 case L2CAP_CID_LE_DATA:
4394 l2cap_att_channel(conn, cid, skb);
4395 break;
4396
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004397 case L2CAP_CID_SMP:
4398 if (smp_sig_channel(conn, skb))
4399 l2cap_conn_del(conn->hcon, EACCES);
4400 break;
4401
Linus Torvalds1da177e2005-04-16 15:20:36 -07004402 default:
4403 l2cap_data_channel(conn, cid, skb);
4404 break;
4405 }
4406}
4407
4408/* ---- L2CAP interface with lower layer (HCI) ---- */
4409
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004410int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004411{
4412 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004413 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4416
4417 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004418 read_lock(&chan_list_lock);
4419 list_for_each_entry(c, &chan_list, global_l) {
4420 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004421
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004422 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 continue;
4424
4425 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004426 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004427 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004428 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004430 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4431 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004432 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004433 lm2 |= HCI_LM_MASTER;
4434 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004435 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004436 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004437
4438 return exact ? lm1 : lm2;
4439}
4440
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004441int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004442{
Marcel Holtmann01394182006-07-03 10:02:46 +02004443 struct l2cap_conn *conn;
4444
Linus Torvalds1da177e2005-04-16 15:20:36 -07004445 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4446
Linus Torvalds1da177e2005-04-16 15:20:36 -07004447 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004448 conn = l2cap_conn_add(hcon, status);
4449 if (conn)
4450 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004451 } else
Joe Perchese1750722011-06-29 18:18:29 -07004452 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004453
4454 return 0;
4455}
4456
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004457int l2cap_disconn_ind(struct hci_conn *hcon)
Marcel Holtmann2950f212009-02-12 14:02:50 +01004458{
4459 struct l2cap_conn *conn = hcon->l2cap_data;
4460
4461 BT_DBG("hcon %p", hcon);
4462
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004463 if (!conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004464 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004465 return conn->disc_reason;
4466}
4467
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004468int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004469{
4470 BT_DBG("hcon %p reason %d", hcon, reason);
4471
Joe Perchese1750722011-06-29 18:18:29 -07004472 l2cap_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004473 return 0;
4474}
4475
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004476static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004477{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004478 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004479 return;
4480
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004481 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004482 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004483 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004484 __set_chan_timer(chan,
4485 msecs_to_jiffies(L2CAP_ENC_TIMEOUT));
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004486 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004487 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004488 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004489 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004490 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004491 }
4492}
4493
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004494int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004496 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004497 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498
Marcel Holtmann01394182006-07-03 10:02:46 +02004499 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004500 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004501
Linus Torvalds1da177e2005-04-16 15:20:36 -07004502 BT_DBG("conn %p", conn);
4503
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004504 if (hcon->type == LE_LINK) {
4505 smp_distribute_keys(conn, 0);
Ulisses Furquim371fd832011-12-21 20:02:36 -02004506 __cancel_delayed_work(&conn->security_timer);
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004507 }
4508
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004509 rcu_read_lock();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004510
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004511 list_for_each_entry_rcu(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004512 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004513
Linus Torvalds1da177e2005-04-16 15:20:36 -07004514 bh_lock_sock(sk);
4515
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004516 BT_DBG("chan->scid %d", chan->scid);
4517
4518 if (chan->scid == L2CAP_CID_LE_DATA) {
4519 if (!status && encrypt) {
4520 chan->sec_level = hcon->sec_level;
4521 l2cap_chan_ready(sk);
4522 }
4523
4524 bh_unlock_sock(sk);
4525 continue;
4526 }
4527
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004528 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004529 bh_unlock_sock(sk);
4530 continue;
4531 }
4532
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004533 if (!status && (chan->state == BT_CONNECTED ||
4534 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004535 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004536 bh_unlock_sock(sk);
4537 continue;
4538 }
4539
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004540 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004541 if (!status) {
4542 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004543 req.scid = cpu_to_le16(chan->scid);
4544 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004545
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004546 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004547 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004548
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004549 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004550 L2CAP_CONN_REQ, sizeof(req), &req);
4551 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004552 __clear_chan_timer(chan);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004553 __set_chan_timer(chan,
4554 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004555 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004556 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004557 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004558 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004559
4560 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004561 if (bt_sk(sk)->defer_setup) {
4562 struct sock *parent = bt_sk(sk)->parent;
4563 res = L2CAP_CR_PEND;
4564 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004565 if (parent)
4566 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004567 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004568 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004569 res = L2CAP_CR_SUCCESS;
4570 stat = L2CAP_CS_NO_INFO;
4571 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004572 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004573 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekb83ddfe2012-01-04 12:10:42 +01004574 __set_chan_timer(chan,
4575 msecs_to_jiffies(L2CAP_DISC_TIMEOUT));
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004576 res = L2CAP_CR_SEC_BLOCK;
4577 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004578 }
4579
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004580 rsp.scid = cpu_to_le16(chan->dcid);
4581 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004582 rsp.result = cpu_to_le16(res);
4583 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004584 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4585 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 }
4587
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588 bh_unlock_sock(sk);
4589 }
4590
Gustavo F. Padovan3d57dc62011-12-17 10:56:45 -02004591 rcu_read_unlock();
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004592
Linus Torvalds1da177e2005-04-16 15:20:36 -07004593 return 0;
4594}
4595
Ulisses Furquim686ebf22011-12-21 10:11:33 -02004596int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004597{
4598 struct l2cap_conn *conn = hcon->l2cap_data;
4599
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004600 if (!conn)
4601 conn = l2cap_conn_add(hcon, 0);
4602
4603 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004604 goto drop;
4605
4606 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4607
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004608 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004609 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004610 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004611 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004612 int len;
4613
4614 if (conn->rx_len) {
4615 BT_ERR("Unexpected start frame (len %d)", skb->len);
4616 kfree_skb(conn->rx_skb);
4617 conn->rx_skb = NULL;
4618 conn->rx_len = 0;
4619 l2cap_conn_unreliable(conn, ECOMM);
4620 }
4621
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004622 /* Start fragment always begin with Basic L2CAP header */
4623 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004624 BT_ERR("Frame is too short (len %d)", skb->len);
4625 l2cap_conn_unreliable(conn, ECOMM);
4626 goto drop;
4627 }
4628
4629 hdr = (struct l2cap_hdr *) skb->data;
4630 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004631 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632
4633 if (len == skb->len) {
4634 /* Complete frame received */
4635 l2cap_recv_frame(conn, skb);
4636 return 0;
4637 }
4638
4639 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4640
4641 if (skb->len > len) {
4642 BT_ERR("Frame is too long (len %d, expected len %d)",
4643 skb->len, len);
4644 l2cap_conn_unreliable(conn, ECOMM);
4645 goto drop;
4646 }
4647
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004648 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004649
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004650 if (chan && chan->sk) {
4651 struct sock *sk = chan->sk;
4652
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004653 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004654 BT_ERR("Frame exceeding recv MTU (len %d, "
4655 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004656 chan->imtu);
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004657 release_sock(sk);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004658 l2cap_conn_unreliable(conn, ECOMM);
4659 goto drop;
4660 }
Gustavo F. Padovanaa2ac882011-06-24 01:53:01 -03004661 release_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004662 }
4663
Linus Torvalds1da177e2005-04-16 15:20:36 -07004664 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004665 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4666 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 goto drop;
4668
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004669 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004670 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004671 conn->rx_len = len - skb->len;
4672 } else {
4673 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4674
4675 if (!conn->rx_len) {
4676 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4677 l2cap_conn_unreliable(conn, ECOMM);
4678 goto drop;
4679 }
4680
4681 if (skb->len > conn->rx_len) {
4682 BT_ERR("Fragment is too long (len %d, expected %d)",
4683 skb->len, conn->rx_len);
4684 kfree_skb(conn->rx_skb);
4685 conn->rx_skb = NULL;
4686 conn->rx_len = 0;
4687 l2cap_conn_unreliable(conn, ECOMM);
4688 goto drop;
4689 }
4690
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004691 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004692 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693 conn->rx_len -= skb->len;
4694
4695 if (!conn->rx_len) {
4696 /* Complete frame received */
4697 l2cap_recv_frame(conn, conn->rx_skb);
4698 conn->rx_skb = NULL;
4699 }
4700 }
4701
4702drop:
4703 kfree_skb(skb);
4704 return 0;
4705}
4706
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004707static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004708{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004709 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004711 read_lock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004712
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004713 list_for_each_entry(c, &chan_list, global_l) {
4714 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004715
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004716 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 +01004717 batostr(&bt_sk(sk)->src),
4718 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004719 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004720 c->scid, c->dcid, c->imtu, c->omtu,
4721 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004722}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723
Gustavo F. Padovan333055f2011-12-22 15:14:39 -02004724 read_unlock(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004725
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004726 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004727}
4728
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004729static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4730{
4731 return single_open(file, l2cap_debugfs_show, inode->i_private);
4732}
4733
4734static const struct file_operations l2cap_debugfs_fops = {
4735 .open = l2cap_debugfs_open,
4736 .read = seq_read,
4737 .llseek = seq_lseek,
4738 .release = single_release,
4739};
4740
4741static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004743int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744{
4745 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004746
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004747 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748 if (err < 0)
4749 return err;
4750
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004751 if (bt_debugfs) {
4752 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4753 bt_debugfs, NULL, &l2cap_debugfs_fops);
4754 if (!l2cap_debugfs)
4755 BT_ERR("Failed to create L2CAP debug file");
4756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759}
4760
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004761void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004763 debugfs_remove(l2cap_debugfs);
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004764 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765}
4766
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004767module_param(disable_ertm, bool, 0644);
4768MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");