blob: 450cdcd88e5c9a624372927639433f67fc2fde1d [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
4
5 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090015 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090020 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth SCO sockets. */
26
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/module.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010028#include <linux/debugfs.h>
29#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
31#include <net/bluetooth/bluetooth.h>
32#include <net/bluetooth/hci_core.h>
33#include <net/bluetooth/sco.h>
34
Rusty Russelleb939922011-12-19 14:08:01 +000035static bool disable_esco;
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Eric Dumazet90ddc4f2005-12-22 12:49:22 -080037static const struct proto_ops sco_sock_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39static struct bt_sock_list sco_sk_list = {
Robert P. J. Dayd5fb2962008-03-28 16:17:38 -070040 .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070041};
42
43static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
44static void sco_chan_del(struct sock *sk, int err);
45
Linus Torvalds1da177e2005-04-16 15:20:36 -070046static void sco_sock_close(struct sock *sk);
47static void sco_sock_kill(struct sock *sk);
48
49/* ---- SCO timers ---- */
50static void sco_sock_timeout(unsigned long arg)
51{
52 struct sock *sk = (struct sock *) arg;
53
54 BT_DBG("sock %p state %d", sk, sk->sk_state);
55
56 bh_lock_sock(sk);
57 sk->sk_err = ETIMEDOUT;
58 sk->sk_state_change(sk);
59 bh_unlock_sock(sk);
60
61 sco_sock_kill(sk);
62 sock_put(sk);
63}
64
65static void sco_sock_set_timer(struct sock *sk, long timeout)
66{
67 BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
68 sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
69}
70
71static void sco_sock_clear_timer(struct sock *sk)
72{
73 BT_DBG("sock %p state %d", sk, sk->sk_state);
74 sk_stop_timer(sk, &sk->sk_timer);
75}
76
Linus Torvalds1da177e2005-04-16 15:20:36 -070077/* ---- SCO connections ---- */
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +020078static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079{
80 struct hci_dev *hdev = hcon->hdev;
Marcel Holtmann25ea6db2006-07-06 15:40:09 +020081 struct sco_conn *conn = hcon->sco_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +020083 if (conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 return conn;
85
Marcel Holtmann25ea6db2006-07-06 15:40:09 +020086 conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
87 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 spin_lock_init(&conn->lock);
91
92 hcon->sco_data = conn;
93 conn->hcon = hcon;
94
95 conn->src = &hdev->bdaddr;
96 conn->dst = &hcon->dst;
97
98 if (hdev->sco_mtu > 0)
99 conn->mtu = hdev->sco_mtu;
100 else
101 conn->mtu = 60;
102
103 BT_DBG("hcon %p conn %p", hcon, conn);
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200104
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 return conn;
106}
107
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300108static struct sock *sco_chan_get(struct sco_conn *conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109{
110 struct sock *sk = NULL;
111 sco_conn_lock(conn);
112 sk = conn->sk;
113 sco_conn_unlock(conn);
114 return sk;
115}
116
117static int sco_conn_del(struct hci_conn *hcon, int err)
118{
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200119 struct sco_conn *conn = hcon->sco_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120 struct sock *sk;
121
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200122 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return 0;
124
125 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
126
127 /* Kill socket */
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200128 sk = sco_chan_get(conn);
129 if (sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130 bh_lock_sock(sk);
131 sco_sock_clear_timer(sk);
132 sco_chan_del(sk, err);
133 bh_unlock_sock(sk);
Gustavo Padovan269c4842012-06-15 02:30:20 -0300134
135 sco_conn_lock(conn);
136 conn->sk = NULL;
137 sco_pi(sk)->conn = NULL;
138 sco_conn_unlock(conn);
139
140 if (conn->hcon)
141 hci_conn_put(conn->hcon);
142
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 sco_sock_kill(sk);
144 }
145
146 hcon->sco_data = NULL;
147 kfree(conn);
148 return 0;
149}
150
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300151static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
152 struct sock *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153{
154 int err = 0;
155
156 sco_conn_lock(conn);
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300157 if (conn->sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158 err = -EBUSY;
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300159 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 __sco_chan_add(conn, sk, parent);
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300161
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 sco_conn_unlock(conn);
163 return err;
164}
165
166static int sco_connect(struct sock *sk)
167{
168 bdaddr_t *src = &bt_sk(sk)->src;
169 bdaddr_t *dst = &bt_sk(sk)->dst;
170 struct sco_conn *conn;
171 struct hci_conn *hcon;
172 struct hci_dev *hdev;
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200173 int err, type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174
Andrei Emeltchenko6ed93dc2012-09-25 12:49:43 +0300175 BT_DBG("%pMR -> %pMR", src, dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200177 hdev = hci_get_route(dst, src);
178 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 return -EHOSTUNREACH;
180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300181 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182
Marcel Holtmann7cb127d2008-07-14 20:13:53 +0200183 if (lmp_esco_capable(hdev) && !disable_esco)
184 type = ESCO_LINK;
185 else
186 type = SCO_LINK;
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200187
Andre Guedesb12f62c2012-04-24 21:02:54 -0300188 hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW,
189 HCI_AT_NO_BONDING);
Ville Tervo30e76272011-02-22 16:10:53 -0300190 if (IS_ERR(hcon)) {
191 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -0300193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +0200195 conn = sco_conn_add(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196 if (!conn) {
197 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -0300198 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199 goto done;
200 }
201
202 /* Update source addr of the socket */
203 bacpy(src, conn->src);
204
205 err = sco_chan_add(conn, sk, NULL);
206 if (err)
207 goto done;
208
209 if (hcon->state == BT_CONNECTED) {
210 sco_sock_clear_timer(sk);
211 sk->sk_state = BT_CONNECTED;
212 } else {
213 sk->sk_state = BT_CONNECT;
214 sco_sock_set_timer(sk, sk->sk_sndtimeo);
215 }
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200216
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300218 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 hci_dev_put(hdev);
220 return err;
221}
222
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300223static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224{
225 struct sco_conn *conn = sco_pi(sk)->conn;
226 struct sk_buff *skb;
Mikel Astiz088ce082012-04-11 08:48:48 +0200227 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228
229 /* Check outgoing MTU */
230 if (len > conn->mtu)
231 return -EINVAL;
232
233 BT_DBG("sk %p len %d", sk, len);
234
Mikel Astiz088ce082012-04-11 08:48:48 +0200235 skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300236 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 return err;
238
Mikel Astiz088ce082012-04-11 08:48:48 +0200239 if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300240 kfree_skb(skb);
241 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243
Gustavo F. Padovan0d861d82010-05-01 16:15:35 -0300244 hci_send_sco(conn->hcon, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245
Mikel Astiz088ce082012-04-11 08:48:48 +0200246 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700247}
248
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300249static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250{
251 struct sock *sk = sco_chan_get(conn);
252
253 if (!sk)
254 goto drop;
255
256 BT_DBG("sk %p len %d", sk, skb->len);
257
258 if (sk->sk_state != BT_CONNECTED)
259 goto drop;
260
261 if (!sock_queue_rcv_skb(sk, skb))
262 return;
263
264drop:
265 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266}
267
268/* -------- Socket interface ---------- */
Marcel Holtmannfb334052012-04-19 14:37:58 +0200269static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271 struct hlist_node *node;
Marcel Holtmannfb334052012-04-19 14:37:58 +0200272 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Marcel Holtmannfb334052012-04-19 14:37:58 +0200274 sk_for_each(sk, node, &sco_sk_list.head) {
275 if (sk->sk_state != BT_LISTEN)
276 continue;
277
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 if (!bacmp(&bt_sk(sk)->src, ba))
Marcel Holtmannfb334052012-04-19 14:37:58 +0200279 return sk;
280 }
281
282 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283}
284
285/* Find socket listening on source bdaddr.
286 * Returns closest match.
287 */
288static struct sock *sco_get_sock_listen(bdaddr_t *src)
289{
290 struct sock *sk = NULL, *sk1 = NULL;
291 struct hlist_node *node;
292
293 read_lock(&sco_sk_list.lock);
294
295 sk_for_each(sk, node, &sco_sk_list.head) {
296 if (sk->sk_state != BT_LISTEN)
297 continue;
298
299 /* Exact match. */
300 if (!bacmp(&bt_sk(sk)->src, src))
301 break;
302
303 /* Closest match */
304 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
305 sk1 = sk;
306 }
307
308 read_unlock(&sco_sk_list.lock);
309
310 return node ? sk : sk1;
311}
312
313static void sco_sock_destruct(struct sock *sk)
314{
315 BT_DBG("sk %p", sk);
316
317 skb_queue_purge(&sk->sk_receive_queue);
318 skb_queue_purge(&sk->sk_write_queue);
319}
320
321static void sco_sock_cleanup_listen(struct sock *parent)
322{
323 struct sock *sk;
324
325 BT_DBG("parent %p", parent);
326
327 /* Close not yet accepted channels */
328 while ((sk = bt_accept_dequeue(parent, NULL))) {
329 sco_sock_close(sk);
330 sco_sock_kill(sk);
331 }
332
333 parent->sk_state = BT_CLOSED;
334 sock_set_flag(parent, SOCK_ZAPPED);
335}
336
337/* Kill socket (only if zapped and orphan)
338 * Must be called on unlocked socket.
339 */
340static void sco_sock_kill(struct sock *sk)
341{
342 if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
343 return;
344
345 BT_DBG("sk %p state %d", sk, sk->sk_state);
346
347 /* Kill poor orphan */
348 bt_sock_unlink(&sco_sk_list, sk);
349 sock_set_flag(sk, SOCK_DEAD);
350 sock_put(sk);
351}
352
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200353static void __sco_sock_close(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354{
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200355 BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 switch (sk->sk_state) {
358 case BT_LISTEN:
359 sco_sock_cleanup_listen(sk);
360 break;
361
362 case BT_CONNECTED:
363 case BT_CONFIG:
Luiz Augusto von Dentz4a777082011-05-12 11:13:15 +0300364 if (sco_pi(sk)->conn) {
365 sk->sk_state = BT_DISCONN;
366 sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
367 hci_conn_put(sco_pi(sk)->conn->hcon);
368 sco_pi(sk)->conn->hcon = NULL;
369 } else
370 sco_chan_del(sk, ECONNRESET);
371 break;
372
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373 case BT_CONNECT:
374 case BT_DISCONN:
375 sco_chan_del(sk, ECONNRESET);
376 break;
377
378 default:
379 sock_set_flag(sk, SOCK_ZAPPED);
380 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700381 }
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200382}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200384/* Must be called on unlocked socket. */
385static void sco_sock_close(struct sock *sk)
386{
387 sco_sock_clear_timer(sk);
388 lock_sock(sk);
389 __sco_sock_close(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 sco_sock_kill(sk);
392}
393
394static void sco_sock_init(struct sock *sk, struct sock *parent)
395{
396 BT_DBG("sk %p", sk);
397
Paul Moore6230c9b2011-10-07 09:40:59 +0000398 if (parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 sk->sk_type = parent->sk_type;
Paul Moore6230c9b2011-10-07 09:40:59 +0000400 security_sk_clone(parent, sk);
401 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402}
403
404static struct proto sco_proto = {
405 .name = "SCO",
406 .owner = THIS_MODULE,
407 .obj_size = sizeof(struct sco_pinfo)
408};
409
Eric W. Biederman1b8d7ae2007-10-08 23:24:22 -0700410static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411{
412 struct sock *sk;
413
Pavel Emelyanov6257ff22007-11-01 00:39:31 -0700414 sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415 if (!sk)
416 return NULL;
417
418 sock_init_data(sock, sk);
419 INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
420
421 sk->sk_destruct = sco_sock_destruct;
422 sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
423
424 sock_reset_flag(sk, SOCK_ZAPPED);
425
426 sk->sk_protocol = proto;
427 sk->sk_state = BT_OPEN;
428
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800429 setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430
431 bt_sock_link(&sco_sk_list, sk);
432 return sk;
433}
434
Eric Paris3f378b62009-11-05 22:18:14 -0800435static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
436 int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 struct sock *sk;
439
440 BT_DBG("sock %p", sock);
441
442 sock->state = SS_UNCONNECTED;
443
444 if (sock->type != SOCK_SEQPACKET)
445 return -ESOCKTNOSUPPORT;
446
447 sock->ops = &sco_sock_ops;
448
Eric W. Biederman1b8d7ae2007-10-08 23:24:22 -0700449 sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC);
Marcel Holtmann74da6262006-10-15 17:31:14 +0200450 if (!sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451 return -ENOMEM;
452
453 sco_sock_init(sk, NULL);
454 return 0;
455}
456
457static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
458{
459 struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
460 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 int err = 0;
462
Andrei Emeltchenko6ed93dc2012-09-25 12:49:43 +0300463 BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
465 if (!addr || addr->sa_family != AF_BLUETOOTH)
466 return -EINVAL;
467
468 lock_sock(sk);
469
470 if (sk->sk_state != BT_OPEN) {
471 err = -EBADFD;
472 goto done;
473 }
474
Marcel Holtmann8ed21f72012-04-19 13:43:53 +0200475 if (sk->sk_type != SOCK_SEQPACKET) {
476 err = -EINVAL;
477 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700478 }
479
Marcel Holtmann8ed21f72012-04-19 13:43:53 +0200480 bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
481
482 sk->sk_state = BT_BOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483
484done:
485 release_sock(sk);
486 return err;
487}
488
489static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
490{
491 struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
492 struct sock *sk = sock->sk;
493 int err = 0;
494
495
496 BT_DBG("sk %p", sk);
497
Changli Gao6503d962010-03-31 22:58:26 +0000498 if (alen < sizeof(struct sockaddr_sco) ||
499 addr->sa_family != AF_BLUETOOTH)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500 return -EINVAL;
501
502 if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
503 return -EBADFD;
504
505 if (sk->sk_type != SOCK_SEQPACKET)
506 return -EINVAL;
507
508 lock_sock(sk);
509
510 /* Set destination address and psm */
511 bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
512
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200513 err = sco_connect(sk);
514 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 goto done;
516
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900517 err = bt_sock_wait_state(sk, BT_CONNECTED,
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300518 sock_sndtimeo(sk, flags & O_NONBLOCK));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520done:
521 release_sock(sk);
522 return err;
523}
524
525static int sco_sock_listen(struct socket *sock, int backlog)
526{
527 struct sock *sk = sock->sk;
Marcel Holtmannfb334052012-04-19 14:37:58 +0200528 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 int err = 0;
530
531 BT_DBG("sk %p backlog %d", sk, backlog);
532
533 lock_sock(sk);
534
Marcel Holtmann7d5d7752012-04-19 13:43:52 +0200535 if (sk->sk_state != BT_BOUND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 err = -EBADFD;
537 goto done;
538 }
539
Marcel Holtmann7d5d7752012-04-19 13:43:52 +0200540 if (sk->sk_type != SOCK_SEQPACKET) {
541 err = -EINVAL;
542 goto done;
543 }
544
Marcel Holtmannfb334052012-04-19 14:37:58 +0200545 write_lock(&sco_sk_list.lock);
546
547 if (__sco_get_sock_listen_by_addr(src)) {
548 err = -EADDRINUSE;
549 goto unlock;
550 }
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 sk->sk_max_ack_backlog = backlog;
553 sk->sk_ack_backlog = 0;
Marcel Holtmannfb334052012-04-19 14:37:58 +0200554
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555 sk->sk_state = BT_LISTEN;
556
Marcel Holtmannfb334052012-04-19 14:37:58 +0200557unlock:
558 write_unlock(&sco_sk_list.lock);
559
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560done:
561 release_sock(sk);
562 return err;
563}
564
565static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
566{
567 DECLARE_WAITQUEUE(wait, current);
568 struct sock *sk = sock->sk, *ch;
569 long timeo;
570 int err = 0;
571
572 lock_sock(sk);
573
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574 timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
575
576 BT_DBG("sk %p timeo %ld", sk, timeo);
577
578 /* Wait for an incoming connection. (wake-one). */
Eric Dumazetaa395142010-04-20 13:03:51 +0000579 add_wait_queue_exclusive(sk_sleep(sk), &wait);
Peter Hurley552b0d32011-07-24 00:11:01 -0400580 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700581 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583 if (sk->sk_state != BT_LISTEN) {
584 err = -EBADFD;
585 break;
586 }
587
Peter Hurley552b0d32011-07-24 00:11:01 -0400588 ch = bt_accept_dequeue(sk, newsock);
589 if (ch)
590 break;
591
592 if (!timeo) {
593 err = -EAGAIN;
594 break;
595 }
596
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 if (signal_pending(current)) {
598 err = sock_intr_errno(timeo);
599 break;
600 }
Peter Hurley552b0d32011-07-24 00:11:01 -0400601
602 release_sock(sk);
603 timeo = schedule_timeout(timeo);
604 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700605 }
Peter Hurley552b0d32011-07-24 00:11:01 -0400606 __set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000607 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700608
609 if (err)
610 goto done;
611
612 newsock->state = SS_CONNECTED;
613
614 BT_DBG("new socket %p", ch);
615
616done:
617 release_sock(sk);
618 return err;
619}
620
621static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
622{
623 struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
624 struct sock *sk = sock->sk;
625
626 BT_DBG("sock %p, sk %p", sock, sk);
627
628 addr->sa_family = AF_BLUETOOTH;
629 *len = sizeof(struct sockaddr_sco);
630
631 if (peer)
632 bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
633 else
634 bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
635
636 return 0;
637}
638
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900639static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 struct msghdr *msg, size_t len)
641{
642 struct sock *sk = sock->sk;
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300643 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644
645 BT_DBG("sock %p, sk %p", sock, sk);
646
Benjamin LaHaisec1cbe4b2005-12-13 23:22:19 -0800647 err = sock_error(sk);
648 if (err)
649 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 if (msg->msg_flags & MSG_OOB)
652 return -EOPNOTSUPP;
653
654 lock_sock(sk);
655
656 if (sk->sk_state == BT_CONNECTED)
657 err = sco_send_frame(sk, msg, len);
658 else
659 err = -ENOTCONN;
660
661 release_sock(sk);
662 return err;
663}
664
David S. Millerb7058842009-09-30 16:12:20 -0700665static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666{
667 struct sock *sk = sock->sk;
668 int err = 0;
669
670 BT_DBG("sk %p", sk);
671
672 lock_sock(sk);
673
674 switch (optname) {
675 default:
676 err = -ENOPROTOOPT;
677 break;
678 }
679
680 release_sock(sk);
681 return err;
682}
683
Marcel Holtmannd58daf42009-01-15 21:52:14 +0100684static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685{
686 struct sock *sk = sock->sk;
687 struct sco_options opts;
688 struct sco_conninfo cinfo;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900689 int len, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690
691 BT_DBG("sk %p", sk);
692
693 if (get_user(len, optlen))
694 return -EFAULT;
695
696 lock_sock(sk);
697
698 switch (optname) {
699 case SCO_OPTIONS:
700 if (sk->sk_state != BT_CONNECTED) {
701 err = -ENOTCONN;
702 break;
703 }
704
705 opts.mtu = sco_pi(sk)->conn->mtu;
706
707 BT_DBG("mtu %d", opts.mtu);
708
709 len = min_t(unsigned int, len, sizeof(opts));
710 if (copy_to_user(optval, (char *)&opts, len))
711 err = -EFAULT;
712
713 break;
714
715 case SCO_CONNINFO:
716 if (sk->sk_state != BT_CONNECTED) {
717 err = -ENOTCONN;
718 break;
719 }
720
Vasiliy Kulikovc4c896e2011-02-14 13:54:26 +0300721 memset(&cinfo, 0, sizeof(cinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
723 memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
724
725 len = min_t(unsigned int, len, sizeof(cinfo));
726 if (copy_to_user(optval, (char *)&cinfo, len))
727 err = -EFAULT;
728
729 break;
730
731 default:
732 err = -ENOPROTOOPT;
733 break;
734 }
735
736 release_sock(sk);
737 return err;
738}
739
Marcel Holtmannd58daf42009-01-15 21:52:14 +0100740static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
741{
742 struct sock *sk = sock->sk;
743 int len, err = 0;
744
745 BT_DBG("sk %p", sk);
746
747 if (level == SOL_SCO)
748 return sco_sock_getsockopt_old(sock, optname, optval, optlen);
749
750 if (get_user(len, optlen))
751 return -EFAULT;
752
753 lock_sock(sk);
754
755 switch (optname) {
756 default:
757 err = -ENOPROTOOPT;
758 break;
759 }
760
761 release_sock(sk);
762 return err;
763}
764
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200765static int sco_sock_shutdown(struct socket *sock, int how)
766{
767 struct sock *sk = sock->sk;
768 int err = 0;
769
770 BT_DBG("sock %p, sk %p", sock, sk);
771
772 if (!sk)
773 return 0;
774
775 lock_sock(sk);
776 if (!sk->sk_shutdown) {
777 sk->sk_shutdown = SHUTDOWN_MASK;
778 sco_sock_clear_timer(sk);
779 __sco_sock_close(sk);
780
781 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
782 err = bt_sock_wait_state(sk, BT_CLOSED,
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300783 sk->sk_lingertime);
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200784 }
785 release_sock(sk);
786 return err;
787}
788
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789static int sco_sock_release(struct socket *sock)
790{
791 struct sock *sk = sock->sk;
792 int err = 0;
793
794 BT_DBG("sock %p, sk %p", sock, sk);
795
796 if (!sk)
797 return 0;
798
799 sco_sock_close(sk);
800
801 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {
802 lock_sock(sk);
803 err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
804 release_sock(sk);
805 }
806
807 sock_orphan(sk);
808 sco_sock_kill(sk);
809 return err;
810}
811
812static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
813{
814 BT_DBG("conn %p", conn);
815
816 sco_pi(sk)->conn = conn;
817 conn->sk = sk;
818
819 if (parent)
820 bt_accept_enqueue(parent, sk);
821}
822
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900823/* Delete channel.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 * Must be called on the locked socket. */
825static void sco_chan_del(struct sock *sk, int err)
826{
827 struct sco_conn *conn;
828
829 conn = sco_pi(sk)->conn;
830
831 BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
832
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 sk->sk_state = BT_CLOSED;
834 sk->sk_err = err;
835 sk->sk_state_change(sk);
836
837 sock_set_flag(sk, SOCK_ZAPPED);
838}
839
840static void sco_conn_ready(struct sco_conn *conn)
841{
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200842 struct sock *parent;
843 struct sock *sk = conn->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844
845 BT_DBG("conn %p", conn);
846
847 sco_conn_lock(conn);
848
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200849 if (sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 sco_sock_clear_timer(sk);
851 bh_lock_sock(sk);
852 sk->sk_state = BT_CONNECTED;
853 sk->sk_state_change(sk);
854 bh_unlock_sock(sk);
855 } else {
856 parent = sco_get_sock_listen(conn->src);
857 if (!parent)
858 goto done;
859
860 bh_lock_sock(parent);
861
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300862 sk = sco_sock_alloc(sock_net(parent), NULL,
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300863 BTPROTO_SCO, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 if (!sk) {
865 bh_unlock_sock(parent);
866 goto done;
867 }
868
869 sco_sock_init(sk, parent);
870
871 bacpy(&bt_sk(sk)->src, conn->src);
872 bacpy(&bt_sk(sk)->dst, conn->dst);
873
874 hci_conn_hold(conn->hcon);
875 __sco_chan_add(conn, sk, parent);
876
877 sk->sk_state = BT_CONNECTED;
878
879 /* Wake up parent */
880 parent->sk_data_ready(parent, 1);
881
882 bh_unlock_sock(parent);
883 }
884
885done:
886 sco_conn_unlock(conn);
887}
888
889/* ----- SCO interface with lower layer (HCI) ----- */
Ulisses Furquim686ebf22011-12-21 10:11:33 -0200890int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891{
Gustavo Padovanfc5fef62012-05-23 04:04:19 -0300892 struct sock *sk;
Marcel Holtmann71aeeaa2009-01-15 21:57:02 +0100893 struct hlist_node *node;
894 int lm = 0;
895
Andrei Emeltchenko6ed93dc2012-09-25 12:49:43 +0300896 BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
Marcel Holtmann71aeeaa2009-01-15 21:57:02 +0100898 /* Find listening sockets */
899 read_lock(&sco_sk_list.lock);
900 sk_for_each(sk, node, &sco_sk_list.head) {
901 if (sk->sk_state != BT_LISTEN)
902 continue;
903
904 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300905 !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
Marcel Holtmann71aeeaa2009-01-15 21:57:02 +0100906 lm |= HCI_LM_ACCEPT;
907 break;
908 }
909 }
910 read_unlock(&sco_sk_list.lock);
911
912 return lm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913}
914
Andrei Emeltchenko9e664632012-07-24 16:06:15 +0300915void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
Andrei Emeltchenko6ed93dc2012-09-25 12:49:43 +0300917 BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (!status) {
919 struct sco_conn *conn;
920
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +0200921 conn = sco_conn_add(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 if (conn)
923 sco_conn_ready(conn);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900924 } else
Joe Perchese1750722011-06-29 18:18:29 -0700925 sco_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926}
927
Andrei Emeltchenko9e664632012-07-24 16:06:15 +0300928void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929{
930 BT_DBG("hcon %p reason %d", hcon, reason);
931
Joe Perchese1750722011-06-29 18:18:29 -0700932 sco_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933}
934
Ulisses Furquim686ebf22011-12-21 10:11:33 -0200935int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700936{
937 struct sco_conn *conn = hcon->sco_data;
938
939 if (!conn)
940 goto drop;
941
942 BT_DBG("conn %p len %d", conn, skb->len);
943
944 if (skb->len) {
945 sco_recv_frame(conn, skb);
946 return 0;
947 }
948
949drop:
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900950 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700951 return 0;
952}
953
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100954static int sco_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955{
956 struct sock *sk;
957 struct hlist_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
Gustavo F. Padovanee65d192011-12-27 15:28:46 -0200959 read_lock(&sco_sk_list.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Marcel Holtmannbe9d1222005-11-08 09:57:38 -0800961 sk_for_each(sk, node, &sco_sk_list.head) {
Andrei Emeltchenkofcb73332012-09-25 12:49:44 +0300962 seq_printf(f, "%pMR %pMR %d\n", &bt_sk(sk)->src,
963 &bt_sk(sk)->dst, sk->sk_state);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -0800964 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700965
Gustavo F. Padovanee65d192011-12-27 15:28:46 -0200966 read_unlock(&sco_sk_list.lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -0800967
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100968 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969}
970
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100971static int sco_debugfs_open(struct inode *inode, struct file *file)
972{
973 return single_open(file, sco_debugfs_show, inode->i_private);
974}
975
976static const struct file_operations sco_debugfs_fops = {
977 .open = sco_debugfs_open,
978 .read = seq_read,
979 .llseek = seq_lseek,
980 .release = single_release,
981};
982
983static struct dentry *sco_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700984
Eric Dumazet90ddc4f2005-12-22 12:49:22 -0800985static const struct proto_ops sco_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700986 .family = PF_BLUETOOTH,
987 .owner = THIS_MODULE,
988 .release = sco_sock_release,
989 .bind = sco_sock_bind,
990 .connect = sco_sock_connect,
991 .listen = sco_sock_listen,
992 .accept = sco_sock_accept,
993 .getname = sco_sock_getname,
994 .sendmsg = sco_sock_sendmsg,
995 .recvmsg = bt_sock_recvmsg,
996 .poll = bt_sock_poll,
Marcel Holtmann3241ad82008-07-14 20:13:50 +0200997 .ioctl = bt_sock_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998 .mmap = sock_no_mmap,
999 .socketpair = sock_no_socketpair,
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +02001000 .shutdown = sco_sock_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 .setsockopt = sco_sock_setsockopt,
1002 .getsockopt = sco_sock_getsockopt
1003};
1004
Stephen Hemmingerec1b4cf2009-10-05 05:58:39 +00001005static const struct net_proto_family sco_sock_family_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 .family = PF_BLUETOOTH,
1007 .owner = THIS_MODULE,
1008 .create = sco_sock_create,
1009};
1010
Gustavo F. Padovan64274512011-02-07 20:08:52 -02001011int __init sco_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012{
1013 int err;
1014
1015 err = proto_register(&sco_proto, 0);
1016 if (err < 0)
1017 return err;
1018
1019 err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
1020 if (err < 0) {
1021 BT_ERR("SCO socket registration failed");
1022 goto error;
1023 }
1024
Masatake YAMATOde9b9212012-07-26 01:30:12 +09001025 err = bt_procfs_init(THIS_MODULE, &init_net, "sco", &sco_sk_list, NULL);
1026 if (err < 0) {
1027 BT_ERR("Failed to create SCO proc file");
1028 bt_sock_unregister(BTPROTO_SCO);
1029 goto error;
1030 }
1031
Marcel Holtmannaef7d972010-03-21 05:27:45 +01001032 if (bt_debugfs) {
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -03001033 sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
1034 NULL, &sco_debugfs_fops);
Marcel Holtmannaef7d972010-03-21 05:27:45 +01001035 if (!sco_debugfs)
1036 BT_ERR("Failed to create SCO debug file");
1037 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001038
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 BT_INFO("SCO socket layer initialized");
1040
1041 return 0;
1042
1043error:
1044 proto_unregister(&sco_proto);
1045 return err;
1046}
1047
Gustavo F. Padovan64274512011-02-07 20:08:52 -02001048void __exit sco_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
Masatake YAMATOde9b9212012-07-26 01:30:12 +09001050 bt_procfs_cleanup(&init_net, "sco");
1051
Marcel Holtmannaef7d972010-03-21 05:27:45 +01001052 debugfs_remove(sco_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
1054 if (bt_sock_unregister(BTPROTO_SCO) < 0)
1055 BT_ERR("SCO socket unregistration failed");
1056
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 proto_unregister(&sco_proto);
1058}
1059
Marcel Holtmann7cb127d2008-07-14 20:13:53 +02001060module_param(disable_esco, bool, 0644);
1061MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");