11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds BlueZ - Bluetooth protocol stack for Linux
31da177e4SLinus Torvalds Copyright (C) 2000-2001 Qualcomm Incorporated
41da177e4SLinus Torvalds
51da177e4SLinus Torvalds Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
61da177e4SLinus Torvalds
71da177e4SLinus Torvalds This program is free software; you can redistribute it and/or modify
81da177e4SLinus Torvalds it under the terms of the GNU General Public License version 2 as
91da177e4SLinus Torvalds published by the Free Software Foundation;
101da177e4SLinus Torvalds
111da177e4SLinus Torvalds THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
121da177e4SLinus Torvalds OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
131da177e4SLinus Torvalds FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
141da177e4SLinus Torvalds IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
151da177e4SLinus Torvalds CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
161da177e4SLinus Torvalds WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
171da177e4SLinus Torvalds ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
181da177e4SLinus Torvalds OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
211da177e4SLinus Torvalds COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
221da177e4SLinus Torvalds SOFTWARE IS DISCLAIMED.
231da177e4SLinus Torvalds */
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds /* Bluetooth SCO sockets. */
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds #include <linux/module.h>
28aef7d97cSMarcel Holtmann #include <linux/debugfs.h>
29aef7d97cSMarcel Holtmann #include <linux/seq_file.h>
30174cd4b1SIngo Molnar #include <linux/sched/signal.h>
311da177e4SLinus Torvalds
321da177e4SLinus Torvalds #include <net/bluetooth/bluetooth.h>
331da177e4SLinus Torvalds #include <net/bluetooth/hci_core.h>
341da177e4SLinus Torvalds #include <net/bluetooth/sco.h>
351da177e4SLinus Torvalds
36eb939922SRusty Russell static bool disable_esco;
371da177e4SLinus Torvalds
3890ddc4f0SEric Dumazet static const struct proto_ops sco_sock_ops;
391da177e4SLinus Torvalds
401da177e4SLinus Torvalds static struct bt_sock_list sco_sk_list = {
41d5fb2962SRobert P. J. Day .lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock)
421da177e4SLinus Torvalds };
431da177e4SLinus Torvalds
44fc8f525aSMarcel Holtmann /* ---- SCO connections ---- */
45fc8f525aSMarcel Holtmann struct sco_conn {
46fc8f525aSMarcel Holtmann struct hci_conn *hcon;
47fc8f525aSMarcel Holtmann
48fc8f525aSMarcel Holtmann spinlock_t lock;
49fc8f525aSMarcel Holtmann struct sock *sk;
50fc8f525aSMarcel Holtmann
51ba316be1SDesmond Cheong Zhi Xi struct delayed_work timeout_work;
52ba316be1SDesmond Cheong Zhi Xi
53fc8f525aSMarcel Holtmann unsigned int mtu;
54fc8f525aSMarcel Holtmann };
55fc8f525aSMarcel Holtmann
560f90d320SMeng Yu #define sco_conn_lock(c) spin_lock(&c->lock)
570f90d320SMeng Yu #define sco_conn_unlock(c) spin_unlock(&c->lock)
58fc8f525aSMarcel Holtmann
591da177e4SLinus Torvalds static void sco_sock_close(struct sock *sk);
601da177e4SLinus Torvalds static void sco_sock_kill(struct sock *sk);
611da177e4SLinus Torvalds
622a0dccb3SMarcel Holtmann /* ----- SCO socket info ----- */
632a0dccb3SMarcel Holtmann #define sco_pi(sk) ((struct sco_pinfo *) sk)
642a0dccb3SMarcel Holtmann
652a0dccb3SMarcel Holtmann struct sco_pinfo {
662a0dccb3SMarcel Holtmann struct bt_sock bt;
672a0dccb3SMarcel Holtmann bdaddr_t src;
682a0dccb3SMarcel Holtmann bdaddr_t dst;
692a0dccb3SMarcel Holtmann __u32 flags;
702a0dccb3SMarcel Holtmann __u16 setting;
71f6873401SKiran K struct bt_codec codec;
722a0dccb3SMarcel Holtmann struct sco_conn *conn;
732a0dccb3SMarcel Holtmann };
742a0dccb3SMarcel Holtmann
751da177e4SLinus Torvalds /* ---- SCO timers ---- */
76068d69e5SMarcel Holtmann #define SCO_CONN_TIMEOUT (HZ * 40)
77068d69e5SMarcel Holtmann #define SCO_DISCONN_TIMEOUT (HZ * 2)
78068d69e5SMarcel Holtmann
sco_sock_hold(struct sco_conn * conn)79d30803f6SLuiz Augusto von Dentz static struct sock *sco_sock_hold(struct sco_conn *conn)
80d30803f6SLuiz Augusto von Dentz {
81d30803f6SLuiz Augusto von Dentz if (!conn || !bt_sock_linked(&sco_sk_list, conn->sk))
82d30803f6SLuiz Augusto von Dentz return NULL;
83d30803f6SLuiz Augusto von Dentz
84d30803f6SLuiz Augusto von Dentz sock_hold(conn->sk);
85d30803f6SLuiz Augusto von Dentz
86d30803f6SLuiz Augusto von Dentz return conn->sk;
87d30803f6SLuiz Augusto von Dentz }
88d30803f6SLuiz Augusto von Dentz
sco_sock_timeout(struct work_struct * work)89ba316be1SDesmond Cheong Zhi Xi static void sco_sock_timeout(struct work_struct *work)
901da177e4SLinus Torvalds {
91ba316be1SDesmond Cheong Zhi Xi struct sco_conn *conn = container_of(work, struct sco_conn,
92ba316be1SDesmond Cheong Zhi Xi timeout_work.work);
93ba316be1SDesmond Cheong Zhi Xi struct sock *sk;
94ba316be1SDesmond Cheong Zhi Xi
95ba316be1SDesmond Cheong Zhi Xi sco_conn_lock(conn);
96012363cbSDuoming Zhou if (!conn->hcon) {
97012363cbSDuoming Zhou sco_conn_unlock(conn);
98012363cbSDuoming Zhou return;
99012363cbSDuoming Zhou }
100d30803f6SLuiz Augusto von Dentz sk = sco_sock_hold(conn);
101ba316be1SDesmond Cheong Zhi Xi sco_conn_unlock(conn);
102ba316be1SDesmond Cheong Zhi Xi
103ba316be1SDesmond Cheong Zhi Xi if (!sk)
104ba316be1SDesmond Cheong Zhi Xi return;
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds BT_DBG("sock %p state %d", sk, sk->sk_state);
1071da177e4SLinus Torvalds
10827c24fdaSDesmond Cheong Zhi Xi lock_sock(sk);
1091da177e4SLinus Torvalds sk->sk_err = ETIMEDOUT;
1101da177e4SLinus Torvalds sk->sk_state_change(sk);
11127c24fdaSDesmond Cheong Zhi Xi release_sock(sk);
1121da177e4SLinus Torvalds sock_put(sk);
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds
sco_sock_set_timer(struct sock * sk,long timeout)1151da177e4SLinus Torvalds static void sco_sock_set_timer(struct sock *sk, long timeout)
1161da177e4SLinus Torvalds {
117ba316be1SDesmond Cheong Zhi Xi if (!sco_pi(sk)->conn)
118ba316be1SDesmond Cheong Zhi Xi return;
119ba316be1SDesmond Cheong Zhi Xi
1201da177e4SLinus Torvalds BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
121ba316be1SDesmond Cheong Zhi Xi cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
122ba316be1SDesmond Cheong Zhi Xi schedule_delayed_work(&sco_pi(sk)->conn->timeout_work, timeout);
1231da177e4SLinus Torvalds }
1241da177e4SLinus Torvalds
sco_sock_clear_timer(struct sock * sk)1251da177e4SLinus Torvalds static void sco_sock_clear_timer(struct sock *sk)
1261da177e4SLinus Torvalds {
127ba316be1SDesmond Cheong Zhi Xi if (!sco_pi(sk)->conn)
128ba316be1SDesmond Cheong Zhi Xi return;
129ba316be1SDesmond Cheong Zhi Xi
1301da177e4SLinus Torvalds BT_DBG("sock %p state %d", sk, sk->sk_state);
131ba316be1SDesmond Cheong Zhi Xi cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds
1341da177e4SLinus Torvalds /* ---- SCO connections ---- */
sco_conn_add(struct hci_conn * hcon)135519e42b3SLukasz Rymanowski static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
1361da177e4SLinus Torvalds {
13725ea6db0SMarcel Holtmann struct sco_conn *conn = hcon->sco_data;
1381da177e4SLinus Torvalds
1393dcaa192SPauli Virtanen if (conn) {
1403dcaa192SPauli Virtanen if (!conn->hcon)
1413dcaa192SPauli Virtanen conn->hcon = hcon;
1421da177e4SLinus Torvalds return conn;
1433dcaa192SPauli Virtanen }
1441da177e4SLinus Torvalds
145c10cc5a9SClaudio Takahasi conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
14625ea6db0SMarcel Holtmann if (!conn)
1471da177e4SLinus Torvalds return NULL;
1481da177e4SLinus Torvalds
1491da177e4SLinus Torvalds spin_lock_init(&conn->lock);
15049d8a560SDesmond Cheong Zhi Xi INIT_DELAYED_WORK(&conn->timeout_work, sco_sock_timeout);
1511da177e4SLinus Torvalds
1521da177e4SLinus Torvalds hcon->sco_data = conn;
1531da177e4SLinus Torvalds conn->hcon = hcon;
154ad3f7986SSungwoo Kim conn->mtu = hcon->mtu;
1551da177e4SLinus Torvalds
156ad3f7986SSungwoo Kim if (hcon->mtu > 0)
157ad3f7986SSungwoo Kim conn->mtu = hcon->mtu;
1581da177e4SLinus Torvalds else
1591da177e4SLinus Torvalds conn->mtu = 60;
1601da177e4SLinus Torvalds
1611da177e4SLinus Torvalds BT_DBG("hcon %p conn %p", hcon, conn);
16225ea6db0SMarcel Holtmann
1631da177e4SLinus Torvalds return conn;
1641da177e4SLinus Torvalds }
1651da177e4SLinus Torvalds
166e03ab519SMarcel Holtmann /* Delete channel.
167e03ab519SMarcel Holtmann * Must be called on the locked socket. */
sco_chan_del(struct sock * sk,int err)168e03ab519SMarcel Holtmann static void sco_chan_del(struct sock *sk, int err)
169e03ab519SMarcel Holtmann {
170e03ab519SMarcel Holtmann struct sco_conn *conn;
171e03ab519SMarcel Holtmann
172e03ab519SMarcel Holtmann conn = sco_pi(sk)->conn;
173e03ab519SMarcel Holtmann
174e03ab519SMarcel Holtmann BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
175e03ab519SMarcel Holtmann
176e03ab519SMarcel Holtmann if (conn) {
177e03ab519SMarcel Holtmann sco_conn_lock(conn);
178e03ab519SMarcel Holtmann conn->sk = NULL;
179e03ab519SMarcel Holtmann sco_pi(sk)->conn = NULL;
180e03ab519SMarcel Holtmann sco_conn_unlock(conn);
181e03ab519SMarcel Holtmann
182e03ab519SMarcel Holtmann if (conn->hcon)
183e03ab519SMarcel Holtmann hci_conn_drop(conn->hcon);
184e03ab519SMarcel Holtmann }
185e03ab519SMarcel Holtmann
186e03ab519SMarcel Holtmann sk->sk_state = BT_CLOSED;
187e03ab519SMarcel Holtmann sk->sk_err = err;
188e03ab519SMarcel Holtmann sk->sk_state_change(sk);
189e03ab519SMarcel Holtmann
190e03ab519SMarcel Holtmann sock_set_flag(sk, SOCK_ZAPPED);
191e03ab519SMarcel Holtmann }
192e03ab519SMarcel Holtmann
sco_conn_del(struct hci_conn * hcon,int err)193df945360SNicholas Krause static void sco_conn_del(struct hci_conn *hcon, int err)
1941da177e4SLinus Torvalds {
195735cbc47SAndrei Emeltchenko struct sco_conn *conn = hcon->sco_data;
1961da177e4SLinus Torvalds struct sock *sk;
1971da177e4SLinus Torvalds
198735cbc47SAndrei Emeltchenko if (!conn)
199df945360SNicholas Krause return;
2001da177e4SLinus Torvalds
2011da177e4SLinus Torvalds BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
2021da177e4SLinus Torvalds
2031da177e4SLinus Torvalds /* Kill socket */
204eb5a4de8SMarcel Holtmann sco_conn_lock(conn);
205d30803f6SLuiz Augusto von Dentz sk = sco_sock_hold(conn);
206eb5a4de8SMarcel Holtmann sco_conn_unlock(conn);
207eb5a4de8SMarcel Holtmann
208735cbc47SAndrei Emeltchenko if (sk) {
20927c24fdaSDesmond Cheong Zhi Xi lock_sock(sk);
2101da177e4SLinus Torvalds sco_sock_clear_timer(sk);
2111da177e4SLinus Torvalds sco_chan_del(sk, err);
21227c24fdaSDesmond Cheong Zhi Xi release_sock(sk);
21375e34f5cSKuba Pawlak sock_put(sk);
21449d8a560SDesmond Cheong Zhi Xi }
215ba316be1SDesmond Cheong Zhi Xi
216ba316be1SDesmond Cheong Zhi Xi /* Ensure no more work items will run before freeing conn. */
217ba316be1SDesmond Cheong Zhi Xi cancel_delayed_work_sync(&conn->timeout_work);
2181da177e4SLinus Torvalds
2191da177e4SLinus Torvalds hcon->sco_data = NULL;
2201da177e4SLinus Torvalds kfree(conn);
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds
__sco_chan_add(struct sco_conn * conn,struct sock * sk,struct sock * parent)223c4297e8fSMarcel Holtmann static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
224c4297e8fSMarcel Holtmann struct sock *parent)
225015b01cbSMarcel Holtmann {
226015b01cbSMarcel Holtmann BT_DBG("conn %p", conn);
227015b01cbSMarcel Holtmann
228015b01cbSMarcel Holtmann sco_pi(sk)->conn = conn;
229015b01cbSMarcel Holtmann conn->sk = sk;
230015b01cbSMarcel Holtmann
231015b01cbSMarcel Holtmann if (parent)
232c4f5627fSMatthias Kaehlcke bt_accept_enqueue(parent, sk, true);
233015b01cbSMarcel Holtmann }
234015b01cbSMarcel Holtmann
sco_chan_add(struct sco_conn * conn,struct sock * sk,struct sock * parent)2356039aa73SGustavo Padovan static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
2366039aa73SGustavo Padovan struct sock *parent)
2371da177e4SLinus Torvalds {
2381da177e4SLinus Torvalds int err = 0;
2391da177e4SLinus Torvalds
2401da177e4SLinus Torvalds sco_conn_lock(conn);
241b9dbdbc1SGustavo F. Padovan if (conn->sk)
2421da177e4SLinus Torvalds err = -EBUSY;
243b9dbdbc1SGustavo F. Padovan else
2441da177e4SLinus Torvalds __sco_chan_add(conn, sk, parent);
245b9dbdbc1SGustavo F. Padovan
2461da177e4SLinus Torvalds sco_conn_unlock(conn);
2471da177e4SLinus Torvalds return err;
2481da177e4SLinus Torvalds }
2491da177e4SLinus Torvalds
sco_connect(struct sock * sk)2509a8ec9e8SLuiz Augusto von Dentz static int sco_connect(struct sock *sk)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds struct sco_conn *conn;
2531da177e4SLinus Torvalds struct hci_conn *hcon;
2549a8ec9e8SLuiz Augusto von Dentz struct hci_dev *hdev;
255b6a0dc82SMarcel Holtmann int err, type;
2561da177e4SLinus Torvalds
257eea96364SMarcel Holtmann BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst);
2581da177e4SLinus Torvalds
2599a8ec9e8SLuiz Augusto von Dentz hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
2609a8ec9e8SLuiz Augusto von Dentz if (!hdev)
2619a8ec9e8SLuiz Augusto von Dentz return -EHOSTUNREACH;
2629a8ec9e8SLuiz Augusto von Dentz
2639a8ec9e8SLuiz Augusto von Dentz hci_dev_lock(hdev);
2649a8ec9e8SLuiz Augusto von Dentz
2657cb127d5SMarcel Holtmann if (lmp_esco_capable(hdev) && !disable_esco)
2667cb127d5SMarcel Holtmann type = ESCO_LINK;
2677cb127d5SMarcel Holtmann else
2687cb127d5SMarcel Holtmann type = SCO_LINK;
269b6a0dc82SMarcel Holtmann
2703bf09c68SFrédéric Danis switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) {
2713bf09c68SFrédéric Danis case SCO_AIRMODE_TRANSP:
2723bf09c68SFrédéric Danis if (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev)) {
2739a8ec9e8SLuiz Augusto von Dentz err = -EOPNOTSUPP;
2749a8ec9e8SLuiz Augusto von Dentz goto unlock;
2759a8ec9e8SLuiz Augusto von Dentz }
2763bf09c68SFrédéric Danis break;
2773bf09c68SFrédéric Danis }
27879dc0087SFrédéric Dalleau
279eea96364SMarcel Holtmann hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
280b2af264aSKiran K sco_pi(sk)->setting, &sco_pi(sk)->codec);
2819a8ec9e8SLuiz Augusto von Dentz if (IS_ERR(hcon)) {
2829a8ec9e8SLuiz Augusto von Dentz err = PTR_ERR(hcon);
2839a8ec9e8SLuiz Augusto von Dentz goto unlock;
2849a8ec9e8SLuiz Augusto von Dentz }
2859a8ec9e8SLuiz Augusto von Dentz
286519e42b3SLukasz Rymanowski conn = sco_conn_add(hcon);
2871da177e4SLinus Torvalds if (!conn) {
28876a68ba0SDavid Herrmann hci_conn_drop(hcon);
2893dcaa192SPauli Virtanen err = -ENOMEM;
2903dcaa192SPauli Virtanen goto unlock;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds
2939a8ec9e8SLuiz Augusto von Dentz lock_sock(sk);
2949a8ec9e8SLuiz Augusto von Dentz
2953dcaa192SPauli Virtanen err = sco_chan_add(conn, sk, NULL);
2963dcaa192SPauli Virtanen if (err) {
2973dcaa192SPauli Virtanen release_sock(sk);
2983dcaa192SPauli Virtanen goto unlock;
2993dcaa192SPauli Virtanen }
3003dcaa192SPauli Virtanen
3019a8ec9e8SLuiz Augusto von Dentz /* Update source addr of the socket */
3029a8ec9e8SLuiz Augusto von Dentz bacpy(&sco_pi(sk)->src, &hcon->src);
3039a8ec9e8SLuiz Augusto von Dentz
3041da177e4SLinus Torvalds if (hcon->state == BT_CONNECTED) {
3051da177e4SLinus Torvalds sco_sock_clear_timer(sk);
3061da177e4SLinus Torvalds sk->sk_state = BT_CONNECTED;
3071da177e4SLinus Torvalds } else {
3081da177e4SLinus Torvalds sk->sk_state = BT_CONNECT;
3091da177e4SLinus Torvalds sco_sock_set_timer(sk, sk->sk_sndtimeo);
3101da177e4SLinus Torvalds }
311b6a0dc82SMarcel Holtmann
3129a8ec9e8SLuiz Augusto von Dentz release_sock(sk);
3139a8ec9e8SLuiz Augusto von Dentz
3149a8ec9e8SLuiz Augusto von Dentz unlock:
3159a8ec9e8SLuiz Augusto von Dentz hci_dev_unlock(hdev);
3169a8ec9e8SLuiz Augusto von Dentz hci_dev_put(hdev);
3171da177e4SLinus Torvalds return err;
3181da177e4SLinus Torvalds }
3191da177e4SLinus Torvalds
sco_send_frame(struct sock * sk,struct sk_buff * skb)3200771cbb3SLuiz Augusto von Dentz static int sco_send_frame(struct sock *sk, struct sk_buff *skb)
3211da177e4SLinus Torvalds {
3221da177e4SLinus Torvalds struct sco_conn *conn = sco_pi(sk)->conn;
323037ce005SLuiz Augusto von Dentz int len = skb->len;
3241da177e4SLinus Torvalds
3251da177e4SLinus Torvalds /* Check outgoing MTU */
326037ce005SLuiz Augusto von Dentz if (len > conn->mtu)
3271da177e4SLinus Torvalds return -EINVAL;
3281da177e4SLinus Torvalds
329037ce005SLuiz Augusto von Dentz BT_DBG("sk %p len %d", sk, len);
3301da177e4SLinus Torvalds
3310d861d8bSGustavo F. Padovan hci_send_sco(conn->hcon, skb);
3321da177e4SLinus Torvalds
333037ce005SLuiz Augusto von Dentz return len;
3341da177e4SLinus Torvalds }
3351da177e4SLinus Torvalds
sco_recv_frame(struct sco_conn * conn,struct sk_buff * skb)3366039aa73SGustavo Padovan static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
3371da177e4SLinus Torvalds {
338eb5a4de8SMarcel Holtmann struct sock *sk;
339eb5a4de8SMarcel Holtmann
340eb5a4de8SMarcel Holtmann sco_conn_lock(conn);
341eb5a4de8SMarcel Holtmann sk = conn->sk;
342eb5a4de8SMarcel Holtmann sco_conn_unlock(conn);
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds if (!sk)
3451da177e4SLinus Torvalds goto drop;
3461da177e4SLinus Torvalds
34779dbeafeSKai Ye BT_DBG("sk %p len %u", sk, skb->len);
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds if (sk->sk_state != BT_CONNECTED)
3501da177e4SLinus Torvalds goto drop;
3511da177e4SLinus Torvalds
3521da177e4SLinus Torvalds if (!sock_queue_rcv_skb(sk, skb))
3531da177e4SLinus Torvalds return;
3541da177e4SLinus Torvalds
3551da177e4SLinus Torvalds drop:
3561da177e4SLinus Torvalds kfree_skb(skb);
3571da177e4SLinus Torvalds }
3581da177e4SLinus Torvalds
3591da177e4SLinus Torvalds /* -------- Socket interface ---------- */
__sco_get_sock_listen_by_addr(bdaddr_t * ba)360fb334059SMarcel Holtmann static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
3611da177e4SLinus Torvalds {
362fb334059SMarcel Holtmann struct sock *sk;
3631da177e4SLinus Torvalds
364b67bfe0dSSasha Levin sk_for_each(sk, &sco_sk_list.head) {
365fb334059SMarcel Holtmann if (sk->sk_state != BT_LISTEN)
366fb334059SMarcel Holtmann continue;
367fb334059SMarcel Holtmann
368eea96364SMarcel Holtmann if (!bacmp(&sco_pi(sk)->src, ba))
3691da177e4SLinus Torvalds return sk;
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds
372fb334059SMarcel Holtmann return NULL;
373fb334059SMarcel Holtmann }
374fb334059SMarcel Holtmann
3751da177e4SLinus Torvalds /* Find socket listening on source bdaddr.
3761da177e4SLinus Torvalds * Returns closest match.
3771da177e4SLinus Torvalds */
sco_get_sock_listen(bdaddr_t * src)3781da177e4SLinus Torvalds static struct sock *sco_get_sock_listen(bdaddr_t *src)
3791da177e4SLinus Torvalds {
3801da177e4SLinus Torvalds struct sock *sk = NULL, *sk1 = NULL;
3811da177e4SLinus Torvalds
3821da177e4SLinus Torvalds read_lock(&sco_sk_list.lock);
3831da177e4SLinus Torvalds
384b67bfe0dSSasha Levin sk_for_each(sk, &sco_sk_list.head) {
3851da177e4SLinus Torvalds if (sk->sk_state != BT_LISTEN)
3861da177e4SLinus Torvalds continue;
3871da177e4SLinus Torvalds
3881da177e4SLinus Torvalds /* Exact match. */
389eea96364SMarcel Holtmann if (!bacmp(&sco_pi(sk)->src, src))
3901da177e4SLinus Torvalds break;
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds /* Closest match */
393eea96364SMarcel Holtmann if (!bacmp(&sco_pi(sk)->src, BDADDR_ANY))
3941da177e4SLinus Torvalds sk1 = sk;
3951da177e4SLinus Torvalds }
3961da177e4SLinus Torvalds
3971da177e4SLinus Torvalds read_unlock(&sco_sk_list.lock);
3981da177e4SLinus Torvalds
399b67bfe0dSSasha Levin return sk ? sk : sk1;
4001da177e4SLinus Torvalds }
4011da177e4SLinus Torvalds
sco_sock_destruct(struct sock * sk)4021da177e4SLinus Torvalds static void sco_sock_destruct(struct sock *sk)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds BT_DBG("sk %p", sk);
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds skb_queue_purge(&sk->sk_receive_queue);
4071da177e4SLinus Torvalds skb_queue_purge(&sk->sk_write_queue);
4081da177e4SLinus Torvalds }
4091da177e4SLinus Torvalds
sco_sock_cleanup_listen(struct sock * parent)4101da177e4SLinus Torvalds static void sco_sock_cleanup_listen(struct sock *parent)
4111da177e4SLinus Torvalds {
4121da177e4SLinus Torvalds struct sock *sk;
4131da177e4SLinus Torvalds
4141da177e4SLinus Torvalds BT_DBG("parent %p", parent);
4151da177e4SLinus Torvalds
4161da177e4SLinus Torvalds /* Close not yet accepted channels */
4171da177e4SLinus Torvalds while ((sk = bt_accept_dequeue(parent, NULL))) {
4181da177e4SLinus Torvalds sco_sock_close(sk);
4191da177e4SLinus Torvalds sco_sock_kill(sk);
4201da177e4SLinus Torvalds }
4211da177e4SLinus Torvalds
4221da177e4SLinus Torvalds parent->sk_state = BT_CLOSED;
4231da177e4SLinus Torvalds sock_set_flag(parent, SOCK_ZAPPED);
4241da177e4SLinus Torvalds }
4251da177e4SLinus Torvalds
4261da177e4SLinus Torvalds /* Kill socket (only if zapped and orphan)
4271da177e4SLinus Torvalds * Must be called on unlocked socket.
4281da177e4SLinus Torvalds */
sco_sock_kill(struct sock * sk)4291da177e4SLinus Torvalds static void sco_sock_kill(struct sock *sk)
4301da177e4SLinus Torvalds {
431e1dee2c1SDesmond Cheong Zhi Xi if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
4321da177e4SLinus Torvalds return;
4331da177e4SLinus Torvalds
4341da177e4SLinus Torvalds BT_DBG("sk %p state %d", sk, sk->sk_state);
4351da177e4SLinus Torvalds
4361da177e4SLinus Torvalds /* Kill poor orphan */
4371da177e4SLinus Torvalds bt_sock_unlink(&sco_sk_list, sk);
4381da177e4SLinus Torvalds sock_set_flag(sk, SOCK_DEAD);
4391da177e4SLinus Torvalds sock_put(sk);
4401da177e4SLinus Torvalds }
4411da177e4SLinus Torvalds
__sco_sock_close(struct sock * sk)442fd0b3ff7SMarcel Holtmann static void __sco_sock_close(struct sock *sk)
4431da177e4SLinus Torvalds {
444fd0b3ff7SMarcel Holtmann BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
4451da177e4SLinus Torvalds
4461da177e4SLinus Torvalds switch (sk->sk_state) {
4471da177e4SLinus Torvalds case BT_LISTEN:
4481da177e4SLinus Torvalds sco_sock_cleanup_listen(sk);
4491da177e4SLinus Torvalds break;
4501da177e4SLinus Torvalds
4511da177e4SLinus Torvalds case BT_CONNECTED:
4521da177e4SLinus Torvalds case BT_CONFIG:
453b7e98b51SGustavo Padovan if (sco_pi(sk)->conn->hcon) {
4544a77708bSLuiz Augusto von Dentz sk->sk_state = BT_DISCONN;
4554a77708bSLuiz Augusto von Dentz sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
456435c5133SKuba Pawlak sco_conn_lock(sco_pi(sk)->conn);
45776a68ba0SDavid Herrmann hci_conn_drop(sco_pi(sk)->conn->hcon);
4584a77708bSLuiz Augusto von Dentz sco_pi(sk)->conn->hcon = NULL;
459435c5133SKuba Pawlak sco_conn_unlock(sco_pi(sk)->conn);
4604a77708bSLuiz Augusto von Dentz } else
4614a77708bSLuiz Augusto von Dentz sco_chan_del(sk, ECONNRESET);
4624a77708bSLuiz Augusto von Dentz break;
4634a77708bSLuiz Augusto von Dentz
464eb20ff9cSVinicius Costa Gomes case BT_CONNECT2:
4651da177e4SLinus Torvalds case BT_CONNECT:
4661da177e4SLinus Torvalds case BT_DISCONN:
4671da177e4SLinus Torvalds sco_chan_del(sk, ECONNRESET);
4681da177e4SLinus Torvalds break;
4691da177e4SLinus Torvalds
4701da177e4SLinus Torvalds default:
4711da177e4SLinus Torvalds sock_set_flag(sk, SOCK_ZAPPED);
4721da177e4SLinus Torvalds break;
4733ff50b79SStephen Hemminger }
474f6873401SKiran K
475fd0b3ff7SMarcel Holtmann }
4761da177e4SLinus Torvalds
477fd0b3ff7SMarcel Holtmann /* Must be called on unlocked socket. */
sco_sock_close(struct sock * sk)478fd0b3ff7SMarcel Holtmann static void sco_sock_close(struct sock *sk)
479fd0b3ff7SMarcel Holtmann {
480fd0b3ff7SMarcel Holtmann lock_sock(sk);
4813f2c89fbSDesmond Cheong Zhi Xi sco_sock_clear_timer(sk);
482fd0b3ff7SMarcel Holtmann __sco_sock_close(sk);
4831da177e4SLinus Torvalds release_sock(sk);
4841da177e4SLinus Torvalds }
4851da177e4SLinus Torvalds
sco_sock_init(struct sock * sk,struct sock * parent)4861da177e4SLinus Torvalds static void sco_sock_init(struct sock *sk, struct sock *parent)
4871da177e4SLinus Torvalds {
4881da177e4SLinus Torvalds BT_DBG("sk %p", sk);
4891da177e4SLinus Torvalds
4906230c9b4SPaul Moore if (parent) {
4911da177e4SLinus Torvalds sk->sk_type = parent->sk_type;
49220714bfeSFrédéric Dalleau bt_sk(sk)->flags = bt_sk(parent)->flags;
4936230c9b4SPaul Moore security_sk_clone(parent, sk);
4946230c9b4SPaul Moore }
4951da177e4SLinus Torvalds }
4961da177e4SLinus Torvalds
4971da177e4SLinus Torvalds static struct proto sco_proto = {
4981da177e4SLinus Torvalds .name = "SCO",
4991da177e4SLinus Torvalds .owner = THIS_MODULE,
5001da177e4SLinus Torvalds .obj_size = sizeof(struct sco_pinfo)
5011da177e4SLinus Torvalds };
5021da177e4SLinus Torvalds
sco_sock_alloc(struct net * net,struct socket * sock,int proto,gfp_t prio,int kern)503c4297e8fSMarcel Holtmann static struct sock *sco_sock_alloc(struct net *net, struct socket *sock,
504c4297e8fSMarcel Holtmann int proto, gfp_t prio, int kern)
5051da177e4SLinus Torvalds {
5061da177e4SLinus Torvalds struct sock *sk;
5071da177e4SLinus Torvalds
5086bfa273eSLuiz Augusto von Dentz sk = bt_sock_alloc(net, sock, &sco_proto, proto, prio, kern);
5091da177e4SLinus Torvalds if (!sk)
5101da177e4SLinus Torvalds return NULL;
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds sk->sk_destruct = sco_sock_destruct;
5131da177e4SLinus Torvalds sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
5141da177e4SLinus Torvalds
515ad10b1a4SFrédéric Dalleau sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
516f6873401SKiran K sco_pi(sk)->codec.id = BT_CODEC_CVSD;
517f6873401SKiran K sco_pi(sk)->codec.cid = 0xffff;
518f6873401SKiran K sco_pi(sk)->codec.vid = 0xffff;
519f6873401SKiran K sco_pi(sk)->codec.data_path = 0x00;
520ad10b1a4SFrédéric Dalleau
5211da177e4SLinus Torvalds bt_sock_link(&sco_sk_list, sk);
5221da177e4SLinus Torvalds return sk;
5231da177e4SLinus Torvalds }
5241da177e4SLinus Torvalds
sco_sock_create(struct net * net,struct socket * sock,int protocol,int kern)5253f378b68SEric Paris static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
5263f378b68SEric Paris int kern)
5271da177e4SLinus Torvalds {
5281da177e4SLinus Torvalds struct sock *sk;
5291da177e4SLinus Torvalds
5301da177e4SLinus Torvalds BT_DBG("sock %p", sock);
5311da177e4SLinus Torvalds
5321da177e4SLinus Torvalds sock->state = SS_UNCONNECTED;
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds if (sock->type != SOCK_SEQPACKET)
5351da177e4SLinus Torvalds return -ESOCKTNOSUPPORT;
5361da177e4SLinus Torvalds
5371da177e4SLinus Torvalds sock->ops = &sco_sock_ops;
5381da177e4SLinus Torvalds
53911aa9c28SEric W. Biederman sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
54074da626aSMarcel Holtmann if (!sk)
5411da177e4SLinus Torvalds return -ENOMEM;
5421da177e4SLinus Torvalds
5431da177e4SLinus Torvalds sco_sock_init(sk, NULL);
5441da177e4SLinus Torvalds return 0;
5451da177e4SLinus Torvalds }
5461da177e4SLinus Torvalds
sco_sock_bind(struct socket * sock,struct sockaddr * addr,int addr_len)547c4297e8fSMarcel Holtmann static int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
548c4297e8fSMarcel Holtmann int addr_len)
5491da177e4SLinus Torvalds {
5501da177e4SLinus Torvalds struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
5511da177e4SLinus Torvalds struct sock *sk = sock->sk;
5521da177e4SLinus Torvalds int err = 0;
5531da177e4SLinus Torvalds
554d2ecfa76SMateusz Jurczyk if (!addr || addr_len < sizeof(struct sockaddr_sco) ||
555d2ecfa76SMateusz Jurczyk addr->sa_family != AF_BLUETOOTH)
5565233252fSDavid S. Miller return -EINVAL;
5575233252fSDavid S. Miller
558bd7d46ddSTetsuo Handa BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
559bd7d46ddSTetsuo Handa
5601da177e4SLinus Torvalds lock_sock(sk);
5611da177e4SLinus Torvalds
5621da177e4SLinus Torvalds if (sk->sk_state != BT_OPEN) {
5631da177e4SLinus Torvalds err = -EBADFD;
5641da177e4SLinus Torvalds goto done;
5651da177e4SLinus Torvalds }
5661da177e4SLinus Torvalds
5678ed21f7eSMarcel Holtmann if (sk->sk_type != SOCK_SEQPACKET) {
5688ed21f7eSMarcel Holtmann err = -EINVAL;
5698ed21f7eSMarcel Holtmann goto done;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds
572eea96364SMarcel Holtmann bacpy(&sco_pi(sk)->src, &sa->sco_bdaddr);
5738ed21f7eSMarcel Holtmann
5748ed21f7eSMarcel Holtmann sk->sk_state = BT_BOUND;
5751da177e4SLinus Torvalds
5761da177e4SLinus Torvalds done:
5771da177e4SLinus Torvalds release_sock(sk);
5781da177e4SLinus Torvalds return err;
5791da177e4SLinus Torvalds }
5801da177e4SLinus Torvalds
sco_sock_connect(struct socket * sock,struct sockaddr * addr,int alen,int flags)5811da177e4SLinus Torvalds static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
5821da177e4SLinus Torvalds {
5831da177e4SLinus Torvalds struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
5841da177e4SLinus Torvalds struct sock *sk = sock->sk;
58592f185c8SClaudio Takahasi int err;
5861da177e4SLinus Torvalds
5871da177e4SLinus Torvalds BT_DBG("sk %p", sk);
5881da177e4SLinus Torvalds
5896503d961SChangli Gao if (alen < sizeof(struct sockaddr_sco) ||
5906503d961SChangli Gao addr->sa_family != AF_BLUETOOTH)
5911da177e4SLinus Torvalds return -EINVAL;
5921da177e4SLinus Torvalds
5939a8ec9e8SLuiz Augusto von Dentz if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
5949a8ec9e8SLuiz Augusto von Dentz return -EBADFD;
5951da177e4SLinus Torvalds
5969a8ec9e8SLuiz Augusto von Dentz if (sk->sk_type != SOCK_SEQPACKET)
5977aa1e7d1SYing Hsu err = -EINVAL;
5981da177e4SLinus Torvalds
5999a8ec9e8SLuiz Augusto von Dentz lock_sock(sk);
6001da177e4SLinus Torvalds /* Set destination address and psm */
601eea96364SMarcel Holtmann bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
6029a8ec9e8SLuiz Augusto von Dentz release_sock(sk);
6031da177e4SLinus Torvalds
6049a8ec9e8SLuiz Augusto von Dentz err = sco_connect(sk);
605735cbc47SAndrei Emeltchenko if (err)
6069a8ec9e8SLuiz Augusto von Dentz return err;
6079a8ec9e8SLuiz Augusto von Dentz
6089a8ec9e8SLuiz Augusto von Dentz lock_sock(sk);
6091da177e4SLinus Torvalds
6101da177e4SLinus Torvalds err = bt_sock_wait_state(sk, BT_CONNECTED,
6111da177e4SLinus Torvalds sock_sndtimeo(sk, flags & O_NONBLOCK));
6121da177e4SLinus Torvalds
6131da177e4SLinus Torvalds release_sock(sk);
6141da177e4SLinus Torvalds return err;
6151da177e4SLinus Torvalds }
6161da177e4SLinus Torvalds
sco_sock_listen(struct socket * sock,int backlog)6171da177e4SLinus Torvalds static int sco_sock_listen(struct socket *sock, int backlog)
6181da177e4SLinus Torvalds {
6191da177e4SLinus Torvalds struct sock *sk = sock->sk;
620eea96364SMarcel Holtmann bdaddr_t *src = &sco_pi(sk)->src;
6211da177e4SLinus Torvalds int err = 0;
6221da177e4SLinus Torvalds
6231da177e4SLinus Torvalds BT_DBG("sk %p backlog %d", sk, backlog);
6241da177e4SLinus Torvalds
6251da177e4SLinus Torvalds lock_sock(sk);
6261da177e4SLinus Torvalds
6277d5d775aSMarcel Holtmann if (sk->sk_state != BT_BOUND) {
6281da177e4SLinus Torvalds err = -EBADFD;
6291da177e4SLinus Torvalds goto done;
6301da177e4SLinus Torvalds }
6311da177e4SLinus Torvalds
6327d5d775aSMarcel Holtmann if (sk->sk_type != SOCK_SEQPACKET) {
6337d5d775aSMarcel Holtmann err = -EINVAL;
6347d5d775aSMarcel Holtmann goto done;
6357d5d775aSMarcel Holtmann }
6367d5d775aSMarcel Holtmann
637fb334059SMarcel Holtmann write_lock(&sco_sk_list.lock);
638fb334059SMarcel Holtmann
639fb334059SMarcel Holtmann if (__sco_get_sock_listen_by_addr(src)) {
640fb334059SMarcel Holtmann err = -EADDRINUSE;
641fb334059SMarcel Holtmann goto unlock;
642fb334059SMarcel Holtmann }
643fb334059SMarcel Holtmann
6441da177e4SLinus Torvalds sk->sk_max_ack_backlog = backlog;
6451da177e4SLinus Torvalds sk->sk_ack_backlog = 0;
646fb334059SMarcel Holtmann
6471da177e4SLinus Torvalds sk->sk_state = BT_LISTEN;
6481da177e4SLinus Torvalds
649fb334059SMarcel Holtmann unlock:
650fb334059SMarcel Holtmann write_unlock(&sco_sk_list.lock);
651fb334059SMarcel Holtmann
6521da177e4SLinus Torvalds done:
6531da177e4SLinus Torvalds release_sock(sk);
6541da177e4SLinus Torvalds return err;
6551da177e4SLinus Torvalds }
6561da177e4SLinus Torvalds
sco_sock_accept(struct socket * sock,struct socket * newsock,int flags,bool kern)657c4297e8fSMarcel Holtmann static int sco_sock_accept(struct socket *sock, struct socket *newsock,
658cdfbabfbSDavid Howells int flags, bool kern)
6591da177e4SLinus Torvalds {
660dfb2fae7SPeter Hurley DEFINE_WAIT_FUNC(wait, woken_wake_function);
6611da177e4SLinus Torvalds struct sock *sk = sock->sk, *ch;
6621da177e4SLinus Torvalds long timeo;
6631da177e4SLinus Torvalds int err = 0;
6641da177e4SLinus Torvalds
6651da177e4SLinus Torvalds lock_sock(sk);
6661da177e4SLinus Torvalds
6671da177e4SLinus Torvalds timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
6681da177e4SLinus Torvalds
6691da177e4SLinus Torvalds BT_DBG("sk %p timeo %ld", sk, timeo);
6701da177e4SLinus Torvalds
6711da177e4SLinus Torvalds /* Wait for an incoming connection. (wake-one). */
672aa395145SEric Dumazet add_wait_queue_exclusive(sk_sleep(sk), &wait);
673552b0d3cSPeter Hurley while (1) {
6741da177e4SLinus Torvalds if (sk->sk_state != BT_LISTEN) {
6751da177e4SLinus Torvalds err = -EBADFD;
6761da177e4SLinus Torvalds break;
6771da177e4SLinus Torvalds }
6781da177e4SLinus Torvalds
679552b0d3cSPeter Hurley ch = bt_accept_dequeue(sk, newsock);
680552b0d3cSPeter Hurley if (ch)
681552b0d3cSPeter Hurley break;
682552b0d3cSPeter Hurley
683552b0d3cSPeter Hurley if (!timeo) {
684552b0d3cSPeter Hurley err = -EAGAIN;
685552b0d3cSPeter Hurley break;
686552b0d3cSPeter Hurley }
687552b0d3cSPeter Hurley
6881da177e4SLinus Torvalds if (signal_pending(current)) {
6891da177e4SLinus Torvalds err = sock_intr_errno(timeo);
6901da177e4SLinus Torvalds break;
6911da177e4SLinus Torvalds }
692552b0d3cSPeter Hurley
693552b0d3cSPeter Hurley release_sock(sk);
694dfb2fae7SPeter Hurley
695dfb2fae7SPeter Hurley timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
696552b0d3cSPeter Hurley lock_sock(sk);
6971da177e4SLinus Torvalds }
698aa395145SEric Dumazet remove_wait_queue(sk_sleep(sk), &wait);
6991da177e4SLinus Torvalds
7001da177e4SLinus Torvalds if (err)
7011da177e4SLinus Torvalds goto done;
7021da177e4SLinus Torvalds
7031da177e4SLinus Torvalds newsock->state = SS_CONNECTED;
7041da177e4SLinus Torvalds
7051da177e4SLinus Torvalds BT_DBG("new socket %p", ch);
7061da177e4SLinus Torvalds
7071da177e4SLinus Torvalds done:
7081da177e4SLinus Torvalds release_sock(sk);
7091da177e4SLinus Torvalds return err;
7101da177e4SLinus Torvalds }
7111da177e4SLinus Torvalds
sco_sock_getname(struct socket * sock,struct sockaddr * addr,int peer)712c4297e8fSMarcel Holtmann static int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
7139b2c45d4SDenys Vlasenko int peer)
7141da177e4SLinus Torvalds {
7151da177e4SLinus Torvalds struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
7161da177e4SLinus Torvalds struct sock *sk = sock->sk;
7171da177e4SLinus Torvalds
7181da177e4SLinus Torvalds BT_DBG("sock %p, sk %p", sock, sk);
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvalds addr->sa_family = AF_BLUETOOTH;
7211da177e4SLinus Torvalds
7221da177e4SLinus Torvalds if (peer)
723eea96364SMarcel Holtmann bacpy(&sa->sco_bdaddr, &sco_pi(sk)->dst);
7241da177e4SLinus Torvalds else
725eea96364SMarcel Holtmann bacpy(&sa->sco_bdaddr, &sco_pi(sk)->src);
7261da177e4SLinus Torvalds
7279b2c45d4SDenys Vlasenko return sizeof(struct sockaddr_sco);
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds
sco_sock_sendmsg(struct socket * sock,struct msghdr * msg,size_t len)7301b784140SYing Xue static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg,
7311b784140SYing Xue size_t len)
7321da177e4SLinus Torvalds {
7331da177e4SLinus Torvalds struct sock *sk = sock->sk;
7340771cbb3SLuiz Augusto von Dentz struct sk_buff *skb;
735b9dbdbc1SGustavo F. Padovan int err;
7361da177e4SLinus Torvalds
7371da177e4SLinus Torvalds BT_DBG("sock %p, sk %p", sock, sk);
7381da177e4SLinus Torvalds
739c1cbe4b7SBenjamin LaHaise err = sock_error(sk);
740c1cbe4b7SBenjamin LaHaise if (err)
741c1cbe4b7SBenjamin LaHaise return err;
7421da177e4SLinus Torvalds
7431da177e4SLinus Torvalds if (msg->msg_flags & MSG_OOB)
7441da177e4SLinus Torvalds return -EOPNOTSUPP;
7451da177e4SLinus Torvalds
7460771cbb3SLuiz Augusto von Dentz skb = bt_skb_sendmsg(sk, msg, len, len, 0, 0);
747266191aaSLuiz Augusto von Dentz if (IS_ERR(skb))
7480771cbb3SLuiz Augusto von Dentz return PTR_ERR(skb);
74999c23da0STakashi Iwai
7501da177e4SLinus Torvalds lock_sock(sk);
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds if (sk->sk_state == BT_CONNECTED)
7530771cbb3SLuiz Augusto von Dentz err = sco_send_frame(sk, skb);
7541da177e4SLinus Torvalds else
7551da177e4SLinus Torvalds err = -ENOTCONN;
7561da177e4SLinus Torvalds
7571da177e4SLinus Torvalds release_sock(sk);
758037ce005SLuiz Augusto von Dentz
759037ce005SLuiz Augusto von Dentz if (err < 0)
7600771cbb3SLuiz Augusto von Dentz kfree_skb(skb);
7611da177e4SLinus Torvalds return err;
7621da177e4SLinus Torvalds }
7631da177e4SLinus Torvalds
sco_conn_defer_accept(struct hci_conn * conn,u16 setting)7642f69a82aSFrédéric Dalleau static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting)
765fa5513beSFrédéric Dalleau {
766fa5513beSFrédéric Dalleau struct hci_dev *hdev = conn->hdev;
767fa5513beSFrédéric Dalleau
768fa5513beSFrédéric Dalleau BT_DBG("conn %p", conn);
769fa5513beSFrédéric Dalleau
770fa5513beSFrédéric Dalleau conn->state = BT_CONFIG;
771fa5513beSFrédéric Dalleau
772fa5513beSFrédéric Dalleau if (!lmp_esco_capable(hdev)) {
773fa5513beSFrédéric Dalleau struct hci_cp_accept_conn_req cp;
774fa5513beSFrédéric Dalleau
775fa5513beSFrédéric Dalleau bacpy(&cp.bdaddr, &conn->dst);
77633f24048SFrédéric Dalleau cp.role = 0x00; /* Ignored */
777fa5513beSFrédéric Dalleau
778fa5513beSFrédéric Dalleau hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
779fa5513beSFrédéric Dalleau } else {
780fa5513beSFrédéric Dalleau struct hci_cp_accept_sync_conn_req cp;
781fa5513beSFrédéric Dalleau
782fa5513beSFrédéric Dalleau bacpy(&cp.bdaddr, &conn->dst);
783fa5513beSFrédéric Dalleau cp.pkt_type = cpu_to_le16(conn->pkt_type);
784fa5513beSFrédéric Dalleau
785dcf4adbfSJoe Perches cp.tx_bandwidth = cpu_to_le32(0x00001f40);
786dcf4adbfSJoe Perches cp.rx_bandwidth = cpu_to_le32(0x00001f40);
7872f69a82aSFrédéric Dalleau cp.content_format = cpu_to_le16(setting);
7882f69a82aSFrédéric Dalleau
7892f69a82aSFrédéric Dalleau switch (setting & SCO_AIRMODE_MASK) {
7902f69a82aSFrédéric Dalleau case SCO_AIRMODE_TRANSP:
7912f69a82aSFrédéric Dalleau if (conn->pkt_type & ESCO_2EV3)
792dcf4adbfSJoe Perches cp.max_latency = cpu_to_le16(0x0008);
7932f69a82aSFrédéric Dalleau else
794dcf4adbfSJoe Perches cp.max_latency = cpu_to_le16(0x000D);
7952f69a82aSFrédéric Dalleau cp.retrans_effort = 0x02;
7962f69a82aSFrédéric Dalleau break;
7972f69a82aSFrédéric Dalleau case SCO_AIRMODE_CVSD:
798dcf4adbfSJoe Perches cp.max_latency = cpu_to_le16(0xffff);
799fa5513beSFrédéric Dalleau cp.retrans_effort = 0xff;
8002f69a82aSFrédéric Dalleau break;
80159da0b38SDan Carpenter default:
80259da0b38SDan Carpenter /* use CVSD settings as fallback */
80359da0b38SDan Carpenter cp.max_latency = cpu_to_le16(0xffff);
80459da0b38SDan Carpenter cp.retrans_effort = 0xff;
80559da0b38SDan Carpenter break;
8062f69a82aSFrédéric Dalleau }
807fa5513beSFrédéric Dalleau
808fa5513beSFrédéric Dalleau hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
809fa5513beSFrédéric Dalleau sizeof(cp), &cp);
810fa5513beSFrédéric Dalleau }
811fa5513beSFrédéric Dalleau }
812fa5513beSFrédéric Dalleau
sco_sock_recvmsg(struct socket * sock,struct msghdr * msg,size_t len,int flags)8131b784140SYing Xue static int sco_sock_recvmsg(struct socket *sock, struct msghdr *msg,
8141b784140SYing Xue size_t len, int flags)
81520714bfeSFrédéric Dalleau {
81620714bfeSFrédéric Dalleau struct sock *sk = sock->sk;
81720714bfeSFrédéric Dalleau struct sco_pinfo *pi = sco_pi(sk);
81820714bfeSFrédéric Dalleau
81920714bfeSFrédéric Dalleau lock_sock(sk);
82020714bfeSFrédéric Dalleau
82120714bfeSFrédéric Dalleau if (sk->sk_state == BT_CONNECT2 &&
82220714bfeSFrédéric Dalleau test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
8232f69a82aSFrédéric Dalleau sco_conn_defer_accept(pi->conn->hcon, pi->setting);
82420714bfeSFrédéric Dalleau sk->sk_state = BT_CONFIG;
82520714bfeSFrédéric Dalleau
82620714bfeSFrédéric Dalleau release_sock(sk);
82720714bfeSFrédéric Dalleau return 0;
82820714bfeSFrédéric Dalleau }
82920714bfeSFrédéric Dalleau
83020714bfeSFrédéric Dalleau release_sock(sk);
83120714bfeSFrédéric Dalleau
8321b784140SYing Xue return bt_sock_recvmsg(sock, msg, len, flags);
83320714bfeSFrédéric Dalleau }
83420714bfeSFrédéric Dalleau
sco_sock_setsockopt(struct socket * sock,int level,int optname,sockptr_t optval,unsigned int optlen)835c4297e8fSMarcel Holtmann static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
836a7b75c5aSChristoph Hellwig sockptr_t optval, unsigned int optlen)
8371da177e4SLinus Torvalds {
8381da177e4SLinus Torvalds struct sock *sk = sock->sk;
83972473db9SLuiz Augusto von Dentz int err = 0;
840ad10b1a4SFrédéric Dalleau struct bt_voice voice;
841b96e9c67SFrédéric Dalleau u32 opt;
842f6873401SKiran K struct bt_codecs *codecs;
843f6873401SKiran K struct hci_dev *hdev;
844f6873401SKiran K __u8 buffer[255];
8451da177e4SLinus Torvalds
8461da177e4SLinus Torvalds BT_DBG("sk %p", sk);
8471da177e4SLinus Torvalds
8481da177e4SLinus Torvalds lock_sock(sk);
8491da177e4SLinus Torvalds
8501da177e4SLinus Torvalds switch (optname) {
851b96e9c67SFrédéric Dalleau
852b96e9c67SFrédéric Dalleau case BT_DEFER_SETUP:
853b96e9c67SFrédéric Dalleau if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
854b96e9c67SFrédéric Dalleau err = -EINVAL;
855b96e9c67SFrédéric Dalleau break;
856b96e9c67SFrédéric Dalleau }
857b96e9c67SFrédéric Dalleau
85872473db9SLuiz Augusto von Dentz err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
85972473db9SLuiz Augusto von Dentz if (err)
860b96e9c67SFrédéric Dalleau break;
861b96e9c67SFrédéric Dalleau
862b96e9c67SFrédéric Dalleau if (opt)
863b96e9c67SFrédéric Dalleau set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
864b96e9c67SFrédéric Dalleau else
865b96e9c67SFrédéric Dalleau clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
866b96e9c67SFrédéric Dalleau break;
867b96e9c67SFrédéric Dalleau
868ad10b1a4SFrédéric Dalleau case BT_VOICE:
869ad10b1a4SFrédéric Dalleau if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
870ad10b1a4SFrédéric Dalleau sk->sk_state != BT_CONNECT2) {
871ad10b1a4SFrédéric Dalleau err = -EINVAL;
872ad10b1a4SFrédéric Dalleau break;
873ad10b1a4SFrédéric Dalleau }
874ad10b1a4SFrédéric Dalleau
875ad10b1a4SFrédéric Dalleau voice.setting = sco_pi(sk)->setting;
876ad10b1a4SFrédéric Dalleau
87772473db9SLuiz Augusto von Dentz err = bt_copy_from_sockptr(&voice, sizeof(voice), optval,
87872473db9SLuiz Augusto von Dentz optlen);
87972473db9SLuiz Augusto von Dentz if (err)
880ad10b1a4SFrédéric Dalleau break;
881ad10b1a4SFrédéric Dalleau
882ad10b1a4SFrédéric Dalleau sco_pi(sk)->setting = voice.setting;
883b2af264aSKiran K hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
884b2af264aSKiran K BDADDR_BREDR);
885b2af264aSKiran K if (!hdev) {
886b2af264aSKiran K err = -EBADFD;
887b2af264aSKiran K break;
888b2af264aSKiran K }
8893bf09c68SFrédéric Danis
8903bf09c68SFrédéric Danis switch (sco_pi(sk)->setting & SCO_AIRMODE_MASK) {
8913bf09c68SFrédéric Danis case SCO_AIRMODE_TRANSP:
8923bf09c68SFrédéric Danis if (enhanced_sync_conn_capable(hdev))
893b2af264aSKiran K sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
8943bf09c68SFrédéric Danis break;
8953bf09c68SFrédéric Danis }
8963bf09c68SFrédéric Danis
897b2af264aSKiran K hci_dev_put(hdev);
898ad10b1a4SFrédéric Dalleau break;
899ad10b1a4SFrédéric Dalleau
90000398e1dSAlain Michaud case BT_PKT_STATUS:
90172473db9SLuiz Augusto von Dentz err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
90272473db9SLuiz Augusto von Dentz if (err)
90300398e1dSAlain Michaud break;
90400398e1dSAlain Michaud
90500398e1dSAlain Michaud if (opt)
9063f19ffb2SLuiz Augusto von Dentz set_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
90700398e1dSAlain Michaud else
9083f19ffb2SLuiz Augusto von Dentz clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
90900398e1dSAlain Michaud break;
91000398e1dSAlain Michaud
911f6873401SKiran K case BT_CODEC:
912f6873401SKiran K if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
913f6873401SKiran K sk->sk_state != BT_CONNECT2) {
914f6873401SKiran K err = -EINVAL;
915f6873401SKiran K break;
916f6873401SKiran K }
917f6873401SKiran K
918f6873401SKiran K hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
919f6873401SKiran K BDADDR_BREDR);
920f6873401SKiran K if (!hdev) {
921f6873401SKiran K err = -EBADFD;
922f6873401SKiran K break;
923f6873401SKiran K }
924f6873401SKiran K
925f6873401SKiran K if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
926f6873401SKiran K hci_dev_put(hdev);
927f6873401SKiran K err = -EOPNOTSUPP;
928f6873401SKiran K break;
929f6873401SKiran K }
930f6873401SKiran K
931f6873401SKiran K if (!hdev->get_data_path_id) {
932f6873401SKiran K hci_dev_put(hdev);
933f6873401SKiran K err = -EOPNOTSUPP;
934f6873401SKiran K break;
935f6873401SKiran K }
936f6873401SKiran K
937f6873401SKiran K if (optlen < sizeof(struct bt_codecs) ||
938f6873401SKiran K optlen > sizeof(buffer)) {
939f6873401SKiran K hci_dev_put(hdev);
940f6873401SKiran K err = -EINVAL;
941f6873401SKiran K break;
942f6873401SKiran K }
943f6873401SKiran K
94472473db9SLuiz Augusto von Dentz err = bt_copy_from_sockptr(buffer, optlen, optval, optlen);
94572473db9SLuiz Augusto von Dentz if (err) {
946f6873401SKiran K hci_dev_put(hdev);
947f6873401SKiran K break;
948f6873401SKiran K }
949f6873401SKiran K
950f6873401SKiran K codecs = (void *)buffer;
951f6873401SKiran K
952f6873401SKiran K if (codecs->num_codecs > 1) {
953f6873401SKiran K hci_dev_put(hdev);
954f6873401SKiran K err = -EINVAL;
955f6873401SKiran K break;
956f6873401SKiran K }
957f6873401SKiran K
958f6873401SKiran K sco_pi(sk)->codec = codecs->codecs[0];
959f6873401SKiran K hci_dev_put(hdev);
960f6873401SKiran K break;
961f6873401SKiran K
9621da177e4SLinus Torvalds default:
9631da177e4SLinus Torvalds err = -ENOPROTOOPT;
9641da177e4SLinus Torvalds break;
9651da177e4SLinus Torvalds }
9661da177e4SLinus Torvalds
9671da177e4SLinus Torvalds release_sock(sk);
9681da177e4SLinus Torvalds return err;
9691da177e4SLinus Torvalds }
9701da177e4SLinus Torvalds
sco_sock_getsockopt_old(struct socket * sock,int optname,char __user * optval,int __user * optlen)971c4297e8fSMarcel Holtmann static int sco_sock_getsockopt_old(struct socket *sock, int optname,
972c4297e8fSMarcel Holtmann char __user *optval, int __user *optlen)
9731da177e4SLinus Torvalds {
9741da177e4SLinus Torvalds struct sock *sk = sock->sk;
9751da177e4SLinus Torvalds struct sco_options opts;
9761da177e4SLinus Torvalds struct sco_conninfo cinfo;
9774eb706b1SNathan Chancellor int err = 0;
9784eb706b1SNathan Chancellor size_t len;
9791da177e4SLinus Torvalds
9801da177e4SLinus Torvalds BT_DBG("sk %p", sk);
9811da177e4SLinus Torvalds
9821da177e4SLinus Torvalds if (get_user(len, optlen))
9831da177e4SLinus Torvalds return -EFAULT;
9841da177e4SLinus Torvalds
9851da177e4SLinus Torvalds lock_sock(sk);
9861da177e4SLinus Torvalds
9871da177e4SLinus Torvalds switch (optname) {
9881da177e4SLinus Torvalds case SCO_OPTIONS:
9899d225d22SJohan Hedberg if (sk->sk_state != BT_CONNECTED &&
9909d225d22SJohan Hedberg !(sk->sk_state == BT_CONNECT2 &&
9919d225d22SJohan Hedberg test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
9921da177e4SLinus Torvalds err = -ENOTCONN;
9931da177e4SLinus Torvalds break;
9941da177e4SLinus Torvalds }
9951da177e4SLinus Torvalds
9961da177e4SLinus Torvalds opts.mtu = sco_pi(sk)->conn->mtu;
9971da177e4SLinus Torvalds
99879dbeafeSKai Ye BT_DBG("mtu %u", opts.mtu);
9991da177e4SLinus Torvalds
10004eb706b1SNathan Chancellor len = min(len, sizeof(opts));
10011da177e4SLinus Torvalds if (copy_to_user(optval, (char *)&opts, len))
10021da177e4SLinus Torvalds err = -EFAULT;
10031da177e4SLinus Torvalds
10041da177e4SLinus Torvalds break;
10051da177e4SLinus Torvalds
10061da177e4SLinus Torvalds case SCO_CONNINFO:
10079d225d22SJohan Hedberg if (sk->sk_state != BT_CONNECTED &&
10089d225d22SJohan Hedberg !(sk->sk_state == BT_CONNECT2 &&
10099d225d22SJohan Hedberg test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
10101da177e4SLinus Torvalds err = -ENOTCONN;
10111da177e4SLinus Torvalds break;
10121da177e4SLinus Torvalds }
10131da177e4SLinus Torvalds
1014c4c896e1SVasiliy Kulikov memset(&cinfo, 0, sizeof(cinfo));
10151da177e4SLinus Torvalds cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
10161da177e4SLinus Torvalds memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
10171da177e4SLinus Torvalds
10184eb706b1SNathan Chancellor len = min(len, sizeof(cinfo));
10191da177e4SLinus Torvalds if (copy_to_user(optval, (char *)&cinfo, len))
10201da177e4SLinus Torvalds err = -EFAULT;
10211da177e4SLinus Torvalds
10221da177e4SLinus Torvalds break;
10231da177e4SLinus Torvalds
10241da177e4SLinus Torvalds default:
10251da177e4SLinus Torvalds err = -ENOPROTOOPT;
10261da177e4SLinus Torvalds break;
10271da177e4SLinus Torvalds }
10281da177e4SLinus Torvalds
10291da177e4SLinus Torvalds release_sock(sk);
10301da177e4SLinus Torvalds return err;
10311da177e4SLinus Torvalds }
10321da177e4SLinus Torvalds
sco_sock_getsockopt(struct socket * sock,int level,int optname,char __user * optval,int __user * optlen)1033c4297e8fSMarcel Holtmann static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
1034c4297e8fSMarcel Holtmann char __user *optval, int __user *optlen)
1035d58daf42SMarcel Holtmann {
1036d58daf42SMarcel Holtmann struct sock *sk = sock->sk;
1037d58daf42SMarcel Holtmann int len, err = 0;
1038ad10b1a4SFrédéric Dalleau struct bt_voice voice;
1039eab2404bSLuiz Augusto von Dentz u32 phys;
1040248733e8SKiran K int buf_len;
1041248733e8SKiran K struct codec_list *c;
1042248733e8SKiran K u8 num_codecs, i, __user *ptr;
1043248733e8SKiran K struct hci_dev *hdev;
1044248733e8SKiran K struct hci_codec_caps *caps;
1045248733e8SKiran K struct bt_codec codec;
1046d58daf42SMarcel Holtmann
1047d58daf42SMarcel Holtmann BT_DBG("sk %p", sk);
1048d58daf42SMarcel Holtmann
1049d58daf42SMarcel Holtmann if (level == SOL_SCO)
1050d58daf42SMarcel Holtmann return sco_sock_getsockopt_old(sock, optname, optval, optlen);
1051d58daf42SMarcel Holtmann
1052d58daf42SMarcel Holtmann if (get_user(len, optlen))
1053d58daf42SMarcel Holtmann return -EFAULT;
1054d58daf42SMarcel Holtmann
1055d58daf42SMarcel Holtmann lock_sock(sk);
1056d58daf42SMarcel Holtmann
1057d58daf42SMarcel Holtmann switch (optname) {
1058b96e9c67SFrédéric Dalleau
1059b96e9c67SFrédéric Dalleau case BT_DEFER_SETUP:
1060b96e9c67SFrédéric Dalleau if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
1061b96e9c67SFrédéric Dalleau err = -EINVAL;
1062b96e9c67SFrédéric Dalleau break;
1063b96e9c67SFrédéric Dalleau }
1064b96e9c67SFrédéric Dalleau
1065b96e9c67SFrédéric Dalleau if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
1066b96e9c67SFrédéric Dalleau (u32 __user *)optval))
1067b96e9c67SFrédéric Dalleau err = -EFAULT;
1068b96e9c67SFrédéric Dalleau
1069b96e9c67SFrédéric Dalleau break;
1070b96e9c67SFrédéric Dalleau
1071ad10b1a4SFrédéric Dalleau case BT_VOICE:
1072ad10b1a4SFrédéric Dalleau voice.setting = sco_pi(sk)->setting;
1073ad10b1a4SFrédéric Dalleau
1074ad10b1a4SFrédéric Dalleau len = min_t(unsigned int, len, sizeof(voice));
1075ad10b1a4SFrédéric Dalleau if (copy_to_user(optval, (char *)&voice, len))
1076ad10b1a4SFrédéric Dalleau err = -EFAULT;
1077ad10b1a4SFrédéric Dalleau
1078ad10b1a4SFrédéric Dalleau break;
1079ad10b1a4SFrédéric Dalleau
1080eab2404bSLuiz Augusto von Dentz case BT_PHY:
1081a2a8b0b4SLuiz Augusto von Dentz if (sk->sk_state != BT_CONNECTED) {
1082eab2404bSLuiz Augusto von Dentz err = -ENOTCONN;
1083eab2404bSLuiz Augusto von Dentz break;
1084eab2404bSLuiz Augusto von Dentz }
1085eab2404bSLuiz Augusto von Dentz
1086eab2404bSLuiz Augusto von Dentz phys = hci_conn_get_phy(sco_pi(sk)->conn->hcon);
1087eab2404bSLuiz Augusto von Dentz
1088eab2404bSLuiz Augusto von Dentz if (put_user(phys, (u32 __user *) optval))
1089eab2404bSLuiz Augusto von Dentz err = -EFAULT;
1090eab2404bSLuiz Augusto von Dentz break;
1091eab2404bSLuiz Augusto von Dentz
109200398e1dSAlain Michaud case BT_PKT_STATUS:
10933f19ffb2SLuiz Augusto von Dentz if (put_user(test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags),
10943f19ffb2SLuiz Augusto von Dentz (int __user *)optval))
109500398e1dSAlain Michaud err = -EFAULT;
109600398e1dSAlain Michaud break;
109700398e1dSAlain Michaud
10980fc1a726SJoseph Hwang case BT_SNDMTU:
10990fc1a726SJoseph Hwang case BT_RCVMTU:
1100f6b8c6b5SWei Yongjun if (sk->sk_state != BT_CONNECTED) {
1101f6b8c6b5SWei Yongjun err = -ENOTCONN;
1102f6b8c6b5SWei Yongjun break;
1103f6b8c6b5SWei Yongjun }
1104f6b8c6b5SWei Yongjun
11050fc1a726SJoseph Hwang if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval))
11060fc1a726SJoseph Hwang err = -EFAULT;
11070fc1a726SJoseph Hwang break;
11080fc1a726SJoseph Hwang
1109248733e8SKiran K case BT_CODEC:
1110248733e8SKiran K num_codecs = 0;
1111248733e8SKiran K buf_len = 0;
1112248733e8SKiran K
1113248733e8SKiran K hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
1114248733e8SKiran K if (!hdev) {
1115248733e8SKiran K err = -EBADFD;
1116248733e8SKiran K break;
1117248733e8SKiran K }
1118248733e8SKiran K
1119248733e8SKiran K if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
1120248733e8SKiran K hci_dev_put(hdev);
1121248733e8SKiran K err = -EOPNOTSUPP;
1122248733e8SKiran K break;
1123248733e8SKiran K }
1124248733e8SKiran K
1125248733e8SKiran K if (!hdev->get_data_path_id) {
1126248733e8SKiran K hci_dev_put(hdev);
1127248733e8SKiran K err = -EOPNOTSUPP;
1128248733e8SKiran K break;
1129248733e8SKiran K }
1130248733e8SKiran K
1131975abc0cSLuiz Augusto von Dentz release_sock(sk);
1132975abc0cSLuiz Augusto von Dentz
1133248733e8SKiran K /* find total buffer size required to copy codec + caps */
1134248733e8SKiran K hci_dev_lock(hdev);
1135248733e8SKiran K list_for_each_entry(c, &hdev->local_codecs, list) {
1136248733e8SKiran K if (c->transport != HCI_TRANSPORT_SCO_ESCO)
1137248733e8SKiran K continue;
1138248733e8SKiran K num_codecs++;
1139248733e8SKiran K for (i = 0, caps = c->caps; i < c->num_caps; i++) {
1140248733e8SKiran K buf_len += 1 + caps->len;
1141248733e8SKiran K caps = (void *)&caps->data[caps->len];
1142248733e8SKiran K }
1143248733e8SKiran K buf_len += sizeof(struct bt_codec);
1144248733e8SKiran K }
1145248733e8SKiran K hci_dev_unlock(hdev);
1146248733e8SKiran K
1147248733e8SKiran K buf_len += sizeof(struct bt_codecs);
1148248733e8SKiran K if (buf_len > len) {
1149248733e8SKiran K hci_dev_put(hdev);
1150975abc0cSLuiz Augusto von Dentz return -ENOBUFS;
1151248733e8SKiran K }
1152248733e8SKiran K ptr = optval;
1153248733e8SKiran K
1154248733e8SKiran K if (put_user(num_codecs, ptr)) {
1155248733e8SKiran K hci_dev_put(hdev);
1156975abc0cSLuiz Augusto von Dentz return -EFAULT;
1157248733e8SKiran K }
1158248733e8SKiran K ptr += sizeof(num_codecs);
1159248733e8SKiran K
1160248733e8SKiran K /* Iterate all the codecs supported over SCO and populate
1161248733e8SKiran K * codec data
1162248733e8SKiran K */
1163248733e8SKiran K hci_dev_lock(hdev);
1164248733e8SKiran K list_for_each_entry(c, &hdev->local_codecs, list) {
1165248733e8SKiran K if (c->transport != HCI_TRANSPORT_SCO_ESCO)
1166248733e8SKiran K continue;
1167248733e8SKiran K
1168248733e8SKiran K codec.id = c->id;
1169248733e8SKiran K codec.cid = c->cid;
1170248733e8SKiran K codec.vid = c->vid;
1171248733e8SKiran K err = hdev->get_data_path_id(hdev, &codec.data_path);
1172248733e8SKiran K if (err < 0)
1173248733e8SKiran K break;
1174248733e8SKiran K codec.num_caps = c->num_caps;
1175248733e8SKiran K if (copy_to_user(ptr, &codec, sizeof(codec))) {
1176248733e8SKiran K err = -EFAULT;
1177248733e8SKiran K break;
1178248733e8SKiran K }
1179248733e8SKiran K ptr += sizeof(codec);
1180248733e8SKiran K
1181248733e8SKiran K /* find codec capabilities data length */
1182248733e8SKiran K len = 0;
1183248733e8SKiran K for (i = 0, caps = c->caps; i < c->num_caps; i++) {
1184248733e8SKiran K len += 1 + caps->len;
1185248733e8SKiran K caps = (void *)&caps->data[caps->len];
1186248733e8SKiran K }
1187248733e8SKiran K
1188248733e8SKiran K /* copy codec capabilities data */
1189248733e8SKiran K if (len && copy_to_user(ptr, c->caps, len)) {
1190248733e8SKiran K err = -EFAULT;
1191248733e8SKiran K break;
1192248733e8SKiran K }
1193248733e8SKiran K ptr += len;
1194248733e8SKiran K }
1195248733e8SKiran K
1196248733e8SKiran K hci_dev_unlock(hdev);
1197248733e8SKiran K hci_dev_put(hdev);
1198248733e8SKiran K
1199975abc0cSLuiz Augusto von Dentz lock_sock(sk);
1200975abc0cSLuiz Augusto von Dentz
1201975abc0cSLuiz Augusto von Dentz if (!err && put_user(buf_len, optlen))
1202975abc0cSLuiz Augusto von Dentz err = -EFAULT;
1203975abc0cSLuiz Augusto von Dentz
1204248733e8SKiran K break;
1205248733e8SKiran K
1206d58daf42SMarcel Holtmann default:
1207d58daf42SMarcel Holtmann err = -ENOPROTOOPT;
1208d58daf42SMarcel Holtmann break;
1209d58daf42SMarcel Holtmann }
1210d58daf42SMarcel Holtmann
1211d58daf42SMarcel Holtmann release_sock(sk);
1212d58daf42SMarcel Holtmann return err;
1213d58daf42SMarcel Holtmann }
1214d58daf42SMarcel Holtmann
sco_sock_shutdown(struct socket * sock,int how)1215fd0b3ff7SMarcel Holtmann static int sco_sock_shutdown(struct socket *sock, int how)
1216fd0b3ff7SMarcel Holtmann {
1217fd0b3ff7SMarcel Holtmann struct sock *sk = sock->sk;
1218fd0b3ff7SMarcel Holtmann int err = 0;
1219fd0b3ff7SMarcel Holtmann
1220fd0b3ff7SMarcel Holtmann BT_DBG("sock %p, sk %p", sock, sk);
1221fd0b3ff7SMarcel Holtmann
1222fd0b3ff7SMarcel Holtmann if (!sk)
1223fd0b3ff7SMarcel Holtmann return 0;
1224fd0b3ff7SMarcel Holtmann
12251da5537eSKuba Pawlak sock_hold(sk);
1226fd0b3ff7SMarcel Holtmann lock_sock(sk);
12271da5537eSKuba Pawlak
1228fd0b3ff7SMarcel Holtmann if (!sk->sk_shutdown) {
1229fd0b3ff7SMarcel Holtmann sk->sk_shutdown = SHUTDOWN_MASK;
1230fd0b3ff7SMarcel Holtmann sco_sock_clear_timer(sk);
1231fd0b3ff7SMarcel Holtmann __sco_sock_close(sk);
1232fd0b3ff7SMarcel Holtmann
1233093facf3SVladimir Davydov if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
1234093facf3SVladimir Davydov !(current->flags & PF_EXITING))
1235fd0b3ff7SMarcel Holtmann err = bt_sock_wait_state(sk, BT_CLOSED,
1236fd0b3ff7SMarcel Holtmann sk->sk_lingertime);
1237fd0b3ff7SMarcel Holtmann }
12381da5537eSKuba Pawlak
1239fd0b3ff7SMarcel Holtmann release_sock(sk);
12401da5537eSKuba Pawlak sock_put(sk);
12411da5537eSKuba Pawlak
1242fd0b3ff7SMarcel Holtmann return err;
1243fd0b3ff7SMarcel Holtmann }
1244fd0b3ff7SMarcel Holtmann
sco_sock_release(struct socket * sock)12451da177e4SLinus Torvalds static int sco_sock_release(struct socket *sock)
12461da177e4SLinus Torvalds {
12471da177e4SLinus Torvalds struct sock *sk = sock->sk;
12481da177e4SLinus Torvalds int err = 0;
12491da177e4SLinus Torvalds
12501da177e4SLinus Torvalds BT_DBG("sock %p, sk %p", sock, sk);
12511da177e4SLinus Torvalds
12521da177e4SLinus Torvalds if (!sk)
12531da177e4SLinus Torvalds return 0;
12541da177e4SLinus Torvalds
12551da177e4SLinus Torvalds sco_sock_close(sk);
12561da177e4SLinus Torvalds
1257bc1fb82aSEric Dumazet if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
1258093facf3SVladimir Davydov !(current->flags & PF_EXITING)) {
12591da177e4SLinus Torvalds lock_sock(sk);
12601da177e4SLinus Torvalds err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
12611da177e4SLinus Torvalds release_sock(sk);
12621da177e4SLinus Torvalds }
12631da177e4SLinus Torvalds
12641da177e4SLinus Torvalds sock_orphan(sk);
12651da177e4SLinus Torvalds sco_sock_kill(sk);
12661da177e4SLinus Torvalds return err;
12671da177e4SLinus Torvalds }
12681da177e4SLinus Torvalds
sco_conn_ready(struct sco_conn * conn)12691da177e4SLinus Torvalds static void sco_conn_ready(struct sco_conn *conn)
12701da177e4SLinus Torvalds {
1271735cbc47SAndrei Emeltchenko struct sock *parent;
1272735cbc47SAndrei Emeltchenko struct sock *sk = conn->sk;
12731da177e4SLinus Torvalds
12741da177e4SLinus Torvalds BT_DBG("conn %p", conn);
12751da177e4SLinus Torvalds
1276735cbc47SAndrei Emeltchenko if (sk) {
127727c24fdaSDesmond Cheong Zhi Xi lock_sock(sk);
12783f2c89fbSDesmond Cheong Zhi Xi sco_sock_clear_timer(sk);
12791da177e4SLinus Torvalds sk->sk_state = BT_CONNECTED;
12801da177e4SLinus Torvalds sk->sk_state_change(sk);
128127c24fdaSDesmond Cheong Zhi Xi release_sock(sk);
12821da177e4SLinus Torvalds } else {
128340528088SAndre Guedes sco_conn_lock(conn);
128440528088SAndre Guedes
12852c501cddSKuba Pawlak if (!conn->hcon) {
12862c501cddSKuba Pawlak sco_conn_unlock(conn);
12872c501cddSKuba Pawlak return;
12882c501cddSKuba Pawlak }
12892c501cddSKuba Pawlak
1290041987cfSMarcel Holtmann parent = sco_get_sock_listen(&conn->hcon->src);
129140528088SAndre Guedes if (!parent) {
129240528088SAndre Guedes sco_conn_unlock(conn);
129340528088SAndre Guedes return;
129440528088SAndre Guedes }
12951da177e4SLinus Torvalds
129627c24fdaSDesmond Cheong Zhi Xi lock_sock(parent);
12971da177e4SLinus Torvalds
1298b9dbdbc1SGustavo F. Padovan sk = sco_sock_alloc(sock_net(parent), NULL,
129911aa9c28SEric W. Biederman BTPROTO_SCO, GFP_ATOMIC, 0);
13001da177e4SLinus Torvalds if (!sk) {
130127c24fdaSDesmond Cheong Zhi Xi release_sock(parent);
130240528088SAndre Guedes sco_conn_unlock(conn);
130340528088SAndre Guedes return;
13041da177e4SLinus Torvalds }
13051da177e4SLinus Torvalds
13061da177e4SLinus Torvalds sco_sock_init(sk, parent);
13071da177e4SLinus Torvalds
1308eea96364SMarcel Holtmann bacpy(&sco_pi(sk)->src, &conn->hcon->src);
1309eea96364SMarcel Holtmann bacpy(&sco_pi(sk)->dst, &conn->hcon->dst);
13101da177e4SLinus Torvalds
13111da177e4SLinus Torvalds hci_conn_hold(conn->hcon);
13121da177e4SLinus Torvalds __sco_chan_add(conn, sk, parent);
13131da177e4SLinus Torvalds
131420714bfeSFrédéric Dalleau if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
131520714bfeSFrédéric Dalleau sk->sk_state = BT_CONNECT2;
131620714bfeSFrédéric Dalleau else
13171da177e4SLinus Torvalds sk->sk_state = BT_CONNECTED;
13181da177e4SLinus Torvalds
13191da177e4SLinus Torvalds /* Wake up parent */
1320676d2369SDavid S. Miller parent->sk_data_ready(parent);
13211da177e4SLinus Torvalds
132227c24fdaSDesmond Cheong Zhi Xi release_sock(parent);
13231da177e4SLinus Torvalds
13241da177e4SLinus Torvalds sco_conn_unlock(conn);
13251da177e4SLinus Torvalds }
132640528088SAndre Guedes }
13271da177e4SLinus Torvalds
13281da177e4SLinus Torvalds /* ----- SCO interface with lower layer (HCI) ----- */
sco_connect_ind(struct hci_dev * hdev,bdaddr_t * bdaddr,__u8 * flags)132920714bfeSFrédéric Dalleau int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
13301da177e4SLinus Torvalds {
1331fc5fef61SGustavo Padovan struct sock *sk;
133271aeeaa1SMarcel Holtmann int lm = 0;
133371aeeaa1SMarcel Holtmann
13346ed93dc6SAndrei Emeltchenko BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
13351da177e4SLinus Torvalds
133671aeeaa1SMarcel Holtmann /* Find listening sockets */
133771aeeaa1SMarcel Holtmann read_lock(&sco_sk_list.lock);
1338b67bfe0dSSasha Levin sk_for_each(sk, &sco_sk_list.head) {
133971aeeaa1SMarcel Holtmann if (sk->sk_state != BT_LISTEN)
134071aeeaa1SMarcel Holtmann continue;
134171aeeaa1SMarcel Holtmann
1342eea96364SMarcel Holtmann if (!bacmp(&sco_pi(sk)->src, &hdev->bdaddr) ||
1343eea96364SMarcel Holtmann !bacmp(&sco_pi(sk)->src, BDADDR_ANY)) {
134471aeeaa1SMarcel Holtmann lm |= HCI_LM_ACCEPT;
134520714bfeSFrédéric Dalleau
134620714bfeSFrédéric Dalleau if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
134720714bfeSFrédéric Dalleau *flags |= HCI_PROTO_DEFER;
134871aeeaa1SMarcel Holtmann break;
134971aeeaa1SMarcel Holtmann }
135071aeeaa1SMarcel Holtmann }
135171aeeaa1SMarcel Holtmann read_unlock(&sco_sk_list.lock);
135271aeeaa1SMarcel Holtmann
135371aeeaa1SMarcel Holtmann return lm;
13541da177e4SLinus Torvalds }
13551da177e4SLinus Torvalds
sco_match(struct hci_conn * hcon)1356539c496dSJohan Hedberg static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
13571da177e4SLinus Torvalds {
1358*5e8ce74fSLuiz Augusto von Dentz if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
1359*5e8ce74fSLuiz Augusto von Dentz return;
1360*5e8ce74fSLuiz Augusto von Dentz
136179dbeafeSKai Ye BT_DBG("hcon %p bdaddr %pMR status %u", hcon, &hcon->dst, status);
1362539c496dSJohan Hedberg
13631da177e4SLinus Torvalds if (!status) {
13641da177e4SLinus Torvalds struct sco_conn *conn;
13651da177e4SLinus Torvalds
1366519e42b3SLukasz Rymanowski conn = sco_conn_add(hcon);
13671da177e4SLinus Torvalds if (conn)
13681da177e4SLinus Torvalds sco_conn_ready(conn);
13691da177e4SLinus Torvalds } else
1370e175072fSJoe Perches sco_conn_del(hcon, bt_to_errno(status));
13711da177e4SLinus Torvalds }
13721da177e4SLinus Torvalds
13733a6d576bSJohan Hedberg static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
13741da177e4SLinus Torvalds {
sco_disconn_cfm(struct hci_conn * hcon,__u8 reason)1375*5e8ce74fSLuiz Augusto von Dentz if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
1376*5e8ce74fSLuiz Augusto von Dentz return;
1377*5e8ce74fSLuiz Augusto von Dentz
13781da177e4SLinus Torvalds BT_DBG("hcon %p reason %d", hcon, reason);
13791da177e4SLinus Torvalds
1380e175072fSJoe Perches sco_conn_del(hcon, bt_to_errno(reason));
13811da177e4SLinus Torvalds }
sco_recv_scodata(struct hci_conn * hcon,struct sk_buff * skb)13821da177e4SLinus Torvalds
13839b4c3336SArron Wang void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
13841da177e4SLinus Torvalds {
13851da177e4SLinus Torvalds struct sco_conn *conn = hcon->sco_data;
13861da177e4SLinus Torvalds
13871da177e4SLinus Torvalds if (!conn)
13881da177e4SLinus Torvalds goto drop;
13891da177e4SLinus Torvalds
139079dbeafeSKai Ye BT_DBG("conn %p len %u", conn, skb->len);
13911da177e4SLinus Torvalds
13921da177e4SLinus Torvalds if (skb->len) {
13931da177e4SLinus Torvalds sco_recv_frame(conn, skb);
13949b4c3336SArron Wang return;
13951da177e4SLinus Torvalds }
13961da177e4SLinus Torvalds
13971da177e4SLinus Torvalds drop:
13981da177e4SLinus Torvalds kfree_skb(skb);
13991da177e4SLinus Torvalds }
14001da177e4SLinus Torvalds
1401539c496dSJohan Hedberg static struct hci_cb sco_cb = {
1402539c496dSJohan Hedberg .name = "SCO",
1403539c496dSJohan Hedberg .connect_cfm = sco_connect_cfm,
14043a6d576bSJohan Hedberg .disconn_cfm = sco_disconn_cfm,
1405539c496dSJohan Hedberg };
1406539c496dSJohan Hedberg
sco_debugfs_show(struct seq_file * f,void * p)1407aef7d97cSMarcel Holtmann static int sco_debugfs_show(struct seq_file *f, void *p)
14081da177e4SLinus Torvalds {
14091da177e4SLinus Torvalds struct sock *sk;
14101da177e4SLinus Torvalds
1411ee65d19eSGustavo F. Padovan read_lock(&sco_sk_list.lock);
14121da177e4SLinus Torvalds
1413b67bfe0dSSasha Levin sk_for_each(sk, &sco_sk_list.head) {
1414eea96364SMarcel Holtmann seq_printf(f, "%pMR %pMR %d\n", &sco_pi(sk)->src,
1415eea96364SMarcel Holtmann &sco_pi(sk)->dst, sk->sk_state);
14161da177e4SLinus Torvalds }
14171da177e4SLinus Torvalds
1418ee65d19eSGustavo F. Padovan read_unlock(&sco_sk_list.lock);
1419be9d1227SMarcel Holtmann
1420aef7d97cSMarcel Holtmann return 0;
14211da177e4SLinus Torvalds }
14221da177e4SLinus Torvalds
14238e2924e3SYangtao Li DEFINE_SHOW_ATTRIBUTE(sco_debugfs);
1424aef7d97cSMarcel Holtmann
1425aef7d97cSMarcel Holtmann static struct dentry *sco_debugfs;
14261da177e4SLinus Torvalds
142790ddc4f0SEric Dumazet static const struct proto_ops sco_sock_ops = {
14281da177e4SLinus Torvalds .family = PF_BLUETOOTH,
14291da177e4SLinus Torvalds .owner = THIS_MODULE,
14301da177e4SLinus Torvalds .release = sco_sock_release,
14311da177e4SLinus Torvalds .bind = sco_sock_bind,
14321da177e4SLinus Torvalds .connect = sco_sock_connect,
14331da177e4SLinus Torvalds .listen = sco_sock_listen,
14341da177e4SLinus Torvalds .accept = sco_sock_accept,
14351da177e4SLinus Torvalds .getname = sco_sock_getname,
14361da177e4SLinus Torvalds .sendmsg = sco_sock_sendmsg,
143720714bfeSFrédéric Dalleau .recvmsg = sco_sock_recvmsg,
1438a11e1d43SLinus Torvalds .poll = bt_sock_poll,
14393241ad82SMarcel Holtmann .ioctl = bt_sock_ioctl,
1440c7cbdbf2SArnd Bergmann .gettstamp = sock_gettstamp,
14411da177e4SLinus Torvalds .mmap = sock_no_mmap,
14421da177e4SLinus Torvalds .socketpair = sock_no_socketpair,
1443fd0b3ff7SMarcel Holtmann .shutdown = sco_sock_shutdown,
14441da177e4SLinus Torvalds .setsockopt = sco_sock_setsockopt,
14451da177e4SLinus Torvalds .getsockopt = sco_sock_getsockopt
14461da177e4SLinus Torvalds };
14471da177e4SLinus Torvalds
1448ec1b4cf7SStephen Hemminger static const struct net_proto_family sco_sock_family_ops = {
14491da177e4SLinus Torvalds .family = PF_BLUETOOTH,
14501da177e4SLinus Torvalds .owner = THIS_MODULE,
14511da177e4SLinus Torvalds .create = sco_sock_create,
14521da177e4SLinus Torvalds };
14531da177e4SLinus Torvalds
sco_init(void)145464274518SGustavo F. Padovan int __init sco_init(void)
14551da177e4SLinus Torvalds {
14561da177e4SLinus Torvalds int err;
14571da177e4SLinus Torvalds
145815762fa7SMarcel Holtmann BUILD_BUG_ON(sizeof(struct sockaddr_sco) > sizeof(struct sockaddr));
145915762fa7SMarcel Holtmann
14601da177e4SLinus Torvalds err = proto_register(&sco_proto, 0);
14611da177e4SLinus Torvalds if (err < 0)
14621da177e4SLinus Torvalds return err;
14631da177e4SLinus Torvalds
14641da177e4SLinus Torvalds err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
14651da177e4SLinus Torvalds if (err < 0) {
14661da177e4SLinus Torvalds BT_ERR("SCO socket registration failed");
14671da177e4SLinus Torvalds goto error;
14681da177e4SLinus Torvalds }
14691da177e4SLinus Torvalds
1470b0316615SAl Viro err = bt_procfs_init(&init_net, "sco", &sco_sk_list, NULL);
1471de9b9212SMasatake YAMATO if (err < 0) {
1472de9b9212SMasatake YAMATO BT_ERR("Failed to create SCO proc file");
1473de9b9212SMasatake YAMATO bt_sock_unregister(BTPROTO_SCO);
1474de9b9212SMasatake YAMATO goto error;
1475de9b9212SMasatake YAMATO }
1476de9b9212SMasatake YAMATO
14771120e4bfSMarcel Holtmann BT_INFO("SCO socket layer initialized");
14781120e4bfSMarcel Holtmann
1479539c496dSJohan Hedberg hci_register_cb(&sco_cb);
1480539c496dSJohan Hedberg
14811120e4bfSMarcel Holtmann if (IS_ERR_OR_NULL(bt_debugfs))
14821120e4bfSMarcel Holtmann return 0;
14831120e4bfSMarcel Holtmann
1484be7c2b99SGustavo Padovan sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
1485be7c2b99SGustavo Padovan NULL, &sco_debugfs_fops);
14861da177e4SLinus Torvalds
14871da177e4SLinus Torvalds return 0;
14881da177e4SLinus Torvalds
14891da177e4SLinus Torvalds error:
14901da177e4SLinus Torvalds proto_unregister(&sco_proto);
14911da177e4SLinus Torvalds return err;
14921da177e4SLinus Torvalds }
14931da177e4SLinus Torvalds
sco_exit(void)14940402d9f2SAlexander Aring void sco_exit(void)
14951da177e4SLinus Torvalds {
1496de9b9212SMasatake YAMATO bt_procfs_cleanup(&init_net, "sco");
1497de9b9212SMasatake YAMATO
1498aef7d97cSMarcel Holtmann debugfs_remove(sco_debugfs);
14991da177e4SLinus Torvalds
1500539c496dSJohan Hedberg hci_unregister_cb(&sco_cb);
1501539c496dSJohan Hedberg
15025e9d7f86SDavid Herrmann bt_sock_unregister(BTPROTO_SCO);
15031da177e4SLinus Torvalds
15041da177e4SLinus Torvalds proto_unregister(&sco_proto);
15051da177e4SLinus Torvalds }
15061da177e4SLinus Torvalds
15077cb127d5SMarcel Holtmann module_param(disable_esco, bool, 0644);
15087cb127d5SMarcel Holtmann MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
1509