blob: 7c746ec85143df17c570322603e7f9af5005f74b [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
Gustavo F. Padovance5706b2010-07-13 11:57:11 -03004 Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
Gustavo F. Padovan5d8868f2010-07-16 16:18:39 -03005 Copyright (C) 2010 Google Inc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006
7 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation;
12
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
16 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090017 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
18 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070020 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090022 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
23 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 SOFTWARE IS DISCLAIMED.
25*/
26
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020027/* Bluetooth L2CAP core. */
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/module.h>
30
31#include <linux/types.h>
Randy Dunlap4fc268d2006-01-11 12:17:47 -080032#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/errno.h>
34#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/sched.h>
36#include <linux/slab.h>
37#include <linux/poll.h>
38#include <linux/fcntl.h>
39#include <linux/init.h>
40#include <linux/interrupt.h>
41#include <linux/socket.h>
42#include <linux/skbuff.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080044#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010045#include <linux/debugfs.h>
46#include <linux/seq_file.h>
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -030047#include <linux/uaccess.h>
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -030048#include <linux/crc16.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <net/sock.h>
50
51#include <asm/system.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070052#include <asm/unaligned.h>
53
54#include <net/bluetooth/bluetooth.h>
55#include <net/bluetooth/hci_core.h>
56#include <net/bluetooth/l2cap.h>
Anderson Brigliab501d6a2011-06-07 18:46:31 -030057#include <net/bluetooth/smp.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -020059int disable_ertm;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +030060int enable_hs;
Marcel Holtmannf0709e02007-10-20 13:38:51 +020061
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -070062static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
Mat Martineau50a147c2011-11-02 16:18:34 -070063static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
Johannes Bergb5ad8b72011-06-01 08:54:45 +020065static LIST_HEAD(chan_list);
66static DEFINE_RWLOCK(chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067
Linus Torvalds1da177e2005-04-16 15:20:36 -070068static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
69 u8 code, u8 ident, u16 dlen, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030070static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
71 void *data);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -030072static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -030073static void l2cap_send_disconn_req(struct l2cap_conn *conn,
74 struct l2cap_chan *chan, int err);
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -030076static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
77
Marcel Holtmann01394182006-07-03 10:02:46 +020078/* ---- L2CAP channels ---- */
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -030079
80static inline void chan_hold(struct l2cap_chan *c)
81{
82 atomic_inc(&c->refcnt);
83}
84
85static inline void chan_put(struct l2cap_chan *c)
86{
87 if (atomic_dec_and_test(&c->refcnt))
88 kfree(c);
89}
90
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030091static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +020092{
Gustavo F. Padovan48454072011-03-25 00:22:30 -030093 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030094
95 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -030096 if (c->dcid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030097 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +020098 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -030099 return NULL;
100
Marcel Holtmann01394182006-07-03 10:02:46 +0200101}
102
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300103static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200104{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300105 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300106
107 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300108 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300109 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200110 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300111 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200112}
113
114/* Find channel with given SCID.
115 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300116static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200117{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300118 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300119
120 read_lock(&conn->chan_lock);
121 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300122 if (c)
123 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300124 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300125 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200126}
127
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300128static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200129{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300130 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300131
132 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300133 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300134 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200135 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300136 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200137}
138
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300139static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200140{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300141 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300142
143 read_lock(&conn->chan_lock);
144 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300145 if (c)
146 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300147 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300148 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200149}
150
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300151static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300152{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300153 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300154
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300155 list_for_each_entry(c, &chan_list, global_l) {
156 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100157 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300158 }
Szymon Janc250938c2011-11-16 09:32:22 +0100159 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300160}
161
162int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
163{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300164 int err;
165
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300166 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300167
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300168 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300169 err = -EADDRINUSE;
170 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300171 }
172
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300173 if (psm) {
174 chan->psm = psm;
175 chan->sport = psm;
176 err = 0;
177 } else {
178 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300179
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300180 err = -EINVAL;
181 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300182 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300183 chan->psm = cpu_to_le16(p);
184 chan->sport = cpu_to_le16(p);
185 err = 0;
186 break;
187 }
188 }
189
190done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300191 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300192 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300193}
194
195int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
196{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300197 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300198
199 chan->scid = scid;
200
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300201 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300202
203 return 0;
204}
205
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300206static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200207{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300208 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200209
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300210 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300211 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200212 return cid;
213 }
214
215 return 0;
216}
217
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300218static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300219{
Andrei Emeltchenko457f4852011-10-31 16:17:21 +0200220 BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300221
Mat Martineau942ecc92011-06-29 14:35:21 -0700222 if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
Mat Martineau774e5652011-06-29 14:35:20 -0700223 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300224}
225
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300226static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300227{
Mat Martineau774e5652011-06-29 14:35:20 -0700228 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300229
Mat Martineau774e5652011-06-29 14:35:20 -0700230 if (timer_pending(timer) && del_timer(timer))
231 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300232}
233
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300234static void l2cap_state_change(struct l2cap_chan *chan, int state)
235{
236 chan->state = state;
237 chan->ops->state_change(chan->data, state);
238}
239
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300240static void l2cap_chan_timeout(unsigned long arg)
241{
242 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
243 struct sock *sk = chan->sk;
244 int reason;
245
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300246 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300247
248 bh_lock_sock(sk);
249
250 if (sock_owned_by_user(sk)) {
251 /* sk is owned by user. Try again later */
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -0200252 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300253 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300254 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300255 return;
256 }
257
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300258 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300259 reason = ECONNREFUSED;
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300260 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300261 chan->sec_level != BT_SECURITY_SDP)
262 reason = ECONNREFUSED;
263 else
264 reason = ETIMEDOUT;
265
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300266 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300267
268 bh_unlock_sock(sk);
269
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300270 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300271 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300272}
273
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300274struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200275{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300276 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200277
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300278 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
279 if (!chan)
280 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200281
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300282 chan->sk = sk;
283
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300284 write_lock_bh(&chan_list_lock);
285 list_add(&chan->global_l, &chan_list);
286 write_unlock_bh(&chan_list_lock);
287
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300288 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
289
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300290 chan->state = BT_OPEN;
291
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300292 atomic_set(&chan->refcnt, 1);
293
Szymon Jancabc545b2011-11-03 16:05:44 +0100294 BT_DBG("sk %p chan %p", sk, chan);
295
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300296 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200297}
298
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300299void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300300{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300301 write_lock_bh(&chan_list_lock);
302 list_del(&chan->global_l);
303 write_unlock_bh(&chan_list_lock);
304
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300305 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300306}
307
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300308static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200309{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300310 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300311 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200312
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200313 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100314
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300315 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200316
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300317 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300318 if (conn->hcon->type == LE_LINK) {
319 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300320 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300321 chan->scid = L2CAP_CID_LE_DATA;
322 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300323 } else {
324 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300325 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300326 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300327 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300328 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200329 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300330 chan->scid = L2CAP_CID_CONN_LESS;
331 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300332 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200333 } else {
334 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300335 chan->scid = L2CAP_CID_SIGNALING;
336 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300337 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200338 }
339
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300340 chan->local_id = L2CAP_BESTEFFORT_ID;
341 chan->local_stype = L2CAP_SERV_BESTEFFORT;
342 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
343 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
344 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
345 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
346
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300347 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300348
349 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200350}
351
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900352/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200353 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300354static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200355{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300356 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300357 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200358 struct sock *parent = bt_sk(sk)->parent;
359
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300360 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200361
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300362 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200363
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900364 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300365 /* Delete from channel list */
366 write_lock_bh(&conn->chan_lock);
367 list_del(&chan->list);
368 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300369 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300370
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300371 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200372 hci_conn_put(conn->hcon);
373 }
374
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300375 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200376 sock_set_flag(sk, SOCK_ZAPPED);
377
378 if (err)
379 sk->sk_err = err;
380
381 if (parent) {
382 bt_accept_unlink(sk);
383 parent->sk_data_ready(parent, 0);
384 } else
385 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300386
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300387 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
388 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300389 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300390
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300391 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300392
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300393 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300394 struct srej_list *l, *tmp;
395
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300396 __clear_retrans_timer(chan);
397 __clear_monitor_timer(chan);
398 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300399
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300400 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300401
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300402 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300403 list_del(&l->list);
404 kfree(l);
405 }
406 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200407}
408
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300409static void l2cap_chan_cleanup_listen(struct sock *parent)
410{
411 struct sock *sk;
412
413 BT_DBG("parent %p", parent);
414
415 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300416 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300417 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300418 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300419 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300420 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300421 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300422 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300423 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300424}
425
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300426void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300427{
428 struct l2cap_conn *conn = chan->conn;
429 struct sock *sk = chan->sk;
430
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300431 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300432
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300433 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300434 case BT_LISTEN:
435 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300436
437 l2cap_state_change(chan, BT_CLOSED);
438 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300439 break;
440
441 case BT_CONNECTED:
442 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300443 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300444 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300445 __clear_chan_timer(chan);
446 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300447 l2cap_send_disconn_req(conn, chan, reason);
448 } else
449 l2cap_chan_del(chan, reason);
450 break;
451
452 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300453 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300454 conn->hcon->type == ACL_LINK) {
455 struct l2cap_conn_rsp rsp;
456 __u16 result;
457
458 if (bt_sk(sk)->defer_setup)
459 result = L2CAP_CR_SEC_BLOCK;
460 else
461 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300462 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300463
464 rsp.scid = cpu_to_le16(chan->dcid);
465 rsp.dcid = cpu_to_le16(chan->scid);
466 rsp.result = cpu_to_le16(result);
467 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
468 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
469 sizeof(rsp), &rsp);
470 }
471
472 l2cap_chan_del(chan, reason);
473 break;
474
475 case BT_CONNECT:
476 case BT_DISCONN:
477 l2cap_chan_del(chan, reason);
478 break;
479
480 default:
481 sock_set_flag(sk, SOCK_ZAPPED);
482 break;
483 }
484}
485
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300486static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530487{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300488 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300489 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530490 case BT_SECURITY_HIGH:
491 return HCI_AT_DEDICATED_BONDING_MITM;
492 case BT_SECURITY_MEDIUM:
493 return HCI_AT_DEDICATED_BONDING;
494 default:
495 return HCI_AT_NO_BONDING;
496 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300497 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300498 if (chan->sec_level == BT_SECURITY_LOW)
499 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530500
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300501 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530502 return HCI_AT_NO_BONDING_MITM;
503 else
504 return HCI_AT_NO_BONDING;
505 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300506 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530507 case BT_SECURITY_HIGH:
508 return HCI_AT_GENERAL_BONDING_MITM;
509 case BT_SECURITY_MEDIUM:
510 return HCI_AT_GENERAL_BONDING;
511 default:
512 return HCI_AT_NO_BONDING;
513 }
514 }
515}
516
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200517/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200518int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200519{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300520 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100521 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200522
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300523 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100524
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300525 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200526}
527
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200528static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200529{
530 u8 id;
531
532 /* Get next available identificator.
533 * 1 - 128 are used by kernel.
534 * 129 - 199 are reserved.
535 * 200 - 254 are used by utilities like l2ping, etc.
536 */
537
538 spin_lock_bh(&conn->lock);
539
540 if (++conn->tx_ident > 128)
541 conn->tx_ident = 1;
542
543 id = conn->tx_ident;
544
545 spin_unlock_bh(&conn->lock);
546
547 return id;
548}
549
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300550static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200551{
552 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200553 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200554
555 BT_DBG("code 0x%2.2x", code);
556
557 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300558 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200559
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200560 if (lmp_no_flush_capable(conn->hcon->hdev))
561 flags = ACL_START_NO_FLUSH;
562 else
563 flags = ACL_START;
564
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700565 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200566 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700567
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200568 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200569}
570
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200571static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
572{
573 struct hci_conn *hcon = chan->conn->hcon;
574 u16 flags;
575
576 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
577 skb->priority);
578
579 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
580 lmp_no_flush_capable(hcon->hdev))
581 flags = ACL_START_NO_FLUSH;
582 else
583 flags = ACL_START;
584
585 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
586 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587}
588
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300589static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300590{
591 struct sk_buff *skb;
592 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300593 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300594 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300595
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300596 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300597 return;
598
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300599 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
600 hlen = L2CAP_EXT_HDR_SIZE;
601 else
602 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300603
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300604 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300605 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300606
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300607 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300608
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300609 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300610
611 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300612
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300613 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300614 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300615
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300616 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300617 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300618
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300619 skb = bt_skb_alloc(count, GFP_ATOMIC);
620 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300621 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300622
623 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300624 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300625 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300626
627 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300628
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300629 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300630 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
631 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300632 }
633
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200634 skb->priority = HCI_PRIO_MAX;
635 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300636}
637
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300638static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300639{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300640 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300641 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300642 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300643 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300644 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300645
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300646 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300647
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300648 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300649}
650
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300651static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300652{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300653 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300654}
655
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300656static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200657{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300658 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200659
660 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100661 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
662 return;
663
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200664 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300665 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200666 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300667 req.scid = cpu_to_le16(chan->scid);
668 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200669
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300670 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300671 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200672
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300673 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
674 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200675 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200676 } else {
677 struct l2cap_info_req req;
678 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
679
680 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
681 conn->info_ident = l2cap_get_ident(conn);
682
683 mod_timer(&conn->info_timer, jiffies +
684 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
685
686 l2cap_send_cmd(conn, conn->info_ident,
687 L2CAP_INFO_REQ, sizeof(req), &req);
688 }
689}
690
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300691static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
692{
693 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300694 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300695 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
696
697 switch (mode) {
698 case L2CAP_MODE_ERTM:
699 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
700 case L2CAP_MODE_STREAMING:
701 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
702 default:
703 return 0x00;
704 }
705}
706
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300707static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300708{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300709 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300710 struct l2cap_disconn_req req;
711
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300712 if (!conn)
713 return;
714
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300715 sk = chan->sk;
716
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300717 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300718 __clear_retrans_timer(chan);
719 __clear_monitor_timer(chan);
720 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300721 }
722
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300723 req.dcid = cpu_to_le16(chan->dcid);
724 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300725 l2cap_send_cmd(conn, l2cap_get_ident(conn),
726 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300727
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300728 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300729 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300730}
731
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200733static void l2cap_conn_start(struct l2cap_conn *conn)
734{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300735 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200736
737 BT_DBG("conn %p", conn);
738
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300739 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200740
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300741 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300742 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300743
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200744 bh_lock_sock(sk);
745
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300746 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200747 bh_unlock_sock(sk);
748 continue;
749 }
750
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300751 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300752 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300753
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200754 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300755 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300756 bh_unlock_sock(sk);
757 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200758 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300759
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300760 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
761 && test_bit(CONF_STATE2_DEVICE,
762 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300763 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300764 * so release the lock */
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300765 read_unlock(&conn->chan_lock);
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300766 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300767 read_lock(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300768 bh_unlock_sock(sk);
769 continue;
770 }
771
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300772 req.scid = cpu_to_le16(chan->scid);
773 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300774
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300775 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300776 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300777
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300778 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
779 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300780
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300781 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200782 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300783 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300784 rsp.scid = cpu_to_le16(chan->dcid);
785 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200786
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200787 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100788 if (bt_sk(sk)->defer_setup) {
789 struct sock *parent = bt_sk(sk)->parent;
790 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
791 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000792 if (parent)
793 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100794
795 } else {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300796 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100797 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
798 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
799 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200800 } else {
801 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
802 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
803 }
804
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300805 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
806 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300807
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300808 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300809 rsp.result != L2CAP_CR_SUCCESS) {
810 bh_unlock_sock(sk);
811 continue;
812 }
813
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300814 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300815 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300816 l2cap_build_conf_req(chan, buf), buf);
817 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200818 }
819
820 bh_unlock_sock(sk);
821 }
822
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300823 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200824}
825
Ville Tervob62f3282011-02-10 22:38:50 -0300826/* Find socket with cid and source bdaddr.
827 * Returns closest match, locked.
828 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300829static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300830{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300831 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300832
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300833 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300834
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300835 list_for_each_entry(c, &chan_list, global_l) {
836 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300837
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300838 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300839 continue;
840
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300841 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300842 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300843 if (!bacmp(&bt_sk(sk)->src, src)) {
844 read_unlock(&chan_list_lock);
845 return c;
846 }
Ville Tervob62f3282011-02-10 22:38:50 -0300847
848 /* Closest match */
849 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300850 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300851 }
852 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300853
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300854 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300855
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300856 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300857}
858
859static void l2cap_le_conn_ready(struct l2cap_conn *conn)
860{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300861 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300862 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300863
864 BT_DBG("");
865
866 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300867 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300868 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300869 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300870 return;
871
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300872 parent = pchan->sk;
873
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300874 bh_lock_sock(parent);
875
Ville Tervob62f3282011-02-10 22:38:50 -0300876 /* Check for backlog size */
877 if (sk_acceptq_is_full(parent)) {
878 BT_DBG("backlog full %d", parent->sk_ack_backlog);
879 goto clean;
880 }
881
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300882 chan = pchan->ops->new_connection(pchan->data);
883 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300884 goto clean;
885
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300886 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300887
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300888 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300889
890 hci_conn_hold(conn->hcon);
891
Ville Tervob62f3282011-02-10 22:38:50 -0300892 bacpy(&bt_sk(sk)->src, conn->src);
893 bacpy(&bt_sk(sk)->dst, conn->dst);
894
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300895 bt_accept_enqueue(parent, sk);
896
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300897 __l2cap_chan_add(conn, chan);
898
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300899 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300900
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300901 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300902 parent->sk_data_ready(parent, 0);
903
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300904 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300905
906clean:
907 bh_unlock_sock(parent);
908}
909
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300910static void l2cap_chan_ready(struct sock *sk)
911{
912 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
913 struct sock *parent = bt_sk(sk)->parent;
914
915 BT_DBG("sk %p, parent %p", sk, parent);
916
917 chan->conf_state = 0;
918 __clear_chan_timer(chan);
919
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300920 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300921 sk->sk_state_change(sk);
922
923 if (parent)
924 parent->sk_data_ready(parent, 0);
925}
926
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200927static void l2cap_conn_ready(struct l2cap_conn *conn)
928{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300929 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200930
931 BT_DBG("conn %p", conn);
932
Ville Tervob62f3282011-02-10 22:38:50 -0300933 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
934 l2cap_le_conn_ready(conn);
935
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300936 if (conn->hcon->out && conn->hcon->type == LE_LINK)
937 smp_conn_security(conn, conn->hcon->pending_sec_level);
938
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300939 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200940
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300941 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300942 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300943
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200944 bh_lock_sock(sk);
945
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300946 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300947 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300948 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300949
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300950 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300951 __clear_chan_timer(chan);
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300952 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200953 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300954
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -0300955 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300956 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200957
958 bh_unlock_sock(sk);
959 }
960
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300961 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200962}
963
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200964/* Notify sockets that we cannot guaranty reliability anymore */
965static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
966{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300967 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200968
969 BT_DBG("conn %p", conn);
970
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300971 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200972
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300973 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300974 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300975
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300976 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200977 sk->sk_err = err;
978 }
979
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300980 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200981}
982
983static void l2cap_info_timeout(unsigned long arg)
984{
985 struct l2cap_conn *conn = (void *) arg;
986
Marcel Holtmann984947d2009-02-06 23:35:19 +0100987 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100988 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100989
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200990 l2cap_conn_start(conn);
991}
992
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300993static void l2cap_conn_del(struct hci_conn *hcon, int err)
994{
995 struct l2cap_conn *conn = hcon->l2cap_data;
996 struct l2cap_chan *chan, *l;
997 struct sock *sk;
998
999 if (!conn)
1000 return;
1001
1002 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1003
1004 kfree_skb(conn->rx_skb);
1005
1006 /* Kill channels */
1007 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1008 sk = chan->sk;
1009 bh_lock_sock(sk);
1010 l2cap_chan_del(chan, err);
1011 bh_unlock_sock(sk);
1012 chan->ops->close(chan->data);
1013 }
1014
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001015 hci_chan_del(conn->hchan);
1016
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001017 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1018 del_timer_sync(&conn->info_timer);
1019
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001020 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001021 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001022 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001023 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001024
1025 hcon->l2cap_data = NULL;
1026 kfree(conn);
1027}
1028
1029static void security_timeout(unsigned long arg)
1030{
1031 struct l2cap_conn *conn = (void *) arg;
1032
1033 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1034}
1035
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1037{
Marcel Holtmann01394182006-07-03 10:02:46 +02001038 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001039 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001040
Marcel Holtmann01394182006-07-03 10:02:46 +02001041 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 return conn;
1043
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001044 hchan = hci_chan_create(hcon);
1045 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001048 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1049 if (!conn) {
1050 hci_chan_del(hchan);
1051 return NULL;
1052 }
1053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 hcon->l2cap_data = conn;
1055 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001056 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001058 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001059
Ville Tervoacd7d372011-02-10 22:38:49 -03001060 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1061 conn->mtu = hcon->hdev->le_mtu;
1062 else
1063 conn->mtu = hcon->hdev->acl_mtu;
1064
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065 conn->src = &hcon->hdev->bdaddr;
1066 conn->dst = &hcon->dst;
1067
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001068 conn->feat_mask = 0;
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001071 rwlock_init(&conn->chan_lock);
1072
1073 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001074
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001075 if (hcon->type == LE_LINK)
1076 setup_timer(&conn->security_timer, security_timeout,
1077 (unsigned long) conn);
1078 else
Ville Tervob62f3282011-02-10 22:38:50 -03001079 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001080 (unsigned long) conn);
1081
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001082 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001083
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 return conn;
1085}
1086
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001087static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001089 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001090 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001091 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092}
1093
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096/* Find socket with psm and source bdaddr.
1097 * Returns closest match.
1098 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001099static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001100{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001101 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001103 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001104
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001105 list_for_each_entry(c, &chan_list, global_l) {
1106 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001107
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03001108 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001109 continue;
1110
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001111 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001113 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001114 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001115 return c;
1116 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
1118 /* Closest match */
1119 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001120 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001124 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001125
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001126 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127}
1128
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001129int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001131 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132 bdaddr_t *src = &bt_sk(sk)->src;
1133 bdaddr_t *dst = &bt_sk(sk)->dst;
1134 struct l2cap_conn *conn;
1135 struct hci_conn *hcon;
1136 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001137 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001138 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001140 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001141 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001143 hdev = hci_get_route(dst, src);
1144 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001145 return -EHOSTUNREACH;
1146
1147 hci_dev_lock_bh(hdev);
1148
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001149 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001150
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001151 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001152 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001153 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001154 else
1155 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001156 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001157
Ville Tervo30e76272011-02-22 16:10:53 -03001158 if (IS_ERR(hcon)) {
1159 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001160 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001161 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001162
1163 conn = l2cap_conn_add(hcon, 0);
1164 if (!conn) {
1165 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001166 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 goto done;
1168 }
1169
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 /* Update source addr of the socket */
1171 bacpy(src, conn->src);
1172
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001173 l2cap_chan_add(conn, chan);
1174
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03001175 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001176 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001177
1178 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001179 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001180 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001181 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03001182 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001183 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001184 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185 }
1186
Ville Tervo30e76272011-02-22 16:10:53 -03001187 err = 0;
1188
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189done:
1190 hci_dev_unlock_bh(hdev);
1191 hci_dev_put(hdev);
1192 return err;
1193}
1194
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001195int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001196{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001197 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001198 DECLARE_WAITQUEUE(wait, current);
1199 int err = 0;
1200 int timeo = HZ/5;
1201
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001202 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001203 set_current_state(TASK_INTERRUPTIBLE);
1204 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001205 if (!timeo)
1206 timeo = HZ/5;
1207
1208 if (signal_pending(current)) {
1209 err = sock_intr_errno(timeo);
1210 break;
1211 }
1212
1213 release_sock(sk);
1214 timeo = schedule_timeout(timeo);
1215 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001216 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001217
1218 err = sock_error(sk);
1219 if (err)
1220 break;
1221 }
1222 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001223 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001224 return err;
1225}
1226
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001227static void l2cap_monitor_timeout(unsigned long arg)
1228{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001229 struct l2cap_chan *chan = (void *) arg;
1230 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001231
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001232 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001233
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001234 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001235 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001236 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001237 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001238 return;
1239 }
1240
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001241 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001242 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001243
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001244 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001245 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001246}
1247
1248static void l2cap_retrans_timeout(unsigned long arg)
1249{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001250 struct l2cap_chan *chan = (void *) arg;
1251 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001252
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001253 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001254
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001255 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001256 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001257 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001258
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001259 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001260
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001261 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001262 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001263}
1264
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001265static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001266{
1267 struct sk_buff *skb;
1268
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001269 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001270 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001271 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001272 break;
1273
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001274 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001275 kfree_skb(skb);
1276
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001277 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001278 }
1279
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001280 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001281 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001282}
1283
Szymon Janc67c9e842011-07-28 16:24:33 +02001284static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001285{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001286 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001287 u32 control;
1288 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001289
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001290 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001291 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001292 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001293 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001294
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001295 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001296 fcs = crc16(0, (u8 *)skb->data,
1297 skb->len - L2CAP_FCS_SIZE);
1298 put_unaligned_le16(fcs,
1299 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001300 }
1301
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001302 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001303
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001304 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001305 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001306}
1307
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001308static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001309{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001310 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001311 u16 fcs;
1312 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001313
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001314 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001315 if (!skb)
1316 return;
1317
Szymon Jancd1726b62011-11-16 09:32:20 +01001318 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001319 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001320 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001321
Szymon Jancd1726b62011-11-16 09:32:20 +01001322 skb = skb_queue_next(&chan->tx_q, skb);
1323 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001324
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001325 if (chan->remote_max_tx &&
1326 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001327 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001328 return;
1329 }
1330
1331 tx_skb = skb_clone(skb, GFP_ATOMIC);
1332 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001333
1334 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001335 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001336
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001337 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001338 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001339
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001340 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001341 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001342
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001343 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -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 *)tx_skb->data,
1347 tx_skb->len - L2CAP_FCS_SIZE);
1348 put_unaligned_le16(fcs,
1349 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001350 }
1351
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001352 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001353}
1354
Szymon Janc67c9e842011-07-28 16:24:33 +02001355static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001356{
1357 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001358 u16 fcs;
1359 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001360 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001361
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03001362 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001363 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001364
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001365 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001366
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001367 if (chan->remote_max_tx &&
1368 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001369 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001370 break;
1371 }
1372
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001373 tx_skb = skb_clone(skb, GFP_ATOMIC);
1374
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001375 bt_cb(skb)->retries++;
1376
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001377 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001378 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001379
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001380 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001381 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001382
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001383 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001384 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001385
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001386 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001387
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001388 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001389 fcs = crc16(0, (u8 *)skb->data,
1390 tx_skb->len - L2CAP_FCS_SIZE);
1391 put_unaligned_le16(fcs, skb->data +
1392 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001393 }
1394
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001395 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001396
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001397 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001398
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001399 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001400
1401 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001402
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301403 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001404 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301405
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001406 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001407
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001408 if (skb_queue_is_last(&chan->tx_q, skb))
1409 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001410 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001411 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001412
1413 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001414 }
1415
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001416 return nsent;
1417}
1418
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001419static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001420{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001421 int ret;
1422
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001423 if (!skb_queue_empty(&chan->tx_q))
1424 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001425
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001426 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001427 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001428 return ret;
1429}
1430
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001431static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001432{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001433 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001434
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001435 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001436
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001437 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001438 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001439 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001440 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001441 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001442 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001443
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001444 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001445 return;
1446
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001447 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001448 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001449}
1450
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001451static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001452{
1453 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001454 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001455
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001456 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001457 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001458
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001459 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001460 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001461
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001462 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001463}
1464
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001465static 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 -07001466{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001467 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001468 struct sk_buff **frag;
1469 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001471 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001472 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001473
1474 sent += count;
1475 len -= count;
1476
1477 /* Continuation fragments (no L2CAP header) */
1478 frag = &skb_shinfo(skb)->frag_list;
1479 while (len) {
1480 count = min_t(unsigned int, conn->mtu, len);
1481
1482 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1483 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001484 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001485 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1486 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001487
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001488 (*frag)->priority = skb->priority;
1489
Linus Torvalds1da177e2005-04-16 15:20:36 -07001490 sent += count;
1491 len -= count;
1492
1493 frag = &(*frag)->next;
1494 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
1496 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001497}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001499static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1500 struct msghdr *msg, size_t len,
1501 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001502{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001503 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001504 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001505 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001506 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001507 struct l2cap_hdr *lh;
1508
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001509 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001510
1511 count = min_t(unsigned int, (conn->mtu - hlen), len);
1512 skb = bt_skb_send_alloc(sk, count + hlen,
1513 msg->msg_flags & MSG_DONTWAIT, &err);
1514 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001515 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001516
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001517 skb->priority = priority;
1518
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001519 /* Create L2CAP header */
1520 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001521 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001522 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001523 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001524
1525 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1526 if (unlikely(err < 0)) {
1527 kfree_skb(skb);
1528 return ERR_PTR(err);
1529 }
1530 return skb;
1531}
1532
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001533static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1534 struct msghdr *msg, size_t len,
1535 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001536{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001537 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001538 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001539 struct sk_buff *skb;
1540 int err, count, hlen = L2CAP_HDR_SIZE;
1541 struct l2cap_hdr *lh;
1542
1543 BT_DBG("sk %p len %d", sk, (int)len);
1544
1545 count = min_t(unsigned int, (conn->mtu - hlen), len);
1546 skb = bt_skb_send_alloc(sk, count + hlen,
1547 msg->msg_flags & MSG_DONTWAIT, &err);
1548 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001549 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001550
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001551 skb->priority = priority;
1552
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001553 /* Create L2CAP header */
1554 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001555 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001556 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1557
1558 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1559 if (unlikely(err < 0)) {
1560 kfree_skb(skb);
1561 return ERR_PTR(err);
1562 }
1563 return skb;
1564}
1565
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001566static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1567 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001568 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001569{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001570 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001571 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001572 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001573 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001574 struct l2cap_hdr *lh;
1575
1576 BT_DBG("sk %p len %d", sk, (int)len);
1577
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001578 if (!conn)
1579 return ERR_PTR(-ENOTCONN);
1580
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001581 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1582 hlen = L2CAP_EXT_HDR_SIZE;
1583 else
1584 hlen = L2CAP_ENH_HDR_SIZE;
1585
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001586 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001587 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001588
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001589 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001590 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001591
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001592 count = min_t(unsigned int, (conn->mtu - hlen), len);
1593 skb = bt_skb_send_alloc(sk, count + hlen,
1594 msg->msg_flags & MSG_DONTWAIT, &err);
1595 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001596 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001597
1598 /* Create L2CAP header */
1599 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001600 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001601 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001602
1603 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1604
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001605 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001606 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001607
1608 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1609 if (unlikely(err < 0)) {
1610 kfree_skb(skb);
1611 return ERR_PTR(err);
1612 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001613
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001614 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001615 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001616
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001617 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001618 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619}
1620
Szymon Janc67c9e842011-07-28 16:24:33 +02001621static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001622{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001623 struct sk_buff *skb;
1624 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001625 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001626 size_t size = 0;
1627
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001628 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001629 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001630 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001631 if (IS_ERR(skb))
1632 return PTR_ERR(skb);
1633
1634 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001635 len -= chan->remote_mps;
1636 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001637
1638 while (len > 0) {
1639 size_t buflen;
1640
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001641 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001642 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001643 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001644 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001645 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001646 buflen = len;
1647 }
1648
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001649 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001650 if (IS_ERR(skb)) {
1651 skb_queue_purge(&sar_queue);
1652 return PTR_ERR(skb);
1653 }
1654
1655 __skb_queue_tail(&sar_queue, skb);
1656 len -= buflen;
1657 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001658 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001659 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1660 if (chan->tx_send_head == NULL)
1661 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001662
1663 return size;
1664}
1665
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001666int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1667 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001668{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001669 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001670 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001671 int err;
1672
1673 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001674 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001675 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001676 if (IS_ERR(skb))
1677 return PTR_ERR(skb);
1678
1679 l2cap_do_send(chan, skb);
1680 return len;
1681 }
1682
1683 switch (chan->mode) {
1684 case L2CAP_MODE_BASIC:
1685 /* Check outgoing MTU */
1686 if (len > chan->omtu)
1687 return -EMSGSIZE;
1688
1689 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001690 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001691 if (IS_ERR(skb))
1692 return PTR_ERR(skb);
1693
1694 l2cap_do_send(chan, skb);
1695 err = len;
1696 break;
1697
1698 case L2CAP_MODE_ERTM:
1699 case L2CAP_MODE_STREAMING:
1700 /* Entire SDU fits into one PDU */
1701 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001702 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001703 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1704 0);
1705 if (IS_ERR(skb))
1706 return PTR_ERR(skb);
1707
1708 __skb_queue_tail(&chan->tx_q, skb);
1709
1710 if (chan->tx_send_head == NULL)
1711 chan->tx_send_head = skb;
1712
1713 } else {
1714 /* Segment SDU into multiples PDUs */
1715 err = l2cap_sar_segment_sdu(chan, msg, len);
1716 if (err < 0)
1717 return err;
1718 }
1719
1720 if (chan->mode == L2CAP_MODE_STREAMING) {
1721 l2cap_streaming_send(chan);
1722 err = len;
1723 break;
1724 }
1725
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001726 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1727 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001728 err = len;
1729 break;
1730 }
1731
1732 err = l2cap_ertm_send(chan);
1733 if (err >= 0)
1734 err = len;
1735
1736 break;
1737
1738 default:
1739 BT_DBG("bad state %1.1x", chan->mode);
1740 err = -EBADFD;
1741 }
1742
1743 return err;
1744}
1745
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746/* Copy frame to all raw sockets on that connection */
1747static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1748{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001749 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001750 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751
1752 BT_DBG("conn %p", conn);
1753
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001754 read_lock(&conn->chan_lock);
1755 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001756 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001757 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001758 continue;
1759
1760 /* Don't send frame to the socket it came from */
1761 if (skb->sk == sk)
1762 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001763 nskb = skb_clone(skb, GFP_ATOMIC);
1764 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001765 continue;
1766
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001767 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 kfree_skb(nskb);
1769 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001770 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771}
1772
1773/* ---- L2CAP signalling commands ---- */
1774static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1775 u8 code, u8 ident, u16 dlen, void *data)
1776{
1777 struct sk_buff *skb, **frag;
1778 struct l2cap_cmd_hdr *cmd;
1779 struct l2cap_hdr *lh;
1780 int len, count;
1781
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001782 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1783 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001784
1785 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1786 count = min_t(unsigned int, conn->mtu, len);
1787
1788 skb = bt_skb_alloc(count, GFP_ATOMIC);
1789 if (!skb)
1790 return NULL;
1791
1792 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001793 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001794
1795 if (conn->hcon->type == LE_LINK)
1796 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1797 else
1798 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799
1800 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1801 cmd->code = code;
1802 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001803 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001804
1805 if (dlen) {
1806 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1807 memcpy(skb_put(skb, count), data, count);
1808 data += count;
1809 }
1810
1811 len -= skb->len;
1812
1813 /* Continuation fragments (no L2CAP header) */
1814 frag = &skb_shinfo(skb)->frag_list;
1815 while (len) {
1816 count = min_t(unsigned int, conn->mtu, len);
1817
1818 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1819 if (!*frag)
1820 goto fail;
1821
1822 memcpy(skb_put(*frag, count), data, count);
1823
1824 len -= count;
1825 data += count;
1826
1827 frag = &(*frag)->next;
1828 }
1829
1830 return skb;
1831
1832fail:
1833 kfree_skb(skb);
1834 return NULL;
1835}
1836
1837static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1838{
1839 struct l2cap_conf_opt *opt = *ptr;
1840 int len;
1841
1842 len = L2CAP_CONF_OPT_SIZE + opt->len;
1843 *ptr += len;
1844
1845 *type = opt->type;
1846 *olen = opt->len;
1847
1848 switch (opt->len) {
1849 case 1:
1850 *val = *((u8 *) opt->val);
1851 break;
1852
1853 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001854 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001855 break;
1856
1857 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001858 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001859 break;
1860
1861 default:
1862 *val = (unsigned long) opt->val;
1863 break;
1864 }
1865
1866 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1867 return len;
1868}
1869
Linus Torvalds1da177e2005-04-16 15:20:36 -07001870static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1871{
1872 struct l2cap_conf_opt *opt = *ptr;
1873
1874 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1875
1876 opt->type = type;
1877 opt->len = len;
1878
1879 switch (len) {
1880 case 1:
1881 *((u8 *) opt->val) = val;
1882 break;
1883
1884 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001885 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 break;
1887
1888 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001889 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001890 break;
1891
1892 default:
1893 memcpy(opt->val, (void *) val, len);
1894 break;
1895 }
1896
1897 *ptr += L2CAP_CONF_OPT_SIZE + len;
1898}
1899
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001900static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1901{
1902 struct l2cap_conf_efs efs;
1903
1904 switch(chan->mode) {
1905 case L2CAP_MODE_ERTM:
1906 efs.id = chan->local_id;
1907 efs.stype = chan->local_stype;
1908 efs.msdu = cpu_to_le16(chan->local_msdu);
1909 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1910 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1911 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1912 break;
1913
1914 case L2CAP_MODE_STREAMING:
1915 efs.id = 1;
1916 efs.stype = L2CAP_SERV_BESTEFFORT;
1917 efs.msdu = cpu_to_le16(chan->local_msdu);
1918 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1919 efs.acc_lat = 0;
1920 efs.flush_to = 0;
1921 break;
1922
1923 default:
1924 return;
1925 }
1926
1927 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1928 (unsigned long) &efs);
1929}
1930
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001931static void l2cap_ack_timeout(unsigned long arg)
1932{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001933 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001934
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001935 bh_lock_sock(chan->sk);
1936 l2cap_send_ack(chan);
1937 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001938}
1939
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001940static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001941{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001942 struct sock *sk = chan->sk;
1943
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001944 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001945 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001946 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001947 chan->num_acked = 0;
1948 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001949
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001950 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1951 (unsigned long) chan);
1952 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1953 (unsigned long) chan);
1954 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001955
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001956 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001957
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001958 INIT_LIST_HEAD(&chan->srej_l);
1959
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001960
1961 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001962}
1963
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001964static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1965{
1966 switch (mode) {
1967 case L2CAP_MODE_STREAMING:
1968 case L2CAP_MODE_ERTM:
1969 if (l2cap_mode_supported(mode, remote_feat_mask))
1970 return mode;
1971 /* fall through */
1972 default:
1973 return L2CAP_MODE_BASIC;
1974 }
1975}
1976
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001977static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
1978{
1979 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
1980}
1981
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001982static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
1983{
1984 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
1985}
1986
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001987static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
1988{
1989 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001990 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001991 /* use extended control field */
1992 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001993 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
1994 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001995 chan->tx_win = min_t(u16, chan->tx_win,
1996 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001997 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
1998 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001999}
2000
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002001static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002003 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002004 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002006 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002008 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002010 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002011 goto done;
2012
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002013 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002014 case L2CAP_MODE_STREAMING:
2015 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002016 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002017 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002018
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002019 if (__l2cap_efs_supported(chan))
2020 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2021
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002022 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002023 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002024 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002025 break;
2026 }
2027
2028done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002029 if (chan->imtu != L2CAP_DEFAULT_MTU)
2030 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002031
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002032 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002033 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002034 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2035 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002036 break;
2037
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002038 rfc.mode = L2CAP_MODE_BASIC;
2039 rfc.txwin_size = 0;
2040 rfc.max_transmit = 0;
2041 rfc.retrans_timeout = 0;
2042 rfc.monitor_timeout = 0;
2043 rfc.max_pdu_size = 0;
2044
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002045 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2046 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002047 break;
2048
2049 case L2CAP_MODE_ERTM:
2050 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002051 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002052 rfc.retrans_timeout = 0;
2053 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002054
2055 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2056 L2CAP_EXT_HDR_SIZE -
2057 L2CAP_SDULEN_SIZE -
2058 L2CAP_FCS_SIZE);
2059 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002060
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002061 l2cap_txwin_setup(chan);
2062
2063 rfc.txwin_size = min_t(u16, chan->tx_win,
2064 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002065
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002066 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2067 (unsigned long) &rfc);
2068
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002069 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2070 l2cap_add_opt_efs(&ptr, chan);
2071
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002072 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002073 break;
2074
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002075 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002076 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002077 chan->fcs = L2CAP_FCS_NONE;
2078 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002079 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002080
2081 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2082 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2083 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002084 break;
2085
2086 case L2CAP_MODE_STREAMING:
2087 rfc.mode = L2CAP_MODE_STREAMING;
2088 rfc.txwin_size = 0;
2089 rfc.max_transmit = 0;
2090 rfc.retrans_timeout = 0;
2091 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002092
2093 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2094 L2CAP_EXT_HDR_SIZE -
2095 L2CAP_SDULEN_SIZE -
2096 L2CAP_FCS_SIZE);
2097 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002098
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002099 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2100 (unsigned long) &rfc);
2101
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002102 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2103 l2cap_add_opt_efs(&ptr, chan);
2104
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002105 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002106 break;
2107
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002108 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002109 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002110 chan->fcs = L2CAP_FCS_NONE;
2111 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002112 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002113 break;
2114 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002116 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002117 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118
2119 return ptr - data;
2120}
2121
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002122static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002124 struct l2cap_conf_rsp *rsp = data;
2125 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002126 void *req = chan->conf_req;
2127 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002128 int type, hint, olen;
2129 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002130 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002131 struct l2cap_conf_efs efs;
2132 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002133 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002134 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002135 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002136
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002137 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002138
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002139 while (len >= L2CAP_CONF_OPT_SIZE) {
2140 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002142 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002143 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002144
2145 switch (type) {
2146 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002147 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002148 break;
2149
2150 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002151 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002152 break;
2153
2154 case L2CAP_CONF_QOS:
2155 break;
2156
Marcel Holtmann6464f352007-10-20 13:39:51 +02002157 case L2CAP_CONF_RFC:
2158 if (olen == sizeof(rfc))
2159 memcpy(&rfc, (void *) val, olen);
2160 break;
2161
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002162 case L2CAP_CONF_FCS:
2163 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002164 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002165 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002166
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002167 case L2CAP_CONF_EFS:
2168 remote_efs = 1;
2169 if (olen == sizeof(efs))
2170 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002171 break;
2172
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002173 case L2CAP_CONF_EWS:
2174 if (!enable_hs)
2175 return -ECONNREFUSED;
2176
2177 set_bit(FLAG_EXT_CTRL, &chan->flags);
2178 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002179 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002180 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002181 break;
2182
2183 default:
2184 if (hint)
2185 break;
2186
2187 result = L2CAP_CONF_UNKNOWN;
2188 *((u8 *) ptr++) = type;
2189 break;
2190 }
2191 }
2192
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002193 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002194 goto done;
2195
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002196 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002197 case L2CAP_MODE_STREAMING:
2198 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002199 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002200 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002201 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002202 break;
2203 }
2204
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002205 if (remote_efs) {
2206 if (__l2cap_efs_supported(chan))
2207 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2208 else
2209 return -ECONNREFUSED;
2210 }
2211
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002212 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002213 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002214
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002215 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002216 }
2217
2218done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002219 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002220 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002221 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002222
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002223 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002224 return -ECONNREFUSED;
2225
2226 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2227 sizeof(rfc), (unsigned long) &rfc);
2228 }
2229
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002230 if (result == L2CAP_CONF_SUCCESS) {
2231 /* Configure output options and let the other side know
2232 * which ones we don't like. */
2233
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002234 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2235 result = L2CAP_CONF_UNACCEPT;
2236 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002237 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002238 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002239 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002240 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002241
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002242 if (remote_efs) {
2243 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2244 efs.stype != L2CAP_SERV_NOTRAFIC &&
2245 efs.stype != chan->local_stype) {
2246
2247 result = L2CAP_CONF_UNACCEPT;
2248
2249 if (chan->num_conf_req >= 1)
2250 return -ECONNREFUSED;
2251
2252 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002253 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002254 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002255 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002256 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002257 result = L2CAP_CONF_PENDING;
2258 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002259 }
2260 }
2261
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002262 switch (rfc.mode) {
2263 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002264 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002265 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002266 break;
2267
2268 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002269 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2270 chan->remote_tx_win = rfc.txwin_size;
2271 else
2272 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2273
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002274 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002275
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002276 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2277 chan->conn->mtu -
2278 L2CAP_EXT_HDR_SIZE -
2279 L2CAP_SDULEN_SIZE -
2280 L2CAP_FCS_SIZE);
2281 rfc.max_pdu_size = cpu_to_le16(size);
2282 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002283
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002284 rfc.retrans_timeout =
2285 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2286 rfc.monitor_timeout =
2287 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002288
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002289 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002290
2291 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2292 sizeof(rfc), (unsigned long) &rfc);
2293
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002294 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2295 chan->remote_id = efs.id;
2296 chan->remote_stype = efs.stype;
2297 chan->remote_msdu = le16_to_cpu(efs.msdu);
2298 chan->remote_flush_to =
2299 le32_to_cpu(efs.flush_to);
2300 chan->remote_acc_lat =
2301 le32_to_cpu(efs.acc_lat);
2302 chan->remote_sdu_itime =
2303 le32_to_cpu(efs.sdu_itime);
2304 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2305 sizeof(efs), (unsigned long) &efs);
2306 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002307 break;
2308
2309 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002310 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2311 chan->conn->mtu -
2312 L2CAP_EXT_HDR_SIZE -
2313 L2CAP_SDULEN_SIZE -
2314 L2CAP_FCS_SIZE);
2315 rfc.max_pdu_size = cpu_to_le16(size);
2316 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002317
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002318 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002319
2320 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2321 sizeof(rfc), (unsigned long) &rfc);
2322
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002323 break;
2324
2325 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002326 result = L2CAP_CONF_UNACCEPT;
2327
2328 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002329 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002330 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002331
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002332 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002333 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002334 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002335 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002336 rsp->result = cpu_to_le16(result);
2337 rsp->flags = cpu_to_le16(0x0000);
2338
2339 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002340}
2341
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002342static 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 -03002343{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002344 struct l2cap_conf_req *req = data;
2345 void *ptr = req->data;
2346 int type, olen;
2347 unsigned long val;
2348 struct l2cap_conf_rfc rfc;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002349 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002350
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002351 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002352
2353 while (len >= L2CAP_CONF_OPT_SIZE) {
2354 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2355
2356 switch (type) {
2357 case L2CAP_CONF_MTU:
2358 if (val < L2CAP_DEFAULT_MIN_MTU) {
2359 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002360 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002361 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002362 chan->imtu = val;
2363 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002364 break;
2365
2366 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002367 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002368 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002369 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002370 break;
2371
2372 case L2CAP_CONF_RFC:
2373 if (olen == sizeof(rfc))
2374 memcpy(&rfc, (void *)val, olen);
2375
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002376 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002377 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002378 return -ECONNREFUSED;
2379
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002380 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002381
2382 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2383 sizeof(rfc), (unsigned long) &rfc);
2384 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002385
2386 case L2CAP_CONF_EWS:
2387 chan->tx_win = min_t(u16, val,
2388 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002389 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2390 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002391 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002392
2393 case L2CAP_CONF_EFS:
2394 if (olen == sizeof(efs))
2395 memcpy(&efs, (void *)val, olen);
2396
2397 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2398 efs.stype != L2CAP_SERV_NOTRAFIC &&
2399 efs.stype != chan->local_stype)
2400 return -ECONNREFUSED;
2401
2402 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2403 sizeof(efs), (unsigned long) &efs);
2404 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002405 }
2406 }
2407
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002408 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002409 return -ECONNREFUSED;
2410
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002411 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002412
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002413 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002414 switch (rfc.mode) {
2415 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002416 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2417 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2418 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002419
2420 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2421 chan->local_msdu = le16_to_cpu(efs.msdu);
2422 chan->local_sdu_itime =
2423 le32_to_cpu(efs.sdu_itime);
2424 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2425 chan->local_flush_to =
2426 le32_to_cpu(efs.flush_to);
2427 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002428 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002429
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002430 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002431 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002432 }
2433 }
2434
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002435 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002436 req->flags = cpu_to_le16(0x0000);
2437
2438 return ptr - data;
2439}
2440
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002441static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002442{
2443 struct l2cap_conf_rsp *rsp = data;
2444 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002446 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002448 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002449 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002450 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002451
2452 return ptr - data;
2453}
2454
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002455void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002456{
2457 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002458 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002459 u8 buf[128];
2460
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002461 rsp.scid = cpu_to_le16(chan->dcid);
2462 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002463 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2464 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2465 l2cap_send_cmd(conn, chan->ident,
2466 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2467
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002468 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002469 return;
2470
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002471 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2472 l2cap_build_conf_req(chan, buf), buf);
2473 chan->num_conf_req++;
2474}
2475
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002476static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002477{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002478 int type, olen;
2479 unsigned long val;
2480 struct l2cap_conf_rfc rfc;
2481
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002482 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002483
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002484 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002485 return;
2486
2487 while (len >= L2CAP_CONF_OPT_SIZE) {
2488 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2489
2490 switch (type) {
2491 case L2CAP_CONF_RFC:
2492 if (olen == sizeof(rfc))
2493 memcpy(&rfc, (void *)val, olen);
2494 goto done;
2495 }
2496 }
2497
2498done:
2499 switch (rfc.mode) {
2500 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002501 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2502 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2503 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002504 break;
2505 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002506 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002507 }
2508}
2509
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002510static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2511{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002512 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002513
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002514 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002515 return 0;
2516
2517 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2518 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002519 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002520
2521 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002522 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002523
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002524 l2cap_conn_start(conn);
2525 }
2526
2527 return 0;
2528}
2529
Linus Torvalds1da177e2005-04-16 15:20:36 -07002530static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2531{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002532 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2533 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002534 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002535 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002536 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002537
2538 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002539 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002540
2541 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2542
2543 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002544 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2545 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002546 result = L2CAP_CR_BAD_PSM;
2547 goto sendresp;
2548 }
2549
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002550 parent = pchan->sk;
2551
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002552 bh_lock_sock(parent);
2553
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002554 /* Check if the ACL is secure enough (if not SDP) */
2555 if (psm != cpu_to_le16(0x0001) &&
2556 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002557 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002558 result = L2CAP_CR_SEC_BLOCK;
2559 goto response;
2560 }
2561
Linus Torvalds1da177e2005-04-16 15:20:36 -07002562 result = L2CAP_CR_NO_MEM;
2563
2564 /* Check for backlog size */
2565 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002566 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002567 goto response;
2568 }
2569
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002570 chan = pchan->ops->new_connection(pchan->data);
2571 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002572 goto response;
2573
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002574 sk = chan->sk;
2575
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002576 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002577
2578 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002579 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2580 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002582 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002583 goto response;
2584 }
2585
2586 hci_conn_hold(conn->hcon);
2587
Linus Torvalds1da177e2005-04-16 15:20:36 -07002588 bacpy(&bt_sk(sk)->src, conn->src);
2589 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002590 chan->psm = psm;
2591 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002592
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002593 bt_accept_enqueue(parent, sk);
2594
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002595 __l2cap_chan_add(conn, chan);
2596
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002597 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002598
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002599 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002600
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002601 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002602
Marcel Holtmann984947d2009-02-06 23:35:19 +01002603 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002604 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002605 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002606 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002607 result = L2CAP_CR_PEND;
2608 status = L2CAP_CS_AUTHOR_PEND;
2609 parent->sk_data_ready(parent, 0);
2610 } else {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002611 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002612 result = L2CAP_CR_SUCCESS;
2613 status = L2CAP_CS_NO_INFO;
2614 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002615 } else {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002616 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002617 result = L2CAP_CR_PEND;
2618 status = L2CAP_CS_AUTHEN_PEND;
2619 }
2620 } else {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002621 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002622 result = L2CAP_CR_PEND;
2623 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002624 }
2625
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002626 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002627
2628response:
2629 bh_unlock_sock(parent);
2630
2631sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002632 rsp.scid = cpu_to_le16(scid);
2633 rsp.dcid = cpu_to_le16(dcid);
2634 rsp.result = cpu_to_le16(result);
2635 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002636 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002637
2638 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2639 struct l2cap_info_req info;
2640 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2641
2642 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2643 conn->info_ident = l2cap_get_ident(conn);
2644
2645 mod_timer(&conn->info_timer, jiffies +
2646 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2647
2648 l2cap_send_cmd(conn, conn->info_ident,
2649 L2CAP_INFO_REQ, sizeof(info), &info);
2650 }
2651
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002652 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002653 result == L2CAP_CR_SUCCESS) {
2654 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002655 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002656 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002657 l2cap_build_conf_req(chan, buf), buf);
2658 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002659 }
2660
Linus Torvalds1da177e2005-04-16 15:20:36 -07002661 return 0;
2662}
2663
2664static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2665{
2666 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2667 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002668 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669 struct sock *sk;
2670 u8 req[128];
2671
2672 scid = __le16_to_cpu(rsp->scid);
2673 dcid = __le16_to_cpu(rsp->dcid);
2674 result = __le16_to_cpu(rsp->result);
2675 status = __le16_to_cpu(rsp->status);
2676
2677 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2678
2679 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002680 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002681 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002682 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002684 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002685 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002686 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 }
2688
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002689 sk = chan->sk;
2690
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691 switch (result) {
2692 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002693 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002694 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002695 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002696 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002697
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002698 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002699 break;
2700
Linus Torvalds1da177e2005-04-16 15:20:36 -07002701 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002702 l2cap_build_conf_req(chan, req), req);
2703 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002704 break;
2705
2706 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002707 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 break;
2709
2710 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002711 /* don't delete l2cap channel if sk is owned by user */
2712 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002713 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002714 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002715 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002716 break;
2717 }
2718
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002719 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002720 break;
2721 }
2722
2723 bh_unlock_sock(sk);
2724 return 0;
2725}
2726
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002727static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002728{
2729 /* FCS is enabled only in ERTM or streaming mode, if one or both
2730 * sides request it.
2731 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002732 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002733 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002734 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002735 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002736}
2737
Al Viro88219a02007-07-29 00:17:25 -07002738static 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 -07002739{
2740 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2741 u16 dcid, flags;
2742 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002743 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002744 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002745 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002746
2747 dcid = __le16_to_cpu(req->dcid);
2748 flags = __le16_to_cpu(req->flags);
2749
2750 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2751
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002752 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002753 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002754 return -ENOENT;
2755
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002756 sk = chan->sk;
2757
David S. Miller033b1142011-07-21 13:38:42 -07002758 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002759 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002760
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002761 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2762 rej.scid = cpu_to_le16(chan->scid);
2763 rej.dcid = cpu_to_le16(chan->dcid);
2764
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002765 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2766 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002767 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002768 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002769
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002770 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002771 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002772 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002773 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002774 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002775 L2CAP_CONF_REJECT, flags), rsp);
2776 goto unlock;
2777 }
2778
2779 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002780 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2781 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002782
2783 if (flags & 0x0001) {
2784 /* Incomplete config. Send empty response. */
2785 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002786 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002787 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002788 goto unlock;
2789 }
2790
2791 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002792 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002793 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002794 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002795 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002796 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002797
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002798 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002799 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002800
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002801 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002802 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002803
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002804 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002805 goto unlock;
2806
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002807 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002808 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002809
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002810 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002811
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002812 chan->next_tx_seq = 0;
2813 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002814 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002815 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002816 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002817
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002819 goto unlock;
2820 }
2821
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002822 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002823 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002824 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002825 l2cap_build_conf_req(chan, buf), buf);
2826 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002827 }
2828
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002829 /* Got Conf Rsp PENDING from remote side and asume we sent
2830 Conf Rsp PENDING in the code above */
2831 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2832 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2833
2834 /* check compatibility */
2835
2836 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2837 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2838
2839 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002840 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002841 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2842 }
2843
Linus Torvalds1da177e2005-04-16 15:20:36 -07002844unlock:
2845 bh_unlock_sock(sk);
2846 return 0;
2847}
2848
2849static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2850{
2851 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2852 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002853 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002854 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002855 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002856
2857 scid = __le16_to_cpu(rsp->scid);
2858 flags = __le16_to_cpu(rsp->flags);
2859 result = __le16_to_cpu(rsp->result);
2860
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002861 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2862 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002863
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002864 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002865 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 return 0;
2867
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002868 sk = chan->sk;
2869
Linus Torvalds1da177e2005-04-16 15:20:36 -07002870 switch (result) {
2871 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002872 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002873 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002874 break;
2875
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002876 case L2CAP_CONF_PENDING:
2877 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2878
2879 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2880 char buf[64];
2881
2882 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2883 buf, &result);
2884 if (len < 0) {
2885 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2886 goto done;
2887 }
2888
2889 /* check compatibility */
2890
2891 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2892 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2893
2894 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002895 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002896 L2CAP_CONF_SUCCESS, 0x0000), buf);
2897 }
2898 goto done;
2899
Linus Torvalds1da177e2005-04-16 15:20:36 -07002900 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002901 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002902 char req[64];
2903
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002904 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002905 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002906 goto done;
2907 }
2908
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002909 /* throw out any old stored conf requests */
2910 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002911 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2912 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002913 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002914 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002915 goto done;
2916 }
2917
2918 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2919 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002920 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002921 if (result != L2CAP_CONF_SUCCESS)
2922 goto done;
2923 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924 }
2925
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002926 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002927 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002928 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002929 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002930 goto done;
2931 }
2932
2933 if (flags & 0x01)
2934 goto done;
2935
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002936 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002937
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002938 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002939 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002940
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002941 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002942 chan->next_tx_seq = 0;
2943 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002944 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002945 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002946 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002947
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 l2cap_chan_ready(sk);
2949 }
2950
2951done:
2952 bh_unlock_sock(sk);
2953 return 0;
2954}
2955
2956static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2957{
2958 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2959 struct l2cap_disconn_rsp rsp;
2960 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002961 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 struct sock *sk;
2963
2964 scid = __le16_to_cpu(req->scid);
2965 dcid = __le16_to_cpu(req->dcid);
2966
2967 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2968
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002969 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002970 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002971 return 0;
2972
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002973 sk = chan->sk;
2974
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002975 rsp.dcid = cpu_to_le16(chan->scid);
2976 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2978
2979 sk->sk_shutdown = SHUTDOWN_MASK;
2980
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002981 /* don't delete l2cap channel if sk is owned by user */
2982 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03002983 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002984 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002985 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002986 bh_unlock_sock(sk);
2987 return 0;
2988 }
2989
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002990 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002991 bh_unlock_sock(sk);
2992
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002993 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002994 return 0;
2995}
2996
2997static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2998{
2999 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
3000 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003001 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003002 struct sock *sk;
3003
3004 scid = __le16_to_cpu(rsp->scid);
3005 dcid = __le16_to_cpu(rsp->dcid);
3006
3007 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3008
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003009 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003010 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003011 return 0;
3012
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003013 sk = chan->sk;
3014
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003015 /* don't delete l2cap channel if sk is owned by user */
3016 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03003017 l2cap_state_change(chan,BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03003018 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02003019 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003020 bh_unlock_sock(sk);
3021 return 0;
3022 }
3023
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003024 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003025 bh_unlock_sock(sk);
3026
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003027 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003028 return 0;
3029}
3030
3031static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3032{
3033 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003034 u16 type;
3035
3036 type = __le16_to_cpu(req->type);
3037
3038 BT_DBG("type 0x%4.4x", type);
3039
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003040 if (type == L2CAP_IT_FEAT_MASK) {
3041 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003042 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003043 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3044 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3045 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003046 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003047 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3048 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003049 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003050 feat_mask |= L2CAP_FEAT_EXT_FLOW
3051 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003052
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003053 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003054 l2cap_send_cmd(conn, cmd->ident,
3055 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003056 } else if (type == L2CAP_IT_FIXED_CHAN) {
3057 u8 buf[12];
3058 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003059
3060 if (enable_hs)
3061 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3062 else
3063 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3064
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003065 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3066 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003067 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003068 l2cap_send_cmd(conn, cmd->ident,
3069 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003070 } else {
3071 struct l2cap_info_rsp rsp;
3072 rsp.type = cpu_to_le16(type);
3073 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3074 l2cap_send_cmd(conn, cmd->ident,
3075 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3076 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003077
3078 return 0;
3079}
3080
3081static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3082{
3083 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3084 u16 type, result;
3085
3086 type = __le16_to_cpu(rsp->type);
3087 result = __le16_to_cpu(rsp->result);
3088
3089 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3090
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003091 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3092 if (cmd->ident != conn->info_ident ||
3093 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3094 return 0;
3095
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003096 del_timer(&conn->info_timer);
3097
Ville Tervoadb08ed2010-08-04 09:43:33 +03003098 if (result != L2CAP_IR_SUCCESS) {
3099 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3100 conn->info_ident = 0;
3101
3102 l2cap_conn_start(conn);
3103
3104 return 0;
3105 }
3106
Marcel Holtmann984947d2009-02-06 23:35:19 +01003107 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003108 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003109
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003110 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003111 struct l2cap_info_req req;
3112 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3113
3114 conn->info_ident = l2cap_get_ident(conn);
3115
3116 l2cap_send_cmd(conn, conn->info_ident,
3117 L2CAP_INFO_REQ, sizeof(req), &req);
3118 } else {
3119 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3120 conn->info_ident = 0;
3121
3122 l2cap_conn_start(conn);
3123 }
3124 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003125 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003126 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003127
3128 l2cap_conn_start(conn);
3129 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003130
Linus Torvalds1da177e2005-04-16 15:20:36 -07003131 return 0;
3132}
3133
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003134static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3135 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3136 void *data)
3137{
3138 struct l2cap_create_chan_req *req = data;
3139 struct l2cap_create_chan_rsp rsp;
3140 u16 psm, scid;
3141
3142 if (cmd_len != sizeof(*req))
3143 return -EPROTO;
3144
3145 if (!enable_hs)
3146 return -EINVAL;
3147
3148 psm = le16_to_cpu(req->psm);
3149 scid = le16_to_cpu(req->scid);
3150
3151 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3152
3153 /* Placeholder: Always reject */
3154 rsp.dcid = 0;
3155 rsp.scid = cpu_to_le16(scid);
3156 rsp.result = L2CAP_CR_NO_MEM;
3157 rsp.status = L2CAP_CS_NO_INFO;
3158
3159 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3160 sizeof(rsp), &rsp);
3161
3162 return 0;
3163}
3164
3165static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3166 struct l2cap_cmd_hdr *cmd, void *data)
3167{
3168 BT_DBG("conn %p", conn);
3169
3170 return l2cap_connect_rsp(conn, cmd, data);
3171}
3172
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003173static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3174 u16 icid, u16 result)
3175{
3176 struct l2cap_move_chan_rsp rsp;
3177
3178 BT_DBG("icid %d, result %d", icid, result);
3179
3180 rsp.icid = cpu_to_le16(icid);
3181 rsp.result = cpu_to_le16(result);
3182
3183 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3184}
3185
3186static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3187 struct l2cap_chan *chan, u16 icid, u16 result)
3188{
3189 struct l2cap_move_chan_cfm cfm;
3190 u8 ident;
3191
3192 BT_DBG("icid %d, result %d", icid, result);
3193
3194 ident = l2cap_get_ident(conn);
3195 if (chan)
3196 chan->ident = ident;
3197
3198 cfm.icid = cpu_to_le16(icid);
3199 cfm.result = cpu_to_le16(result);
3200
3201 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3202}
3203
3204static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3205 u16 icid)
3206{
3207 struct l2cap_move_chan_cfm_rsp rsp;
3208
3209 BT_DBG("icid %d", icid);
3210
3211 rsp.icid = cpu_to_le16(icid);
3212 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3213}
3214
3215static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3216 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3217{
3218 struct l2cap_move_chan_req *req = data;
3219 u16 icid = 0;
3220 u16 result = L2CAP_MR_NOT_ALLOWED;
3221
3222 if (cmd_len != sizeof(*req))
3223 return -EPROTO;
3224
3225 icid = le16_to_cpu(req->icid);
3226
3227 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3228
3229 if (!enable_hs)
3230 return -EINVAL;
3231
3232 /* Placeholder: Always refuse */
3233 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3234
3235 return 0;
3236}
3237
3238static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3239 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3240{
3241 struct l2cap_move_chan_rsp *rsp = data;
3242 u16 icid, result;
3243
3244 if (cmd_len != sizeof(*rsp))
3245 return -EPROTO;
3246
3247 icid = le16_to_cpu(rsp->icid);
3248 result = le16_to_cpu(rsp->result);
3249
3250 BT_DBG("icid %d, result %d", icid, result);
3251
3252 /* Placeholder: Always unconfirmed */
3253 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3254
3255 return 0;
3256}
3257
3258static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3259 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3260{
3261 struct l2cap_move_chan_cfm *cfm = data;
3262 u16 icid, result;
3263
3264 if (cmd_len != sizeof(*cfm))
3265 return -EPROTO;
3266
3267 icid = le16_to_cpu(cfm->icid);
3268 result = le16_to_cpu(cfm->result);
3269
3270 BT_DBG("icid %d, result %d", icid, result);
3271
3272 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3273
3274 return 0;
3275}
3276
3277static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3278 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3279{
3280 struct l2cap_move_chan_cfm_rsp *rsp = data;
3281 u16 icid;
3282
3283 if (cmd_len != sizeof(*rsp))
3284 return -EPROTO;
3285
3286 icid = le16_to_cpu(rsp->icid);
3287
3288 BT_DBG("icid %d", icid);
3289
3290 return 0;
3291}
3292
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003293static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003294 u16 to_multiplier)
3295{
3296 u16 max_latency;
3297
3298 if (min > max || min < 6 || max > 3200)
3299 return -EINVAL;
3300
3301 if (to_multiplier < 10 || to_multiplier > 3200)
3302 return -EINVAL;
3303
3304 if (max >= to_multiplier * 8)
3305 return -EINVAL;
3306
3307 max_latency = (to_multiplier * 8 / max) - 1;
3308 if (latency > 499 || latency > max_latency)
3309 return -EINVAL;
3310
3311 return 0;
3312}
3313
3314static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3315 struct l2cap_cmd_hdr *cmd, u8 *data)
3316{
3317 struct hci_conn *hcon = conn->hcon;
3318 struct l2cap_conn_param_update_req *req;
3319 struct l2cap_conn_param_update_rsp rsp;
3320 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003321 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003322
3323 if (!(hcon->link_mode & HCI_LM_MASTER))
3324 return -EINVAL;
3325
3326 cmd_len = __le16_to_cpu(cmd->len);
3327 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3328 return -EPROTO;
3329
3330 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003331 min = __le16_to_cpu(req->min);
3332 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003333 latency = __le16_to_cpu(req->latency);
3334 to_multiplier = __le16_to_cpu(req->to_multiplier);
3335
3336 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3337 min, max, latency, to_multiplier);
3338
3339 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003340
3341 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3342 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003343 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3344 else
3345 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3346
3347 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3348 sizeof(rsp), &rsp);
3349
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003350 if (!err)
3351 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3352
Claudio Takahaside731152011-02-11 19:28:55 -02003353 return 0;
3354}
3355
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003356static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3357 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3358{
3359 int err = 0;
3360
3361 switch (cmd->code) {
3362 case L2CAP_COMMAND_REJ:
3363 l2cap_command_rej(conn, cmd, data);
3364 break;
3365
3366 case L2CAP_CONN_REQ:
3367 err = l2cap_connect_req(conn, cmd, data);
3368 break;
3369
3370 case L2CAP_CONN_RSP:
3371 err = l2cap_connect_rsp(conn, cmd, data);
3372 break;
3373
3374 case L2CAP_CONF_REQ:
3375 err = l2cap_config_req(conn, cmd, cmd_len, data);
3376 break;
3377
3378 case L2CAP_CONF_RSP:
3379 err = l2cap_config_rsp(conn, cmd, data);
3380 break;
3381
3382 case L2CAP_DISCONN_REQ:
3383 err = l2cap_disconnect_req(conn, cmd, data);
3384 break;
3385
3386 case L2CAP_DISCONN_RSP:
3387 err = l2cap_disconnect_rsp(conn, cmd, data);
3388 break;
3389
3390 case L2CAP_ECHO_REQ:
3391 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3392 break;
3393
3394 case L2CAP_ECHO_RSP:
3395 break;
3396
3397 case L2CAP_INFO_REQ:
3398 err = l2cap_information_req(conn, cmd, data);
3399 break;
3400
3401 case L2CAP_INFO_RSP:
3402 err = l2cap_information_rsp(conn, cmd, data);
3403 break;
3404
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003405 case L2CAP_CREATE_CHAN_REQ:
3406 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3407 break;
3408
3409 case L2CAP_CREATE_CHAN_RSP:
3410 err = l2cap_create_channel_rsp(conn, cmd, data);
3411 break;
3412
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003413 case L2CAP_MOVE_CHAN_REQ:
3414 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3415 break;
3416
3417 case L2CAP_MOVE_CHAN_RSP:
3418 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3419 break;
3420
3421 case L2CAP_MOVE_CHAN_CFM:
3422 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3423 break;
3424
3425 case L2CAP_MOVE_CHAN_CFM_RSP:
3426 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3427 break;
3428
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003429 default:
3430 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3431 err = -EINVAL;
3432 break;
3433 }
3434
3435 return err;
3436}
3437
3438static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3439 struct l2cap_cmd_hdr *cmd, u8 *data)
3440{
3441 switch (cmd->code) {
3442 case L2CAP_COMMAND_REJ:
3443 return 0;
3444
3445 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003446 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003447
3448 case L2CAP_CONN_PARAM_UPDATE_RSP:
3449 return 0;
3450
3451 default:
3452 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3453 return -EINVAL;
3454 }
3455}
3456
3457static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3458 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003459{
3460 u8 *data = skb->data;
3461 int len = skb->len;
3462 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003463 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003464
3465 l2cap_raw_recv(conn, skb);
3466
3467 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003468 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003469 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3470 data += L2CAP_CMD_HDR_SIZE;
3471 len -= L2CAP_CMD_HDR_SIZE;
3472
Al Viro88219a02007-07-29 00:17:25 -07003473 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003474
Al Viro88219a02007-07-29 00:17:25 -07003475 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 -07003476
Al Viro88219a02007-07-29 00:17:25 -07003477 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003478 BT_DBG("corrupted command");
3479 break;
3480 }
3481
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003482 if (conn->hcon->type == LE_LINK)
3483 err = l2cap_le_sig_cmd(conn, &cmd, data);
3484 else
3485 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003486
3487 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003488 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003489
3490 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003491
3492 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003493 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003494 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3495 }
3496
Al Viro88219a02007-07-29 00:17:25 -07003497 data += cmd_len;
3498 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003499 }
3500
3501 kfree_skb(skb);
3502}
3503
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003504static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003505{
3506 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003507 int hdr_size;
3508
3509 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3510 hdr_size = L2CAP_EXT_HDR_SIZE;
3511 else
3512 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003513
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003514 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003515 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003516 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3517 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3518
3519 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003520 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003521 }
3522 return 0;
3523}
3524
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003525static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003526{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003527 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003528
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003529 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003530
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003531 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003532
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003533 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003534 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003535 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003536 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003537 }
3538
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003539 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003540 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003541
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003542 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003543
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003544 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003545 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003546 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003547 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003548 }
3549}
3550
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003551static 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 -03003552{
3553 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003554 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003555
3556 bt_cb(skb)->tx_seq = tx_seq;
3557 bt_cb(skb)->sar = sar;
3558
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003559 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003560
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003561 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003562
Szymon Janc039d9572011-11-16 09:32:19 +01003563 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003564 if (bt_cb(next_skb)->tx_seq == tx_seq)
3565 return -EINVAL;
3566
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003567 next_tx_seq_offset = __seq_offset(chan,
3568 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003569
3570 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003571 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003572 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003573 }
3574
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003575 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003576 next_skb = NULL;
3577 else
3578 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3579 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003580
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003581 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003582
3583 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003584}
3585
Mat Martineau84084a32011-07-22 14:54:00 -07003586static void append_skb_frag(struct sk_buff *skb,
3587 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003588{
Mat Martineau84084a32011-07-22 14:54:00 -07003589 /* skb->len reflects data in skb as well as all fragments
3590 * skb->data_len reflects only data in fragments
3591 */
3592 if (!skb_has_frag_list(skb))
3593 skb_shinfo(skb)->frag_list = new_frag;
3594
3595 new_frag->next = NULL;
3596
3597 (*last_frag)->next = new_frag;
3598 *last_frag = new_frag;
3599
3600 skb->len += new_frag->len;
3601 skb->data_len += new_frag->len;
3602 skb->truesize += new_frag->truesize;
3603}
3604
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003605static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003606{
3607 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003608
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003609 switch (__get_ctrl_sar(chan, control)) {
3610 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003611 if (chan->sdu)
3612 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003613
Mat Martineau84084a32011-07-22 14:54:00 -07003614 err = chan->ops->recv(chan->data, skb);
3615 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003616
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003617 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003618 if (chan->sdu)
3619 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003620
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003621 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003622 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003623
Mat Martineau84084a32011-07-22 14:54:00 -07003624 if (chan->sdu_len > chan->imtu) {
3625 err = -EMSGSIZE;
3626 break;
3627 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003628
Mat Martineau84084a32011-07-22 14:54:00 -07003629 if (skb->len >= chan->sdu_len)
3630 break;
3631
3632 chan->sdu = skb;
3633 chan->sdu_last_frag = skb;
3634
3635 skb = NULL;
3636 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003637 break;
3638
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003639 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003640 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003641 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003642
Mat Martineau84084a32011-07-22 14:54:00 -07003643 append_skb_frag(chan->sdu, skb,
3644 &chan->sdu_last_frag);
3645 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003646
Mat Martineau84084a32011-07-22 14:54:00 -07003647 if (chan->sdu->len >= chan->sdu_len)
3648 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003649
Mat Martineau84084a32011-07-22 14:54:00 -07003650 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003651 break;
3652
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003653 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003654 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003655 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003656
Mat Martineau84084a32011-07-22 14:54:00 -07003657 append_skb_frag(chan->sdu, skb,
3658 &chan->sdu_last_frag);
3659 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003660
Mat Martineau84084a32011-07-22 14:54:00 -07003661 if (chan->sdu->len != chan->sdu_len)
3662 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003663
Mat Martineau84084a32011-07-22 14:54:00 -07003664 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003665
Mat Martineau84084a32011-07-22 14:54:00 -07003666 if (!err) {
3667 /* Reassembly complete */
3668 chan->sdu = NULL;
3669 chan->sdu_last_frag = NULL;
3670 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003671 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003672 break;
3673 }
3674
Mat Martineau84084a32011-07-22 14:54:00 -07003675 if (err) {
3676 kfree_skb(skb);
3677 kfree_skb(chan->sdu);
3678 chan->sdu = NULL;
3679 chan->sdu_last_frag = NULL;
3680 chan->sdu_len = 0;
3681 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003682
Mat Martineau84084a32011-07-22 14:54:00 -07003683 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003684}
3685
Mat Martineau26f880d2011-07-07 09:39:01 -07003686static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003687{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003688 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003689
Mat Martineau26f880d2011-07-07 09:39:01 -07003690 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003691
Mat Martineau26f880d2011-07-07 09:39:01 -07003692 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3693
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003694 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003695 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003696 l2cap_send_sframe(chan, control);
3697
3698 set_bit(CONN_RNR_SENT, &chan->conn_state);
3699
3700 __clear_ack_timer(chan);
3701}
3702
3703static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3704{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003705 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003706
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003707 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003708 goto done;
3709
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003710 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003711 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003712 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003713 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003714 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003715
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003716 __clear_retrans_timer(chan);
3717 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003718
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003719 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003720
3721done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003722 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3723 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003724
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003725 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003726}
3727
Mat Martineaue3281402011-07-07 09:39:02 -07003728void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003729{
Mat Martineaue3281402011-07-07 09:39:02 -07003730 if (chan->mode == L2CAP_MODE_ERTM) {
3731 if (busy)
3732 l2cap_ertm_enter_local_busy(chan);
3733 else
3734 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132eb2010-06-21 19:39:50 -03003735 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003736}
3737
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003738static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003739{
3740 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003741 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003742
Mat Martineaue3281402011-07-07 09:39:02 -07003743 while ((skb = skb_peek(&chan->srej_q)) &&
3744 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3745 int err;
3746
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003747 if (bt_cb(skb)->tx_seq != tx_seq)
3748 break;
3749
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003750 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003751 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003752 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003753
3754 if (err < 0) {
3755 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3756 break;
3757 }
3758
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003759 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3760 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003761 }
3762}
3763
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003764static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003765{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003766 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003767 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003768
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003769 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003770 if (l->tx_seq == tx_seq) {
3771 list_del(&l->list);
3772 kfree(l);
3773 return;
3774 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003775 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003776 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003777 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003778 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003779 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003780 }
3781}
3782
Szymon Jancaef89f22011-11-16 09:32:18 +01003783static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003784{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003785 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003786 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003787
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003788 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003789 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003790 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003791 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003792
3793 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003794 if (!new)
3795 return -ENOMEM;
3796
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003797 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003798
3799 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3800
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003801 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003802 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003803
3804 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003805
3806 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003807}
3808
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003809static 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 -03003810{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003811 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003812 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003813 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003814 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003815 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003816 int err = 0;
3817
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003818 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 -03003819 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003820
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003821 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003822 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003823 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003824 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003825 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003826 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003827 }
3828
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003829 chan->expected_ack_seq = req_seq;
3830 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003831
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003832 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003833
3834 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003835 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003836 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003837 goto drop;
3838 }
3839
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003840 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003841 goto drop;
3842
Mat Martineau02f1b642011-06-29 14:35:19 -07003843 if (tx_seq == chan->expected_tx_seq)
3844 goto expected;
3845
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003846 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003847 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003848
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003849 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003850 struct srej_list, list);
3851 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003852 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003853 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003854
3855 list_del(&first->list);
3856 kfree(first);
3857
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003858 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003859 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003860 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003861 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003862 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003863 }
3864 } else {
3865 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003866
3867 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003868 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003869 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003870
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003871 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003872 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003873 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003874 return 0;
3875 }
3876 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003877
3878 err = l2cap_send_srejframe(chan, tx_seq);
3879 if (err < 0) {
3880 l2cap_send_disconn_req(chan->conn, chan, -err);
3881 return err;
3882 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003883 }
3884 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003885 expected_tx_seq_offset = __seq_offset(chan,
3886 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003887
3888 /* duplicated tx_seq */
3889 if (tx_seq_offset < expected_tx_seq_offset)
3890 goto drop;
3891
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003892 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003893
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003894 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003895
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003896 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003897 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003898
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003899 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003900 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003901
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003902 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003903
Szymon Jancaef89f22011-11-16 09:32:18 +01003904 err = l2cap_send_srejframe(chan, tx_seq);
3905 if (err < 0) {
3906 l2cap_send_disconn_req(chan->conn, chan, -err);
3907 return err;
3908 }
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003909
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003910 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003911 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003912 return 0;
3913
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003914expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003915 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003916
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003917 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003918 bt_cb(skb)->tx_seq = tx_seq;
3919 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003920 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003921 return 0;
3922 }
3923
Mat Martineau84084a32011-07-22 14:54:00 -07003924 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003925 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3926
Mat Martineaue3281402011-07-07 09:39:02 -07003927 if (err < 0) {
3928 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3929 return err;
3930 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003931
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003932 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003933 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003934 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003935 }
3936
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003937
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003938 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3939 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003940 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003941 else
3942 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003943
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003944 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003945
3946drop:
3947 kfree_skb(skb);
3948 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003949}
3950
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003951static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003952{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003953 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003954 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003955
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003956 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003957 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003958
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003959 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003960 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3961 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3962 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003963 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003964 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003965
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003966 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003967 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003968 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003969 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003970 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003971
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003972 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003973 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003974
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003975 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003976 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003977
3978 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003979 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003980 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003981 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003982
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003983 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
3984 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003985 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003986 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003987 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003988 }
3989}
3990
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003991static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003992{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003993 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003994
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003995 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003996
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003997 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003998
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003999 chan->expected_ack_seq = tx_seq;
4000 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004001
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004002 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004003 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004004 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004005 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004006 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004007
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004008 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4009 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004010 }
4011}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004012static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004013{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004014 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004015
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004016 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004017
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004018 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004019
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004020 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004021 chan->expected_ack_seq = tx_seq;
4022 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004023
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004024 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004025 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004026
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004027 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004028
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004029 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004030 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004031 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004032 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004033 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004034 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004035 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004036 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004037 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004038 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004039 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004040 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004041 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004042 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004043 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004044 }
4045 }
4046}
4047
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004048static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004049{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004050 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004051
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004052 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004053
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004054 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004055 chan->expected_ack_seq = tx_seq;
4056 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004057
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004058 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004059 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004060
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004061 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004062 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004063 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004064 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004065 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004066 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004067
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004068 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004069 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004070 } else {
4071 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4072 l2cap_send_sframe(chan, rx_control);
4073 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004074}
4075
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004076static 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 -03004077{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004078 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004079
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004080 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004081 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004082 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004083 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004084 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004085 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004086 }
4087
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004088 switch (__get_ctrl_super(chan, rx_control)) {
4089 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004090 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004091 break;
4092
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004093 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004094 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004095 break;
4096
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004097 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004098 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004099 break;
4100
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004101 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004102 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004103 break;
4104 }
4105
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004106 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004107 return 0;
4108}
4109
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004110static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4111{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004112 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004113 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004114 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004115 int len, next_tx_seq_offset, req_seq_offset;
4116
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004117 control = __get_control(chan, skb->data);
4118 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004119 len = skb->len;
4120
4121 /*
4122 * We can just drop the corrupted I-frame here.
4123 * Receiver will miss it and start proper recovery
4124 * procedures and ask retransmission.
4125 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004126 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004127 goto drop;
4128
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004129 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004130 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004131
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004132 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004133 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004134
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004135 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004136 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004137 goto drop;
4138 }
4139
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004140 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004141
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004142 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4143
4144 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4145 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004146
4147 /* check for invalid req-seq */
4148 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004149 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004150 goto drop;
4151 }
4152
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004153 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004154 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004155 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004156 goto drop;
4157 }
4158
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004159 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004160 } else {
4161 if (len != 0) {
4162 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004163 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004164 goto drop;
4165 }
4166
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004167 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004168 }
4169
4170 return 0;
4171
4172drop:
4173 kfree_skb(skb);
4174 return 0;
4175}
4176
Linus Torvalds1da177e2005-04-16 15:20:36 -07004177static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4178{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004179 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004180 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004181 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004182 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004183 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004185 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004186 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 BT_DBG("unknown cid 0x%4.4x", cid);
4188 goto drop;
4189 }
4190
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004191 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004192
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004193 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004194
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004195 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004196 goto drop;
4197
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004198 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004199 case L2CAP_MODE_BASIC:
4200 /* If socket recv buffers overflows we drop data here
4201 * which is *bad* because L2CAP has to be reliable.
4202 * But we don't have any other choice. L2CAP doesn't
4203 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004204
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004205 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004206 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004207
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004208 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004209 goto done;
4210 break;
4211
4212 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004213 if (!sock_owned_by_user(sk)) {
4214 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004215 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004216 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004217 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004218 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004219
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004220 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004221
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004222 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004223 control = __get_control(chan, skb->data);
4224 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004225 len = skb->len;
4226
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004227 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004228 goto drop;
4229
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004230 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004231 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004232
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004233 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004234 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004235
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004236 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004237 goto drop;
4238
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004239 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004240
Mat Martineau84084a32011-07-22 14:54:00 -07004241 if (chan->expected_tx_seq != tx_seq) {
4242 /* Frame(s) missing - must discard partial SDU */
4243 kfree_skb(chan->sdu);
4244 chan->sdu = NULL;
4245 chan->sdu_last_frag = NULL;
4246 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004247
Mat Martineau84084a32011-07-22 14:54:00 -07004248 /* TODO: Notify userland of missing data */
4249 }
4250
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004251 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004252
4253 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4254 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004255
4256 goto done;
4257
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004258 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004259 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004260 break;
4261 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004262
4263drop:
4264 kfree_skb(skb);
4265
4266done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004267 if (sk)
4268 bh_unlock_sock(sk);
4269
Linus Torvalds1da177e2005-04-16 15:20:36 -07004270 return 0;
4271}
4272
Al Viro8e036fc2007-07-29 00:16:36 -07004273static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004274{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004275 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004276 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004277
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004278 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4279 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004280 goto drop;
4281
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004282 sk = chan->sk;
4283
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004284 bh_lock_sock(sk);
4285
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286 BT_DBG("sk %p, len %d", sk, skb->len);
4287
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004288 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004289 goto drop;
4290
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004291 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004292 goto drop;
4293
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004294 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004295 goto done;
4296
4297drop:
4298 kfree_skb(skb);
4299
4300done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004301 if (sk)
4302 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004303 return 0;
4304}
4305
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004306static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4307{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004308 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004309 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004310
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004311 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4312 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004313 goto drop;
4314
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004315 sk = chan->sk;
4316
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004317 bh_lock_sock(sk);
4318
4319 BT_DBG("sk %p, len %d", sk, skb->len);
4320
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004321 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004322 goto drop;
4323
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004324 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004325 goto drop;
4326
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004327 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004328 goto done;
4329
4330drop:
4331 kfree_skb(skb);
4332
4333done:
4334 if (sk)
4335 bh_unlock_sock(sk);
4336 return 0;
4337}
4338
Linus Torvalds1da177e2005-04-16 15:20:36 -07004339static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4340{
4341 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004342 u16 cid, len;
4343 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004344
4345 skb_pull(skb, L2CAP_HDR_SIZE);
4346 cid = __le16_to_cpu(lh->cid);
4347 len = __le16_to_cpu(lh->len);
4348
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004349 if (len != skb->len) {
4350 kfree_skb(skb);
4351 return;
4352 }
4353
Linus Torvalds1da177e2005-04-16 15:20:36 -07004354 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4355
4356 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004357 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004358 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004359 l2cap_sig_channel(conn, skb);
4360 break;
4361
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004362 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004363 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004364 skb_pull(skb, 2);
4365 l2cap_conless_channel(conn, psm, skb);
4366 break;
4367
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004368 case L2CAP_CID_LE_DATA:
4369 l2cap_att_channel(conn, cid, skb);
4370 break;
4371
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004372 case L2CAP_CID_SMP:
4373 if (smp_sig_channel(conn, skb))
4374 l2cap_conn_del(conn->hcon, EACCES);
4375 break;
4376
Linus Torvalds1da177e2005-04-16 15:20:36 -07004377 default:
4378 l2cap_data_channel(conn, cid, skb);
4379 break;
4380 }
4381}
4382
4383/* ---- L2CAP interface with lower layer (HCI) ---- */
4384
4385static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4386{
4387 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004388 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004389
4390 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004391 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004392
4393 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4394
4395 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004396 read_lock(&chan_list_lock);
4397 list_for_each_entry(c, &chan_list, global_l) {
4398 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004399
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004400 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004401 continue;
4402
4403 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004404 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004405 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004406 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004407 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004408 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4409 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004410 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004411 lm2 |= HCI_LM_MASTER;
4412 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004413 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004414 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004415
4416 return exact ? lm1 : lm2;
4417}
4418
4419static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4420{
Marcel Holtmann01394182006-07-03 10:02:46 +02004421 struct l2cap_conn *conn;
4422
Linus Torvalds1da177e2005-04-16 15:20:36 -07004423 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4424
Ville Tervoacd7d372011-02-10 22:38:49 -03004425 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004426 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004427
4428 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004429 conn = l2cap_conn_add(hcon, status);
4430 if (conn)
4431 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004432 } else
Joe Perchese1750722011-06-29 18:18:29 -07004433 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004434
4435 return 0;
4436}
4437
Marcel Holtmann2950f212009-02-12 14:02:50 +01004438static int l2cap_disconn_ind(struct hci_conn *hcon)
4439{
4440 struct l2cap_conn *conn = hcon->l2cap_data;
4441
4442 BT_DBG("hcon %p", hcon);
4443
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004444 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004445 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004446
4447 return conn->disc_reason;
4448}
4449
4450static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004451{
4452 BT_DBG("hcon %p reason %d", hcon, reason);
4453
Ville Tervoacd7d372011-02-10 22:38:49 -03004454 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004455 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004456
Joe Perchese1750722011-06-29 18:18:29 -07004457 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004458
Linus Torvalds1da177e2005-04-16 15:20:36 -07004459 return 0;
4460}
4461
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004462static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004463{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004464 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004465 return;
4466
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004467 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004468 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004469 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004470 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004471 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004472 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004473 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004474 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004475 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004476 }
4477}
4478
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004479static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004480{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004481 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004482 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004483
Marcel Holtmann01394182006-07-03 10:02:46 +02004484 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004485 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004486
Linus Torvalds1da177e2005-04-16 15:20:36 -07004487 BT_DBG("conn %p", conn);
4488
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004489 if (hcon->type == LE_LINK) {
4490 smp_distribute_keys(conn, 0);
4491 del_timer(&conn->security_timer);
4492 }
4493
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004494 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004496 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004497 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004498
Linus Torvalds1da177e2005-04-16 15:20:36 -07004499 bh_lock_sock(sk);
4500
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004501 BT_DBG("chan->scid %d", chan->scid);
4502
4503 if (chan->scid == L2CAP_CID_LE_DATA) {
4504 if (!status && encrypt) {
4505 chan->sec_level = hcon->sec_level;
4506 l2cap_chan_ready(sk);
4507 }
4508
4509 bh_unlock_sock(sk);
4510 continue;
4511 }
4512
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004513 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004514 bh_unlock_sock(sk);
4515 continue;
4516 }
4517
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004518 if (!status && (chan->state == BT_CONNECTED ||
4519 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004520 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004521 bh_unlock_sock(sk);
4522 continue;
4523 }
4524
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004525 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004526 if (!status) {
4527 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004528 req.scid = cpu_to_le16(chan->scid);
4529 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004530
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004531 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004532 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004533
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004534 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004535 L2CAP_CONN_REQ, sizeof(req), &req);
4536 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004537 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004538 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004539 }
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004540 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004541 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004542 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004543
4544 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004545 if (bt_sk(sk)->defer_setup) {
4546 struct sock *parent = bt_sk(sk)->parent;
4547 res = L2CAP_CR_PEND;
4548 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004549 if (parent)
4550 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004551 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004552 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004553 res = L2CAP_CR_SUCCESS;
4554 stat = L2CAP_CS_NO_INFO;
4555 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004556 } else {
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004557 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004558 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004559 res = L2CAP_CR_SEC_BLOCK;
4560 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004561 }
4562
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004563 rsp.scid = cpu_to_le16(chan->dcid);
4564 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004565 rsp.result = cpu_to_le16(res);
4566 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004567 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4568 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004569 }
4570
Linus Torvalds1da177e2005-04-16 15:20:36 -07004571 bh_unlock_sock(sk);
4572 }
4573
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004574 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004575
Linus Torvalds1da177e2005-04-16 15:20:36 -07004576 return 0;
4577}
4578
4579static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4580{
4581 struct l2cap_conn *conn = hcon->l2cap_data;
4582
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004583 if (!conn)
4584 conn = l2cap_conn_add(hcon, 0);
4585
4586 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004587 goto drop;
4588
4589 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4590
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004591 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004592 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004593 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004594 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004595 int len;
4596
4597 if (conn->rx_len) {
4598 BT_ERR("Unexpected start frame (len %d)", skb->len);
4599 kfree_skb(conn->rx_skb);
4600 conn->rx_skb = NULL;
4601 conn->rx_len = 0;
4602 l2cap_conn_unreliable(conn, ECOMM);
4603 }
4604
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004605 /* Start fragment always begin with Basic L2CAP header */
4606 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004607 BT_ERR("Frame is too short (len %d)", skb->len);
4608 l2cap_conn_unreliable(conn, ECOMM);
4609 goto drop;
4610 }
4611
4612 hdr = (struct l2cap_hdr *) skb->data;
4613 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004614 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004615
4616 if (len == skb->len) {
4617 /* Complete frame received */
4618 l2cap_recv_frame(conn, skb);
4619 return 0;
4620 }
4621
4622 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4623
4624 if (skb->len > len) {
4625 BT_ERR("Frame is too long (len %d, expected len %d)",
4626 skb->len, len);
4627 l2cap_conn_unreliable(conn, ECOMM);
4628 goto drop;
4629 }
4630
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004631 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004632
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004633 if (chan && chan->sk) {
4634 struct sock *sk = chan->sk;
4635
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004636 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004637 BT_ERR("Frame exceeding recv MTU (len %d, "
4638 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004639 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004640 bh_unlock_sock(sk);
4641 l2cap_conn_unreliable(conn, ECOMM);
4642 goto drop;
4643 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004644 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004645 }
4646
Linus Torvalds1da177e2005-04-16 15:20:36 -07004647 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004648 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4649 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004650 goto drop;
4651
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004652 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004653 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004654 conn->rx_len = len - skb->len;
4655 } else {
4656 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4657
4658 if (!conn->rx_len) {
4659 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4660 l2cap_conn_unreliable(conn, ECOMM);
4661 goto drop;
4662 }
4663
4664 if (skb->len > conn->rx_len) {
4665 BT_ERR("Fragment is too long (len %d, expected %d)",
4666 skb->len, conn->rx_len);
4667 kfree_skb(conn->rx_skb);
4668 conn->rx_skb = NULL;
4669 conn->rx_len = 0;
4670 l2cap_conn_unreliable(conn, ECOMM);
4671 goto drop;
4672 }
4673
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004674 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004675 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004676 conn->rx_len -= skb->len;
4677
4678 if (!conn->rx_len) {
4679 /* Complete frame received */
4680 l2cap_recv_frame(conn, conn->rx_skb);
4681 conn->rx_skb = NULL;
4682 }
4683 }
4684
4685drop:
4686 kfree_skb(skb);
4687 return 0;
4688}
4689
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004690static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004691{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004692 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004693
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004694 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004695
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004696 list_for_each_entry(c, &chan_list, global_l) {
4697 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004699 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 +01004700 batostr(&bt_sk(sk)->src),
4701 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc500e2011-06-03 00:19:47 -03004702 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004703 c->scid, c->dcid, c->imtu, c->omtu,
4704 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004705}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004707 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004708
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004709 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004710}
4711
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004712static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4713{
4714 return single_open(file, l2cap_debugfs_show, inode->i_private);
4715}
4716
4717static const struct file_operations l2cap_debugfs_fops = {
4718 .open = l2cap_debugfs_open,
4719 .read = seq_read,
4720 .llseek = seq_lseek,
4721 .release = single_release,
4722};
4723
4724static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726static struct hci_proto l2cap_hci_proto = {
4727 .name = "L2CAP",
4728 .id = HCI_PROTO_L2CAP,
4729 .connect_ind = l2cap_connect_ind,
4730 .connect_cfm = l2cap_connect_cfm,
4731 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004732 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004733 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004734 .recv_acldata = l2cap_recv_acldata
4735};
4736
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004737int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738{
4739 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004740
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004741 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004742 if (err < 0)
4743 return err;
4744
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745 err = hci_register_proto(&l2cap_hci_proto);
4746 if (err < 0) {
4747 BT_ERR("L2CAP protocol registration failed");
4748 bt_sock_unregister(BTPROTO_L2CAP);
4749 goto error;
4750 }
4751
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004752 if (bt_debugfs) {
4753 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4754 bt_debugfs, NULL, &l2cap_debugfs_fops);
4755 if (!l2cap_debugfs)
4756 BT_ERR("Failed to create L2CAP debug file");
4757 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758
Linus Torvalds1da177e2005-04-16 15:20:36 -07004759 return 0;
4760
4761error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004762 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763 return err;
4764}
4765
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004766void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004767{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004768 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4771 BT_ERR("L2CAP protocol unregistration failed");
4772
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004773 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004774}
4775
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004776module_param(disable_ertm, bool, 0644);
4777MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03004778
4779module_param(enable_hs, bool, 0644);
4780MODULE_PARM_DESC(enable_hs, "Enable High Speed");