blob: 824ae2fd15ebb73dc4cb2219fbeda14d1942a180 [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>
28
29#include <linux/types.h>
30#include <linux/errno.h>
31#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/sched.h>
33#include <linux/slab.h>
34#include <linux/poll.h>
35#include <linux/fcntl.h>
36#include <linux/init.h>
37#include <linux/interrupt.h>
38#include <linux/socket.h>
39#include <linux/skbuff.h>
Marcel Holtmannbe9d1222005-11-08 09:57:38 -080040#include <linux/device.h>
Marcel Holtmannaef7d972010-03-21 05:27:45 +010041#include <linux/debugfs.h>
42#include <linux/seq_file.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <linux/list.h>
Paul Moore6230c9b2011-10-07 09:40:59 +000044#include <linux/security.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#include <net/sock.h>
46
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +020047#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49#include <net/bluetooth/bluetooth.h>
50#include <net/bluetooth/hci_core.h>
51#include <net/bluetooth/sco.h>
52
Rusty Russelleb939922011-12-19 14:08:01 +000053static bool disable_esco;
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Eric Dumazet90ddc4f2005-12-22 12:49:22 -080055static const struct proto_ops sco_sock_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
57static struct bt_sock_list sco_sk_list = {
Robert P. J. Dayd5fb2962008-03-28 16:17:38 -070058 .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059};
60
61static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);
62static void sco_chan_del(struct sock *sk, int err);
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static void sco_sock_close(struct sock *sk);
65static void sco_sock_kill(struct sock *sk);
66
67/* ---- SCO timers ---- */
68static void sco_sock_timeout(unsigned long arg)
69{
70 struct sock *sk = (struct sock *) arg;
71
72 BT_DBG("sock %p state %d", sk, sk->sk_state);
73
74 bh_lock_sock(sk);
75 sk->sk_err = ETIMEDOUT;
76 sk->sk_state_change(sk);
77 bh_unlock_sock(sk);
78
79 sco_sock_kill(sk);
80 sock_put(sk);
81}
82
83static void sco_sock_set_timer(struct sock *sk, long timeout)
84{
85 BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
86 sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
87}
88
89static void sco_sock_clear_timer(struct sock *sk)
90{
91 BT_DBG("sock %p state %d", sk, sk->sk_state);
92 sk_stop_timer(sk, &sk->sk_timer);
93}
94
Linus Torvalds1da177e2005-04-16 15:20:36 -070095/* ---- SCO connections ---- */
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +020096static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
Linus Torvalds1da177e2005-04-16 15:20:36 -070097{
98 struct hci_dev *hdev = hcon->hdev;
Marcel Holtmann25ea6db2006-07-06 15:40:09 +020099 struct sco_conn *conn = hcon->sco_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +0200101 if (conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102 return conn;
103
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200104 conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC);
105 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
108 spin_lock_init(&conn->lock);
109
110 hcon->sco_data = conn;
111 conn->hcon = hcon;
112
113 conn->src = &hdev->bdaddr;
114 conn->dst = &hcon->dst;
115
116 if (hdev->sco_mtu > 0)
117 conn->mtu = hdev->sco_mtu;
118 else
119 conn->mtu = 60;
120
121 BT_DBG("hcon %p conn %p", hcon, conn);
Marcel Holtmann25ea6db2006-07-06 15:40:09 +0200122
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return conn;
124}
125
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300126static struct sock *sco_chan_get(struct sco_conn *conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127{
128 struct sock *sk = NULL;
129 sco_conn_lock(conn);
130 sk = conn->sk;
131 sco_conn_unlock(conn);
132 return sk;
133}
134
135static int sco_conn_del(struct hci_conn *hcon, int err)
136{
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200137 struct sco_conn *conn = hcon->sco_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 struct sock *sk;
139
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200140 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141 return 0;
142
143 BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
144
145 /* Kill socket */
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200146 sk = sco_chan_get(conn);
147 if (sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 bh_lock_sock(sk);
149 sco_sock_clear_timer(sk);
150 sco_chan_del(sk, err);
151 bh_unlock_sock(sk);
152 sco_sock_kill(sk);
153 }
154
155 hcon->sco_data = NULL;
156 kfree(conn);
157 return 0;
158}
159
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300160static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
161 struct sock *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
163 int err = 0;
164
165 sco_conn_lock(conn);
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300166 if (conn->sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 err = -EBUSY;
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300168 else
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169 __sco_chan_add(conn, sk, parent);
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 sco_conn_unlock(conn);
172 return err;
173}
174
175static int sco_connect(struct sock *sk)
176{
177 bdaddr_t *src = &bt_sk(sk)->src;
178 bdaddr_t *dst = &bt_sk(sk)->dst;
179 struct sco_conn *conn;
180 struct hci_conn *hcon;
181 struct hci_dev *hdev;
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200182 int err, type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
184 BT_DBG("%s -> %s", batostr(src), batostr(dst));
185
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200186 hdev = hci_get_route(dst, src);
187 if (!hdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 return -EHOSTUNREACH;
189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300190 hci_dev_lock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
Marcel Holtmann7cb127d2008-07-14 20:13:53 +0200192 if (lmp_esco_capable(hdev) && !disable_esco)
193 type = ESCO_LINK;
194 else
195 type = SCO_LINK;
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200196
Andre Guedesb12f62c2012-04-24 21:02:54 -0300197 hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW,
198 HCI_AT_NO_BONDING);
Ville Tervo30e76272011-02-22 16:10:53 -0300199 if (IS_ERR(hcon)) {
200 err = PTR_ERR(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 goto done;
Ville Tervo30e76272011-02-22 16:10:53 -0300202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +0200204 conn = sco_conn_add(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205 if (!conn) {
206 hci_conn_put(hcon);
Ville Tervo30e76272011-02-22 16:10:53 -0300207 err = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 goto done;
209 }
210
211 /* Update source addr of the socket */
212 bacpy(src, conn->src);
213
214 err = sco_chan_add(conn, sk, NULL);
215 if (err)
216 goto done;
217
218 if (hcon->state == BT_CONNECTED) {
219 sco_sock_clear_timer(sk);
220 sk->sk_state = BT_CONNECTED;
221 } else {
222 sk->sk_state = BT_CONNECT;
223 sco_sock_set_timer(sk, sk->sk_sndtimeo);
224 }
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200225
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300227 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 hci_dev_put(hdev);
229 return err;
230}
231
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300232static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
234 struct sco_conn *conn = sco_pi(sk)->conn;
235 struct sk_buff *skb;
Mikel Astiz088ce082012-04-11 08:48:48 +0200236 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237
238 /* Check outgoing MTU */
239 if (len > conn->mtu)
240 return -EINVAL;
241
242 BT_DBG("sk %p len %d", sk, len);
243
Mikel Astiz088ce082012-04-11 08:48:48 +0200244 skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300245 if (!skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return err;
247
Mikel Astiz088ce082012-04-11 08:48:48 +0200248 if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300249 kfree_skb(skb);
250 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 }
252
Gustavo F. Padovan0d861d82010-05-01 16:15:35 -0300253 hci_send_sco(conn->hcon, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254
Mikel Astiz088ce082012-04-11 08:48:48 +0200255 return len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256}
257
Gustavo Padovan6039aa732012-05-23 04:04:18 -0300258static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259{
260 struct sock *sk = sco_chan_get(conn);
261
262 if (!sk)
263 goto drop;
264
265 BT_DBG("sk %p len %d", sk, skb->len);
266
267 if (sk->sk_state != BT_CONNECTED)
268 goto drop;
269
270 if (!sock_queue_rcv_skb(sk, skb))
271 return;
272
273drop:
274 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275}
276
277/* -------- Socket interface ---------- */
Marcel Holtmannfb334052012-04-19 14:37:58 +0200278static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 struct hlist_node *node;
Marcel Holtmannfb334052012-04-19 14:37:58 +0200281 struct sock *sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
Marcel Holtmannfb334052012-04-19 14:37:58 +0200283 sk_for_each(sk, node, &sco_sk_list.head) {
284 if (sk->sk_state != BT_LISTEN)
285 continue;
286
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 if (!bacmp(&bt_sk(sk)->src, ba))
Marcel Holtmannfb334052012-04-19 14:37:58 +0200288 return sk;
289 }
290
291 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292}
293
294/* Find socket listening on source bdaddr.
295 * Returns closest match.
296 */
297static struct sock *sco_get_sock_listen(bdaddr_t *src)
298{
299 struct sock *sk = NULL, *sk1 = NULL;
300 struct hlist_node *node;
301
302 read_lock(&sco_sk_list.lock);
303
304 sk_for_each(sk, node, &sco_sk_list.head) {
305 if (sk->sk_state != BT_LISTEN)
306 continue;
307
308 /* Exact match. */
309 if (!bacmp(&bt_sk(sk)->src, src))
310 break;
311
312 /* Closest match */
313 if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
314 sk1 = sk;
315 }
316
317 read_unlock(&sco_sk_list.lock);
318
319 return node ? sk : sk1;
320}
321
322static void sco_sock_destruct(struct sock *sk)
323{
324 BT_DBG("sk %p", sk);
325
326 skb_queue_purge(&sk->sk_receive_queue);
327 skb_queue_purge(&sk->sk_write_queue);
328}
329
330static void sco_sock_cleanup_listen(struct sock *parent)
331{
332 struct sock *sk;
333
334 BT_DBG("parent %p", parent);
335
336 /* Close not yet accepted channels */
337 while ((sk = bt_accept_dequeue(parent, NULL))) {
338 sco_sock_close(sk);
339 sco_sock_kill(sk);
340 }
341
342 parent->sk_state = BT_CLOSED;
343 sock_set_flag(parent, SOCK_ZAPPED);
344}
345
346/* Kill socket (only if zapped and orphan)
347 * Must be called on unlocked socket.
348 */
349static void sco_sock_kill(struct sock *sk)
350{
351 if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
352 return;
353
354 BT_DBG("sk %p state %d", sk, sk->sk_state);
355
356 /* Kill poor orphan */
357 bt_sock_unlink(&sco_sk_list, sk);
358 sock_set_flag(sk, SOCK_DEAD);
359 sock_put(sk);
360}
361
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200362static void __sco_sock_close(struct sock *sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363{
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200364 BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365
366 switch (sk->sk_state) {
367 case BT_LISTEN:
368 sco_sock_cleanup_listen(sk);
369 break;
370
371 case BT_CONNECTED:
372 case BT_CONFIG:
Luiz Augusto von Dentz4a777082011-05-12 11:13:15 +0300373 if (sco_pi(sk)->conn) {
374 sk->sk_state = BT_DISCONN;
375 sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
376 hci_conn_put(sco_pi(sk)->conn->hcon);
377 sco_pi(sk)->conn->hcon = NULL;
378 } else
379 sco_chan_del(sk, ECONNRESET);
380 break;
381
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 case BT_CONNECT:
383 case BT_DISCONN:
384 sco_chan_del(sk, ECONNRESET);
385 break;
386
387 default:
388 sock_set_flag(sk, SOCK_ZAPPED);
389 break;
Stephen Hemminger3ff50b72007-04-20 17:09:22 -0700390 }
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200391}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200393/* Must be called on unlocked socket. */
394static void sco_sock_close(struct sock *sk)
395{
396 sco_sock_clear_timer(sk);
397 lock_sock(sk);
398 __sco_sock_close(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 release_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 sco_sock_kill(sk);
401}
402
403static void sco_sock_init(struct sock *sk, struct sock *parent)
404{
405 BT_DBG("sk %p", sk);
406
Paul Moore6230c9b2011-10-07 09:40:59 +0000407 if (parent) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 sk->sk_type = parent->sk_type;
Paul Moore6230c9b2011-10-07 09:40:59 +0000409 security_sk_clone(parent, sk);
410 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411}
412
413static struct proto sco_proto = {
414 .name = "SCO",
415 .owner = THIS_MODULE,
416 .obj_size = sizeof(struct sco_pinfo)
417};
418
Eric W. Biederman1b8d7ae2007-10-08 23:24:22 -0700419static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700420{
421 struct sock *sk;
422
Pavel Emelyanov6257ff22007-11-01 00:39:31 -0700423 sk = sk_alloc(net, PF_BLUETOOTH, prio, &sco_proto);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 if (!sk)
425 return NULL;
426
427 sock_init_data(sock, sk);
428 INIT_LIST_HEAD(&bt_sk(sk)->accept_q);
429
430 sk->sk_destruct = sco_sock_destruct;
431 sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
432
433 sock_reset_flag(sk, SOCK_ZAPPED);
434
435 sk->sk_protocol = proto;
436 sk->sk_state = BT_OPEN;
437
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800438 setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439
440 bt_sock_link(&sco_sk_list, sk);
441 return sk;
442}
443
Eric Paris3f378b62009-11-05 22:18:14 -0800444static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
445 int kern)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
447 struct sock *sk;
448
449 BT_DBG("sock %p", sock);
450
451 sock->state = SS_UNCONNECTED;
452
453 if (sock->type != SOCK_SEQPACKET)
454 return -ESOCKTNOSUPPORT;
455
456 sock->ops = &sco_sock_ops;
457
Eric W. Biederman1b8d7ae2007-10-08 23:24:22 -0700458 sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC);
Marcel Holtmann74da6262006-10-15 17:31:14 +0200459 if (!sk)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 return -ENOMEM;
461
462 sco_sock_init(sk, NULL);
463 return 0;
464}
465
466static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
467{
468 struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
469 struct sock *sk = sock->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 int err = 0;
471
472 BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
473
474 if (!addr || addr->sa_family != AF_BLUETOOTH)
475 return -EINVAL;
476
477 lock_sock(sk);
478
479 if (sk->sk_state != BT_OPEN) {
480 err = -EBADFD;
481 goto done;
482 }
483
Marcel Holtmann8ed21f72012-04-19 13:43:53 +0200484 if (sk->sk_type != SOCK_SEQPACKET) {
485 err = -EINVAL;
486 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 }
488
Marcel Holtmann8ed21f72012-04-19 13:43:53 +0200489 bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr);
490
491 sk->sk_state = BT_BOUND;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492
493done:
494 release_sock(sk);
495 return err;
496}
497
498static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
499{
500 struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
501 struct sock *sk = sock->sk;
502 int err = 0;
503
504
505 BT_DBG("sk %p", sk);
506
Changli Gao6503d962010-03-31 22:58:26 +0000507 if (alen < sizeof(struct sockaddr_sco) ||
508 addr->sa_family != AF_BLUETOOTH)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509 return -EINVAL;
510
511 if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
512 return -EBADFD;
513
514 if (sk->sk_type != SOCK_SEQPACKET)
515 return -EINVAL;
516
517 lock_sock(sk);
518
519 /* Set destination address and psm */
520 bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
521
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200522 err = sco_connect(sk);
523 if (err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 goto done;
525
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900526 err = bt_sock_wait_state(sk, BT_CONNECTED,
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300527 sock_sndtimeo(sk, flags & O_NONBLOCK));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
529done:
530 release_sock(sk);
531 return err;
532}
533
534static int sco_sock_listen(struct socket *sock, int backlog)
535{
536 struct sock *sk = sock->sk;
Marcel Holtmannfb334052012-04-19 14:37:58 +0200537 bdaddr_t *src = &bt_sk(sk)->src;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 int err = 0;
539
540 BT_DBG("sk %p backlog %d", sk, backlog);
541
542 lock_sock(sk);
543
Marcel Holtmann7d5d7752012-04-19 13:43:52 +0200544 if (sk->sk_state != BT_BOUND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 err = -EBADFD;
546 goto done;
547 }
548
Marcel Holtmann7d5d7752012-04-19 13:43:52 +0200549 if (sk->sk_type != SOCK_SEQPACKET) {
550 err = -EINVAL;
551 goto done;
552 }
553
Marcel Holtmannfb334052012-04-19 14:37:58 +0200554 write_lock(&sco_sk_list.lock);
555
556 if (__sco_get_sock_listen_by_addr(src)) {
557 err = -EADDRINUSE;
558 goto unlock;
559 }
560
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 sk->sk_max_ack_backlog = backlog;
562 sk->sk_ack_backlog = 0;
Marcel Holtmannfb334052012-04-19 14:37:58 +0200563
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564 sk->sk_state = BT_LISTEN;
565
Marcel Holtmannfb334052012-04-19 14:37:58 +0200566unlock:
567 write_unlock(&sco_sk_list.lock);
568
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569done:
570 release_sock(sk);
571 return err;
572}
573
574static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flags)
575{
576 DECLARE_WAITQUEUE(wait, current);
577 struct sock *sk = sock->sk, *ch;
578 long timeo;
579 int err = 0;
580
581 lock_sock(sk);
582
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
584
585 BT_DBG("sk %p timeo %ld", sk, timeo);
586
587 /* Wait for an incoming connection. (wake-one). */
Eric Dumazetaa395142010-04-20 13:03:51 +0000588 add_wait_queue_exclusive(sk_sleep(sk), &wait);
Peter Hurley552b0d32011-07-24 00:11:01 -0400589 while (1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700590 set_current_state(TASK_INTERRUPTIBLE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592 if (sk->sk_state != BT_LISTEN) {
593 err = -EBADFD;
594 break;
595 }
596
Peter Hurley552b0d32011-07-24 00:11:01 -0400597 ch = bt_accept_dequeue(sk, newsock);
598 if (ch)
599 break;
600
601 if (!timeo) {
602 err = -EAGAIN;
603 break;
604 }
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606 if (signal_pending(current)) {
607 err = sock_intr_errno(timeo);
608 break;
609 }
Peter Hurley552b0d32011-07-24 00:11:01 -0400610
611 release_sock(sk);
612 timeo = schedule_timeout(timeo);
613 lock_sock(sk);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614 }
Peter Hurley552b0d32011-07-24 00:11:01 -0400615 __set_current_state(TASK_RUNNING);
Eric Dumazetaa395142010-04-20 13:03:51 +0000616 remove_wait_queue(sk_sleep(sk), &wait);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617
618 if (err)
619 goto done;
620
621 newsock->state = SS_CONNECTED;
622
623 BT_DBG("new socket %p", ch);
624
625done:
626 release_sock(sk);
627 return err;
628}
629
630static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
631{
632 struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
633 struct sock *sk = sock->sk;
634
635 BT_DBG("sock %p, sk %p", sock, sk);
636
637 addr->sa_family = AF_BLUETOOTH;
638 *len = sizeof(struct sockaddr_sco);
639
640 if (peer)
641 bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst);
642 else
643 bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src);
644
645 return 0;
646}
647
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900648static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 struct msghdr *msg, size_t len)
650{
651 struct sock *sk = sock->sk;
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300652 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653
654 BT_DBG("sock %p, sk %p", sock, sk);
655
Benjamin LaHaisec1cbe4b2005-12-13 23:22:19 -0800656 err = sock_error(sk);
657 if (err)
658 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659
660 if (msg->msg_flags & MSG_OOB)
661 return -EOPNOTSUPP;
662
663 lock_sock(sk);
664
665 if (sk->sk_state == BT_CONNECTED)
666 err = sco_send_frame(sk, msg, len);
667 else
668 err = -ENOTCONN;
669
670 release_sock(sk);
671 return err;
672}
673
David S. Millerb7058842009-09-30 16:12:20 -0700674static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675{
676 struct sock *sk = sock->sk;
677 int err = 0;
678
679 BT_DBG("sk %p", sk);
680
681 lock_sock(sk);
682
683 switch (optname) {
684 default:
685 err = -ENOPROTOOPT;
686 break;
687 }
688
689 release_sock(sk);
690 return err;
691}
692
Marcel Holtmannd58daf42009-01-15 21:52:14 +0100693static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
695 struct sock *sk = sock->sk;
696 struct sco_options opts;
697 struct sco_conninfo cinfo;
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900698 int len, err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700 BT_DBG("sk %p", sk);
701
702 if (get_user(len, optlen))
703 return -EFAULT;
704
705 lock_sock(sk);
706
707 switch (optname) {
708 case SCO_OPTIONS:
709 if (sk->sk_state != BT_CONNECTED) {
710 err = -ENOTCONN;
711 break;
712 }
713
714 opts.mtu = sco_pi(sk)->conn->mtu;
715
716 BT_DBG("mtu %d", opts.mtu);
717
718 len = min_t(unsigned int, len, sizeof(opts));
719 if (copy_to_user(optval, (char *)&opts, len))
720 err = -EFAULT;
721
722 break;
723
724 case SCO_CONNINFO:
725 if (sk->sk_state != BT_CONNECTED) {
726 err = -ENOTCONN;
727 break;
728 }
729
Vasiliy Kulikovc4c896e2011-02-14 13:54:26 +0300730 memset(&cinfo, 0, sizeof(cinfo));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
732 memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
733
734 len = min_t(unsigned int, len, sizeof(cinfo));
735 if (copy_to_user(optval, (char *)&cinfo, len))
736 err = -EFAULT;
737
738 break;
739
740 default:
741 err = -ENOPROTOOPT;
742 break;
743 }
744
745 release_sock(sk);
746 return err;
747}
748
Marcel Holtmannd58daf42009-01-15 21:52:14 +0100749static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
750{
751 struct sock *sk = sock->sk;
752 int len, err = 0;
753
754 BT_DBG("sk %p", sk);
755
756 if (level == SOL_SCO)
757 return sco_sock_getsockopt_old(sock, optname, optval, optlen);
758
759 if (get_user(len, optlen))
760 return -EFAULT;
761
762 lock_sock(sk);
763
764 switch (optname) {
765 default:
766 err = -ENOPROTOOPT;
767 break;
768 }
769
770 release_sock(sk);
771 return err;
772}
773
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200774static int sco_sock_shutdown(struct socket *sock, int how)
775{
776 struct sock *sk = sock->sk;
777 int err = 0;
778
779 BT_DBG("sock %p, sk %p", sock, sk);
780
781 if (!sk)
782 return 0;
783
784 lock_sock(sk);
785 if (!sk->sk_shutdown) {
786 sk->sk_shutdown = SHUTDOWN_MASK;
787 sco_sock_clear_timer(sk);
788 __sco_sock_close(sk);
789
790 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
791 err = bt_sock_wait_state(sk, BT_CLOSED,
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300792 sk->sk_lingertime);
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +0200793 }
794 release_sock(sk);
795 return err;
796}
797
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798static int sco_sock_release(struct socket *sock)
799{
800 struct sock *sk = sock->sk;
801 int err = 0;
802
803 BT_DBG("sock %p, sk %p", sock, sk);
804
805 if (!sk)
806 return 0;
807
808 sco_sock_close(sk);
809
810 if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) {
811 lock_sock(sk);
812 err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
813 release_sock(sk);
814 }
815
816 sock_orphan(sk);
817 sco_sock_kill(sk);
818 return err;
819}
820
821static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
822{
823 BT_DBG("conn %p", conn);
824
825 sco_pi(sk)->conn = conn;
826 conn->sk = sk;
827
828 if (parent)
829 bt_accept_enqueue(parent, sk);
830}
831
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900832/* Delete channel.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833 * Must be called on the locked socket. */
834static void sco_chan_del(struct sock *sk, int err)
835{
836 struct sco_conn *conn;
837
838 conn = sco_pi(sk)->conn;
839
840 BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
841
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900842 if (conn) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 sco_conn_lock(conn);
844 conn->sk = NULL;
845 sco_pi(sk)->conn = NULL;
846 sco_conn_unlock(conn);
Luiz Augusto von Dentz4a777082011-05-12 11:13:15 +0300847
848 if (conn->hcon)
849 hci_conn_put(conn->hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
851
852 sk->sk_state = BT_CLOSED;
853 sk->sk_err = err;
854 sk->sk_state_change(sk);
855
856 sock_set_flag(sk, SOCK_ZAPPED);
857}
858
859static void sco_conn_ready(struct sco_conn *conn)
860{
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200861 struct sock *parent;
862 struct sock *sk = conn->sk;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863
864 BT_DBG("conn %p", conn);
865
866 sco_conn_lock(conn);
867
Andrei Emeltchenko735cbc42010-12-01 16:58:22 +0200868 if (sk) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869 sco_sock_clear_timer(sk);
870 bh_lock_sock(sk);
871 sk->sk_state = BT_CONNECTED;
872 sk->sk_state_change(sk);
873 bh_unlock_sock(sk);
874 } else {
875 parent = sco_get_sock_listen(conn->src);
876 if (!parent)
877 goto done;
878
879 bh_lock_sock(parent);
880
Gustavo F. Padovanb9dbdbc2010-05-01 16:15:35 -0300881 sk = sco_sock_alloc(sock_net(parent), NULL,
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300882 BTPROTO_SCO, GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (!sk) {
884 bh_unlock_sock(parent);
885 goto done;
886 }
887
888 sco_sock_init(sk, parent);
889
890 bacpy(&bt_sk(sk)->src, conn->src);
891 bacpy(&bt_sk(sk)->dst, conn->dst);
892
893 hci_conn_hold(conn->hcon);
894 __sco_chan_add(conn, sk, parent);
895
896 sk->sk_state = BT_CONNECTED;
897
898 /* Wake up parent */
899 parent->sk_data_ready(parent, 1);
900
901 bh_unlock_sock(parent);
902 }
903
904done:
905 sco_conn_unlock(conn);
906}
907
908/* ----- SCO interface with lower layer (HCI) ----- */
Ulisses Furquim686ebf22011-12-21 10:11:33 -0200909int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910{
Marcel Holtmann71aeeaa2009-01-15 21:57:02 +0100911 register struct sock *sk;
912 struct hlist_node *node;
913 int lm = 0;
914
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
916
Marcel Holtmann71aeeaa2009-01-15 21:57:02 +0100917 /* Find listening sockets */
918 read_lock(&sco_sk_list.lock);
919 sk_for_each(sk, node, &sco_sk_list.head) {
920 if (sk->sk_state != BT_LISTEN)
921 continue;
922
923 if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300924 !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
Marcel Holtmann71aeeaa2009-01-15 21:57:02 +0100925 lm |= HCI_LM_ACCEPT;
926 break;
927 }
928 }
929 read_unlock(&sco_sk_list.lock);
930
931 return lm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932}
933
Ulisses Furquim686ebf22011-12-21 10:11:33 -0200934int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935{
936 BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 if (!status) {
938 struct sco_conn *conn;
939
Lukasz Rymanowski519e42b2012-04-19 16:12:28 +0200940 conn = sco_conn_add(hcon);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700941 if (conn)
942 sco_conn_ready(conn);
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900943 } else
Joe Perchese1750722011-06-29 18:18:29 -0700944 sco_conn_del(hcon, bt_to_errno(status));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
946 return 0;
947}
948
Ulisses Furquim686ebf22011-12-21 10:11:33 -0200949int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950{
951 BT_DBG("hcon %p reason %d", hcon, reason);
952
Joe Perchese1750722011-06-29 18:18:29 -0700953 sco_conn_del(hcon, bt_to_errno(reason));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700954 return 0;
955}
956
Ulisses Furquim686ebf22011-12-21 10:11:33 -0200957int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958{
959 struct sco_conn *conn = hcon->sco_data;
960
961 if (!conn)
962 goto drop;
963
964 BT_DBG("conn %p len %d", conn, skb->len);
965
966 if (skb->len) {
967 sco_recv_frame(conn, skb);
968 return 0;
969 }
970
971drop:
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900972 kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 return 0;
974}
975
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100976static int sco_debugfs_show(struct seq_file *f, void *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700977{
978 struct sock *sk;
979 struct hlist_node *node;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700980
Gustavo F. Padovanee65d192011-12-27 15:28:46 -0200981 read_lock(&sco_sk_list.lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982
Marcel Holtmannbe9d1222005-11-08 09:57:38 -0800983 sk_for_each(sk, node, &sco_sk_list.head) {
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100984 seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -0300985 batostr(&bt_sk(sk)->dst), sk->sk_state);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -0800986 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Gustavo F. Padovanee65d192011-12-27 15:28:46 -0200988 read_unlock(&sco_sk_list.lock);
Marcel Holtmannbe9d1222005-11-08 09:57:38 -0800989
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100990 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991}
992
Marcel Holtmannaef7d972010-03-21 05:27:45 +0100993static int sco_debugfs_open(struct inode *inode, struct file *file)
994{
995 return single_open(file, sco_debugfs_show, inode->i_private);
996}
997
998static const struct file_operations sco_debugfs_fops = {
999 .open = sco_debugfs_open,
1000 .read = seq_read,
1001 .llseek = seq_lseek,
1002 .release = single_release,
1003};
1004
1005static struct dentry *sco_debugfs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006
Eric Dumazet90ddc4f2005-12-22 12:49:22 -08001007static const struct proto_ops sco_sock_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 .family = PF_BLUETOOTH,
1009 .owner = THIS_MODULE,
1010 .release = sco_sock_release,
1011 .bind = sco_sock_bind,
1012 .connect = sco_sock_connect,
1013 .listen = sco_sock_listen,
1014 .accept = sco_sock_accept,
1015 .getname = sco_sock_getname,
1016 .sendmsg = sco_sock_sendmsg,
1017 .recvmsg = bt_sock_recvmsg,
1018 .poll = bt_sock_poll,
Marcel Holtmann3241ad82008-07-14 20:13:50 +02001019 .ioctl = bt_sock_ioctl,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 .mmap = sock_no_mmap,
1021 .socketpair = sock_no_socketpair,
Marcel Holtmannfd0b3ff2009-06-16 00:01:49 +02001022 .shutdown = sco_sock_shutdown,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001023 .setsockopt = sco_sock_setsockopt,
1024 .getsockopt = sco_sock_getsockopt
1025};
1026
Stephen Hemmingerec1b4cf2009-10-05 05:58:39 +00001027static const struct net_proto_family sco_sock_family_ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 .family = PF_BLUETOOTH,
1029 .owner = THIS_MODULE,
1030 .create = sco_sock_create,
1031};
1032
Gustavo F. Padovan64274512011-02-07 20:08:52 -02001033int __init sco_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034{
1035 int err;
1036
1037 err = proto_register(&sco_proto, 0);
1038 if (err < 0)
1039 return err;
1040
1041 err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
1042 if (err < 0) {
1043 BT_ERR("SCO socket registration failed");
1044 goto error;
1045 }
1046
Marcel Holtmannaef7d972010-03-21 05:27:45 +01001047 if (bt_debugfs) {
Gustavo Padovanbe7c2b92012-05-17 00:36:21 -03001048 sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
1049 NULL, &sco_debugfs_fops);
Marcel Holtmannaef7d972010-03-21 05:27:45 +01001050 if (!sco_debugfs)
1051 BT_ERR("Failed to create SCO debug file");
1052 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 BT_INFO("SCO socket layer initialized");
1055
1056 return 0;
1057
1058error:
1059 proto_unregister(&sco_proto);
1060 return err;
1061}
1062
Gustavo F. Padovan64274512011-02-07 20:08:52 -02001063void __exit sco_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064{
Marcel Holtmannaef7d972010-03-21 05:27:45 +01001065 debugfs_remove(sco_debugfs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001066
1067 if (bt_sock_unregister(BTPROTO_SCO) < 0)
1068 BT_ERR("SCO socket unregistration failed");
1069
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070 proto_unregister(&sco_proto);
1071}
1072
Marcel Holtmann7cb127d2008-07-14 20:13:53 +02001073module_param(disable_esco, bool, 0644);
1074MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");