blob: d63e67007c6b0a3c1a71beac068181dc1934c262 [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;
Marcel Holtmann01394182006-07-03 10:02:46 +0200100}
101
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300102static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200103{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300104 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300105
106 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300107 if (c->scid == cid)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300108 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200109 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300110 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200111}
112
113/* Find channel with given SCID.
114 * Returns locked socket */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300115static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
Marcel Holtmann01394182006-07-03 10:02:46 +0200116{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300117 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300118
119 read_lock(&conn->chan_lock);
120 c = __l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300121 if (c)
122 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300123 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300124 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200125}
126
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300127static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200128{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300129 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300130
131 list_for_each_entry(c, &conn->chan_l, list) {
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300132 if (c->ident == ident)
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300133 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200134 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300135 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200136}
137
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300138static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
Marcel Holtmann01394182006-07-03 10:02:46 +0200139{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300140 struct l2cap_chan *c;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300141
142 read_lock(&conn->chan_lock);
143 c = __l2cap_get_chan_by_ident(conn, ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300144 if (c)
145 bh_lock_sock(c->sk);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300146 read_unlock(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300147 return c;
Marcel Holtmann01394182006-07-03 10:02:46 +0200148}
149
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300150static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300151{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300152 struct l2cap_chan *c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300153
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300154 list_for_each_entry(c, &chan_list, global_l) {
155 if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
Szymon Janc250938c2011-11-16 09:32:22 +0100156 return c;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300157 }
Szymon Janc250938c2011-11-16 09:32:22 +0100158 return NULL;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300159}
160
161int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
162{
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300163 int err;
164
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300165 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300166
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300167 if (psm && __l2cap_global_chan_by_addr(psm, src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300168 err = -EADDRINUSE;
169 goto done;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300170 }
171
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300172 if (psm) {
173 chan->psm = psm;
174 chan->sport = psm;
175 err = 0;
176 } else {
177 u16 p;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300178
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300179 err = -EINVAL;
180 for (p = 0x1001; p < 0x1100; p += 2)
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300181 if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300182 chan->psm = cpu_to_le16(p);
183 chan->sport = cpu_to_le16(p);
184 err = 0;
185 break;
186 }
187 }
188
189done:
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300190 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan73b2ec12011-04-18 19:36:44 -0300191 return err;
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300192}
193
194int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
195{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300196 write_lock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300197
198 chan->scid = scid;
199
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300200 write_unlock_bh(&chan_list_lock);
Gustavo F. Padovan9e4425f2011-04-18 18:38:43 -0300201
202 return 0;
203}
204
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300205static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
Marcel Holtmann01394182006-07-03 10:02:46 +0200206{
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300207 u16 cid = L2CAP_CID_DYN_START;
Marcel Holtmann01394182006-07-03 10:02:46 +0200208
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -0300209 for (; cid < L2CAP_CID_DYN_END; cid++) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300210 if (!__l2cap_get_chan_by_scid(conn, cid))
Marcel Holtmann01394182006-07-03 10:02:46 +0200211 return cid;
212 }
213
214 return 0;
215}
216
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300217static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300218{
Andrei Emeltchenko457f4852011-10-31 16:17:21 +0200219 BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300220
Mat Martineau942ecc92011-06-29 14:35:21 -0700221 if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
Mat Martineau774e5652011-06-29 14:35:20 -0700222 chan_hold(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300223}
224
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300225static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300226{
Mat Martineau774e5652011-06-29 14:35:20 -0700227 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300228
Mat Martineau774e5652011-06-29 14:35:20 -0700229 if (timer_pending(timer) && del_timer(timer))
230 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300231}
232
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300233static void l2cap_state_change(struct l2cap_chan *chan, int state)
234{
235 chan->state = state;
236 chan->ops->state_change(chan->data, state);
237}
238
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300239static void l2cap_chan_timeout(unsigned long arg)
240{
241 struct l2cap_chan *chan = (struct l2cap_chan *) arg;
242 struct sock *sk = chan->sk;
243 int reason;
244
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300245 BT_DBG("chan %p state %d", chan, chan->state);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300246
247 bh_lock_sock(sk);
248
249 if (sock_owned_by_user(sk)) {
250 /* sk is owned by user. Try again later */
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -0200251 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300252 bh_unlock_sock(sk);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300253 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300254 return;
255 }
256
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300257 if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300258 reason = ECONNREFUSED;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300259 else if (chan->state == BT_CONNECT &&
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300260 chan->sec_level != BT_SECURITY_SDP)
261 reason = ECONNREFUSED;
262 else
263 reason = ETIMEDOUT;
264
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300265 l2cap_chan_close(chan, reason);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300266
267 bh_unlock_sock(sk);
268
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300269 chan->ops->close(chan->data);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300270 chan_put(chan);
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300271}
272
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300273struct l2cap_chan *l2cap_chan_create(struct sock *sk)
Marcel Holtmann01394182006-07-03 10:02:46 +0200274{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300275 struct l2cap_chan *chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200276
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300277 chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
278 if (!chan)
279 return NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200280
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300281 chan->sk = sk;
282
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300283 write_lock_bh(&chan_list_lock);
284 list_add(&chan->global_l, &chan_list);
285 write_unlock_bh(&chan_list_lock);
286
Gustavo F. Padovanab078012011-05-02 18:25:01 -0300287 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
288
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300289 chan->state = BT_OPEN;
290
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300291 atomic_set(&chan->refcnt, 1);
292
Szymon Jancabc545b2011-11-03 16:05:44 +0100293 BT_DBG("sk %p chan %p", sk, chan);
294
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300295 return chan;
Marcel Holtmann01394182006-07-03 10:02:46 +0200296}
297
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300298void l2cap_chan_destroy(struct l2cap_chan *chan)
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300299{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300300 write_lock_bh(&chan_list_lock);
301 list_del(&chan->global_l);
302 write_unlock_bh(&chan_list_lock);
303
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300304 chan_put(chan);
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300305}
306
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300307static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Marcel Holtmann01394182006-07-03 10:02:46 +0200308{
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -0300309 BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300310 chan->psm, chan->dcid);
Marcel Holtmann01394182006-07-03 10:02:46 +0200311
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +0200312 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100313
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300314 chan->conn = conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200315
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300316 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED) {
Ville Tervob62f3282011-02-10 22:38:50 -0300317 if (conn->hcon->type == LE_LINK) {
318 /* LE connection */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300319 chan->omtu = L2CAP_LE_DEFAULT_MTU;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300320 chan->scid = L2CAP_CID_LE_DATA;
321 chan->dcid = L2CAP_CID_LE_DATA;
Ville Tervob62f3282011-02-10 22:38:50 -0300322 } else {
323 /* Alloc CID for connection-oriented socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300324 chan->scid = l2cap_alloc_cid(conn);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300325 chan->omtu = L2CAP_DEFAULT_MTU;
Ville Tervob62f3282011-02-10 22:38:50 -0300326 }
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300327 } else if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Marcel Holtmann01394182006-07-03 10:02:46 +0200328 /* Connectionless socket */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300329 chan->scid = L2CAP_CID_CONN_LESS;
330 chan->dcid = L2CAP_CID_CONN_LESS;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300331 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200332 } else {
333 /* Raw socket can send/recv signalling messages only */
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300334 chan->scid = L2CAP_CID_SIGNALING;
335 chan->dcid = L2CAP_CID_SIGNALING;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300336 chan->omtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann01394182006-07-03 10:02:46 +0200337 }
338
Andrei Emeltchenko8f7975b2011-10-13 16:18:54 +0300339 chan->local_id = L2CAP_BESTEFFORT_ID;
340 chan->local_stype = L2CAP_SERV_BESTEFFORT;
341 chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
342 chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
343 chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
344 chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
345
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300346 chan_hold(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300347
348 list_add(&chan->list, &conn->chan_l);
Marcel Holtmann01394182006-07-03 10:02:46 +0200349}
350
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900351/* Delete channel.
Marcel Holtmann01394182006-07-03 10:02:46 +0200352 * Must be called on the locked socket. */
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300353static void l2cap_chan_del(struct l2cap_chan *chan, int err)
Marcel Holtmann01394182006-07-03 10:02:46 +0200354{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300355 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300356 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann01394182006-07-03 10:02:46 +0200357 struct sock *parent = bt_sk(sk)->parent;
358
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300359 __clear_chan_timer(chan);
Marcel Holtmann01394182006-07-03 10:02:46 +0200360
Gustavo F. Padovan49208c92011-04-04 15:59:54 -0300361 BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
Marcel Holtmann01394182006-07-03 10:02:46 +0200362
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900363 if (conn) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300364 /* Delete from channel list */
365 write_lock_bh(&conn->chan_lock);
366 list_del(&chan->list);
367 write_unlock_bh(&conn->chan_lock);
Gustavo F. Padovan71ba0e52011-05-17 14:34:52 -0300368 chan_put(chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300369
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300370 chan->conn = NULL;
Marcel Holtmann01394182006-07-03 10:02:46 +0200371 hci_conn_put(conn->hcon);
372 }
373
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300374 l2cap_state_change(chan, BT_CLOSED);
Marcel Holtmann01394182006-07-03 10:02:46 +0200375 sock_set_flag(sk, SOCK_ZAPPED);
376
377 if (err)
378 sk->sk_err = err;
379
380 if (parent) {
381 bt_accept_unlink(sk);
382 parent->sk_data_ready(parent, 0);
383 } else
384 sk->sk_state_change(sk);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300385
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300386 if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) &&
387 test_bit(CONF_INPUT_DONE, &chan->conf_state)))
Gustavo F. Padovan6ff5abb2011-04-25 15:10:41 -0300388 return;
Gustavo F. Padovan2ead70b2011-04-01 15:13:36 -0300389
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -0300390 skb_queue_purge(&chan->tx_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300391
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300392 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300393 struct srej_list *l, *tmp;
394
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300395 __clear_retrans_timer(chan);
396 __clear_monitor_timer(chan);
397 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300398
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -0300399 skb_queue_purge(&chan->srej_q);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300400
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -0300401 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300402 list_del(&l->list);
403 kfree(l);
404 }
405 }
Marcel Holtmann01394182006-07-03 10:02:46 +0200406}
407
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300408static void l2cap_chan_cleanup_listen(struct sock *parent)
409{
410 struct sock *sk;
411
412 BT_DBG("parent %p", parent);
413
414 /* Close not yet accepted channels */
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300415 while ((sk = bt_accept_dequeue(parent, NULL))) {
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300416 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300417 __clear_chan_timer(chan);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300418 lock_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300419 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300420 release_sock(sk);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -0300421 chan->ops->close(chan->data);
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300422 }
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300423}
424
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300425void l2cap_chan_close(struct l2cap_chan *chan, int reason)
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300426{
427 struct l2cap_conn *conn = chan->conn;
428 struct sock *sk = chan->sk;
429
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300430 BT_DBG("chan %p state %d socket %p", chan, chan->state, sk->sk_socket);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300431
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300432 switch (chan->state) {
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300433 case BT_LISTEN:
434 l2cap_chan_cleanup_listen(sk);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300435
436 l2cap_state_change(chan, BT_CLOSED);
437 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300438 break;
439
440 case BT_CONNECTED:
441 case BT_CONFIG:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300442 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300443 conn->hcon->type == ACL_LINK) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300444 __clear_chan_timer(chan);
445 __set_chan_timer(chan, sk->sk_sndtimeo);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300446 l2cap_send_disconn_req(conn, chan, reason);
447 } else
448 l2cap_chan_del(chan, reason);
449 break;
450
451 case BT_CONNECT2:
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300452 if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300453 conn->hcon->type == ACL_LINK) {
454 struct l2cap_conn_rsp rsp;
455 __u16 result;
456
457 if (bt_sk(sk)->defer_setup)
458 result = L2CAP_CR_SEC_BLOCK;
459 else
460 result = L2CAP_CR_BAD_PSM;
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300461 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300462
463 rsp.scid = cpu_to_le16(chan->dcid);
464 rsp.dcid = cpu_to_le16(chan->scid);
465 rsp.result = cpu_to_le16(result);
466 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
467 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
468 sizeof(rsp), &rsp);
469 }
470
471 l2cap_chan_del(chan, reason);
472 break;
473
474 case BT_CONNECT:
475 case BT_DISCONN:
476 l2cap_chan_del(chan, reason);
477 break;
478
479 default:
480 sock_set_flag(sk, SOCK_ZAPPED);
481 break;
482 }
483}
484
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300485static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530486{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300487 if (chan->chan_type == L2CAP_CHAN_RAW) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300488 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530489 case BT_SECURITY_HIGH:
490 return HCI_AT_DEDICATED_BONDING_MITM;
491 case BT_SECURITY_MEDIUM:
492 return HCI_AT_DEDICATED_BONDING;
493 default:
494 return HCI_AT_NO_BONDING;
495 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300496 } else if (chan->psm == cpu_to_le16(0x0001)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300497 if (chan->sec_level == BT_SECURITY_LOW)
498 chan->sec_level = BT_SECURITY_SDP;
Johan Hedberg8556edd32011-01-19 12:06:50 +0530499
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300500 if (chan->sec_level == BT_SECURITY_HIGH)
Johan Hedberg8556edd32011-01-19 12:06:50 +0530501 return HCI_AT_NO_BONDING_MITM;
502 else
503 return HCI_AT_NO_BONDING;
504 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300505 switch (chan->sec_level) {
Johan Hedberg8556edd32011-01-19 12:06:50 +0530506 case BT_SECURITY_HIGH:
507 return HCI_AT_GENERAL_BONDING_MITM;
508 case BT_SECURITY_MEDIUM:
509 return HCI_AT_GENERAL_BONDING;
510 default:
511 return HCI_AT_NO_BONDING;
512 }
513 }
514}
515
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200516/* Service level security */
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200517int l2cap_chan_check_security(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200518{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300519 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100520 __u8 auth_type;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200521
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300522 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100523
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300524 return hci_conn_security(conn->hcon, chan->sec_level, auth_type);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200525}
526
Johannes Bergb5ad8b72011-06-01 08:54:45 +0200527static u8 l2cap_get_ident(struct l2cap_conn *conn)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200528{
529 u8 id;
530
531 /* Get next available identificator.
532 * 1 - 128 are used by kernel.
533 * 129 - 199 are reserved.
534 * 200 - 254 are used by utilities like l2ping, etc.
535 */
536
537 spin_lock_bh(&conn->lock);
538
539 if (++conn->tx_ident > 128)
540 conn->tx_ident = 1;
541
542 id = conn->tx_ident;
543
544 spin_unlock_bh(&conn->lock);
545
546 return id;
547}
548
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300549static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200550{
551 struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200552 u8 flags;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200553
554 BT_DBG("code 0x%2.2x", code);
555
556 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300557 return;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200558
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +0200559 if (lmp_no_flush_capable(conn->hcon->hdev))
560 flags = ACL_START_NO_FLUSH;
561 else
562 flags = ACL_START;
563
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700564 bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +0200565 skb->priority = HCI_PRIO_MAX;
Jaikumar Ganesh14b12d02011-05-23 18:06:04 -0700566
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200567 hci_send_acl(conn->hchan, skb, flags);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200568}
569
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200570static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
571{
572 struct hci_conn *hcon = chan->conn->hcon;
573 u16 flags;
574
575 BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
576 skb->priority);
577
578 if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
579 lmp_no_flush_capable(hcon->hdev))
580 flags = ACL_START_NO_FLUSH;
581 else
582 flags = ACL_START;
583
584 bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
585 hci_send_acl(chan->conn->hchan, skb, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586}
587
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300588static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300589{
590 struct sk_buff *skb;
591 struct l2cap_hdr *lh;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300592 struct l2cap_conn *conn = chan->conn;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300593 int count, hlen;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300594
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300595 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300596 return;
597
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +0300598 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
599 hlen = L2CAP_EXT_HDR_SIZE;
600 else
601 hlen = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300602
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300603 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300604 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300605
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300606 BT_DBG("chan %p, control 0x%8.8x", chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300607
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300608 count = min_t(unsigned int, conn->mtu, hlen);
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +0300609
610 control |= __set_sframe(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300611
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300612 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +0300613 control |= __set_ctrl_final(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -0300614
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300615 if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +0300616 control |= __set_ctrl_poll(chan);
Gustavo F. Padovanf0946cc2010-05-01 16:15:37 -0300617
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300618 skb = bt_skb_alloc(count, GFP_ATOMIC);
619 if (!skb)
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -0300620 return;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300621
622 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300623 lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300624 lh->cid = cpu_to_le16(chan->dcid);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300625
626 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300627
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -0300628 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +0300629 u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
630 put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -0300631 }
632
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +0200633 skb->priority = HCI_PRIO_MAX;
634 l2cap_do_send(chan, skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -0300635}
636
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +0300637static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300638{
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300639 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300640 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -0300641 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -0300642 } else
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +0300643 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300644
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +0300645 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan2ab25cd2009-10-03 02:34:40 -0300646
Gustavo F. Padovan525cd182011-03-25 19:43:39 -0300647 l2cap_send_sframe(chan, control);
Gustavo F. Padovan7e743092009-08-26 04:04:03 -0300648}
649
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300650static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300651{
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300652 return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
Andrei Emeltchenkoe501d052010-07-08 12:14:41 +0300653}
654
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300655static void l2cap_do_start(struct l2cap_chan *chan)
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200656{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -0300657 struct l2cap_conn *conn = chan->conn;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200658
659 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
Marcel Holtmann984947d2009-02-06 23:35:19 +0100660 if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
661 return;
662
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200663 if (l2cap_chan_check_security(chan) &&
Gustavo F. Padovan43434782011-04-12 18:31:57 -0300664 __l2cap_no_conn_pending(chan)) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200665 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300666 req.scid = cpu_to_le16(chan->scid);
667 req.psm = chan->psm;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200668
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300669 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300670 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200671
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300672 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
673 sizeof(req), &req);
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200674 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200675 } else {
676 struct l2cap_info_req req;
677 req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
678
679 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
680 conn->info_ident = l2cap_get_ident(conn);
681
682 mod_timer(&conn->info_timer, jiffies +
683 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
684
685 l2cap_send_cmd(conn, conn->info_ident,
686 L2CAP_INFO_REQ, sizeof(req), &req);
687 }
688}
689
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300690static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
691{
692 u32 local_feat_mask = l2cap_feat_mask;
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -0300693 if (!disable_ertm)
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300694 local_feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING;
695
696 switch (mode) {
697 case L2CAP_MODE_ERTM:
698 return L2CAP_FEAT_ERTM & feat_mask & local_feat_mask;
699 case L2CAP_MODE_STREAMING:
700 return L2CAP_FEAT_STREAMING & feat_mask & local_feat_mask;
701 default:
702 return 0x00;
703 }
704}
705
Gustavo F. Padovan4519de92011-04-28 17:55:53 -0300706static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300707{
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300708 struct sock *sk;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300709 struct l2cap_disconn_req req;
710
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300711 if (!conn)
712 return;
713
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -0300714 sk = chan->sk;
715
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -0300716 if (chan->mode == L2CAP_MODE_ERTM) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -0300717 __clear_retrans_timer(chan);
718 __clear_monitor_timer(chan);
719 __clear_ack_timer(chan);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300720 }
721
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300722 req.dcid = cpu_to_le16(chan->dcid);
723 req.scid = cpu_to_le16(chan->scid);
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300724 l2cap_send_cmd(conn, l2cap_get_ident(conn),
725 L2CAP_DISCONN_REQ, sizeof(req), &req);
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -0300726
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300727 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovan9b108fc2010-05-20 16:21:53 -0300728 sk->sk_err = err;
Gustavo F. Padovan22121fc2009-07-23 10:27:23 -0300729}
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731/* ---- L2CAP connections ---- */
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200732static void l2cap_conn_start(struct l2cap_conn *conn)
733{
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300734 struct l2cap_chan *chan, *tmp;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200735
736 BT_DBG("conn %p", conn);
737
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300738 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200739
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300740 list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300741 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300742
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200743 bh_lock_sock(sk);
744
Gustavo F. Padovan715ec002011-05-02 17:13:55 -0300745 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200746 bh_unlock_sock(sk);
747 continue;
748 }
749
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300750 if (chan->state == BT_CONNECT) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300751 struct l2cap_conn_req req;
Gustavo F. Padovancf6c2c02010-06-07 20:54:45 -0300752
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200753 if (!l2cap_chan_check_security(chan) ||
Gustavo F. Padovanb4450032011-04-12 18:15:09 -0300754 !__l2cap_no_conn_pending(chan)) {
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300755 bh_unlock_sock(sk);
756 continue;
Marcel Holtmannb1235d72008-07-14 20:13:54 +0200757 }
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300758
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300759 if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
760 && test_bit(CONF_STATE2_DEVICE,
761 &chan->conf_state)) {
Gustavo F. Padovan0f852722011-05-04 19:42:50 -0300762 /* l2cap_chan_close() calls list_del(chan)
Gustavo F. Padovan820ffdb2011-04-01 00:35:21 -0300763 * so release the lock */
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300764 read_unlock(&conn->chan_lock);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300765 l2cap_chan_close(chan, ECONNRESET);
Gustavo F. Padovan2461daa2011-06-17 12:57:25 -0300766 read_lock(&conn->chan_lock);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300767 bh_unlock_sock(sk);
768 continue;
769 }
770
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300771 req.scid = cpu_to_le16(chan->scid);
772 req.psm = chan->psm;
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300773
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300774 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300775 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300776
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300777 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ,
778 sizeof(req), &req);
Gustavo F. Padovan47731de2010-07-09 16:38:35 -0300779
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300780 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200781 struct l2cap_conn_rsp rsp;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300782 char buf[128];
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300783 rsp.scid = cpu_to_le16(chan->dcid);
784 rsp.dcid = cpu_to_le16(chan->scid);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200785
Gustavo F. Padovand45fc422011-11-05 19:54:24 -0200786 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100787 if (bt_sk(sk)->defer_setup) {
788 struct sock *parent = bt_sk(sk)->parent;
789 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
790 rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +0000791 if (parent)
792 parent->sk_data_ready(parent, 0);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100793
794 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300795 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +0100796 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
797 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
798 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200799 } else {
800 rsp.result = cpu_to_le16(L2CAP_CR_PEND);
801 rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
802 }
803
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300804 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
805 sizeof(rsp), &rsp);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300806
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300807 if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300808 rsp.result != L2CAP_CR_SUCCESS) {
809 bh_unlock_sock(sk);
810 continue;
811 }
812
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -0300813 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -0300814 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -0300815 l2cap_build_conf_req(chan, buf), buf);
816 chan->num_conf_req++;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200817 }
818
819 bh_unlock_sock(sk);
820 }
821
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300822 read_unlock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200823}
824
Ville Tervob62f3282011-02-10 22:38:50 -0300825/* Find socket with cid and source bdaddr.
826 * Returns closest match, locked.
827 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300828static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
Ville Tervob62f3282011-02-10 22:38:50 -0300829{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300830 struct l2cap_chan *c, *c1 = NULL;
Ville Tervob62f3282011-02-10 22:38:50 -0300831
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300832 read_lock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300833
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300834 list_for_each_entry(c, &chan_list, global_l) {
835 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -0300836
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300837 if (state && c->state != state)
Ville Tervob62f3282011-02-10 22:38:50 -0300838 continue;
839
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300840 if (c->scid == cid) {
Ville Tervob62f3282011-02-10 22:38:50 -0300841 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300842 if (!bacmp(&bt_sk(sk)->src, src)) {
843 read_unlock(&chan_list_lock);
844 return c;
845 }
Ville Tervob62f3282011-02-10 22:38:50 -0300846
847 /* Closest match */
848 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300849 c1 = c;
Ville Tervob62f3282011-02-10 22:38:50 -0300850 }
851 }
Gustavo F. Padovan280f2942011-04-13 19:01:22 -0300852
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300853 read_unlock(&chan_list_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300854
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300855 return c1;
Ville Tervob62f3282011-02-10 22:38:50 -0300856}
857
858static void l2cap_le_conn_ready(struct l2cap_conn *conn)
859{
Gustavo F. Padovanc916fbe2011-04-04 16:00:55 -0300860 struct sock *parent, *sk;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300861 struct l2cap_chan *chan, *pchan;
Ville Tervob62f3282011-02-10 22:38:50 -0300862
863 BT_DBG("");
864
865 /* Check if we have socket listening on cid */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300866 pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
Ville Tervob62f3282011-02-10 22:38:50 -0300867 conn->src);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300868 if (!pchan)
Ville Tervob62f3282011-02-10 22:38:50 -0300869 return;
870
Gustavo F. Padovan23691d72011-04-27 18:26:32 -0300871 parent = pchan->sk;
872
Gustavo F. Padovan62f3a2c2011-04-14 18:34:34 -0300873 bh_lock_sock(parent);
874
Ville Tervob62f3282011-02-10 22:38:50 -0300875 /* Check for backlog size */
876 if (sk_acceptq_is_full(parent)) {
877 BT_DBG("backlog full %d", parent->sk_ack_backlog);
878 goto clean;
879 }
880
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300881 chan = pchan->ops->new_connection(pchan->data);
882 if (!chan)
Ville Tervob62f3282011-02-10 22:38:50 -0300883 goto clean;
884
Gustavo F. Padovan80808e42011-05-16 17:24:37 -0300885 sk = chan->sk;
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -0300886
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300887 write_lock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300888
889 hci_conn_hold(conn->hcon);
890
Ville Tervob62f3282011-02-10 22:38:50 -0300891 bacpy(&bt_sk(sk)->src, conn->src);
892 bacpy(&bt_sk(sk)->dst, conn->dst);
893
Gustavo F. Padovand1010242011-03-25 00:39:48 -0300894 bt_accept_enqueue(parent, sk);
895
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300896 __l2cap_chan_add(conn, chan);
897
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300898 __set_chan_timer(chan, sk->sk_sndtimeo);
Ville Tervob62f3282011-02-10 22:38:50 -0300899
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300900 l2cap_state_change(chan, BT_CONNECTED);
Ville Tervob62f3282011-02-10 22:38:50 -0300901 parent->sk_data_ready(parent, 0);
902
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300903 write_unlock_bh(&conn->chan_lock);
Ville Tervob62f3282011-02-10 22:38:50 -0300904
905clean:
906 bh_unlock_sock(parent);
907}
908
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300909static void l2cap_chan_ready(struct sock *sk)
910{
911 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
912 struct sock *parent = bt_sk(sk)->parent;
913
914 BT_DBG("sk %p, parent %p", sk, parent);
915
916 chan->conf_state = 0;
917 __clear_chan_timer(chan);
918
Vinicius Costa Gomes43f3dc42011-06-20 18:53:18 -0300919 l2cap_state_change(chan, BT_CONNECTED);
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300920 sk->sk_state_change(sk);
921
922 if (parent)
923 parent->sk_data_ready(parent, 0);
924}
925
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200926static void l2cap_conn_ready(struct l2cap_conn *conn)
927{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300928 struct l2cap_chan *chan;
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200929
930 BT_DBG("conn %p", conn);
931
Ville Tervob62f3282011-02-10 22:38:50 -0300932 if (!conn->hcon->out && conn->hcon->type == LE_LINK)
933 l2cap_le_conn_ready(conn);
934
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -0300935 if (conn->hcon->out && conn->hcon->type == LE_LINK)
936 smp_conn_security(conn, conn->hcon->pending_sec_level);
937
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300938 read_lock(&conn->chan_lock);
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200939
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300940 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300941 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300942
Marcel Holtmann79d554a2008-07-14 20:13:44 +0200943 bh_lock_sock(sk);
944
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300945 if (conn->hcon->type == LE_LINK) {
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300946 if (smp_conn_security(conn, chan->sec_level))
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -0300947 l2cap_chan_ready(sk);
Ville Tervoacd7d372011-02-10 22:38:49 -0300948
Vinicius Costa Gomes63128452011-06-17 22:46:26 -0300949 } else if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -0300950 __clear_chan_timer(chan);
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300951 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200952 sk->sk_state_change(sk);
Anderson Brigliab501d6a2011-06-07 18:46:31 -0300953
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -0300954 } else if (chan->state == BT_CONNECT)
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -0300955 l2cap_do_start(chan);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200956
957 bh_unlock_sock(sk);
958 }
959
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300960 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200961}
962
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200963/* Notify sockets that we cannot guaranty reliability anymore */
964static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
965{
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300966 struct l2cap_chan *chan;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200967
968 BT_DBG("conn %p", conn);
969
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300970 read_lock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200971
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300972 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -0300973 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300974
Andrei Emeltchenkoecf61bd2011-10-11 14:04:32 +0300975 if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200976 sk->sk_err = err;
977 }
978
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -0300979 read_unlock(&conn->chan_lock);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200980}
981
982static void l2cap_info_timeout(unsigned long arg)
983{
984 struct l2cap_conn *conn = (void *) arg;
985
Marcel Holtmann984947d2009-02-06 23:35:19 +0100986 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +0100987 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +0100988
Marcel Holtmann4e8402a2007-10-20 13:37:56 +0200989 l2cap_conn_start(conn);
990}
991
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -0300992static void l2cap_conn_del(struct hci_conn *hcon, int err)
993{
994 struct l2cap_conn *conn = hcon->l2cap_data;
995 struct l2cap_chan *chan, *l;
996 struct sock *sk;
997
998 if (!conn)
999 return;
1000
1001 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1002
1003 kfree_skb(conn->rx_skb);
1004
1005 /* Kill channels */
1006 list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
1007 sk = chan->sk;
1008 bh_lock_sock(sk);
1009 l2cap_chan_del(chan, err);
1010 bh_unlock_sock(sk);
1011 chan->ops->close(chan->data);
1012 }
1013
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001014 hci_chan_del(conn->hchan);
1015
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001016 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
1017 del_timer_sync(&conn->info_timer);
1018
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001019 if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001020 del_timer(&conn->security_timer);
Vinicius Costa Gomes8aab4752011-09-05 14:31:31 -03001021 smp_chan_destroy(conn);
Vinicius Costa Gomesd26a2342011-08-19 21:06:51 -03001022 }
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001023
1024 hcon->l2cap_data = NULL;
1025 kfree(conn);
1026}
1027
1028static void security_timeout(unsigned long arg)
1029{
1030 struct l2cap_conn *conn = (void *) arg;
1031
1032 l2cap_conn_del(conn->hcon, ETIMEDOUT);
1033}
1034
Linus Torvalds1da177e2005-04-16 15:20:36 -07001035static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
1036{
Marcel Holtmann01394182006-07-03 10:02:46 +02001037 struct l2cap_conn *conn = hcon->l2cap_data;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001038 struct hci_chan *hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039
Marcel Holtmann01394182006-07-03 10:02:46 +02001040 if (conn || status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001041 return conn;
1042
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001043 hchan = hci_chan_create(hcon);
1044 if (!hchan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001045 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001047 conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
1048 if (!conn) {
1049 hci_chan_del(hchan);
1050 return NULL;
1051 }
1052
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053 hcon->l2cap_data = conn;
1054 conn->hcon = hcon;
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001055 conn->hchan = hchan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056
Luiz Augusto von Dentz73d80de2011-11-02 15:52:01 +02001057 BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
Marcel Holtmann01394182006-07-03 10:02:46 +02001058
Ville Tervoacd7d372011-02-10 22:38:49 -03001059 if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
1060 conn->mtu = hcon->hdev->le_mtu;
1061 else
1062 conn->mtu = hcon->hdev->acl_mtu;
1063
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064 conn->src = &hcon->hdev->bdaddr;
1065 conn->dst = &hcon->dst;
1066
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02001067 conn->feat_mask = 0;
1068
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069 spin_lock_init(&conn->lock);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001070 rwlock_init(&conn->chan_lock);
1071
1072 INIT_LIST_HEAD(&conn->chan_l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Vinicius Costa Gomes5d3de7d2011-06-14 13:37:41 -03001074 if (hcon->type == LE_LINK)
1075 setup_timer(&conn->security_timer, security_timeout,
1076 (unsigned long) conn);
1077 else
Ville Tervob62f3282011-02-10 22:38:50 -03001078 setup_timer(&conn->info_timer, l2cap_info_timeout,
Dave Young45054dc2009-10-18 20:28:30 +00001079 (unsigned long) conn);
1080
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02001081 conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01001082
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 return conn;
1084}
1085
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001086static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001087{
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001088 write_lock_bh(&conn->chan_lock);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001089 __l2cap_chan_add(conn, chan);
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001090 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091}
1092
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093/* ---- Socket interface ---- */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094
1095/* Find socket with psm and source bdaddr.
1096 * Returns closest match.
1097 */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001098static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001100 struct l2cap_chan *c, *c1 = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001102 read_lock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001103
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001104 list_for_each_entry(c, &chan_list, global_l) {
1105 struct sock *sk = c->sk;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001106
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001107 if (state && c->state != state)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 continue;
1109
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001110 if (c->psm == psm) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 /* Exact match. */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001112 if (!bacmp(&bt_sk(sk)->src, src)) {
Johannes Berga7567b22011-06-01 08:29:54 +02001113 read_unlock(&chan_list_lock);
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001114 return c;
1115 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116
1117 /* Closest match */
1118 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001119 c1 = c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 }
1121 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001122
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001123 read_unlock(&chan_list_lock);
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00001124
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03001125 return c1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126}
1127
Gustavo F. Padovan77a74c72011-04-12 18:17:14 -03001128int l2cap_chan_connect(struct l2cap_chan *chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129{
Gustavo F. Padovan5d41ce12011-04-08 15:40:02 -03001130 struct sock *sk = chan->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 bdaddr_t *src = &bt_sk(sk)->src;
1132 bdaddr_t *dst = &bt_sk(sk)->dst;
1133 struct l2cap_conn *conn;
1134 struct hci_conn *hcon;
1135 struct hci_dev *hdev;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001136 __u8 auth_type;
Marcel Holtmann44d0e482009-04-20 07:09:16 +02001137 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138
Marcel Holtmannf29972d2009-02-12 05:07:45 +01001139 BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001140 chan->psm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001141
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001142 hdev = hci_get_route(dst, src);
1143 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 return -EHOSTUNREACH;
1145
1146 hci_dev_lock_bh(hdev);
1147
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001148 auth_type = l2cap_get_auth_type(chan);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +02001149
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001150 if (chan->dcid == L2CAP_CID_LE_DATA)
Ville Tervoacd7d372011-02-10 22:38:49 -03001151 hcon = hci_connect(hdev, LE_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001152 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001153 else
1154 hcon = hci_connect(hdev, ACL_LINK, dst,
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001155 chan->sec_level, auth_type);
Ville Tervoacd7d372011-02-10 22:38:49 -03001156
Ville Tervo30e76272011-02-22 16:10:53 -03001157 if (IS_ERR(hcon)) {
1158 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -03001160 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
1162 conn = l2cap_conn_add(hcon, 0);
1163 if (!conn) {
1164 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -03001165 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 goto done;
1167 }
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169 /* Update source addr of the socket */
1170 bacpy(src, conn->src);
1171
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001172 l2cap_chan_add(conn, chan);
1173
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001174 l2cap_state_change(chan, BT_CONNECT);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001175 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176
1177 if (hcon->state == BT_CONNECTED) {
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001178 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03001179 __clear_chan_timer(chan);
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02001180 if (l2cap_chan_check_security(chan))
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001181 l2cap_state_change(chan, BT_CONNECTED);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02001182 } else
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03001183 l2cap_do_start(chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184 }
1185
Ville Tervo30e76272011-02-22 16:10:53 -03001186 err = 0;
1187
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188done:
1189 hci_dev_unlock_bh(hdev);
1190 hci_dev_put(hdev);
1191 return err;
1192}
1193
Gustavo F. Padovandcba0db2011-02-04 03:08:36 -02001194int __l2cap_wait_ack(struct sock *sk)
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001195{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001196 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001197 DECLARE_WAITQUEUE(wait, current);
1198 int err = 0;
1199 int timeo = HZ/5;
1200
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001201 add_wait_queue(sk_sleep(sk), &wait);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001202 set_current_state(TASK_INTERRUPTIBLE);
1203 while (chan->unacked_frames > 0 && chan->conn) {
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001204 if (!timeo)
1205 timeo = HZ/5;
1206
1207 if (signal_pending(current)) {
1208 err = sock_intr_errno(timeo);
1209 break;
1210 }
1211
1212 release_sock(sk);
1213 timeo = schedule_timeout(timeo);
1214 lock_sock(sk);
Peter Hurleya71a0cf2011-07-25 18:36:26 -04001215 set_current_state(TASK_INTERRUPTIBLE);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001216
1217 err = sock_error(sk);
1218 if (err)
1219 break;
1220 }
1221 set_current_state(TASK_RUNNING);
Marcel Holtmann2b0b05d2010-05-10 11:33:10 +02001222 remove_wait_queue(sk_sleep(sk), &wait);
Gustavo F. Padovan6161c032010-05-01 16:15:44 -03001223 return err;
1224}
1225
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001226static void l2cap_monitor_timeout(unsigned long arg)
1227{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001228 struct l2cap_chan *chan = (void *) arg;
1229 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001230
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001231 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001232
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001233 bh_lock_sock(sk);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001234 if (chan->retry_count >= chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001235 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Andrei Emeltchenkob13f5862009-12-15 11:38:04 +02001236 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001237 return;
1238 }
1239
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001240 chan->retry_count++;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001241 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001242
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001243 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001244 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001245}
1246
1247static void l2cap_retrans_timeout(unsigned long arg)
1248{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001249 struct l2cap_chan *chan = (void *) arg;
1250 struct sock *sk = chan->sk;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001251
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03001252 BT_DBG("chan %p", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03001253
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001254 bh_lock_sock(sk);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001255 chan->retry_count = 1;
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001256 __set_monitor_timer(chan);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001257
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001258 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001259
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001260 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
Gustavo F. Padovane6862192009-08-24 00:45:19 -03001261 bh_unlock_sock(sk);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001262}
1263
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001264static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001265{
1266 struct sk_buff *skb;
1267
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001268 while ((skb = skb_peek(&chan->tx_q)) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001269 chan->unacked_frames) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001270 if (bt_cb(skb)->tx_seq == chan->expected_ack_seq)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001271 break;
1272
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001273 skb = skb_dequeue(&chan->tx_q);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001274 kfree_skb(skb);
1275
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001276 chan->unacked_frames--;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001277 }
1278
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001279 if (!chan->unacked_frames)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001280 __clear_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001281}
1282
Szymon Janc67c9e842011-07-28 16:24:33 +02001283static void l2cap_streaming_send(struct l2cap_chan *chan)
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001284{
Gustavo F. Padovanccbb84a2010-08-30 18:44:44 -03001285 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001286 u32 control;
1287 u16 fcs;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001288
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001289 while ((skb = skb_dequeue(&chan->tx_q))) {
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001290 control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001291 control |= __set_txseq(chan, chan->next_tx_seq);
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001292 __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001293
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001294 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001295 fcs = crc16(0, (u8 *)skb->data,
1296 skb->len - L2CAP_FCS_SIZE);
1297 put_unaligned_le16(fcs,
1298 skb->data + skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001299 }
1300
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001301 l2cap_do_send(chan, skb);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001302
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001303 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001304 }
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03001305}
1306
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001307static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001308{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001309 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001310 u16 fcs;
1311 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001312
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001313 skb = skb_peek(&chan->tx_q);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001314 if (!skb)
1315 return;
1316
Szymon Jancd1726b62011-11-16 09:32:20 +01001317 while (bt_cb(skb)->tx_seq != tx_seq) {
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001318 if (skb_queue_is_last(&chan->tx_q, skb))
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001319 return;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001320
Szymon Jancd1726b62011-11-16 09:32:20 +01001321 skb = skb_queue_next(&chan->tx_q, skb);
1322 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001323
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001324 if (chan->remote_max_tx &&
1325 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001326 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001327 return;
1328 }
1329
1330 tx_skb = skb_clone(skb, GFP_ATOMIC);
1331 bt_cb(skb)->retries++;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001332
1333 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001334 control &= __get_sar_mask(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001335
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001336 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001337 control |= __set_ctrl_final(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001338
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001339 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001340 control |= __set_txseq(chan, tx_seq);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03001341
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001342 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001343
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001344 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001345 fcs = crc16(0, (u8 *)tx_skb->data,
1346 tx_skb->len - L2CAP_FCS_SIZE);
1347 put_unaligned_le16(fcs,
1348 tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanf11d6762010-05-01 16:15:44 -03001349 }
1350
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001351 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03001352}
1353
Szymon Janc67c9e842011-07-28 16:24:33 +02001354static int l2cap_ertm_send(struct l2cap_chan *chan)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001355{
1356 struct sk_buff *skb, *tx_skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001357 u16 fcs;
1358 u32 control;
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001359 int nsent = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001360
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03001361 if (chan->state != BT_CONNECTED)
Gustavo F. Padovanc13ffa62010-05-13 20:50:12 -03001362 return -ENOTCONN;
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001363
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001364 while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001365
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001366 if (chan->remote_max_tx &&
1367 bt_cb(skb)->retries == chan->remote_max_tx) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001368 l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001369 break;
1370 }
1371
Andrei Emeltchenkoe420aba2009-12-23 13:07:14 +02001372 tx_skb = skb_clone(skb, GFP_ATOMIC);
1373
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001374 bt_cb(skb)->retries++;
1375
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001376 control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001377 control &= __get_sar_mask(chan);
Gustavo F. Padovan95ffa972010-06-18 20:37:33 -03001378
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001379 if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001380 control |= __set_ctrl_final(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001381
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001382 control |= __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03001383 control |= __set_txseq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001384
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001385 __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001386
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001387 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001388 fcs = crc16(0, (u8 *)skb->data,
1389 tx_skb->len - L2CAP_FCS_SIZE);
1390 put_unaligned_le16(fcs, skb->data +
1391 tx_skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001392 }
1393
Gustavo F. Padovan43434782011-04-12 18:31:57 -03001394 l2cap_do_send(chan, tx_skb);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001395
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03001396 __set_retrans_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001397
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001398 bt_cb(skb)->tx_seq = chan->next_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001399
1400 chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001401
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301402 if (bt_cb(skb)->retries == 1)
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001403 chan->unacked_frames++;
Suraj Sumangala23e9fde2011-03-09 14:44:05 +05301404
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001405 chan->frames_sent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001406
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001407 if (skb_queue_is_last(&chan->tx_q, skb))
1408 chan->tx_send_head = NULL;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001409 else
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001410 chan->tx_send_head = skb_queue_next(&chan->tx_q, skb);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001411
1412 nsent++;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001413 }
1414
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001415 return nsent;
1416}
1417
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001418static int l2cap_retransmit_frames(struct l2cap_chan *chan)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001419{
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001420 int ret;
1421
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001422 if (!skb_queue_empty(&chan->tx_q))
1423 chan->tx_send_head = chan->tx_q.next;
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001424
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001425 chan->next_tx_seq = chan->expected_ack_seq;
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001426 ret = l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001427 return ret;
1428}
1429
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001430static void l2cap_send_ack(struct l2cap_chan *chan)
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001431{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001432 u32 control = 0;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001433
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001434 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001435
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001436 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001437 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001438 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001439 l2cap_send_sframe(chan, control);
Gustavo F. Padovan9a9c6a32010-05-01 16:15:43 -03001440 return;
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03001441 }
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001442
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001443 if (l2cap_ertm_send(chan) > 0)
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03001444 return;
1445
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001446 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001447 l2cap_send_sframe(chan, control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001448}
1449
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001450static void l2cap_send_srejtail(struct l2cap_chan *chan)
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001451{
1452 struct srej_list *tail;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001453 u32 control;
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001454
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03001455 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03001456 control |= __set_ctrl_final(chan);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001457
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001458 tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03001459 control |= __set_reqseq(chan, tail->tx_seq);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001460
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001461 l2cap_send_sframe(chan, control);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03001462}
1463
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001464static 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 -07001465{
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001466 struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001467 struct sk_buff **frag;
1468 int err, sent = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001469
Gustavo F. Padovan59203a22010-05-01 16:15:43 -03001470 if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001471 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472
1473 sent += count;
1474 len -= count;
1475
1476 /* Continuation fragments (no L2CAP header) */
1477 frag = &skb_shinfo(skb)->frag_list;
1478 while (len) {
1479 count = min_t(unsigned int, conn->mtu, len);
1480
1481 *frag = bt_skb_send_alloc(sk, count, msg->msg_flags & MSG_DONTWAIT, &err);
1482 if (!*frag)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001483 return err;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001484 if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
1485 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001487 (*frag)->priority = skb->priority;
1488
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 sent += count;
1490 len -= count;
1491
1492 frag = &(*frag)->next;
1493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001494
1495 return sent;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001496}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001498static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
1499 struct msghdr *msg, size_t len,
1500 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001501{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001502 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001503 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001504 struct sk_buff *skb;
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001505 int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001506 struct l2cap_hdr *lh;
1507
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001508 BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001509
1510 count = min_t(unsigned int, (conn->mtu - hlen), len);
1511 skb = bt_skb_send_alloc(sk, count + hlen,
1512 msg->msg_flags & MSG_DONTWAIT, &err);
1513 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001514 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001515
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001516 skb->priority = priority;
1517
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001518 /* Create L2CAP header */
1519 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001520 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001521 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001522 put_unaligned_le16(chan->psm, skb_put(skb, 2));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001523
1524 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1525 if (unlikely(err < 0)) {
1526 kfree_skb(skb);
1527 return ERR_PTR(err);
1528 }
1529 return skb;
1530}
1531
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001532static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
1533 struct msghdr *msg, size_t len,
1534 u32 priority)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001535{
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001536 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001537 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001538 struct sk_buff *skb;
1539 int err, count, hlen = L2CAP_HDR_SIZE;
1540 struct l2cap_hdr *lh;
1541
1542 BT_DBG("sk %p len %d", sk, (int)len);
1543
1544 count = min_t(unsigned int, (conn->mtu - hlen), len);
1545 skb = bt_skb_send_alloc(sk, count + hlen,
1546 msg->msg_flags & MSG_DONTWAIT, &err);
1547 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001548 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001549
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001550 skb->priority = priority;
1551
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001552 /* Create L2CAP header */
1553 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001554 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001555 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
1556
1557 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1558 if (unlikely(err < 0)) {
1559 kfree_skb(skb);
1560 return ERR_PTR(err);
1561 }
1562 return skb;
1563}
1564
Luiz Augusto von Dentzab0ff762011-09-12 20:00:50 +03001565static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
1566 struct msghdr *msg, size_t len,
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001567 u32 control, u16 sdulen)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001568{
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001569 struct sock *sk = chan->sk;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03001570 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001571 struct sk_buff *skb;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001572 int err, count, hlen;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001573 struct l2cap_hdr *lh;
1574
1575 BT_DBG("sk %p len %d", sk, (int)len);
1576
Gustavo F. Padovan0ee0d202010-05-01 16:15:41 -03001577 if (!conn)
1578 return ERR_PTR(-ENOTCONN);
1579
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03001580 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
1581 hlen = L2CAP_EXT_HDR_SIZE;
1582 else
1583 hlen = L2CAP_ENH_HDR_SIZE;
1584
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001585 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001586 hlen += L2CAP_SDULEN_SIZE;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001587
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001588 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001589 hlen += L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001590
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001591 count = min_t(unsigned int, (conn->mtu - hlen), len);
1592 skb = bt_skb_send_alloc(sk, count + hlen,
1593 msg->msg_flags & MSG_DONTWAIT, &err);
1594 if (!skb)
Gustavo F. Padovan0175d622010-09-24 20:30:57 -03001595 return ERR_PTR(err);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001596
1597 /* Create L2CAP header */
1598 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03001599 lh->cid = cpu_to_le16(chan->dcid);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001600 lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001601
1602 __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
1603
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001604 if (sdulen)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001605 put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001606
1607 err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
1608 if (unlikely(err < 0)) {
1609 kfree_skb(skb);
1610 return ERR_PTR(err);
1611 }
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001612
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001613 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03001614 put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03001615
Gustavo F. Padovane90bac02009-08-20 22:26:00 -03001616 bt_cb(skb)->retries = 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03001617 return skb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618}
1619
Szymon Janc67c9e842011-07-28 16:24:33 +02001620static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001621{
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001622 struct sk_buff *skb;
1623 struct sk_buff_head sar_queue;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001624 u32 control;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001625 size_t size = 0;
1626
Gustavo F. Padovanff12fd62010-05-05 22:09:15 -03001627 skb_queue_head_init(&sar_queue);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001628 control = __set_ctrl_sar(chan, L2CAP_SAR_START);
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001629 skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001630 if (IS_ERR(skb))
1631 return PTR_ERR(skb);
1632
1633 __skb_queue_tail(&sar_queue, skb);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001634 len -= chan->remote_mps;
1635 size += chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001636
1637 while (len > 0) {
1638 size_t buflen;
1639
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001640 if (len > chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001641 control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03001642 buflen = chan->remote_mps;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001643 } else {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001644 control = __set_ctrl_sar(chan, L2CAP_SAR_END);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001645 buflen = len;
1646 }
1647
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03001648 skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0);
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001649 if (IS_ERR(skb)) {
1650 skb_queue_purge(&sar_queue);
1651 return PTR_ERR(skb);
1652 }
1653
1654 __skb_queue_tail(&sar_queue, skb);
1655 len -= buflen;
1656 size += buflen;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001657 }
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03001658 skb_queue_splice_tail(&sar_queue, &chan->tx_q);
1659 if (chan->tx_send_head == NULL)
1660 chan->tx_send_head = sar_queue.next;
Gustavo F. Padovanc74e5602009-08-20 22:25:58 -03001661
1662 return size;
1663}
1664
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001665int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
1666 u32 priority)
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001667{
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001668 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03001669 u32 control;
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001670 int err;
1671
1672 /* Connectionless channel */
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001673 if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001674 skb = l2cap_create_connless_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001675 if (IS_ERR(skb))
1676 return PTR_ERR(skb);
1677
1678 l2cap_do_send(chan, skb);
1679 return len;
1680 }
1681
1682 switch (chan->mode) {
1683 case L2CAP_MODE_BASIC:
1684 /* Check outgoing MTU */
1685 if (len > chan->omtu)
1686 return -EMSGSIZE;
1687
1688 /* Create a basic PDU */
Luiz Augusto von Dentz5e59b792011-11-01 10:58:57 +02001689 skb = l2cap_create_basic_pdu(chan, msg, len, priority);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001690 if (IS_ERR(skb))
1691 return PTR_ERR(skb);
1692
1693 l2cap_do_send(chan, skb);
1694 err = len;
1695 break;
1696
1697 case L2CAP_MODE_ERTM:
1698 case L2CAP_MODE_STREAMING:
1699 /* Entire SDU fits into one PDU */
1700 if (len <= chan->remote_mps) {
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03001701 control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001702 skb = l2cap_create_iframe_pdu(chan, msg, len, control,
1703 0);
1704 if (IS_ERR(skb))
1705 return PTR_ERR(skb);
1706
1707 __skb_queue_tail(&chan->tx_q, skb);
1708
1709 if (chan->tx_send_head == NULL)
1710 chan->tx_send_head = skb;
1711
1712 } else {
1713 /* Segment SDU into multiples PDUs */
1714 err = l2cap_sar_segment_sdu(chan, msg, len);
1715 if (err < 0)
1716 return err;
1717 }
1718
1719 if (chan->mode == L2CAP_MODE_STREAMING) {
1720 l2cap_streaming_send(chan);
1721 err = len;
1722 break;
1723 }
1724
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03001725 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
1726 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan9a91a042011-04-28 18:50:17 -03001727 err = len;
1728 break;
1729 }
1730
1731 err = l2cap_ertm_send(chan);
1732 if (err >= 0)
1733 err = len;
1734
1735 break;
1736
1737 default:
1738 BT_DBG("bad state %1.1x", chan->mode);
1739 err = -EBADFD;
1740 }
1741
1742 return err;
1743}
1744
Linus Torvalds1da177e2005-04-16 15:20:36 -07001745/* Copy frame to all raw sockets on that connection */
1746static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
1747{
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 struct sk_buff *nskb;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001749 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750
1751 BT_DBG("conn %p", conn);
1752
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001753 read_lock(&conn->chan_lock);
1754 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03001755 struct sock *sk = chan->sk;
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03001756 if (chan->chan_type != L2CAP_CHAN_RAW)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 continue;
1758
1759 /* Don't send frame to the socket it came from */
1760 if (skb->sk == sk)
1761 continue;
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001762 nskb = skb_clone(skb, GFP_ATOMIC);
1763 if (!nskb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 continue;
1765
Gustavo F. Padovan23070492011-05-16 17:57:22 -03001766 if (chan->ops->recv(chan->data, nskb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001767 kfree_skb(nskb);
1768 }
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03001769 read_unlock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001770}
1771
1772/* ---- L2CAP signalling commands ---- */
1773static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
1774 u8 code, u8 ident, u16 dlen, void *data)
1775{
1776 struct sk_buff *skb, **frag;
1777 struct l2cap_cmd_hdr *cmd;
1778 struct l2cap_hdr *lh;
1779 int len, count;
1780
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03001781 BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d",
1782 conn, code, ident, dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001783
1784 len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
1785 count = min_t(unsigned int, conn->mtu, len);
1786
1787 skb = bt_skb_alloc(count, GFP_ATOMIC);
1788 if (!skb)
1789 return NULL;
1790
1791 lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001792 lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02001793
1794 if (conn->hcon->type == LE_LINK)
1795 lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING);
1796 else
1797 lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001798
1799 cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE);
1800 cmd->code = code;
1801 cmd->ident = ident;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001802 cmd->len = cpu_to_le16(dlen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
1804 if (dlen) {
1805 count -= L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE;
1806 memcpy(skb_put(skb, count), data, count);
1807 data += count;
1808 }
1809
1810 len -= skb->len;
1811
1812 /* Continuation fragments (no L2CAP header) */
1813 frag = &skb_shinfo(skb)->frag_list;
1814 while (len) {
1815 count = min_t(unsigned int, conn->mtu, len);
1816
1817 *frag = bt_skb_alloc(count, GFP_ATOMIC);
1818 if (!*frag)
1819 goto fail;
1820
1821 memcpy(skb_put(*frag, count), data, count);
1822
1823 len -= count;
1824 data += count;
1825
1826 frag = &(*frag)->next;
1827 }
1828
1829 return skb;
1830
1831fail:
1832 kfree_skb(skb);
1833 return NULL;
1834}
1835
1836static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
1837{
1838 struct l2cap_conf_opt *opt = *ptr;
1839 int len;
1840
1841 len = L2CAP_CONF_OPT_SIZE + opt->len;
1842 *ptr += len;
1843
1844 *type = opt->type;
1845 *olen = opt->len;
1846
1847 switch (opt->len) {
1848 case 1:
1849 *val = *((u8 *) opt->val);
1850 break;
1851
1852 case 2:
steven miaobfaaeb32010-10-16 18:29:47 -04001853 *val = get_unaligned_le16(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001854 break;
1855
1856 case 4:
steven miaobfaaeb32010-10-16 18:29:47 -04001857 *val = get_unaligned_le32(opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001858 break;
1859
1860 default:
1861 *val = (unsigned long) opt->val;
1862 break;
1863 }
1864
1865 BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val);
1866 return len;
1867}
1868
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
1870{
1871 struct l2cap_conf_opt *opt = *ptr;
1872
1873 BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val);
1874
1875 opt->type = type;
1876 opt->len = len;
1877
1878 switch (len) {
1879 case 1:
1880 *((u8 *) opt->val) = val;
1881 break;
1882
1883 case 2:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001884 put_unaligned_le16(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001885 break;
1886
1887 case 4:
Gustavo F. Padovan4f8b6912010-10-18 14:25:53 -02001888 put_unaligned_le32(val, opt->val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 break;
1890
1891 default:
1892 memcpy(opt->val, (void *) val, len);
1893 break;
1894 }
1895
1896 *ptr += L2CAP_CONF_OPT_SIZE + len;
1897}
1898
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001899static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
1900{
1901 struct l2cap_conf_efs efs;
1902
Szymon Janc1ec918c2011-11-16 09:32:21 +01001903 switch (chan->mode) {
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001904 case L2CAP_MODE_ERTM:
1905 efs.id = chan->local_id;
1906 efs.stype = chan->local_stype;
1907 efs.msdu = cpu_to_le16(chan->local_msdu);
1908 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1909 efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
1910 efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
1911 break;
1912
1913 case L2CAP_MODE_STREAMING:
1914 efs.id = 1;
1915 efs.stype = L2CAP_SERV_BESTEFFORT;
1916 efs.msdu = cpu_to_le16(chan->local_msdu);
1917 efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
1918 efs.acc_lat = 0;
1919 efs.flush_to = 0;
1920 break;
1921
1922 default:
1923 return;
1924 }
1925
1926 l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
1927 (unsigned long) &efs);
1928}
1929
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001930static void l2cap_ack_timeout(unsigned long arg)
1931{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001932 struct l2cap_chan *chan = (void *) arg;
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001933
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001934 bh_lock_sock(chan->sk);
1935 l2cap_send_ack(chan);
1936 bh_unlock_sock(chan->sk);
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03001937}
1938
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001939static inline void l2cap_ertm_init(struct l2cap_chan *chan)
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001940{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03001941 struct sock *sk = chan->sk;
1942
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001943 chan->expected_ack_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001944 chan->unacked_frames = 0;
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03001945 chan->buffer_seq = 0;
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03001946 chan->num_acked = 0;
1947 chan->frames_sent = 0;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001948
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03001949 setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
1950 (unsigned long) chan);
1951 setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
1952 (unsigned long) chan);
1953 setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001954
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03001955 skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03001956
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03001957 INIT_LIST_HEAD(&chan->srej_l);
1958
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03001959
1960 sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03001961}
1962
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03001963static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
1964{
1965 switch (mode) {
1966 case L2CAP_MODE_STREAMING:
1967 case L2CAP_MODE_ERTM:
1968 if (l2cap_mode_supported(mode, remote_feat_mask))
1969 return mode;
1970 /* fall through */
1971 default:
1972 return L2CAP_MODE_BASIC;
1973 }
1974}
1975
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001976static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
1977{
1978 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
1979}
1980
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03001981static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
1982{
1983 return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
1984}
1985
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001986static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
1987{
1988 if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001989 __l2cap_ews_supported(chan)) {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001990 /* use extended control field */
1991 set_bit(FLAG_EXT_CTRL, &chan->flags);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001992 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
1993 } else {
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001994 chan->tx_win = min_t(u16, chan->tx_win,
1995 L2CAP_DEFAULT_TX_WINDOW);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03001996 chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
1997 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03001998}
1999
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002000static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 struct l2cap_conf_req *req = data;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002003 struct l2cap_conf_rfc rfc = { .mode = chan->mode };
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 void *ptr = req->data;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002005 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002006
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03002007 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002008
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002009 if (chan->num_conf_req || chan->num_conf_rsp)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002010 goto done;
2011
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002012 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002013 case L2CAP_MODE_STREAMING:
2014 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002015 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002016 break;
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002017
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002018 if (__l2cap_efs_supported(chan))
2019 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2020
Gustavo F. Padovan2ba13ed2010-06-09 16:39:05 -03002021 /* fall through */
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002022 default:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002023 chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002024 break;
2025 }
2026
2027done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002028 if (chan->imtu != L2CAP_DEFAULT_MTU)
2029 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovan7990681c2011-01-24 16:01:43 -02002030
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002031 switch (chan->mode) {
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002032 case L2CAP_MODE_BASIC:
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002033 if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
2034 !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002035 break;
2036
Gustavo F. Padovan62547752010-06-08 20:05:31 -03002037 rfc.mode = L2CAP_MODE_BASIC;
2038 rfc.txwin_size = 0;
2039 rfc.max_transmit = 0;
2040 rfc.retrans_timeout = 0;
2041 rfc.monitor_timeout = 0;
2042 rfc.max_pdu_size = 0;
2043
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002044 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2045 (unsigned long) &rfc);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002046 break;
2047
2048 case L2CAP_MODE_ERTM:
2049 rfc.mode = L2CAP_MODE_ERTM;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002050 rfc.max_transmit = chan->max_tx;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002051 rfc.retrans_timeout = 0;
2052 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002053
2054 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2055 L2CAP_EXT_HDR_SIZE -
2056 L2CAP_SDULEN_SIZE -
2057 L2CAP_FCS_SIZE);
2058 rfc.max_pdu_size = cpu_to_le16(size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002059
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002060 l2cap_txwin_setup(chan);
2061
2062 rfc.txwin_size = min_t(u16, chan->tx_win,
2063 L2CAP_DEFAULT_TX_WINDOW);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002064
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002065 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2066 (unsigned long) &rfc);
2067
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002068 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2069 l2cap_add_opt_efs(&ptr, chan);
2070
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002071 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002072 break;
2073
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002074 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002075 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002076 chan->fcs = L2CAP_FCS_NONE;
2077 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002078 }
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002079
2080 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
2081 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2082 chan->tx_win);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002083 break;
2084
2085 case L2CAP_MODE_STREAMING:
2086 rfc.mode = L2CAP_MODE_STREAMING;
2087 rfc.txwin_size = 0;
2088 rfc.max_transmit = 0;
2089 rfc.retrans_timeout = 0;
2090 rfc.monitor_timeout = 0;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002091
2092 size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
2093 L2CAP_EXT_HDR_SIZE -
2094 L2CAP_SDULEN_SIZE -
2095 L2CAP_FCS_SIZE);
2096 rfc.max_pdu_size = cpu_to_le16(size);
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002097
Gustavo F. Padovan63406502010-08-03 23:49:29 -03002098 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
2099 (unsigned long) &rfc);
2100
Andrei Emeltchenkof89cef02011-10-13 16:18:55 +03002101 if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
2102 l2cap_add_opt_efs(&ptr, chan);
2103
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002104 if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002105 break;
2106
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002107 if (chan->fcs == L2CAP_FCS_NONE ||
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002108 test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002109 chan->fcs = L2CAP_FCS_NONE;
2110 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002111 }
Marcel Holtmann65c7c492009-05-02 23:07:53 -07002112 break;
2113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002115 req->dcid = cpu_to_le16(chan->dcid);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002116 req->flags = cpu_to_le16(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002117
2118 return ptr - data;
2119}
2120
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002121static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122{
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002123 struct l2cap_conf_rsp *rsp = data;
2124 void *ptr = rsp->data;
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002125 void *req = chan->conf_req;
2126 int len = chan->conf_len;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002127 int type, hint, olen;
2128 unsigned long val;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002129 struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002130 struct l2cap_conf_efs efs;
2131 u8 remote_efs = 0;
Marcel Holtmann861d6882007-10-20 13:37:06 +02002132 u16 mtu = L2CAP_DEFAULT_MTU;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002133 u16 result = L2CAP_CONF_SUCCESS;
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002134 u16 size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002136 BT_DBG("chan %p", chan);
Marcel Holtmann820ae1b2006-11-18 22:15:00 +01002137
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002138 while (len >= L2CAP_CONF_OPT_SIZE) {
2139 len -= l2cap_get_conf_opt(&req, &type, &olen, &val);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002140
Gustavo F. Padovan589d2742009-04-20 01:31:07 -03002141 hint = type & L2CAP_CONF_HINT;
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07002142 type &= L2CAP_CONF_MASK;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002143
2144 switch (type) {
2145 case L2CAP_CONF_MTU:
Marcel Holtmann861d6882007-10-20 13:37:06 +02002146 mtu = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002147 break;
2148
2149 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002150 chan->flush_to = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002151 break;
2152
2153 case L2CAP_CONF_QOS:
2154 break;
2155
Marcel Holtmann6464f352007-10-20 13:39:51 +02002156 case L2CAP_CONF_RFC:
2157 if (olen == sizeof(rfc))
2158 memcpy(&rfc, (void *) val, olen);
2159 break;
2160
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002161 case L2CAP_CONF_FCS:
2162 if (val == L2CAP_FCS_NONE)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002163 set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002164 break;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002165
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002166 case L2CAP_CONF_EFS:
2167 remote_efs = 1;
2168 if (olen == sizeof(efs))
2169 memcpy(&efs, (void *) val, olen);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002170 break;
2171
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002172 case L2CAP_CONF_EWS:
2173 if (!enable_hs)
2174 return -ECONNREFUSED;
2175
2176 set_bit(FLAG_EXT_CTRL, &chan->flags);
2177 set_bit(CONF_EWS_RECV, &chan->conf_state);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03002178 chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002179 chan->remote_tx_win = val;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002180 break;
2181
2182 default:
2183 if (hint)
2184 break;
2185
2186 result = L2CAP_CONF_UNKNOWN;
2187 *((u8 *) ptr++) = type;
2188 break;
2189 }
2190 }
2191
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002192 if (chan->num_conf_rsp || chan->num_conf_req > 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002193 goto done;
2194
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002195 switch (chan->mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002196 case L2CAP_MODE_STREAMING:
2197 case L2CAP_MODE_ERTM:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002198 if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002199 chan->mode = l2cap_select_mode(rfc.mode,
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002200 chan->conn->feat_mask);
Gustavo F. Padovan85eb53c2010-06-03 18:43:28 -03002201 break;
2202 }
2203
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002204 if (remote_efs) {
2205 if (__l2cap_efs_supported(chan))
2206 set_bit(FLAG_EFS_ENABLE, &chan->flags);
2207 else
2208 return -ECONNREFUSED;
2209 }
2210
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002211 if (chan->mode != rfc.mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002212 return -ECONNREFUSED;
Gustavo F. Padovan742e5192010-06-08 19:09:48 -03002213
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002214 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002215 }
2216
2217done:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002218 if (chan->mode != rfc.mode) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002219 result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002220 rfc.mode = chan->mode;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002221
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002222 if (chan->num_conf_rsp == 1)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002223 return -ECONNREFUSED;
2224
2225 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2226 sizeof(rfc), (unsigned long) &rfc);
2227 }
2228
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002229 if (result == L2CAP_CONF_SUCCESS) {
2230 /* Configure output options and let the other side know
2231 * which ones we don't like. */
2232
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002233 if (mtu < L2CAP_DEFAULT_MIN_MTU)
2234 result = L2CAP_CONF_UNACCEPT;
2235 else {
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002236 chan->omtu = mtu;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002237 set_bit(CONF_MTU_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002238 }
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002239 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002240
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002241 if (remote_efs) {
2242 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2243 efs.stype != L2CAP_SERV_NOTRAFIC &&
2244 efs.stype != chan->local_stype) {
2245
2246 result = L2CAP_CONF_UNACCEPT;
2247
2248 if (chan->num_conf_req >= 1)
2249 return -ECONNREFUSED;
2250
2251 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002252 sizeof(efs),
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002253 (unsigned long) &efs);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002254 } else {
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002255 /* Send PENDING Conf Rsp */
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002256 result = L2CAP_CONF_PENDING;
2257 set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002258 }
2259 }
2260
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002261 switch (rfc.mode) {
2262 case L2CAP_MODE_BASIC:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002263 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002264 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002265 break;
2266
2267 case L2CAP_MODE_ERTM:
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002268 if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
2269 chan->remote_tx_win = rfc.txwin_size;
2270 else
2271 rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
2272
Gustavo F. Padovan2c03a7a2011-03-25 20:15:28 -03002273 chan->remote_max_tx = rfc.max_transmit;
Mat Martineau86b1b262010-08-05 15:54:22 -07002274
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002275 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2276 chan->conn->mtu -
2277 L2CAP_EXT_HDR_SIZE -
2278 L2CAP_SDULEN_SIZE -
2279 L2CAP_FCS_SIZE);
2280 rfc.max_pdu_size = cpu_to_le16(size);
2281 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002282
Gustavo F. Padovan10467e92010-05-01 16:15:40 -03002283 rfc.retrans_timeout =
2284 le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
2285 rfc.monitor_timeout =
2286 le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002287
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002288 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002289
2290 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2291 sizeof(rfc), (unsigned long) &rfc);
2292
Andrei Emeltchenko42dceae2011-10-17 14:35:30 +03002293 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2294 chan->remote_id = efs.id;
2295 chan->remote_stype = efs.stype;
2296 chan->remote_msdu = le16_to_cpu(efs.msdu);
2297 chan->remote_flush_to =
2298 le32_to_cpu(efs.flush_to);
2299 chan->remote_acc_lat =
2300 le32_to_cpu(efs.acc_lat);
2301 chan->remote_sdu_itime =
2302 le32_to_cpu(efs.sdu_itime);
2303 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2304 sizeof(efs), (unsigned long) &efs);
2305 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002306 break;
2307
2308 case L2CAP_MODE_STREAMING:
Andrei Emeltchenkoc8f79162011-10-17 12:19:59 +03002309 size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
2310 chan->conn->mtu -
2311 L2CAP_EXT_HDR_SIZE -
2312 L2CAP_SDULEN_SIZE -
2313 L2CAP_FCS_SIZE);
2314 rfc.max_pdu_size = cpu_to_le16(size);
2315 chan->remote_mps = size;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002316
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002317 set_bit(CONF_MODE_DONE, &chan->conf_state);
Gustavo F. Padovan68ae6632009-10-17 21:41:01 -03002318
2319 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2320 sizeof(rfc), (unsigned long) &rfc);
2321
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002322 break;
2323
2324 default:
Marcel Holtmann6464f352007-10-20 13:39:51 +02002325 result = L2CAP_CONF_UNACCEPT;
2326
2327 memset(&rfc, 0, sizeof(rfc));
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002328 rfc.mode = chan->mode;
Marcel Holtmann6464f352007-10-20 13:39:51 +02002329 }
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002330
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002331 if (result == L2CAP_CONF_SUCCESS)
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002332 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002333 }
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002334 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002335 rsp->result = cpu_to_le16(result);
2336 rsp->flags = cpu_to_le16(0x0000);
2337
2338 return ptr - data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002339}
2340
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002341static 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 -03002342{
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002343 struct l2cap_conf_req *req = data;
2344 void *ptr = req->data;
2345 int type, olen;
2346 unsigned long val;
2347 struct l2cap_conf_rfc rfc;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002348 struct l2cap_conf_efs efs;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002349
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002350 BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002351
2352 while (len >= L2CAP_CONF_OPT_SIZE) {
2353 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2354
2355 switch (type) {
2356 case L2CAP_CONF_MTU:
2357 if (val < L2CAP_DEFAULT_MIN_MTU) {
2358 *result = L2CAP_CONF_UNACCEPT;
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002359 chan->imtu = L2CAP_DEFAULT_MIN_MTU;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002360 } else
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002361 chan->imtu = val;
2362 l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002363 break;
2364
2365 case L2CAP_CONF_FLUSH_TO:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002366 chan->flush_to = val;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002367 l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002368 2, chan->flush_to);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002369 break;
2370
2371 case L2CAP_CONF_RFC:
2372 if (olen == sizeof(rfc))
2373 memcpy(&rfc, (void *)val, olen);
2374
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002375 if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002376 rfc.mode != chan->mode)
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002377 return -ECONNREFUSED;
2378
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002379 chan->fcs = 0;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002380
2381 l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
2382 sizeof(rfc), (unsigned long) &rfc);
2383 break;
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002384
2385 case L2CAP_CONF_EWS:
2386 chan->tx_win = min_t(u16, val,
2387 L2CAP_DEFAULT_EXT_WINDOW);
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002388 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
2389 chan->tx_win);
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03002390 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002391
2392 case L2CAP_CONF_EFS:
2393 if (olen == sizeof(efs))
2394 memcpy(&efs, (void *)val, olen);
2395
2396 if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
2397 efs.stype != L2CAP_SERV_NOTRAFIC &&
2398 efs.stype != chan->local_stype)
2399 return -ECONNREFUSED;
2400
2401 l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
2402 sizeof(efs), (unsigned long) &efs);
2403 break;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002404 }
2405 }
2406
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002407 if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode)
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002408 return -ECONNREFUSED;
2409
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002410 chan->mode = rfc.mode;
Gustavo F. Padovan6c2ea7a2010-06-08 20:08:49 -03002411
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002412 if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002413 switch (rfc.mode) {
2414 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002415 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2416 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2417 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002418
2419 if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
2420 chan->local_msdu = le16_to_cpu(efs.msdu);
2421 chan->local_sdu_itime =
2422 le32_to_cpu(efs.sdu_itime);
2423 chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
2424 chan->local_flush_to =
2425 le32_to_cpu(efs.flush_to);
2426 }
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002427 break;
Andrei Emeltchenko66af7aa2011-11-07 14:20:33 +02002428
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002429 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002430 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002431 }
2432 }
2433
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002434 req->dcid = cpu_to_le16(chan->dcid);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002435 req->flags = cpu_to_le16(0x0000);
2436
2437 return ptr - data;
2438}
2439
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002440static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002441{
2442 struct l2cap_conf_rsp *rsp = data;
2443 void *ptr = rsp->data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002444
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002445 BT_DBG("chan %p", chan);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002446
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002447 rsp->scid = cpu_to_le16(chan->dcid);
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002448 rsp->result = cpu_to_le16(result);
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002449 rsp->flags = cpu_to_le16(flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002450
2451 return ptr - data;
2452}
2453
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002454void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002455{
2456 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03002457 struct l2cap_conn *conn = chan->conn;
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002458 u8 buf[128];
2459
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002460 rsp.scid = cpu_to_le16(chan->dcid);
2461 rsp.dcid = cpu_to_le16(chan->scid);
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002462 rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
2463 rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
2464 l2cap_send_cmd(conn, chan->ident,
2465 L2CAP_CONN_RSP, sizeof(rsp), &rsp);
2466
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002467 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002468 return;
2469
Gustavo F. Padovan710f9b02011-03-25 14:30:37 -03002470 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
2471 l2cap_build_conf_req(chan, buf), buf);
2472 chan->num_conf_req++;
2473}
2474
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002475static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002476{
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002477 int type, olen;
2478 unsigned long val;
2479 struct l2cap_conf_rfc rfc;
2480
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002481 BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002482
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002483 if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002484 return;
2485
2486 while (len >= L2CAP_CONF_OPT_SIZE) {
2487 len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val);
2488
2489 switch (type) {
2490 case L2CAP_CONF_RFC:
2491 if (olen == sizeof(rfc))
2492 memcpy(&rfc, (void *)val, olen);
2493 goto done;
2494 }
2495 }
2496
2497done:
2498 switch (rfc.mode) {
2499 case L2CAP_MODE_ERTM:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002500 chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
2501 chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
2502 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002503 break;
2504 case L2CAP_MODE_STREAMING:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002505 chan->mps = le16_to_cpu(rfc.max_pdu_size);
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002506 }
2507}
2508
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002509static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2510{
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002511 struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002512
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002513 if (rej->reason != L2CAP_REJ_NOT_UNDERSTOOD)
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002514 return 0;
2515
2516 if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
2517 cmd->ident == conn->info_ident) {
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002518 del_timer(&conn->info_timer);
Marcel Holtmann984947d2009-02-06 23:35:19 +01002519
2520 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01002521 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01002522
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02002523 l2cap_conn_start(conn);
2524 }
2525
2526 return 0;
2527}
2528
Linus Torvalds1da177e2005-04-16 15:20:36 -07002529static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2530{
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
2532 struct l2cap_conn_rsp rsp;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002533 struct l2cap_chan *chan = NULL, *pchan;
Nathan Holsteind793fe82010-10-15 11:54:02 -04002534 struct sock *parent, *sk = NULL;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002535 int result, status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002536
2537 u16 dcid = 0, scid = __le16_to_cpu(req->scid);
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002538 __le16 psm = req->psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002539
2540 BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
2541
2542 /* Check if we have socket listening on psm */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002543 pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
2544 if (!pchan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 result = L2CAP_CR_BAD_PSM;
2546 goto sendresp;
2547 }
2548
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03002549 parent = pchan->sk;
2550
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00002551 bh_lock_sock(parent);
2552
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002553 /* Check if the ACL is secure enough (if not SDP) */
2554 if (psm != cpu_to_le16(0x0001) &&
2555 !hci_conn_check_link_mode(conn->hcon)) {
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02002556 conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +02002557 result = L2CAP_CR_SEC_BLOCK;
2558 goto response;
2559 }
2560
Linus Torvalds1da177e2005-04-16 15:20:36 -07002561 result = L2CAP_CR_NO_MEM;
2562
2563 /* Check for backlog size */
2564 if (sk_acceptq_is_full(parent)) {
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002565 BT_DBG("backlog full %d", parent->sk_ack_backlog);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 goto response;
2567 }
2568
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002569 chan = pchan->ops->new_connection(pchan->data);
2570 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002571 goto response;
2572
Gustavo F. Padovan80808e42011-05-16 17:24:37 -03002573 sk = chan->sk;
2574
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002575 write_lock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002576
2577 /* Check if we already have channel with that dcid */
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002578 if (__l2cap_get_chan_by_dcid(conn, scid)) {
2579 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002580 sock_set_flag(sk, SOCK_ZAPPED);
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002581 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002582 goto response;
2583 }
2584
2585 hci_conn_hold(conn->hcon);
2586
Linus Torvalds1da177e2005-04-16 15:20:36 -07002587 bacpy(&bt_sk(sk)->src, conn->src);
2588 bacpy(&bt_sk(sk)->dst, conn->dst);
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002589 chan->psm = psm;
2590 chan->dcid = scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002591
Gustavo F. Padovand1010242011-03-25 00:39:48 -03002592 bt_accept_enqueue(parent, sk);
2593
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002594 __l2cap_chan_add(conn, chan);
2595
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002596 dcid = chan->scid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002597
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002598 __set_chan_timer(chan, sk->sk_sndtimeo);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002600 chan->ident = cmd->ident;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002601
Marcel Holtmann984947d2009-02-06 23:35:19 +01002602 if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
Gustavo F. Padovand45fc422011-11-05 19:54:24 -02002603 if (l2cap_chan_check_security(chan)) {
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002604 if (bt_sk(sk)->defer_setup) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002605 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002606 result = L2CAP_CR_PEND;
2607 status = L2CAP_CS_AUTHOR_PEND;
2608 parent->sk_data_ready(parent, 0);
2609 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002610 l2cap_state_change(chan, BT_CONFIG);
Marcel Holtmannf66dc812009-01-15 21:57:00 +01002611 result = L2CAP_CR_SUCCESS;
2612 status = L2CAP_CS_NO_INFO;
2613 }
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002614 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002615 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002616 result = L2CAP_CR_PEND;
2617 status = L2CAP_CS_AUTHEN_PEND;
2618 }
2619 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002620 l2cap_state_change(chan, BT_CONNECT2);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002621 result = L2CAP_CR_PEND;
2622 status = L2CAP_CS_NO_INFO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623 }
2624
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002625 write_unlock_bh(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002626
2627response:
2628 bh_unlock_sock(parent);
2629
2630sendresp:
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07002631 rsp.scid = cpu_to_le16(scid);
2632 rsp.dcid = cpu_to_le16(dcid);
2633 rsp.result = cpu_to_le16(result);
2634 rsp.status = cpu_to_le16(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002635 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002636
2637 if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
2638 struct l2cap_info_req info;
2639 info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
2640
2641 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
2642 conn->info_ident = l2cap_get_ident(conn);
2643
2644 mod_timer(&conn->info_timer, jiffies +
2645 msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
2646
2647 l2cap_send_cmd(conn, conn->info_ident,
2648 L2CAP_INFO_REQ, sizeof(info), &info);
2649 }
2650
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002651 if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002652 result == L2CAP_CR_SUCCESS) {
2653 u8 buf[128];
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002654 set_bit(CONF_REQ_SENT, &chan->conf_state);
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002655 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002656 l2cap_build_conf_req(chan, buf), buf);
2657 chan->num_conf_req++;
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002658 }
2659
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660 return 0;
2661}
2662
2663static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2664{
2665 struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
2666 u16 scid, dcid, result, status;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002667 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002668 struct sock *sk;
2669 u8 req[128];
2670
2671 scid = __le16_to_cpu(rsp->scid);
2672 dcid = __le16_to_cpu(rsp->dcid);
2673 result = __le16_to_cpu(rsp->result);
2674 status = __le16_to_cpu(rsp->status);
2675
2676 BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status);
2677
2678 if (scid) {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002679 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002680 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002681 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002682 } else {
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002683 chan = l2cap_get_chan_by_ident(conn, cmd->ident);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002684 if (!chan)
João Paulo Rechi Vita57d3b222010-06-22 13:56:26 -03002685 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002686 }
2687
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002688 sk = chan->sk;
2689
Linus Torvalds1da177e2005-04-16 15:20:36 -07002690 switch (result) {
2691 case L2CAP_CR_SUCCESS:
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002692 l2cap_state_change(chan, BT_CONFIG);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03002693 chan->ident = 0;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002694 chan->dcid = dcid;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002695 clear_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01002696
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002697 if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
Gustavo F. Padovane9aeb2d2010-07-08 20:08:18 -03002698 break;
2699
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002701 l2cap_build_conf_req(chan, req), req);
2702 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002703 break;
2704
2705 case L2CAP_CR_PEND:
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002706 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002707 break;
2708
2709 default:
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002710 /* don't delete l2cap channel if sk is owned by user */
2711 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002712 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002713 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002714 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002715 break;
2716 }
2717
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002718 l2cap_chan_del(chan, ECONNREFUSED);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002719 break;
2720 }
2721
2722 bh_unlock_sock(sk);
2723 return 0;
2724}
2725
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002726static inline void set_default_fcs(struct l2cap_chan *chan)
Mat Martineau8c462b62010-08-24 15:35:42 -07002727{
2728 /* FCS is enabled only in ERTM or streaming mode, if one or both
2729 * sides request it.
2730 */
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002731 if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING)
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002732 chan->fcs = L2CAP_FCS_NONE;
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002733 else if (!test_bit(CONF_NO_FCS_RECV, &chan->conf_state))
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002734 chan->fcs = L2CAP_FCS_CRC16;
Mat Martineau8c462b62010-08-24 15:35:42 -07002735}
2736
Al Viro88219a02007-07-29 00:17:25 -07002737static 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 -07002738{
2739 struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
2740 u16 dcid, flags;
2741 u8 rsp[64];
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002742 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002743 struct sock *sk;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002744 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002745
2746 dcid = __le16_to_cpu(req->dcid);
2747 flags = __le16_to_cpu(req->flags);
2748
2749 BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags);
2750
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002751 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002752 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002753 return -ENOENT;
2754
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002755 sk = chan->sk;
2756
David S. Miller033b1142011-07-21 13:38:42 -07002757 if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002758 struct l2cap_cmd_rej_cid rej;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002759
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03002760 rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID);
2761 rej.scid = cpu_to_le16(chan->scid);
2762 rej.dcid = cpu_to_le16(chan->dcid);
2763
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002764 l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
2765 sizeof(rej), &rej);
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002766 goto unlock;
Gustavo F. Padovandf6bd742010-06-14 02:26:15 -03002767 }
Marcel Holtmann354f60a2006-11-18 22:15:20 +01002768
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002769 /* Reject if config buffer is too small. */
Al Viro88219a02007-07-29 00:17:25 -07002770 len = cmd_len - sizeof(*req);
Dan Rosenberg7ac28812011-06-24 08:38:05 -04002771 if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002772 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002773 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002774 L2CAP_CONF_REJECT, flags), rsp);
2775 goto unlock;
2776 }
2777
2778 /* Store config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002779 memcpy(chan->conf_req + chan->conf_len, req->data, len);
2780 chan->conf_len += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
2782 if (flags & 0x0001) {
2783 /* Incomplete config. Send empty response. */
2784 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002785 l2cap_build_conf_rsp(chan, rsp,
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002786 L2CAP_CONF_SUCCESS, 0x0001), rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002787 goto unlock;
2788 }
2789
2790 /* Complete config. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002791 len = l2cap_parse_conf_req(chan, rsp);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002792 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002793 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002794 goto unlock;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002795 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002797 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002798 chan->num_conf_rsp++;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002799
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002800 /* Reset config buffer. */
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002801 chan->conf_len = 0;
Marcel Holtmann5dee9e72007-05-24 14:27:19 +02002802
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002803 if (!test_bit(CONF_OUTPUT_DONE, &chan->conf_state))
Marcel Holtmann876d9482007-10-20 13:35:42 +02002804 goto unlock;
2805
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002806 if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002807 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002808
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002809 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002810
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002811 chan->next_tx_seq = 0;
2812 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002813 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002814 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002815 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002816
Linus Torvalds1da177e2005-04-16 15:20:36 -07002817 l2cap_chan_ready(sk);
Marcel Holtmann876d9482007-10-20 13:35:42 +02002818 goto unlock;
2819 }
2820
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002821 if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
Marcel Holtmann79d554a2008-07-14 20:13:44 +02002822 u8 buf[64];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823 l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002824 l2cap_build_conf_req(chan, buf), buf);
2825 chan->num_conf_req++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 }
2827
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002828 /* Got Conf Rsp PENDING from remote side and asume we sent
2829 Conf Rsp PENDING in the code above */
2830 if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
2831 test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2832
2833 /* check compatibility */
2834
2835 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2836 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2837
2838 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002839 l2cap_build_conf_rsp(chan, rsp,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002840 L2CAP_CONF_SUCCESS, 0x0000), rsp);
2841 }
2842
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843unlock:
2844 bh_unlock_sock(sk);
2845 return 0;
2846}
2847
2848static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2849{
2850 struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
2851 u16 scid, flags, result;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002852 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 struct sock *sk;
Gustavo F. Padovan7b1c0042010-05-01 16:15:39 -03002854 int len = cmd->len - sizeof(*rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002855
2856 scid = __le16_to_cpu(rsp->scid);
2857 flags = __le16_to_cpu(rsp->flags);
2858 result = __le16_to_cpu(rsp->result);
2859
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03002860 BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x",
2861 scid, flags, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002862
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002863 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002864 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002865 return 0;
2866
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002867 sk = chan->sk;
2868
Linus Torvalds1da177e2005-04-16 15:20:36 -07002869 switch (result) {
2870 case L2CAP_CONF_SUCCESS:
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002871 l2cap_conf_rfc_get(chan, rsp->data, len);
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002872 clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 break;
2874
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002875 case L2CAP_CONF_PENDING:
2876 set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
2877
2878 if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
2879 char buf[64];
2880
2881 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2882 buf, &result);
2883 if (len < 0) {
2884 l2cap_send_disconn_req(conn, chan, ECONNRESET);
2885 goto done;
2886 }
2887
2888 /* check compatibility */
2889
2890 clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
2891 set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
2892
2893 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
Gustavo F. Padovan3e6b3b92011-11-01 14:06:23 -02002894 l2cap_build_conf_rsp(chan, buf,
Andrei Emeltchenko0e8b2072011-10-17 14:35:32 +03002895 L2CAP_CONF_SUCCESS, 0x0000), buf);
2896 }
2897 goto done;
2898
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 case L2CAP_CONF_UNACCEPT:
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002900 if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002901 char req[64];
2902
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002903 if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002904 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Andrei Emeltchenkoc2c77ec2010-03-19 10:26:28 +02002905 goto done;
2906 }
2907
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002908 /* throw out any old stored conf requests */
2909 result = L2CAP_CONF_SUCCESS;
Gustavo F. Padovanb4450032011-04-12 18:15:09 -03002910 len = l2cap_parse_conf_rsp(chan, rsp->data, len,
2911 req, &result);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002912 if (len < 0) {
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002913 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002914 goto done;
2915 }
2916
2917 l2cap_send_cmd(conn, l2cap_get_ident(conn),
2918 L2CAP_CONF_REQ, len, req);
Gustavo F. Padovan73ffa902011-03-25 14:16:54 -03002919 chan->num_conf_req++;
Gustavo F. Padovanf2fcfcd2009-07-04 15:06:24 -03002920 if (result != L2CAP_CONF_SUCCESS)
2921 goto done;
2922 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002923 }
2924
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09002925 default:
Marcel Holtmannb1235d72008-07-14 20:13:54 +02002926 sk->sk_err = ECONNRESET;
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002927 __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
Gustavo F. Padovane92c8e72011-04-01 00:53:45 -03002928 l2cap_send_disconn_req(conn, chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002929 goto done;
2930 }
2931
2932 if (flags & 0x01)
2933 goto done;
2934
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002935 set_bit(CONF_INPUT_DONE, &chan->conf_state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002936
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03002937 if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) {
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03002938 set_default_fcs(chan);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03002939
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002940 l2cap_state_change(chan, BT_CONNECTED);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03002941 chan->next_tx_seq = 0;
2942 chan->expected_tx_seq = 0;
Gustavo F. Padovan58d35f82011-04-04 16:16:44 -03002943 skb_queue_head_init(&chan->tx_q);
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03002944 if (chan->mode == L2CAP_MODE_ERTM)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03002945 l2cap_ertm_init(chan);
Gustavo F. Padovan0565c1c2009-10-03 02:34:36 -03002946
Linus Torvalds1da177e2005-04-16 15:20:36 -07002947 l2cap_chan_ready(sk);
2948 }
2949
2950done:
2951 bh_unlock_sock(sk);
2952 return 0;
2953}
2954
2955static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2956{
2957 struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
2958 struct l2cap_disconn_rsp rsp;
2959 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002960 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002961 struct sock *sk;
2962
2963 scid = __le16_to_cpu(req->scid);
2964 dcid = __le16_to_cpu(req->dcid);
2965
2966 BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid);
2967
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03002968 chan = l2cap_get_chan_by_scid(conn, dcid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002969 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002970 return 0;
2971
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002972 sk = chan->sk;
2973
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03002974 rsp.dcid = cpu_to_le16(chan->scid);
2975 rsp.scid = cpu_to_le16(chan->dcid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002976 l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp);
2977
2978 sk->sk_shutdown = SHUTDOWN_MASK;
2979
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002980 /* don't delete l2cap channel if sk is owned by user */
2981 if (sock_owned_by_user(sk)) {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03002982 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03002983 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02002984 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02002985 bh_unlock_sock(sk);
2986 return 0;
2987 }
2988
Gustavo F. Padovan48454072011-03-25 00:22:30 -03002989 l2cap_chan_del(chan, ECONNRESET);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002990 bh_unlock_sock(sk);
2991
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03002992 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 return 0;
2994}
2995
2996static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
2997{
2998 struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
2999 u16 dcid, scid;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003000 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003001 struct sock *sk;
3002
3003 scid = __le16_to_cpu(rsp->scid);
3004 dcid = __le16_to_cpu(rsp->dcid);
3005
3006 BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid);
3007
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03003008 chan = l2cap_get_chan_by_scid(conn, scid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003009 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003010 return 0;
3011
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003012 sk = chan->sk;
3013
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003014 /* don't delete l2cap channel if sk is owned by user */
3015 if (sock_owned_by_user(sk)) {
Szymon Janc1ec918c2011-11-16 09:32:21 +01003016 l2cap_state_change(chan, BT_DISCONN);
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03003017 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02003018 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Andrei Emeltchenkoa49184c2010-11-03 12:32:44 +02003019 bh_unlock_sock(sk);
3020 return 0;
3021 }
3022
Gustavo F. Padovan48454072011-03-25 00:22:30 -03003023 l2cap_chan_del(chan, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003024 bh_unlock_sock(sk);
3025
Gustavo F. Padovanba3bd0e2011-05-16 18:23:24 -03003026 chan->ops->close(chan->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003027 return 0;
3028}
3029
3030static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3031{
3032 struct l2cap_info_req *req = (struct l2cap_info_req *) data;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003033 u16 type;
3034
3035 type = __le16_to_cpu(req->type);
3036
3037 BT_DBG("type 0x%4.4x", type);
3038
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003039 if (type == L2CAP_IT_FEAT_MASK) {
3040 u8 buf[8];
Marcel Holtmann44dd46d2009-05-02 19:09:01 -07003041 u32 feat_mask = l2cap_feat_mask;
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003042 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
3043 rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
3044 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03003045 if (!disable_ertm)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003046 feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
3047 | L2CAP_FEAT_FCS;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003048 if (enable_hs)
Andrei Emeltchenko6327eb92011-10-11 13:37:42 +03003049 feat_mask |= L2CAP_FEAT_EXT_FLOW
3050 | L2CAP_FEAT_EXT_WINDOW;
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03003051
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03003052 put_unaligned_le32(feat_mask, rsp->data);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003053 l2cap_send_cmd(conn, cmd->ident,
3054 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003055 } else if (type == L2CAP_IT_FIXED_CHAN) {
3056 u8 buf[12];
3057 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
Mat Martineau50a147c2011-11-02 16:18:34 -07003058
3059 if (enable_hs)
3060 l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
3061 else
3062 l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
3063
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003064 rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3065 rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
Andrei Emeltchenkoc6337ea2011-10-20 17:02:44 +03003066 memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003067 l2cap_send_cmd(conn, cmd->ident,
3068 L2CAP_INFO_RSP, sizeof(buf), buf);
Marcel Holtmannf0709e02007-10-20 13:38:51 +02003069 } else {
3070 struct l2cap_info_rsp rsp;
3071 rsp.type = cpu_to_le16(type);
3072 rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP);
3073 l2cap_send_cmd(conn, cmd->ident,
3074 L2CAP_INFO_RSP, sizeof(rsp), &rsp);
3075 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003076
3077 return 0;
3078}
3079
3080static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
3081{
3082 struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
3083 u16 type, result;
3084
3085 type = __le16_to_cpu(rsp->type);
3086 result = __le16_to_cpu(rsp->result);
3087
3088 BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
3089
Andrei Emeltchenkoe90165b2011-03-25 11:31:41 +02003090 /* L2CAP Info req/rsp are unbound to channels, add extra checks */
3091 if (cmd->ident != conn->info_ident ||
3092 conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
3093 return 0;
3094
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003095 del_timer(&conn->info_timer);
3096
Ville Tervoadb08ed2010-08-04 09:43:33 +03003097 if (result != L2CAP_IR_SUCCESS) {
3098 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3099 conn->info_ident = 0;
3100
3101 l2cap_conn_start(conn);
3102
3103 return 0;
3104 }
3105
Marcel Holtmann984947d2009-02-06 23:35:19 +01003106 if (type == L2CAP_IT_FEAT_MASK) {
Harvey Harrison83985312008-05-02 16:25:46 -07003107 conn->feat_mask = get_unaligned_le32(rsp->data);
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003108
Marcel Holtmann47ec1dcd2009-05-02 18:57:55 -07003109 if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) {
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003110 struct l2cap_info_req req;
3111 req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
3112
3113 conn->info_ident = l2cap_get_ident(conn);
3114
3115 l2cap_send_cmd(conn, conn->info_ident,
3116 L2CAP_INFO_REQ, sizeof(req), &req);
3117 } else {
3118 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
3119 conn->info_ident = 0;
3120
3121 l2cap_conn_start(conn);
3122 }
3123 } else if (type == L2CAP_IT_FIXED_CHAN) {
Marcel Holtmann984947d2009-02-06 23:35:19 +01003124 conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
Marcel Holtmanne1027a72009-02-09 09:18:02 +01003125 conn->info_ident = 0;
Marcel Holtmann984947d2009-02-06 23:35:19 +01003126
3127 l2cap_conn_start(conn);
3128 }
Marcel Holtmann4e8402a2007-10-20 13:37:56 +02003129
Linus Torvalds1da177e2005-04-16 15:20:36 -07003130 return 0;
3131}
3132
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003133static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
3134 struct l2cap_cmd_hdr *cmd, u16 cmd_len,
3135 void *data)
3136{
3137 struct l2cap_create_chan_req *req = data;
3138 struct l2cap_create_chan_rsp rsp;
3139 u16 psm, scid;
3140
3141 if (cmd_len != sizeof(*req))
3142 return -EPROTO;
3143
3144 if (!enable_hs)
3145 return -EINVAL;
3146
3147 psm = le16_to_cpu(req->psm);
3148 scid = le16_to_cpu(req->scid);
3149
3150 BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
3151
3152 /* Placeholder: Always reject */
3153 rsp.dcid = 0;
3154 rsp.scid = cpu_to_le16(scid);
3155 rsp.result = L2CAP_CR_NO_MEM;
3156 rsp.status = L2CAP_CS_NO_INFO;
3157
3158 l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
3159 sizeof(rsp), &rsp);
3160
3161 return 0;
3162}
3163
3164static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
3165 struct l2cap_cmd_hdr *cmd, void *data)
3166{
3167 BT_DBG("conn %p", conn);
3168
3169 return l2cap_connect_rsp(conn, cmd, data);
3170}
3171
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003172static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
3173 u16 icid, u16 result)
3174{
3175 struct l2cap_move_chan_rsp rsp;
3176
3177 BT_DBG("icid %d, result %d", icid, result);
3178
3179 rsp.icid = cpu_to_le16(icid);
3180 rsp.result = cpu_to_le16(result);
3181
3182 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
3183}
3184
3185static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
3186 struct l2cap_chan *chan, u16 icid, u16 result)
3187{
3188 struct l2cap_move_chan_cfm cfm;
3189 u8 ident;
3190
3191 BT_DBG("icid %d, result %d", icid, result);
3192
3193 ident = l2cap_get_ident(conn);
3194 if (chan)
3195 chan->ident = ident;
3196
3197 cfm.icid = cpu_to_le16(icid);
3198 cfm.result = cpu_to_le16(result);
3199
3200 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
3201}
3202
3203static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
3204 u16 icid)
3205{
3206 struct l2cap_move_chan_cfm_rsp rsp;
3207
3208 BT_DBG("icid %d", icid);
3209
3210 rsp.icid = cpu_to_le16(icid);
3211 l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
3212}
3213
3214static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
3215 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3216{
3217 struct l2cap_move_chan_req *req = data;
3218 u16 icid = 0;
3219 u16 result = L2CAP_MR_NOT_ALLOWED;
3220
3221 if (cmd_len != sizeof(*req))
3222 return -EPROTO;
3223
3224 icid = le16_to_cpu(req->icid);
3225
3226 BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
3227
3228 if (!enable_hs)
3229 return -EINVAL;
3230
3231 /* Placeholder: Always refuse */
3232 l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
3233
3234 return 0;
3235}
3236
3237static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
3238 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3239{
3240 struct l2cap_move_chan_rsp *rsp = data;
3241 u16 icid, result;
3242
3243 if (cmd_len != sizeof(*rsp))
3244 return -EPROTO;
3245
3246 icid = le16_to_cpu(rsp->icid);
3247 result = le16_to_cpu(rsp->result);
3248
3249 BT_DBG("icid %d, result %d", icid, result);
3250
3251 /* Placeholder: Always unconfirmed */
3252 l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
3253
3254 return 0;
3255}
3256
3257static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
3258 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3259{
3260 struct l2cap_move_chan_cfm *cfm = data;
3261 u16 icid, result;
3262
3263 if (cmd_len != sizeof(*cfm))
3264 return -EPROTO;
3265
3266 icid = le16_to_cpu(cfm->icid);
3267 result = le16_to_cpu(cfm->result);
3268
3269 BT_DBG("icid %d, result %d", icid, result);
3270
3271 l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
3272
3273 return 0;
3274}
3275
3276static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
3277 struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
3278{
3279 struct l2cap_move_chan_cfm_rsp *rsp = data;
3280 u16 icid;
3281
3282 if (cmd_len != sizeof(*rsp))
3283 return -EPROTO;
3284
3285 icid = le16_to_cpu(rsp->icid);
3286
3287 BT_DBG("icid %d", icid);
3288
3289 return 0;
3290}
3291
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003292static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
Claudio Takahaside731152011-02-11 19:28:55 -02003293 u16 to_multiplier)
3294{
3295 u16 max_latency;
3296
3297 if (min > max || min < 6 || max > 3200)
3298 return -EINVAL;
3299
3300 if (to_multiplier < 10 || to_multiplier > 3200)
3301 return -EINVAL;
3302
3303 if (max >= to_multiplier * 8)
3304 return -EINVAL;
3305
3306 max_latency = (to_multiplier * 8 / max) - 1;
3307 if (latency > 499 || latency > max_latency)
3308 return -EINVAL;
3309
3310 return 0;
3311}
3312
3313static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
3314 struct l2cap_cmd_hdr *cmd, u8 *data)
3315{
3316 struct hci_conn *hcon = conn->hcon;
3317 struct l2cap_conn_param_update_req *req;
3318 struct l2cap_conn_param_update_rsp rsp;
3319 u16 min, max, latency, to_multiplier, cmd_len;
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003320 int err;
Claudio Takahaside731152011-02-11 19:28:55 -02003321
3322 if (!(hcon->link_mode & HCI_LM_MASTER))
3323 return -EINVAL;
3324
3325 cmd_len = __le16_to_cpu(cmd->len);
3326 if (cmd_len != sizeof(struct l2cap_conn_param_update_req))
3327 return -EPROTO;
3328
3329 req = (struct l2cap_conn_param_update_req *) data;
Gustavo F. Padovane2174ca2011-02-17 19:16:55 -03003330 min = __le16_to_cpu(req->min);
3331 max = __le16_to_cpu(req->max);
Claudio Takahaside731152011-02-11 19:28:55 -02003332 latency = __le16_to_cpu(req->latency);
3333 to_multiplier = __le16_to_cpu(req->to_multiplier);
3334
3335 BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
3336 min, max, latency, to_multiplier);
3337
3338 memset(&rsp, 0, sizeof(rsp));
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003339
3340 err = l2cap_check_conn_param(min, max, latency, to_multiplier);
3341 if (err)
Claudio Takahaside731152011-02-11 19:28:55 -02003342 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED);
3343 else
3344 rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
3345
3346 l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
3347 sizeof(rsp), &rsp);
3348
Claudio Takahasi2ce603e2011-02-16 20:44:53 -02003349 if (!err)
3350 hci_le_conn_update(hcon, min, max, latency, to_multiplier);
3351
Claudio Takahaside731152011-02-11 19:28:55 -02003352 return 0;
3353}
3354
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003355static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
3356 struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
3357{
3358 int err = 0;
3359
3360 switch (cmd->code) {
3361 case L2CAP_COMMAND_REJ:
3362 l2cap_command_rej(conn, cmd, data);
3363 break;
3364
3365 case L2CAP_CONN_REQ:
3366 err = l2cap_connect_req(conn, cmd, data);
3367 break;
3368
3369 case L2CAP_CONN_RSP:
3370 err = l2cap_connect_rsp(conn, cmd, data);
3371 break;
3372
3373 case L2CAP_CONF_REQ:
3374 err = l2cap_config_req(conn, cmd, cmd_len, data);
3375 break;
3376
3377 case L2CAP_CONF_RSP:
3378 err = l2cap_config_rsp(conn, cmd, data);
3379 break;
3380
3381 case L2CAP_DISCONN_REQ:
3382 err = l2cap_disconnect_req(conn, cmd, data);
3383 break;
3384
3385 case L2CAP_DISCONN_RSP:
3386 err = l2cap_disconnect_rsp(conn, cmd, data);
3387 break;
3388
3389 case L2CAP_ECHO_REQ:
3390 l2cap_send_cmd(conn, cmd->ident, L2CAP_ECHO_RSP, cmd_len, data);
3391 break;
3392
3393 case L2CAP_ECHO_RSP:
3394 break;
3395
3396 case L2CAP_INFO_REQ:
3397 err = l2cap_information_req(conn, cmd, data);
3398 break;
3399
3400 case L2CAP_INFO_RSP:
3401 err = l2cap_information_rsp(conn, cmd, data);
3402 break;
3403
Mat Martineauf94ff6f2011-11-02 16:18:32 -07003404 case L2CAP_CREATE_CHAN_REQ:
3405 err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
3406 break;
3407
3408 case L2CAP_CREATE_CHAN_RSP:
3409 err = l2cap_create_channel_rsp(conn, cmd, data);
3410 break;
3411
Mat Martineau8d5a04a2011-11-02 16:18:35 -07003412 case L2CAP_MOVE_CHAN_REQ:
3413 err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
3414 break;
3415
3416 case L2CAP_MOVE_CHAN_RSP:
3417 err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
3418 break;
3419
3420 case L2CAP_MOVE_CHAN_CFM:
3421 err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
3422 break;
3423
3424 case L2CAP_MOVE_CHAN_CFM_RSP:
3425 err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
3426 break;
3427
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003428 default:
3429 BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
3430 err = -EINVAL;
3431 break;
3432 }
3433
3434 return err;
3435}
3436
3437static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
3438 struct l2cap_cmd_hdr *cmd, u8 *data)
3439{
3440 switch (cmd->code) {
3441 case L2CAP_COMMAND_REJ:
3442 return 0;
3443
3444 case L2CAP_CONN_PARAM_UPDATE_REQ:
Claudio Takahaside731152011-02-11 19:28:55 -02003445 return l2cap_conn_param_update_req(conn, cmd, data);
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003446
3447 case L2CAP_CONN_PARAM_UPDATE_RSP:
3448 return 0;
3449
3450 default:
3451 BT_ERR("Unknown LE signaling command 0x%2.2x", cmd->code);
3452 return -EINVAL;
3453 }
3454}
3455
3456static inline void l2cap_sig_channel(struct l2cap_conn *conn,
3457 struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003458{
3459 u8 *data = skb->data;
3460 int len = skb->len;
3461 struct l2cap_cmd_hdr cmd;
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003462 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003463
3464 l2cap_raw_recv(conn, skb);
3465
3466 while (len >= L2CAP_CMD_HDR_SIZE) {
Al Viro88219a02007-07-29 00:17:25 -07003467 u16 cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003468 memcpy(&cmd, data, L2CAP_CMD_HDR_SIZE);
3469 data += L2CAP_CMD_HDR_SIZE;
3470 len -= L2CAP_CMD_HDR_SIZE;
3471
Al Viro88219a02007-07-29 00:17:25 -07003472 cmd_len = le16_to_cpu(cmd.len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003473
Al Viro88219a02007-07-29 00:17:25 -07003474 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 -07003475
Al Viro88219a02007-07-29 00:17:25 -07003476 if (cmd_len > len || !cmd.ident) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003477 BT_DBG("corrupted command");
3478 break;
3479 }
3480
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02003481 if (conn->hcon->type == LE_LINK)
3482 err = l2cap_le_sig_cmd(conn, &cmd, data);
3483 else
3484 err = l2cap_bredr_sig_cmd(conn, &cmd, cmd_len, data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003485
3486 if (err) {
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003487 struct l2cap_cmd_rej_unk rej;
Gustavo F. Padovan2c6d1a22011-03-23 14:38:32 -03003488
3489 BT_ERR("Wrong link type (%d)", err);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003490
3491 /* FIXME: Map err to a valid reason */
Ilia Kolomisnkye2fd3182011-07-10 08:47:44 +03003492 rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003493 l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
3494 }
3495
Al Viro88219a02007-07-29 00:17:25 -07003496 data += cmd_len;
3497 len -= cmd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003498 }
3499
3500 kfree_skb(skb);
3501}
3502
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003503static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003504{
3505 u16 our_fcs, rcv_fcs;
Andrei Emeltchenkoe4ca6d92011-10-11 13:37:52 +03003506 int hdr_size;
3507
3508 if (test_bit(FLAG_EXT_CTRL, &chan->flags))
3509 hdr_size = L2CAP_EXT_HDR_SIZE;
3510 else
3511 hdr_size = L2CAP_ENH_HDR_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003512
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003513 if (chan->fcs == L2CAP_FCS_CRC16) {
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003514 skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003515 rcv_fcs = get_unaligned_le16(skb->data + skb->len);
3516 our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
3517
3518 if (our_fcs != rcv_fcs)
João Paulo Rechi Vita7a560e52010-06-22 13:56:27 -03003519 return -EBADMSG;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03003520 }
3521 return 0;
3522}
3523
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003524static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003525{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003526 u32 control = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003527
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003528 chan->frames_sent = 0;
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003529
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003530 control |= __set_reqseq(chan, chan->buffer_seq);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003531
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003532 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003533 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003534 l2cap_send_sframe(chan, control);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003535 set_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003536 }
3537
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003538 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003539 l2cap_retransmit_frames(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003540
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003541 l2cap_ertm_send(chan);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003542
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003543 if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003544 chan->frames_sent == 0) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003545 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003546 l2cap_send_sframe(chan, control);
Gustavo F. Padovand5392c82010-05-01 16:15:36 -03003547 }
3548}
3549
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003550static 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 -03003551{
3552 struct sk_buff *next_skb;
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003553 int tx_seq_offset, next_tx_seq_offset;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003554
3555 bt_cb(skb)->tx_seq = tx_seq;
3556 bt_cb(skb)->sar = sar;
3557
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003558 next_skb = skb_peek(&chan->srej_q);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003559
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003560 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003561
Szymon Janc039d9572011-11-16 09:32:19 +01003562 while (next_skb) {
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003563 if (bt_cb(next_skb)->tx_seq == tx_seq)
3564 return -EINVAL;
3565
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003566 next_tx_seq_offset = __seq_offset(chan,
3567 bt_cb(next_skb)->tx_seq, chan->buffer_seq);
João Paulo Rechi Vitabfbacc12010-05-31 18:35:44 -03003568
3569 if (next_tx_seq_offset > tx_seq_offset) {
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003570 __skb_queue_before(&chan->srej_q, next_skb, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003571 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003572 }
3573
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003574 if (skb_queue_is_last(&chan->srej_q, next_skb))
Szymon Janc039d9572011-11-16 09:32:19 +01003575 next_skb = NULL;
3576 else
3577 next_skb = skb_queue_next(&chan->srej_q, next_skb);
3578 }
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003579
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003580 __skb_queue_tail(&chan->srej_q, skb);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003581
3582 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003583}
3584
Mat Martineau84084a32011-07-22 14:54:00 -07003585static void append_skb_frag(struct sk_buff *skb,
3586 struct sk_buff *new_frag, struct sk_buff **last_frag)
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003587{
Mat Martineau84084a32011-07-22 14:54:00 -07003588 /* skb->len reflects data in skb as well as all fragments
3589 * skb->data_len reflects only data in fragments
3590 */
3591 if (!skb_has_frag_list(skb))
3592 skb_shinfo(skb)->frag_list = new_frag;
3593
3594 new_frag->next = NULL;
3595
3596 (*last_frag)->next = new_frag;
3597 *last_frag = new_frag;
3598
3599 skb->len += new_frag->len;
3600 skb->data_len += new_frag->len;
3601 skb->truesize += new_frag->truesize;
3602}
3603
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003604static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
Mat Martineau84084a32011-07-22 14:54:00 -07003605{
3606 int err = -EINVAL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003607
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003608 switch (__get_ctrl_sar(chan, control)) {
3609 case L2CAP_SAR_UNSEGMENTED:
Mat Martineau84084a32011-07-22 14:54:00 -07003610 if (chan->sdu)
3611 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003612
Mat Martineau84084a32011-07-22 14:54:00 -07003613 err = chan->ops->recv(chan->data, skb);
3614 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003615
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003616 case L2CAP_SAR_START:
Mat Martineau84084a32011-07-22 14:54:00 -07003617 if (chan->sdu)
3618 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003619
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003620 chan->sdu_len = get_unaligned_le16(skb->data);
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03003621 skb_pull(skb, L2CAP_SDULEN_SIZE);
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003622
Mat Martineau84084a32011-07-22 14:54:00 -07003623 if (chan->sdu_len > chan->imtu) {
3624 err = -EMSGSIZE;
3625 break;
3626 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003627
Mat Martineau84084a32011-07-22 14:54:00 -07003628 if (skb->len >= chan->sdu_len)
3629 break;
3630
3631 chan->sdu = skb;
3632 chan->sdu_last_frag = skb;
3633
3634 skb = NULL;
3635 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003636 break;
3637
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003638 case L2CAP_SAR_CONTINUE:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003639 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003640 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003641
Mat Martineau84084a32011-07-22 14:54:00 -07003642 append_skb_frag(chan->sdu, skb,
3643 &chan->sdu_last_frag);
3644 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003645
Mat Martineau84084a32011-07-22 14:54:00 -07003646 if (chan->sdu->len >= chan->sdu_len)
3647 break;
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003648
Mat Martineau84084a32011-07-22 14:54:00 -07003649 err = 0;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003650 break;
3651
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003652 case L2CAP_SAR_END:
Gustavo F. Padovan6f61fd472011-03-25 20:09:37 -03003653 if (!chan->sdu)
Mat Martineau84084a32011-07-22 14:54:00 -07003654 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003655
Mat Martineau84084a32011-07-22 14:54:00 -07003656 append_skb_frag(chan->sdu, skb,
3657 &chan->sdu_last_frag);
3658 skb = NULL;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003659
Mat Martineau84084a32011-07-22 14:54:00 -07003660 if (chan->sdu->len != chan->sdu_len)
3661 break;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003662
Mat Martineau84084a32011-07-22 14:54:00 -07003663 err = chan->ops->recv(chan->data, chan->sdu);
Gustavo F. Padovan4178ba42010-05-01 16:15:45 -03003664
Mat Martineau84084a32011-07-22 14:54:00 -07003665 if (!err) {
3666 /* Reassembly complete */
3667 chan->sdu = NULL;
3668 chan->sdu_last_frag = NULL;
3669 chan->sdu_len = 0;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003670 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003671 break;
3672 }
3673
Mat Martineau84084a32011-07-22 14:54:00 -07003674 if (err) {
3675 kfree_skb(skb);
3676 kfree_skb(chan->sdu);
3677 chan->sdu = NULL;
3678 chan->sdu_last_frag = NULL;
3679 chan->sdu_len = 0;
3680 }
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003681
Mat Martineau84084a32011-07-22 14:54:00 -07003682 return err;
Gustavo F. Padovan18778a62010-05-01 16:15:44 -03003683}
3684
Mat Martineau26f880d2011-07-07 09:39:01 -07003685static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003686{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003687 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003688
Mat Martineau26f880d2011-07-07 09:39:01 -07003689 BT_DBG("chan %p, Enter local busy", chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003690
Mat Martineau26f880d2011-07-07 09:39:01 -07003691 set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3692
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003693 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003694 control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
Mat Martineau26f880d2011-07-07 09:39:01 -07003695 l2cap_send_sframe(chan, control);
3696
3697 set_bit(CONN_RNR_SENT, &chan->conn_state);
3698
3699 __clear_ack_timer(chan);
3700}
3701
3702static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
3703{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003704 u32 control;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003705
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003706 if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003707 goto done;
3708
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003709 control = __set_reqseq(chan, chan->buffer_seq);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003710 control |= __set_ctrl_poll(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003711 control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003712 l2cap_send_sframe(chan, control);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003713 chan->retry_count = 1;
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003714
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003715 __clear_retrans_timer(chan);
3716 __set_monitor_timer(chan);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003717
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003718 set_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003719
3720done:
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003721 clear_bit(CONN_LOCAL_BUSY, &chan->conn_state);
3722 clear_bit(CONN_RNR_SENT, &chan->conn_state);
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003723
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003724 BT_DBG("chan %p, Exit local busy", chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003725}
3726
Mat Martineaue3281402011-07-07 09:39:02 -07003727void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003728{
Mat Martineaue3281402011-07-07 09:39:02 -07003729 if (chan->mode == L2CAP_MODE_ERTM) {
3730 if (busy)
3731 l2cap_ertm_enter_local_busy(chan);
3732 else
3733 l2cap_ertm_exit_local_busy(chan);
Gustavo F. Padovan712132e2010-06-21 19:39:50 -03003734 }
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003735}
3736
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003737static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003738{
3739 struct sk_buff *skb;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003740 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003741
Mat Martineaue3281402011-07-07 09:39:02 -07003742 while ((skb = skb_peek(&chan->srej_q)) &&
3743 !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
3744 int err;
3745
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003746 if (bt_cb(skb)->tx_seq != tx_seq)
3747 break;
3748
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003749 skb = skb_dequeue(&chan->srej_q);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003750 control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
Mat Martineau84084a32011-07-22 14:54:00 -07003751 err = l2cap_reassemble_sdu(chan, skb, control);
Mat Martineaue3281402011-07-07 09:39:02 -07003752
3753 if (err < 0) {
3754 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3755 break;
3756 }
3757
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003758 chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
3759 tx_seq = __next_seq(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003760 }
3761}
3762
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003763static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003764{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003765 struct srej_list *l, *tmp;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003766 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003767
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003768 list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003769 if (l->tx_seq == tx_seq) {
3770 list_del(&l->list);
3771 kfree(l);
3772 return;
3773 }
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003774 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003775 control |= __set_reqseq(chan, l->tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003776 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003777 list_del(&l->list);
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003778 list_add_tail(&l->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003779 }
3780}
3781
Szymon Jancaef89f22011-11-16 09:32:18 +01003782static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003783{
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003784 struct srej_list *new;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003785 u32 control;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003786
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003787 while (tx_seq != chan->expected_tx_seq) {
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03003788 control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003789 control |= __set_reqseq(chan, chan->expected_tx_seq);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003790 l2cap_send_sframe(chan, control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003791
3792 new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
Szymon Jancaef89f22011-11-16 09:32:18 +01003793 if (!new)
3794 return -ENOMEM;
3795
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003796 new->tx_seq = chan->expected_tx_seq;
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003797
3798 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
3799
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003800 list_add_tail(&new->list, &chan->srej_l);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003801 }
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003802
3803 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Szymon Jancaef89f22011-11-16 09:32:18 +01003804
3805 return 0;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003806}
3807
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003808static 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 -03003809{
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03003810 u16 tx_seq = __get_txseq(chan, rx_control);
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003811 u16 req_seq = __get_reqseq(chan, rx_control);
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03003812 u8 sar = __get_ctrl_sar(chan, rx_control);
Gustavo F. Padovanf6337c72010-05-10 18:32:04 -03003813 int tx_seq_offset, expected_tx_seq_offset;
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003814 int num_to_ack = (chan->tx_win/6) + 1;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003815 int err = 0;
3816
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003817 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 -03003818 tx_seq, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003819
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003820 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003821 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003822 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003823 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003824 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003825 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03003826 }
3827
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003828 chan->expected_ack_seq = req_seq;
3829 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan9f121a52009-10-03 02:34:38 -03003830
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003831 tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003832
3833 /* invalid tx_seq */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03003834 if (tx_seq_offset >= chan->tx_win) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03003835 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003836 goto drop;
3837 }
3838
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003839 if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state))
Gustavo F. Padovan1890d362010-05-01 16:15:44 -03003840 goto drop;
3841
Mat Martineau02f1b642011-06-29 14:35:19 -07003842 if (tx_seq == chan->expected_tx_seq)
3843 goto expected;
3844
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003845 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003846 struct srej_list *first;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003847
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003848 first = list_first_entry(&chan->srej_l,
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003849 struct srej_list, list);
3850 if (tx_seq == first->tx_seq) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003851 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003852 l2cap_check_srej_gap(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003853
3854 list_del(&first->list);
3855 kfree(first);
3856
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003857 if (list_empty(&chan->srej_l)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003858 chan->buffer_seq = chan->buffer_seq_srej;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003859 clear_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003860 l2cap_send_ack(chan);
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003861 BT_DBG("chan %p, Exit SREJ_SENT", chan);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003862 }
3863 } else {
3864 struct srej_list *l;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003865
3866 /* duplicated tx_seq */
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003867 if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0)
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003868 goto drop;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003869
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003870 list_for_each_entry(l, &chan->srej_l, list) {
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003871 if (l->tx_seq == tx_seq) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003872 l2cap_resend_srejframe(chan, tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003873 return 0;
3874 }
3875 }
Szymon Jancaef89f22011-11-16 09:32:18 +01003876
3877 err = l2cap_send_srejframe(chan, tx_seq);
3878 if (err < 0) {
3879 l2cap_send_disconn_req(chan->conn, chan, -err);
3880 return err;
3881 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003882 }
3883 } else {
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003884 expected_tx_seq_offset = __seq_offset(chan,
3885 chan->expected_tx_seq, chan->buffer_seq);
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003886
3887 /* duplicated tx_seq */
3888 if (tx_seq_offset < expected_tx_seq_offset)
3889 goto drop;
3890
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003891 set_bit(CONN_SREJ_SENT, &chan->conn_state);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003892
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03003893 BT_DBG("chan %p, Enter SREJ", chan);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003894
Gustavo F. Padovan39d5a3e2011-04-04 15:40:12 -03003895 INIT_LIST_HEAD(&chan->srej_l);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003896 chan->buffer_seq_srej = chan->buffer_seq;
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003897
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003898 __skb_queue_head_init(&chan->srej_q);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003899 l2cap_add_to_srej_queue(chan, skb, tx_seq, sar);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003900
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003901 set_bit(CONN_SEND_PBIT, &chan->conn_state);
Gustavo F. Padovanef54fd92009-08-20 22:26:04 -03003902
Szymon Jancaef89f22011-11-16 09:32:18 +01003903 err = l2cap_send_srejframe(chan, tx_seq);
3904 if (err < 0) {
3905 l2cap_send_disconn_req(chan->conn, chan, -err);
3906 return err;
3907 }
Gustavo F. Padovan7fe9b292010-05-12 18:32:04 -03003908
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003909 __clear_ack_timer(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003910 }
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03003911 return 0;
3912
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003913expected:
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003914 chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003915
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003916 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan3b1a9f32010-05-01 16:15:42 -03003917 bt_cb(skb)->tx_seq = tx_seq;
3918 bt_cb(skb)->sar = sar;
Gustavo F. Padovanf1c67752011-03-25 20:36:10 -03003919 __skb_queue_tail(&chan->srej_q, skb);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003920 return 0;
3921 }
3922
Mat Martineau84084a32011-07-22 14:54:00 -07003923 err = l2cap_reassemble_sdu(chan, skb, rx_control);
Andrei Emeltchenko836be932011-10-17 12:19:57 +03003924 chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
3925
Mat Martineaue3281402011-07-07 09:39:02 -07003926 if (err < 0) {
3927 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
3928 return err;
3929 }
Gustavo F. Padovan2ece3682010-06-16 17:21:44 -03003930
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003931 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003932 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003933 l2cap_retransmit_frames(chan);
Gustavo F. Padovan4ec10d92009-10-03 02:34:39 -03003934 }
3935
Gustavo F. Padovanc1b4f432010-05-01 16:15:39 -03003936
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003937 chan->num_acked = (chan->num_acked + 1) % num_to_ack;
3938 if (chan->num_acked == num_to_ack - 1)
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003939 l2cap_send_ack(chan);
Gustavo F. Padovan4d611e42011-06-23 19:30:48 -03003940 else
3941 __set_ack_timer(chan);
Gustavo F. Padovan9e917af2010-05-01 16:15:37 -03003942
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03003943 return 0;
João Paulo Rechi Vita9b533502010-05-01 16:15:44 -03003944
3945drop:
3946 kfree_skb(skb);
3947 return 0;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003948}
3949
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003950static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003951{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003952 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003953 __get_reqseq(chan, rx_control), rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003954
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003955 chan->expected_ack_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003956 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03003957
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03003958 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003959 set_bit(CONN_SEND_FBIT, &chan->conn_state);
3960 if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
3961 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003962 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003963 __set_retrans_timer(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003964
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003965 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003966 l2cap_send_srejtail(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003967 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003968 l2cap_send_i_or_rr_or_rnr(chan);
Gustavo F. Padovan05fbd892010-05-01 16:15:39 -03003969 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003970
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03003971 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003972 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003973
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003974 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003975 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003976
3977 } else {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003978 if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03003979 (chan->unacked_frames > 0))
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03003980 __set_retrans_timer(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003981
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003982 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
3983 if (test_bit(CONN_SREJ_SENT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003984 l2cap_send_ack(chan);
Andrei Emeltchenko894718a2010-12-01 16:58:24 +02003985 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03003986 l2cap_ertm_send(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003987 }
3988}
3989
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003990static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003991{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03003992 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003993
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03003994 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03003995
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03003996 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03003997
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03003998 chan->expected_ack_seq = tx_seq;
3999 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004000
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004001 if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004002 if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004003 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004004 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004005 l2cap_retransmit_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004006
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004007 if (test_bit(CONN_WAIT_F, &chan->conn_state))
4008 set_bit(CONN_REJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004009 }
4010}
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004011static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004012{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004013 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004014
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004015 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004016
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004017 clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004018
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004019 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004020 chan->expected_ack_seq = tx_seq;
4021 l2cap_drop_acked_frames(chan);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004022
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004023 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004024 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004025
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004026 l2cap_ertm_send(chan);
Gustavo F. Padovandfc909b2010-05-01 16:15:45 -03004027
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004028 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004029 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004030 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004031 }
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004032 } else if (__is_ctrl_final(chan, rx_control)) {
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004033 if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004034 chan->srej_save_reqseq == tx_seq)
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004035 clear_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004036 else
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004037 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004038 } else {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004039 l2cap_retransmit_one_frame(chan, tx_seq);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004040 if (test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004041 chan->srej_save_reqseq = tx_seq;
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004042 set_bit(CONN_SREJ_ACT, &chan->conn_state);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004043 }
4044 }
4045}
4046
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004047static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004048{
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004049 u16 tx_seq = __get_reqseq(chan, rx_control);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004050
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004051 BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
Gustavo F. Padovan0e989582010-04-19 14:45:38 -03004052
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004053 set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
Gustavo F. Padovan42e5c802011-03-25 19:58:34 -03004054 chan->expected_ack_seq = tx_seq;
4055 l2cap_drop_acked_frames(chan);
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004056
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004057 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004058 set_bit(CONN_SEND_FBIT, &chan->conn_state);
Gustavo F. Padovan3cb123d2010-05-29 02:24:35 -03004059
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004060 if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004061 __clear_retrans_timer(chan);
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004062 if (__is_ctrl_poll(chan, rx_control))
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004063 l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004064 return;
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004065 }
Gustavo F. Padovan99b0d4b2010-05-01 16:15:38 -03004066
Andrei Emeltchenkoe3781732011-10-11 13:37:50 +03004067 if (__is_ctrl_poll(chan, rx_control)) {
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004068 l2cap_send_srejtail(chan);
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004069 } else {
4070 rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
4071 l2cap_send_sframe(chan, rx_control);
4072 }
Gustavo F. Padovane0727452010-05-01 16:15:38 -03004073}
4074
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004075static 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 -03004076{
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004077 BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004078
Andrei Emeltchenko03f67152011-10-11 13:37:49 +03004079 if (__is_ctrl_final(chan, rx_control) &&
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004080 test_bit(CONN_WAIT_F, &chan->conn_state)) {
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004081 __clear_monitor_timer(chan);
Gustavo F. Padovan6a026612011-04-01 00:38:50 -03004082 if (chan->unacked_frames > 0)
Gustavo F. Padovan1a09bcb2011-05-17 15:13:19 -03004083 __set_retrans_timer(chan);
Gustavo F. Padovane2ab4352011-06-10 21:28:49 -03004084 clear_bit(CONN_WAIT_F, &chan->conn_state);
Gustavo F. Padovan1d8f5d12010-05-01 16:15:37 -03004085 }
4086
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004087 switch (__get_ctrl_super(chan, rx_control)) {
4088 case L2CAP_SUPER_RR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004089 l2cap_data_channel_rrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004090 break;
4091
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004092 case L2CAP_SUPER_REJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004093 l2cap_data_channel_rejframe(chan, rx_control);
Gustavo F. Padovan30afb5b2009-08-20 22:25:59 -03004094 break;
4095
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004096 case L2CAP_SUPER_SREJ:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004097 l2cap_data_channel_srejframe(chan, rx_control);
Gustavo F. Padovan8f171542009-08-20 22:26:03 -03004098 break;
4099
Andrei Emeltchenkoab784b72011-10-11 13:37:44 +03004100 case L2CAP_SUPER_RNR:
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004101 l2cap_data_channel_rnrframe(chan, rx_control);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004102 break;
4103 }
4104
Gustavo F. Padovanfaaebd12010-05-01 16:15:35 -03004105 kfree_skb(skb);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004106 return 0;
4107}
4108
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004109static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
4110{
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004111 struct l2cap_chan *chan = l2cap_pi(sk)->chan;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004112 u32 control;
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004113 u16 req_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004114 int len, next_tx_seq_offset, req_seq_offset;
4115
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004116 control = __get_control(chan, skb->data);
4117 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004118 len = skb->len;
4119
4120 /*
4121 * We can just drop the corrupted I-frame here.
4122 * Receiver will miss it and start proper recovery
4123 * procedures and ask retransmission.
4124 */
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004125 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004126 goto drop;
4127
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004128 if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004129 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004130
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004131 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004132 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004133
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004134 if (len > chan->mps) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004135 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004136 goto drop;
4137 }
4138
Andrei Emeltchenko0b209fa2011-10-11 13:37:46 +03004139 req_seq = __get_reqseq(chan, control);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004140
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004141 req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
4142
4143 next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
4144 chan->expected_ack_seq);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004145
4146 /* check for invalid req-seq */
4147 if (req_seq_offset > next_tx_seq_offset) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004148 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004149 goto drop;
4150 }
4151
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004152 if (!__is_sframe(chan, control)) {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004153 if (len < 0) {
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004154 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004155 goto drop;
4156 }
4157
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004158 l2cap_data_channel_iframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004159 } else {
4160 if (len != 0) {
4161 BT_ERR("%d", len);
Gustavo F. Padovan8c1d7872011-04-13 20:23:55 -03004162 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004163 goto drop;
4164 }
4165
Gustavo F. Padovan525cd182011-03-25 19:43:39 -03004166 l2cap_data_channel_sframe(chan, control, skb);
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004167 }
4168
4169 return 0;
4170
4171drop:
4172 kfree_skb(skb);
4173 return 0;
4174}
4175
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb)
4177{
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004178 struct l2cap_chan *chan;
David S. Millerbf734842011-04-25 13:03:02 -07004179 struct sock *sk = NULL;
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004180 u32 control;
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004181 u16 tx_seq;
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004182 int len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004183
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004184 chan = l2cap_get_chan_by_scid(conn, cid);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004185 if (!chan) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004186 BT_DBG("unknown cid 0x%4.4x", cid);
4187 goto drop;
4188 }
4189
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004190 sk = chan->sk;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004191
Gustavo F. Padovan49208c92011-04-04 15:59:54 -03004192 BT_DBG("chan %p, len %d", chan, skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004193
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004194 if (chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004195 goto drop;
4196
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004197 switch (chan->mode) {
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004198 case L2CAP_MODE_BASIC:
4199 /* If socket recv buffers overflows we drop data here
4200 * which is *bad* because L2CAP has to be reliable.
4201 * But we don't have any other choice. L2CAP doesn't
4202 * provide flow control mechanism. */
Linus Torvalds1da177e2005-04-16 15:20:36 -07004203
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004204 if (chan->imtu < skb->len)
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004205 goto drop;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004206
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004207 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004208 goto done;
4209 break;
4210
4211 case L2CAP_MODE_ERTM:
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004212 if (!sock_owned_by_user(sk)) {
4213 l2cap_ertm_data_rcv(sk, skb);
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004214 } else {
Gustavo F. Padovan218bb9d2010-06-21 18:53:22 -03004215 if (sk_add_backlog(sk, skb))
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004216 goto drop;
Gustavo F. Padovan277ffbe2010-05-01 16:15:37 -03004217 }
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004218
Andrei Emeltchenkofcafde22009-12-22 15:58:08 +02004219 goto done;
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004220
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004221 case L2CAP_MODE_STREAMING:
Andrei Emeltchenko88843ab2011-10-17 12:19:56 +03004222 control = __get_control(chan, skb->data);
4223 skb_pull(skb, __ctrl_size(chan));
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004224 len = skb->len;
4225
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004226 if (l2cap_check_fcs(chan, skb))
Gustavo F. Padovan26000082010-05-11 22:02:00 -03004227 goto drop;
4228
Andrei Emeltchenko7e0ef6e2011-10-11 13:37:45 +03004229 if (__is_sar_start(chan, control))
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004230 len -= L2CAP_SDULEN_SIZE;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004231
Gustavo F. Padovan47d1ec62011-04-13 15:57:03 -03004232 if (chan->fcs == L2CAP_FCS_CRC16)
Andrei Emeltchenko03a51212011-10-17 12:19:58 +03004233 len -= L2CAP_FCS_SIZE;
Gustavo F. Padovanfcc203c2009-08-20 22:26:02 -03004234
Andrei Emeltchenko793c2f12011-10-11 13:37:48 +03004235 if (len > chan->mps || len < 0 || __is_sframe(chan, control))
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004236 goto drop;
4237
Andrei Emeltchenkofb45de72011-10-11 13:37:47 +03004238 tx_seq = __get_txseq(chan, control);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004239
Mat Martineau84084a32011-07-22 14:54:00 -07004240 if (chan->expected_tx_seq != tx_seq) {
4241 /* Frame(s) missing - must discard partial SDU */
4242 kfree_skb(chan->sdu);
4243 chan->sdu = NULL;
4244 chan->sdu_last_frag = NULL;
4245 chan->sdu_len = 0;
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004246
Mat Martineau84084a32011-07-22 14:54:00 -07004247 /* TODO: Notify userland of missing data */
4248 }
4249
Andrei Emeltchenko836be932011-10-17 12:19:57 +03004250 chan->expected_tx_seq = __next_seq(chan, tx_seq);
Mat Martineau84084a32011-07-22 14:54:00 -07004251
4252 if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
4253 l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
Gustavo F. Padovan6840ed02009-08-20 22:26:01 -03004254
4255 goto done;
4256
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004257 default:
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004258 BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode);
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004259 break;
4260 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004261
4262drop:
4263 kfree_skb(skb);
4264
4265done:
Marcel Holtmann01394182006-07-03 10:02:46 +02004266 if (sk)
4267 bh_unlock_sock(sk);
4268
Linus Torvalds1da177e2005-04-16 15:20:36 -07004269 return 0;
4270}
4271
Al Viro8e036fc2007-07-29 00:16:36 -07004272static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004273{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004274 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004275 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004277 chan = l2cap_global_chan_by_psm(0, psm, conn->src);
4278 if (!chan)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279 goto drop;
4280
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004281 sk = chan->sk;
4282
Gustavo F. Padovane0f0cb52010-11-01 18:43:53 +00004283 bh_lock_sock(sk);
4284
Linus Torvalds1da177e2005-04-16 15:20:36 -07004285 BT_DBG("sk %p, len %d", sk, skb->len);
4286
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004287 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004288 goto drop;
4289
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004290 if (chan->imtu < skb->len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 goto drop;
4292
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004293 if (!chan->ops->recv(chan->data, skb))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004294 goto done;
4295
4296drop:
4297 kfree_skb(skb);
4298
4299done:
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004300 if (sk)
4301 bh_unlock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 return 0;
4303}
4304
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004305static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
4306{
David S. Miller6dcae1e2011-05-16 23:09:26 -04004307 struct sock *sk = NULL;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004308 struct l2cap_chan *chan;
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004309
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004310 chan = l2cap_global_chan_by_scid(0, cid, conn->src);
4311 if (!chan)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004312 goto drop;
4313
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004314 sk = chan->sk;
4315
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004316 bh_lock_sock(sk);
4317
4318 BT_DBG("sk %p, len %d", sk, skb->len);
4319
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004320 if (chan->state != BT_BOUND && chan->state != BT_CONNECTED)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004321 goto drop;
4322
Vinicius Costa Gomese13e21d2011-06-17 22:46:27 -03004323 if (chan->imtu < skb->len)
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004324 goto drop;
4325
Gustavo F. Padovan23070492011-05-16 17:57:22 -03004326 if (!chan->ops->recv(chan->data, skb))
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004327 goto done;
4328
4329drop:
4330 kfree_skb(skb);
4331
4332done:
4333 if (sk)
4334 bh_unlock_sock(sk);
4335 return 0;
4336}
4337
Linus Torvalds1da177e2005-04-16 15:20:36 -07004338static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
4339{
4340 struct l2cap_hdr *lh = (void *) skb->data;
Al Viro8e036fc2007-07-29 00:16:36 -07004341 u16 cid, len;
4342 __le16 psm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004343
4344 skb_pull(skb, L2CAP_HDR_SIZE);
4345 cid = __le16_to_cpu(lh->cid);
4346 len = __le16_to_cpu(lh->len);
4347
Gustavo F. Padovan1c2acff2009-08-20 22:25:57 -03004348 if (len != skb->len) {
4349 kfree_skb(skb);
4350 return;
4351 }
4352
Linus Torvalds1da177e2005-04-16 15:20:36 -07004353 BT_DBG("len %d, cid 0x%4.4x", len, cid);
4354
4355 switch (cid) {
Claudio Takahasi3300d9a2011-02-11 19:28:54 -02004356 case L2CAP_CID_LE_SIGNALING:
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004357 case L2CAP_CID_SIGNALING:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004358 l2cap_sig_channel(conn, skb);
4359 break;
4360
Gustavo F. Padovan8db4dc42009-04-20 01:31:05 -03004361 case L2CAP_CID_CONN_LESS:
Gustavo F. Padovan1b7bf4e2009-08-24 00:45:20 -03004362 psm = get_unaligned_le16(skb->data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004363 skb_pull(skb, 2);
4364 l2cap_conless_channel(conn, psm, skb);
4365 break;
4366
Gustavo F. Padovan9f69bda2011-04-07 16:40:25 -03004367 case L2CAP_CID_LE_DATA:
4368 l2cap_att_channel(conn, cid, skb);
4369 break;
4370
Anderson Brigliab501d6a2011-06-07 18:46:31 -03004371 case L2CAP_CID_SMP:
4372 if (smp_sig_channel(conn, skb))
4373 l2cap_conn_del(conn->hcon, EACCES);
4374 break;
4375
Linus Torvalds1da177e2005-04-16 15:20:36 -07004376 default:
4377 l2cap_data_channel(conn, cid, skb);
4378 break;
4379 }
4380}
4381
4382/* ---- L2CAP interface with lower layer (HCI) ---- */
4383
4384static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
4385{
4386 int exact = 0, lm1 = 0, lm2 = 0;
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004387 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004388
4389 if (type != ACL_LINK)
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004390 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004391
4392 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
4393
4394 /* Find listening sockets and check their link_mode */
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004395 read_lock(&chan_list_lock);
4396 list_for_each_entry(c, &chan_list, global_l) {
4397 struct sock *sk = c->sk;
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004398
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004399 if (c->state != BT_LISTEN)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004400 continue;
4401
4402 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004403 lm1 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004404 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004405 lm1 |= HCI_LM_MASTER;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004406 exact++;
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004407 } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
4408 lm2 |= HCI_LM_ACCEPT;
Andrei Emeltchenko43bd0f32011-10-11 14:04:34 +03004409 if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
Marcel Holtmann2af6b9d2009-01-15 21:58:38 +01004410 lm2 |= HCI_LM_MASTER;
4411 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004412 }
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004413 read_unlock(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004414
4415 return exact ? lm1 : lm2;
4416}
4417
4418static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
4419{
Marcel Holtmann01394182006-07-03 10:02:46 +02004420 struct l2cap_conn *conn;
4421
Linus Torvalds1da177e2005-04-16 15:20:36 -07004422 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
4423
Ville Tervoacd7d372011-02-10 22:38:49 -03004424 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004425 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004426
4427 if (!status) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428 conn = l2cap_conn_add(hcon, status);
4429 if (conn)
4430 l2cap_conn_ready(conn);
Marcel Holtmann01394182006-07-03 10:02:46 +02004431 } else
Joe Perchese1750722011-06-29 18:18:29 -07004432 l2cap_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -07004433
4434 return 0;
4435}
4436
Marcel Holtmann2950f212009-02-12 14:02:50 +01004437static int l2cap_disconn_ind(struct hci_conn *hcon)
4438{
4439 struct l2cap_conn *conn = hcon->l2cap_data;
4440
4441 BT_DBG("hcon %p", hcon);
4442
Gustavo F. Padovanb5694502011-06-08 19:09:13 -03004443 if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
Andrei Emeltchenko9f5a0d72011-11-07 14:20:25 +02004444 return HCI_ERROR_REMOTE_USER_TERM;
Marcel Holtmann2950f212009-02-12 14:02:50 +01004445
4446 return conn->disc_reason;
4447}
4448
4449static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004450{
4451 BT_DBG("hcon %p reason %d", hcon, reason);
4452
Ville Tervoacd7d372011-02-10 22:38:49 -03004453 if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
João Paulo Rechi Vita963cf682010-06-22 13:56:28 -03004454 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004455
Joe Perchese1750722011-06-29 18:18:29 -07004456 l2cap_conn_del(hcon, bt_to_errno(reason));
Marcel Holtmann01394182006-07-03 10:02:46 +02004457
Linus Torvalds1da177e2005-04-16 15:20:36 -07004458 return 0;
4459}
4460
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004461static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004462{
Gustavo F. Padovan715ec002011-05-02 17:13:55 -03004463 if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED)
Marcel Holtmann255c7602009-02-04 21:07:19 +01004464 return;
4465
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004466 if (encrypt == 0x00) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004467 if (chan->sec_level == BT_SECURITY_MEDIUM) {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004468 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004469 __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004470 } else if (chan->sec_level == BT_SECURITY_HIGH)
Gustavo F. Padovan0f852722011-05-04 19:42:50 -03004471 l2cap_chan_close(chan, ECONNREFUSED);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004472 } else {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004473 if (chan->sec_level == BT_SECURITY_MEDIUM)
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004474 __clear_chan_timer(chan);
Marcel Holtmannf62e4322009-01-15 21:58:44 +01004475 }
4476}
4477
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004478static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004479{
Marcel Holtmann40be4922008-07-14 20:13:50 +02004480 struct l2cap_conn *conn = hcon->l2cap_data;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004481 struct l2cap_chan *chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004482
Marcel Holtmann01394182006-07-03 10:02:46 +02004483 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004484 return 0;
Marcel Holtmann01394182006-07-03 10:02:46 +02004485
Linus Torvalds1da177e2005-04-16 15:20:36 -07004486 BT_DBG("conn %p", conn);
4487
Vinicius Costa Gomes160dc6a2011-08-19 21:06:55 -03004488 if (hcon->type == LE_LINK) {
4489 smp_distribute_keys(conn, 0);
4490 del_timer(&conn->security_timer);
4491 }
4492
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004493 read_lock(&conn->chan_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004494
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004495 list_for_each_entry(chan, &conn->chan_l, list) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004496 struct sock *sk = chan->sk;
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004497
Linus Torvalds1da177e2005-04-16 15:20:36 -07004498 bh_lock_sock(sk);
4499
Vinicius Costa Gomesf1cb9af2011-01-26 21:42:57 -03004500 BT_DBG("chan->scid %d", chan->scid);
4501
4502 if (chan->scid == L2CAP_CID_LE_DATA) {
4503 if (!status && encrypt) {
4504 chan->sec_level = hcon->sec_level;
4505 l2cap_chan_ready(sk);
4506 }
4507
4508 bh_unlock_sock(sk);
4509 continue;
4510 }
4511
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004512 if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
Marcel Holtmann6a8d3012009-02-06 23:56:36 +01004513 bh_unlock_sock(sk);
4514 continue;
4515 }
4516
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004517 if (!status && (chan->state == BT_CONNECTED ||
4518 chan->state == BT_CONFIG)) {
Gustavo F. Padovan43434782011-04-12 18:31:57 -03004519 l2cap_check_encryption(chan, encrypt);
Marcel Holtmann9719f8a2008-07-14 20:13:45 +02004520 bh_unlock_sock(sk);
4521 continue;
4522 }
4523
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004524 if (chan->state == BT_CONNECT) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004525 if (!status) {
4526 struct l2cap_conn_req req;
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004527 req.scid = cpu_to_le16(chan->scid);
4528 req.psm = chan->psm;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004529
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004530 chan->ident = l2cap_get_ident(conn);
Gustavo F. Padovanc1360a12011-06-10 17:02:12 -03004531 set_bit(CONF_CONNECT_PEND, &chan->conf_state);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004532
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004533 l2cap_send_cmd(conn, chan->ident,
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004534 L2CAP_CONN_REQ, sizeof(req), &req);
4535 } else {
Gustavo F. Padovanc9b66672011-05-17 14:59:01 -03004536 __clear_chan_timer(chan);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004537 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004538 }
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004539 } else if (chan->state == BT_CONNECT2) {
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004540 struct l2cap_conn_rsp rsp;
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004541 __u16 res, stat;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004542
4543 if (!status) {
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004544 if (bt_sk(sk)->defer_setup) {
4545 struct sock *parent = bt_sk(sk)->parent;
4546 res = L2CAP_CR_PEND;
4547 stat = L2CAP_CS_AUTHOR_PEND;
Ilia Kolomisnky05e9a2f2011-07-15 18:30:21 +00004548 if (parent)
4549 parent->sk_data_ready(parent, 0);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004550 } else {
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004551 l2cap_state_change(chan, BT_CONFIG);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004552 res = L2CAP_CR_SUCCESS;
4553 stat = L2CAP_CS_NO_INFO;
4554 }
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004555 } else {
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004556 l2cap_state_change(chan, BT_DISCONN);
Andrzej Kaczmarekf3f668b2011-11-07 17:19:04 -02004557 __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004558 res = L2CAP_CR_SEC_BLOCK;
4559 stat = L2CAP_CS_NO_INFO;
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004560 }
4561
Gustavo F. Padovanfe4128e2011-04-13 19:50:45 -03004562 rsp.scid = cpu_to_le16(chan->dcid);
4563 rsp.dcid = cpu_to_le16(chan->scid);
Johan Hedbergdf3c3932011-06-14 12:48:19 +03004564 rsp.result = cpu_to_le16(res);
4565 rsp.status = cpu_to_le16(stat);
Gustavo F. Padovanfc7f8a72011-03-25 13:59:37 -03004566 l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
4567 sizeof(rsp), &rsp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004568 }
4569
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570 bh_unlock_sock(sk);
4571 }
4572
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004573 read_unlock(&conn->chan_lock);
Marcel Holtmannb1235d72008-07-14 20:13:54 +02004574
Linus Torvalds1da177e2005-04-16 15:20:36 -07004575 return 0;
4576}
4577
4578static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
4579{
4580 struct l2cap_conn *conn = hcon->l2cap_data;
4581
Andrei Emeltchenko5a08ecc2011-01-11 17:20:20 +02004582 if (!conn)
4583 conn = l2cap_conn_add(hcon, 0);
4584
4585 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004586 goto drop;
4587
4588 BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
4589
Andrei Emeltchenkoe7021122011-01-03 11:14:36 +02004590 if (!(flags & ACL_CONT)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004591 struct l2cap_hdr *hdr;
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004592 struct l2cap_chan *chan;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004593 u16 cid;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004594 int len;
4595
4596 if (conn->rx_len) {
4597 BT_ERR("Unexpected start frame (len %d)", skb->len);
4598 kfree_skb(conn->rx_skb);
4599 conn->rx_skb = NULL;
4600 conn->rx_len = 0;
4601 l2cap_conn_unreliable(conn, ECOMM);
4602 }
4603
Andrei Emeltchenkoaae7fe22010-09-15 14:28:43 +03004604 /* Start fragment always begin with Basic L2CAP header */
4605 if (skb->len < L2CAP_HDR_SIZE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07004606 BT_ERR("Frame is too short (len %d)", skb->len);
4607 l2cap_conn_unreliable(conn, ECOMM);
4608 goto drop;
4609 }
4610
4611 hdr = (struct l2cap_hdr *) skb->data;
4612 len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004613 cid = __le16_to_cpu(hdr->cid);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614
4615 if (len == skb->len) {
4616 /* Complete frame received */
4617 l2cap_recv_frame(conn, skb);
4618 return 0;
4619 }
4620
4621 BT_DBG("Start: total len %d, frag len %d", len, skb->len);
4622
4623 if (skb->len > len) {
4624 BT_ERR("Frame is too long (len %d, expected len %d)",
4625 skb->len, len);
4626 l2cap_conn_unreliable(conn, ECOMM);
4627 goto drop;
4628 }
4629
Gustavo F. Padovanbaa7e1f2011-03-31 16:17:41 -03004630 chan = l2cap_get_chan_by_scid(conn, cid);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004631
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004632 if (chan && chan->sk) {
4633 struct sock *sk = chan->sk;
4634
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004635 if (chan->imtu < len - L2CAP_HDR_SIZE) {
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004636 BT_ERR("Frame exceeding recv MTU (len %d, "
4637 "MTU %d)", len,
Gustavo F. Padovan0c1bc5c2011-04-13 17:20:49 -03004638 chan->imtu);
Gustavo F. Padovan48454072011-03-25 00:22:30 -03004639 bh_unlock_sock(sk);
4640 l2cap_conn_unreliable(conn, ECOMM);
4641 goto drop;
4642 }
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004643 bh_unlock_sock(sk);
Andrei Emeltchenko89794812010-09-15 14:28:44 +03004644 }
4645
Linus Torvalds1da177e2005-04-16 15:20:36 -07004646 /* Allocate skb for the complete frame (with header) */
Gustavo F. Padovanaf05b30b2009-04-20 01:31:08 -03004647 conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
4648 if (!conn->rx_skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 goto drop;
4650
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004651 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004652 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004653 conn->rx_len = len - skb->len;
4654 } else {
4655 BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
4656
4657 if (!conn->rx_len) {
4658 BT_ERR("Unexpected continuation frame (len %d)", skb->len);
4659 l2cap_conn_unreliable(conn, ECOMM);
4660 goto drop;
4661 }
4662
4663 if (skb->len > conn->rx_len) {
4664 BT_ERR("Fragment is too long (len %d, expected %d)",
4665 skb->len, conn->rx_len);
4666 kfree_skb(conn->rx_skb);
4667 conn->rx_skb = NULL;
4668 conn->rx_len = 0;
4669 l2cap_conn_unreliable(conn, ECOMM);
4670 goto drop;
4671 }
4672
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03004673 skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
Marcel Holtmanne1027a72009-02-09 09:18:02 +01004674 skb->len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004675 conn->rx_len -= skb->len;
4676
4677 if (!conn->rx_len) {
4678 /* Complete frame received */
4679 l2cap_recv_frame(conn, conn->rx_skb);
4680 conn->rx_skb = NULL;
4681 }
4682 }
4683
4684drop:
4685 kfree_skb(skb);
4686 return 0;
4687}
4688
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004689static int l2cap_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004690{
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004691 struct l2cap_chan *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004692
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004693 read_lock_bh(&chan_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004694
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004695 list_for_each_entry(c, &chan_list, global_l) {
4696 struct sock *sk = c->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004697
Gustavo F. Padovan903d3432011-02-10 14:16:06 -02004698 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 +01004699 batostr(&bt_sk(sk)->src),
4700 batostr(&bt_sk(sk)->dst),
Gustavo F. Padovan89bc5002011-06-03 00:19:47 -03004701 c->state, __le16_to_cpu(c->psm),
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004702 c->scid, c->dcid, c->imtu, c->omtu,
4703 c->sec_level, c->mode);
Gustavo F. Padovan05558912011-06-21 14:52:56 -03004704}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004705
Gustavo F. Padovan23691d72011-04-27 18:26:32 -03004706 read_unlock_bh(&chan_list_lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004707
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004708 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004709}
4710
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004711static int l2cap_debugfs_open(struct inode *inode, struct file *file)
4712{
4713 return single_open(file, l2cap_debugfs_show, inode->i_private);
4714}
4715
4716static const struct file_operations l2cap_debugfs_fops = {
4717 .open = l2cap_debugfs_open,
4718 .read = seq_read,
4719 .llseek = seq_lseek,
4720 .release = single_release,
4721};
4722
4723static struct dentry *l2cap_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724
Linus Torvalds1da177e2005-04-16 15:20:36 -07004725static struct hci_proto l2cap_hci_proto = {
4726 .name = "L2CAP",
4727 .id = HCI_PROTO_L2CAP,
4728 .connect_ind = l2cap_connect_ind,
4729 .connect_cfm = l2cap_connect_cfm,
4730 .disconn_ind = l2cap_disconn_ind,
Marcel Holtmann2950f212009-02-12 14:02:50 +01004731 .disconn_cfm = l2cap_disconn_cfm,
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01004732 .security_cfm = l2cap_security_cfm,
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733 .recv_acldata = l2cap_recv_acldata
4734};
4735
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004736int __init l2cap_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004737{
4738 int err;
Marcel Holtmannbe9d1222005-11-08 09:57:38 -08004739
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004740 err = l2cap_init_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 if (err < 0)
4742 return err;
4743
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744 err = hci_register_proto(&l2cap_hci_proto);
4745 if (err < 0) {
4746 BT_ERR("L2CAP protocol registration failed");
4747 bt_sock_unregister(BTPROTO_L2CAP);
4748 goto error;
4749 }
4750
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004751 if (bt_debugfs) {
4752 l2cap_debugfs = debugfs_create_file("l2cap", 0444,
4753 bt_debugfs, NULL, &l2cap_debugfs_fops);
4754 if (!l2cap_debugfs)
4755 BT_ERR("Failed to create L2CAP debug file");
4756 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004757
Linus Torvalds1da177e2005-04-16 15:20:36 -07004758 return 0;
4759
4760error:
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004761 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004762 return err;
4763}
4764
Gustavo F. Padovan64274512011-02-07 20:08:52 -02004765void l2cap_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004766{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01004767 debugfs_remove(l2cap_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768
Linus Torvalds1da177e2005-04-16 15:20:36 -07004769 if (hci_unregister_proto(&l2cap_hci_proto) < 0)
4770 BT_ERR("L2CAP protocol unregistration failed");
4771
Gustavo F. Padovanbb58f742011-02-03 20:50:35 -02004772 l2cap_cleanup_sockets();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773}
4774
Gustavo F. Padovand1c4a172010-07-18 16:25:54 -03004775module_param(disable_ertm, bool, 0644);
4776MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
Andrei Emeltchenkoa5fd6f32011-09-16 16:26:32 +03004777
4778module_param(enable_hs, bool, 0644);
4779MODULE_PARM_DESC(enable_hs, "Enable High Speed");