xref: /openbmc/linux/net/bluetooth/sco.c (revision ad3f7986)
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_timeout(struct work_struct * work)79ba316be1SDesmond Cheong Zhi Xi static void sco_sock_timeout(struct work_struct *work)
801da177e4SLinus Torvalds {
81ba316be1SDesmond Cheong Zhi Xi 	struct sco_conn *conn = container_of(work, struct sco_conn,
82ba316be1SDesmond Cheong Zhi Xi 					     timeout_work.work);
83ba316be1SDesmond Cheong Zhi Xi 	struct sock *sk;
84ba316be1SDesmond Cheong Zhi Xi 
85ba316be1SDesmond Cheong Zhi Xi 	sco_conn_lock(conn);
86012363cbSDuoming Zhou 	if (!conn->hcon) {
87012363cbSDuoming Zhou 		sco_conn_unlock(conn);
88012363cbSDuoming Zhou 		return;
89012363cbSDuoming Zhou 	}
90ba316be1SDesmond Cheong Zhi Xi 	sk = conn->sk;
91ba316be1SDesmond Cheong Zhi Xi 	if (sk)
92ba316be1SDesmond Cheong Zhi Xi 		sock_hold(sk);
93ba316be1SDesmond Cheong Zhi Xi 	sco_conn_unlock(conn);
94ba316be1SDesmond Cheong Zhi Xi 
95ba316be1SDesmond Cheong Zhi Xi 	if (!sk)
96ba316be1SDesmond Cheong Zhi Xi 		return;
971da177e4SLinus Torvalds 
981da177e4SLinus Torvalds 	BT_DBG("sock %p state %d", sk, sk->sk_state);
991da177e4SLinus Torvalds 
10027c24fdaSDesmond Cheong Zhi Xi 	lock_sock(sk);
1011da177e4SLinus Torvalds 	sk->sk_err = ETIMEDOUT;
1021da177e4SLinus Torvalds 	sk->sk_state_change(sk);
10327c24fdaSDesmond Cheong Zhi Xi 	release_sock(sk);
1041da177e4SLinus Torvalds 	sock_put(sk);
1051da177e4SLinus Torvalds }
1061da177e4SLinus Torvalds 
sco_sock_set_timer(struct sock * sk,long timeout)1071da177e4SLinus Torvalds static void sco_sock_set_timer(struct sock *sk, long timeout)
1081da177e4SLinus Torvalds {
109ba316be1SDesmond Cheong Zhi Xi 	if (!sco_pi(sk)->conn)
110ba316be1SDesmond Cheong Zhi Xi 		return;
111ba316be1SDesmond Cheong Zhi Xi 
1121da177e4SLinus Torvalds 	BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
113ba316be1SDesmond Cheong Zhi Xi 	cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
114ba316be1SDesmond Cheong Zhi Xi 	schedule_delayed_work(&sco_pi(sk)->conn->timeout_work, timeout);
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
sco_sock_clear_timer(struct sock * sk)1171da177e4SLinus Torvalds static void sco_sock_clear_timer(struct sock *sk)
1181da177e4SLinus Torvalds {
119ba316be1SDesmond Cheong Zhi Xi 	if (!sco_pi(sk)->conn)
120ba316be1SDesmond Cheong Zhi Xi 		return;
121ba316be1SDesmond Cheong Zhi Xi 
1221da177e4SLinus Torvalds 	BT_DBG("sock %p state %d", sk, sk->sk_state);
123ba316be1SDesmond Cheong Zhi Xi 	cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
1241da177e4SLinus Torvalds }
1251da177e4SLinus Torvalds 
1261da177e4SLinus Torvalds /* ---- SCO connections ---- */
sco_conn_add(struct hci_conn * hcon)127519e42b3SLukasz Rymanowski static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
1281da177e4SLinus Torvalds {
12925ea6db0SMarcel Holtmann 	struct sco_conn *conn = hcon->sco_data;
1301da177e4SLinus Torvalds 
1313dcaa192SPauli Virtanen 	if (conn) {
1323dcaa192SPauli Virtanen 		if (!conn->hcon)
1333dcaa192SPauli Virtanen 			conn->hcon = hcon;
1341da177e4SLinus Torvalds 		return conn;
1353dcaa192SPauli Virtanen 	}
1361da177e4SLinus Torvalds 
137c10cc5a9SClaudio Takahasi 	conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
13825ea6db0SMarcel Holtmann 	if (!conn)
1391da177e4SLinus Torvalds 		return NULL;
1401da177e4SLinus Torvalds 
1411da177e4SLinus Torvalds 	spin_lock_init(&conn->lock);
14249d8a560SDesmond Cheong Zhi Xi 	INIT_DELAYED_WORK(&conn->timeout_work, sco_sock_timeout);
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	hcon->sco_data = conn;
1451da177e4SLinus Torvalds 	conn->hcon = hcon;
146ad3f7986SSungwoo Kim 	conn->mtu = hcon->mtu;
1471da177e4SLinus Torvalds 
148ad3f7986SSungwoo Kim 	if (hcon->mtu > 0)
149ad3f7986SSungwoo Kim 		conn->mtu = hcon->mtu;
1501da177e4SLinus Torvalds 	else
1511da177e4SLinus Torvalds 		conn->mtu = 60;
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds 	BT_DBG("hcon %p conn %p", hcon, conn);
15425ea6db0SMarcel Holtmann 
1551da177e4SLinus Torvalds 	return conn;
1561da177e4SLinus Torvalds }
1571da177e4SLinus Torvalds 
158e03ab519SMarcel Holtmann /* Delete channel.
159e03ab519SMarcel Holtmann  * Must be called on the locked socket. */
sco_chan_del(struct sock * sk,int err)160e03ab519SMarcel Holtmann static void sco_chan_del(struct sock *sk, int err)
161e03ab519SMarcel Holtmann {
162e03ab519SMarcel Holtmann 	struct sco_conn *conn;
163e03ab519SMarcel Holtmann 
164e03ab519SMarcel Holtmann 	conn = sco_pi(sk)->conn;
165e03ab519SMarcel Holtmann 
166e03ab519SMarcel Holtmann 	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
167e03ab519SMarcel Holtmann 
168e03ab519SMarcel Holtmann 	if (conn) {
169e03ab519SMarcel Holtmann 		sco_conn_lock(conn);
170e03ab519SMarcel Holtmann 		conn->sk = NULL;
171e03ab519SMarcel Holtmann 		sco_pi(sk)->conn = NULL;
172e03ab519SMarcel Holtmann 		sco_conn_unlock(conn);
173e03ab519SMarcel Holtmann 
174e03ab519SMarcel Holtmann 		if (conn->hcon)
175e03ab519SMarcel Holtmann 			hci_conn_drop(conn->hcon);
176e03ab519SMarcel Holtmann 	}
177e03ab519SMarcel Holtmann 
178e03ab519SMarcel Holtmann 	sk->sk_state = BT_CLOSED;
179e03ab519SMarcel Holtmann 	sk->sk_err   = err;
180e03ab519SMarcel Holtmann 	sk->sk_state_change(sk);
181e03ab519SMarcel Holtmann 
182e03ab519SMarcel Holtmann 	sock_set_flag(sk, SOCK_ZAPPED);
183e03ab519SMarcel Holtmann }
184e03ab519SMarcel Holtmann 
sco_conn_del(struct hci_conn * hcon,int err)185df945360SNicholas Krause static void sco_conn_del(struct hci_conn *hcon, int err)
1861da177e4SLinus Torvalds {
187735cbc47SAndrei Emeltchenko 	struct sco_conn *conn = hcon->sco_data;
1881da177e4SLinus Torvalds 	struct sock *sk;
1891da177e4SLinus Torvalds 
190735cbc47SAndrei Emeltchenko 	if (!conn)
191df945360SNicholas Krause 		return;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 	/* Kill socket */
196eb5a4de8SMarcel Holtmann 	sco_conn_lock(conn);
197eb5a4de8SMarcel Holtmann 	sk = conn->sk;
198f4712fa9SDesmond Cheong Zhi Xi 	if (sk)
199f4712fa9SDesmond Cheong Zhi Xi 		sock_hold(sk);
200eb5a4de8SMarcel Holtmann 	sco_conn_unlock(conn);
201eb5a4de8SMarcel Holtmann 
202735cbc47SAndrei Emeltchenko 	if (sk) {
20327c24fdaSDesmond Cheong Zhi Xi 		lock_sock(sk);
2041da177e4SLinus Torvalds 		sco_sock_clear_timer(sk);
2051da177e4SLinus Torvalds 		sco_chan_del(sk, err);
20627c24fdaSDesmond Cheong Zhi Xi 		release_sock(sk);
20775e34f5cSKuba Pawlak 		sock_put(sk);
20849d8a560SDesmond Cheong Zhi Xi 	}
209ba316be1SDesmond Cheong Zhi Xi 
210ba316be1SDesmond Cheong Zhi Xi 	/* Ensure no more work items will run before freeing conn. */
211ba316be1SDesmond Cheong Zhi Xi 	cancel_delayed_work_sync(&conn->timeout_work);
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds 	hcon->sco_data = NULL;
2141da177e4SLinus Torvalds 	kfree(conn);
2151da177e4SLinus Torvalds }
2161da177e4SLinus Torvalds 
__sco_chan_add(struct sco_conn * conn,struct sock * sk,struct sock * parent)217c4297e8fSMarcel Holtmann static void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
218c4297e8fSMarcel Holtmann 			   struct sock *parent)
219015b01cbSMarcel Holtmann {
220015b01cbSMarcel Holtmann 	BT_DBG("conn %p", conn);
221015b01cbSMarcel Holtmann 
222015b01cbSMarcel Holtmann 	sco_pi(sk)->conn = conn;
223015b01cbSMarcel Holtmann 	conn->sk = sk;
224015b01cbSMarcel Holtmann 
225015b01cbSMarcel Holtmann 	if (parent)
226c4f5627fSMatthias Kaehlcke 		bt_accept_enqueue(parent, sk, true);
227015b01cbSMarcel Holtmann }
228015b01cbSMarcel Holtmann 
sco_chan_add(struct sco_conn * conn,struct sock * sk,struct sock * parent)2296039aa73SGustavo Padovan static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
2306039aa73SGustavo Padovan 			struct sock *parent)
2311da177e4SLinus Torvalds {
2321da177e4SLinus Torvalds 	int err = 0;
2331da177e4SLinus Torvalds 
2341da177e4SLinus Torvalds 	sco_conn_lock(conn);
235b9dbdbc1SGustavo F. Padovan 	if (conn->sk)
2361da177e4SLinus Torvalds 		err = -EBUSY;
237b9dbdbc1SGustavo F. Padovan 	else
2381da177e4SLinus Torvalds 		__sco_chan_add(conn, sk, parent);
239b9dbdbc1SGustavo F. Padovan 
2401da177e4SLinus Torvalds 	sco_conn_unlock(conn);
2411da177e4SLinus Torvalds 	return err;
2421da177e4SLinus Torvalds }
2431da177e4SLinus Torvalds 
sco_connect(struct sock * sk)2449a8ec9e8SLuiz Augusto von Dentz static int sco_connect(struct sock *sk)
2451da177e4SLinus Torvalds {
2461da177e4SLinus Torvalds 	struct sco_conn *conn;
2471da177e4SLinus Torvalds 	struct hci_conn *hcon;
2489a8ec9e8SLuiz Augusto von Dentz 	struct hci_dev  *hdev;
249b6a0dc82SMarcel Holtmann 	int err, type;
2501da177e4SLinus Torvalds 
251eea96364SMarcel Holtmann 	BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst);
2521da177e4SLinus Torvalds 
2539a8ec9e8SLuiz Augusto von Dentz 	hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
2549a8ec9e8SLuiz Augusto von Dentz 	if (!hdev)
2559a8ec9e8SLuiz Augusto von Dentz 		return -EHOSTUNREACH;
2569a8ec9e8SLuiz Augusto von Dentz 
2579a8ec9e8SLuiz Augusto von Dentz 	hci_dev_lock(hdev);
2589a8ec9e8SLuiz Augusto von Dentz 
2597cb127d5SMarcel Holtmann 	if (lmp_esco_capable(hdev) && !disable_esco)
2607cb127d5SMarcel Holtmann 		type = ESCO_LINK;
2617cb127d5SMarcel Holtmann 	else
2627cb127d5SMarcel Holtmann 		type = SCO_LINK;
263b6a0dc82SMarcel Holtmann 
26479dc0087SFrédéric Dalleau 	if (sco_pi(sk)->setting == BT_VOICE_TRANSPARENT &&
2659a8ec9e8SLuiz Augusto von Dentz 	    (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev))) {
2669a8ec9e8SLuiz Augusto von Dentz 		err = -EOPNOTSUPP;
2679a8ec9e8SLuiz Augusto von Dentz 		goto unlock;
2689a8ec9e8SLuiz Augusto von Dentz 	}
26979dc0087SFrédéric Dalleau 
270eea96364SMarcel Holtmann 	hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
271b2af264aSKiran K 			       sco_pi(sk)->setting, &sco_pi(sk)->codec);
2729a8ec9e8SLuiz Augusto von Dentz 	if (IS_ERR(hcon)) {
2739a8ec9e8SLuiz Augusto von Dentz 		err = PTR_ERR(hcon);
2749a8ec9e8SLuiz Augusto von Dentz 		goto unlock;
2759a8ec9e8SLuiz Augusto von Dentz 	}
2769a8ec9e8SLuiz Augusto von Dentz 
277519e42b3SLukasz Rymanowski 	conn = sco_conn_add(hcon);
2781da177e4SLinus Torvalds 	if (!conn) {
27976a68ba0SDavid Herrmann 		hci_conn_drop(hcon);
2803dcaa192SPauli Virtanen 		err = -ENOMEM;
2813dcaa192SPauli Virtanen 		goto unlock;
2821da177e4SLinus Torvalds 	}
2831da177e4SLinus Torvalds 
2849a8ec9e8SLuiz Augusto von Dentz 	lock_sock(sk);
2859a8ec9e8SLuiz Augusto von Dentz 
2863dcaa192SPauli Virtanen 	err = sco_chan_add(conn, sk, NULL);
2873dcaa192SPauli Virtanen 	if (err) {
2883dcaa192SPauli Virtanen 		release_sock(sk);
2893dcaa192SPauli Virtanen 		goto unlock;
2903dcaa192SPauli Virtanen 	}
2913dcaa192SPauli Virtanen 
2929a8ec9e8SLuiz Augusto von Dentz 	/* Update source addr of the socket */
2939a8ec9e8SLuiz Augusto von Dentz 	bacpy(&sco_pi(sk)->src, &hcon->src);
2949a8ec9e8SLuiz Augusto von Dentz 
2951da177e4SLinus Torvalds 	if (hcon->state == BT_CONNECTED) {
2961da177e4SLinus Torvalds 		sco_sock_clear_timer(sk);
2971da177e4SLinus Torvalds 		sk->sk_state = BT_CONNECTED;
2981da177e4SLinus Torvalds 	} else {
2991da177e4SLinus Torvalds 		sk->sk_state = BT_CONNECT;
3001da177e4SLinus Torvalds 		sco_sock_set_timer(sk, sk->sk_sndtimeo);
3011da177e4SLinus Torvalds 	}
302b6a0dc82SMarcel Holtmann 
3039a8ec9e8SLuiz Augusto von Dentz 	release_sock(sk);
3049a8ec9e8SLuiz Augusto von Dentz 
3059a8ec9e8SLuiz Augusto von Dentz unlock:
3069a8ec9e8SLuiz Augusto von Dentz 	hci_dev_unlock(hdev);
3079a8ec9e8SLuiz Augusto von Dentz 	hci_dev_put(hdev);
3081da177e4SLinus Torvalds 	return err;
3091da177e4SLinus Torvalds }
3101da177e4SLinus Torvalds 
sco_send_frame(struct sock * sk,struct sk_buff * skb)3110771cbb3SLuiz Augusto von Dentz static int sco_send_frame(struct sock *sk, struct sk_buff *skb)
3121da177e4SLinus Torvalds {
3131da177e4SLinus Torvalds 	struct sco_conn *conn = sco_pi(sk)->conn;
314037ce005SLuiz Augusto von Dentz 	int len = skb->len;
3151da177e4SLinus Torvalds 
3161da177e4SLinus Torvalds 	/* Check outgoing MTU */
317037ce005SLuiz Augusto von Dentz 	if (len > conn->mtu)
3181da177e4SLinus Torvalds 		return -EINVAL;
3191da177e4SLinus Torvalds 
320037ce005SLuiz Augusto von Dentz 	BT_DBG("sk %p len %d", sk, len);
3211da177e4SLinus Torvalds 
3220d861d8bSGustavo F. Padovan 	hci_send_sco(conn->hcon, skb);
3231da177e4SLinus Torvalds 
324037ce005SLuiz Augusto von Dentz 	return len;
3251da177e4SLinus Torvalds }
3261da177e4SLinus Torvalds 
sco_recv_frame(struct sco_conn * conn,struct sk_buff * skb)3276039aa73SGustavo Padovan static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
3281da177e4SLinus Torvalds {
329eb5a4de8SMarcel Holtmann 	struct sock *sk;
330eb5a4de8SMarcel Holtmann 
331eb5a4de8SMarcel Holtmann 	sco_conn_lock(conn);
332eb5a4de8SMarcel Holtmann 	sk = conn->sk;
333eb5a4de8SMarcel Holtmann 	sco_conn_unlock(conn);
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds 	if (!sk)
3361da177e4SLinus Torvalds 		goto drop;
3371da177e4SLinus Torvalds 
33879dbeafeSKai Ye 	BT_DBG("sk %p len %u", sk, skb->len);
3391da177e4SLinus Torvalds 
3401da177e4SLinus Torvalds 	if (sk->sk_state != BT_CONNECTED)
3411da177e4SLinus Torvalds 		goto drop;
3421da177e4SLinus Torvalds 
3431da177e4SLinus Torvalds 	if (!sock_queue_rcv_skb(sk, skb))
3441da177e4SLinus Torvalds 		return;
3451da177e4SLinus Torvalds 
3461da177e4SLinus Torvalds drop:
3471da177e4SLinus Torvalds 	kfree_skb(skb);
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds 
3501da177e4SLinus Torvalds /* -------- Socket interface ---------- */
__sco_get_sock_listen_by_addr(bdaddr_t * ba)351fb334059SMarcel Holtmann static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
3521da177e4SLinus Torvalds {
353fb334059SMarcel Holtmann 	struct sock *sk;
3541da177e4SLinus Torvalds 
355b67bfe0dSSasha Levin 	sk_for_each(sk, &sco_sk_list.head) {
356fb334059SMarcel Holtmann 		if (sk->sk_state != BT_LISTEN)
357fb334059SMarcel Holtmann 			continue;
358fb334059SMarcel Holtmann 
359eea96364SMarcel Holtmann 		if (!bacmp(&sco_pi(sk)->src, ba))
3601da177e4SLinus Torvalds 			return sk;
3611da177e4SLinus Torvalds 	}
3621da177e4SLinus Torvalds 
363fb334059SMarcel Holtmann 	return NULL;
364fb334059SMarcel Holtmann }
365fb334059SMarcel Holtmann 
3661da177e4SLinus Torvalds /* Find socket listening on source bdaddr.
3671da177e4SLinus Torvalds  * Returns closest match.
3681da177e4SLinus Torvalds  */
sco_get_sock_listen(bdaddr_t * src)3691da177e4SLinus Torvalds static struct sock *sco_get_sock_listen(bdaddr_t *src)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds 	struct sock *sk = NULL, *sk1 = NULL;
3721da177e4SLinus Torvalds 
3731da177e4SLinus Torvalds 	read_lock(&sco_sk_list.lock);
3741da177e4SLinus Torvalds 
375b67bfe0dSSasha Levin 	sk_for_each(sk, &sco_sk_list.head) {
3761da177e4SLinus Torvalds 		if (sk->sk_state != BT_LISTEN)
3771da177e4SLinus Torvalds 			continue;
3781da177e4SLinus Torvalds 
3791da177e4SLinus Torvalds 		/* Exact match. */
380eea96364SMarcel Holtmann 		if (!bacmp(&sco_pi(sk)->src, src))
3811da177e4SLinus Torvalds 			break;
3821da177e4SLinus Torvalds 
3831da177e4SLinus Torvalds 		/* Closest match */
384eea96364SMarcel Holtmann 		if (!bacmp(&sco_pi(sk)->src, BDADDR_ANY))
3851da177e4SLinus Torvalds 			sk1 = sk;
3861da177e4SLinus Torvalds 	}
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds 	read_unlock(&sco_sk_list.lock);
3891da177e4SLinus Torvalds 
390b67bfe0dSSasha Levin 	return sk ? sk : sk1;
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds 
sco_sock_destruct(struct sock * sk)3931da177e4SLinus Torvalds static void sco_sock_destruct(struct sock *sk)
3941da177e4SLinus Torvalds {
3951da177e4SLinus Torvalds 	BT_DBG("sk %p", sk);
3961da177e4SLinus Torvalds 
3971da177e4SLinus Torvalds 	skb_queue_purge(&sk->sk_receive_queue);
3981da177e4SLinus Torvalds 	skb_queue_purge(&sk->sk_write_queue);
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
sco_sock_cleanup_listen(struct sock * parent)4011da177e4SLinus Torvalds static void sco_sock_cleanup_listen(struct sock *parent)
4021da177e4SLinus Torvalds {
4031da177e4SLinus Torvalds 	struct sock *sk;
4041da177e4SLinus Torvalds 
4051da177e4SLinus Torvalds 	BT_DBG("parent %p", parent);
4061da177e4SLinus Torvalds 
4071da177e4SLinus Torvalds 	/* Close not yet accepted channels */
4081da177e4SLinus Torvalds 	while ((sk = bt_accept_dequeue(parent, NULL))) {
4091da177e4SLinus Torvalds 		sco_sock_close(sk);
4101da177e4SLinus Torvalds 		sco_sock_kill(sk);
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds 
4131da177e4SLinus Torvalds 	parent->sk_state  = BT_CLOSED;
4141da177e4SLinus Torvalds 	sock_set_flag(parent, SOCK_ZAPPED);
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds 
4171da177e4SLinus Torvalds /* Kill socket (only if zapped and orphan)
4181da177e4SLinus Torvalds  * Must be called on unlocked socket.
4191da177e4SLinus Torvalds  */
sco_sock_kill(struct sock * sk)4201da177e4SLinus Torvalds static void sco_sock_kill(struct sock *sk)
4211da177e4SLinus Torvalds {
422e1dee2c1SDesmond Cheong Zhi Xi 	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
4231da177e4SLinus Torvalds 		return;
4241da177e4SLinus Torvalds 
4251da177e4SLinus Torvalds 	BT_DBG("sk %p state %d", sk, sk->sk_state);
4261da177e4SLinus Torvalds 
4271da177e4SLinus Torvalds 	/* Kill poor orphan */
4281da177e4SLinus Torvalds 	bt_sock_unlink(&sco_sk_list, sk);
4291da177e4SLinus Torvalds 	sock_set_flag(sk, SOCK_DEAD);
4301da177e4SLinus Torvalds 	sock_put(sk);
4311da177e4SLinus Torvalds }
4321da177e4SLinus Torvalds 
__sco_sock_close(struct sock * sk)433fd0b3ff7SMarcel Holtmann static void __sco_sock_close(struct sock *sk)
4341da177e4SLinus Torvalds {
435fd0b3ff7SMarcel Holtmann 	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
4361da177e4SLinus Torvalds 
4371da177e4SLinus Torvalds 	switch (sk->sk_state) {
4381da177e4SLinus Torvalds 	case BT_LISTEN:
4391da177e4SLinus Torvalds 		sco_sock_cleanup_listen(sk);
4401da177e4SLinus Torvalds 		break;
4411da177e4SLinus Torvalds 
4421da177e4SLinus Torvalds 	case BT_CONNECTED:
4431da177e4SLinus Torvalds 	case BT_CONFIG:
444b7e98b51SGustavo Padovan 		if (sco_pi(sk)->conn->hcon) {
4454a77708bSLuiz Augusto von Dentz 			sk->sk_state = BT_DISCONN;
4464a77708bSLuiz Augusto von Dentz 			sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
447435c5133SKuba Pawlak 			sco_conn_lock(sco_pi(sk)->conn);
44876a68ba0SDavid Herrmann 			hci_conn_drop(sco_pi(sk)->conn->hcon);
4494a77708bSLuiz Augusto von Dentz 			sco_pi(sk)->conn->hcon = NULL;
450435c5133SKuba Pawlak 			sco_conn_unlock(sco_pi(sk)->conn);
4514a77708bSLuiz Augusto von Dentz 		} else
4524a77708bSLuiz Augusto von Dentz 			sco_chan_del(sk, ECONNRESET);
4534a77708bSLuiz Augusto von Dentz 		break;
4544a77708bSLuiz Augusto von Dentz 
455eb20ff9cSVinicius Costa Gomes 	case BT_CONNECT2:
4561da177e4SLinus Torvalds 	case BT_CONNECT:
4571da177e4SLinus Torvalds 	case BT_DISCONN:
4581da177e4SLinus Torvalds 		sco_chan_del(sk, ECONNRESET);
4591da177e4SLinus Torvalds 		break;
4601da177e4SLinus Torvalds 
4611da177e4SLinus Torvalds 	default:
4621da177e4SLinus Torvalds 		sock_set_flag(sk, SOCK_ZAPPED);
4631da177e4SLinus Torvalds 		break;
4643ff50b79SStephen Hemminger 	}
465f6873401SKiran K 
466fd0b3ff7SMarcel Holtmann }
4671da177e4SLinus Torvalds 
468fd0b3ff7SMarcel Holtmann /* Must be called on unlocked socket. */
sco_sock_close(struct sock * sk)469fd0b3ff7SMarcel Holtmann static void sco_sock_close(struct sock *sk)
470fd0b3ff7SMarcel Holtmann {
471fd0b3ff7SMarcel Holtmann 	lock_sock(sk);
4723f2c89fbSDesmond Cheong Zhi Xi 	sco_sock_clear_timer(sk);
473fd0b3ff7SMarcel Holtmann 	__sco_sock_close(sk);
4741da177e4SLinus Torvalds 	release_sock(sk);
4751da177e4SLinus Torvalds }
4761da177e4SLinus Torvalds 
sco_sock_init(struct sock * sk,struct sock * parent)4771da177e4SLinus Torvalds static void sco_sock_init(struct sock *sk, struct sock *parent)
4781da177e4SLinus Torvalds {
4791da177e4SLinus Torvalds 	BT_DBG("sk %p", sk);
4801da177e4SLinus Torvalds 
4816230c9b4SPaul Moore 	if (parent) {
4821da177e4SLinus Torvalds 		sk->sk_type = parent->sk_type;
48320714bfeSFrédéric Dalleau 		bt_sk(sk)->flags = bt_sk(parent)->flags;
4846230c9b4SPaul Moore 		security_sk_clone(parent, sk);
4856230c9b4SPaul Moore 	}
4861da177e4SLinus Torvalds }
4871da177e4SLinus Torvalds 
4881da177e4SLinus Torvalds static struct proto sco_proto = {
4891da177e4SLinus Torvalds 	.name		= "SCO",
4901da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
4911da177e4SLinus Torvalds 	.obj_size	= sizeof(struct sco_pinfo)
4921da177e4SLinus Torvalds };
4931da177e4SLinus Torvalds 
sco_sock_alloc(struct net * net,struct socket * sock,int proto,gfp_t prio,int kern)494c4297e8fSMarcel Holtmann static struct sock *sco_sock_alloc(struct net *net, struct socket *sock,
495c4297e8fSMarcel Holtmann 				   int proto, gfp_t prio, int kern)
4961da177e4SLinus Torvalds {
4971da177e4SLinus Torvalds 	struct sock *sk;
4981da177e4SLinus Torvalds 
4996bfa273eSLuiz Augusto von Dentz 	sk = bt_sock_alloc(net, sock, &sco_proto, proto, prio, kern);
5001da177e4SLinus Torvalds 	if (!sk)
5011da177e4SLinus Torvalds 		return NULL;
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	sk->sk_destruct = sco_sock_destruct;
5041da177e4SLinus Torvalds 	sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
5051da177e4SLinus Torvalds 
506ad10b1a4SFrédéric Dalleau 	sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
507f6873401SKiran K 	sco_pi(sk)->codec.id = BT_CODEC_CVSD;
508f6873401SKiran K 	sco_pi(sk)->codec.cid = 0xffff;
509f6873401SKiran K 	sco_pi(sk)->codec.vid = 0xffff;
510f6873401SKiran K 	sco_pi(sk)->codec.data_path = 0x00;
511ad10b1a4SFrédéric Dalleau 
5121da177e4SLinus Torvalds 	bt_sock_link(&sco_sk_list, sk);
5131da177e4SLinus Torvalds 	return sk;
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds 
sco_sock_create(struct net * net,struct socket * sock,int protocol,int kern)5163f378b68SEric Paris static int sco_sock_create(struct net *net, struct socket *sock, int protocol,
5173f378b68SEric Paris 			   int kern)
5181da177e4SLinus Torvalds {
5191da177e4SLinus Torvalds 	struct sock *sk;
5201da177e4SLinus Torvalds 
5211da177e4SLinus Torvalds 	BT_DBG("sock %p", sock);
5221da177e4SLinus Torvalds 
5231da177e4SLinus Torvalds 	sock->state = SS_UNCONNECTED;
5241da177e4SLinus Torvalds 
5251da177e4SLinus Torvalds 	if (sock->type != SOCK_SEQPACKET)
5261da177e4SLinus Torvalds 		return -ESOCKTNOSUPPORT;
5271da177e4SLinus Torvalds 
5281da177e4SLinus Torvalds 	sock->ops = &sco_sock_ops;
5291da177e4SLinus Torvalds 
53011aa9c28SEric W. Biederman 	sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
53174da626aSMarcel Holtmann 	if (!sk)
5321da177e4SLinus Torvalds 		return -ENOMEM;
5331da177e4SLinus Torvalds 
5341da177e4SLinus Torvalds 	sco_sock_init(sk, NULL);
5351da177e4SLinus Torvalds 	return 0;
5361da177e4SLinus Torvalds }
5371da177e4SLinus Torvalds 
sco_sock_bind(struct socket * sock,struct sockaddr * addr,int addr_len)538c4297e8fSMarcel Holtmann static int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
539c4297e8fSMarcel Holtmann 			 int addr_len)
5401da177e4SLinus Torvalds {
5411da177e4SLinus Torvalds 	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
5421da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
5431da177e4SLinus Torvalds 	int err = 0;
5441da177e4SLinus Torvalds 
545d2ecfa76SMateusz Jurczyk 	if (!addr || addr_len < sizeof(struct sockaddr_sco) ||
546d2ecfa76SMateusz Jurczyk 	    addr->sa_family != AF_BLUETOOTH)
5475233252fSDavid S. Miller 		return -EINVAL;
5485233252fSDavid S. Miller 
549bd7d46ddSTetsuo Handa 	BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
550bd7d46ddSTetsuo Handa 
5511da177e4SLinus Torvalds 	lock_sock(sk);
5521da177e4SLinus Torvalds 
5531da177e4SLinus Torvalds 	if (sk->sk_state != BT_OPEN) {
5541da177e4SLinus Torvalds 		err = -EBADFD;
5551da177e4SLinus Torvalds 		goto done;
5561da177e4SLinus Torvalds 	}
5571da177e4SLinus Torvalds 
5588ed21f7eSMarcel Holtmann 	if (sk->sk_type != SOCK_SEQPACKET) {
5598ed21f7eSMarcel Holtmann 		err = -EINVAL;
5608ed21f7eSMarcel Holtmann 		goto done;
5611da177e4SLinus Torvalds 	}
5621da177e4SLinus Torvalds 
563eea96364SMarcel Holtmann 	bacpy(&sco_pi(sk)->src, &sa->sco_bdaddr);
5648ed21f7eSMarcel Holtmann 
5658ed21f7eSMarcel Holtmann 	sk->sk_state = BT_BOUND;
5661da177e4SLinus Torvalds 
5671da177e4SLinus Torvalds done:
5681da177e4SLinus Torvalds 	release_sock(sk);
5691da177e4SLinus Torvalds 	return err;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds 
sco_sock_connect(struct socket * sock,struct sockaddr * addr,int alen,int flags)5721da177e4SLinus Torvalds static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
5731da177e4SLinus Torvalds {
5741da177e4SLinus Torvalds 	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
5751da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
57692f185c8SClaudio Takahasi 	int err;
5771da177e4SLinus Torvalds 
5781da177e4SLinus Torvalds 	BT_DBG("sk %p", sk);
5791da177e4SLinus Torvalds 
5806503d961SChangli Gao 	if (alen < sizeof(struct sockaddr_sco) ||
5816503d961SChangli Gao 	    addr->sa_family != AF_BLUETOOTH)
5821da177e4SLinus Torvalds 		return -EINVAL;
5831da177e4SLinus Torvalds 
5849a8ec9e8SLuiz Augusto von Dentz 	if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
5859a8ec9e8SLuiz Augusto von Dentz 		return -EBADFD;
5861da177e4SLinus Torvalds 
5879a8ec9e8SLuiz Augusto von Dentz 	if (sk->sk_type != SOCK_SEQPACKET)
5887aa1e7d1SYing Hsu 		err = -EINVAL;
5891da177e4SLinus Torvalds 
5909a8ec9e8SLuiz Augusto von Dentz 	lock_sock(sk);
5911da177e4SLinus Torvalds 	/* Set destination address and psm */
592eea96364SMarcel Holtmann 	bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
5939a8ec9e8SLuiz Augusto von Dentz 	release_sock(sk);
5941da177e4SLinus Torvalds 
5959a8ec9e8SLuiz Augusto von Dentz 	err = sco_connect(sk);
596735cbc47SAndrei Emeltchenko 	if (err)
5979a8ec9e8SLuiz Augusto von Dentz 		return err;
5989a8ec9e8SLuiz Augusto von Dentz 
5999a8ec9e8SLuiz Augusto von Dentz 	lock_sock(sk);
6001da177e4SLinus Torvalds 
6011da177e4SLinus Torvalds 	err = bt_sock_wait_state(sk, BT_CONNECTED,
6021da177e4SLinus Torvalds 				 sock_sndtimeo(sk, flags & O_NONBLOCK));
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	release_sock(sk);
6051da177e4SLinus Torvalds 	return err;
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds 
sco_sock_listen(struct socket * sock,int backlog)6081da177e4SLinus Torvalds static int sco_sock_listen(struct socket *sock, int backlog)
6091da177e4SLinus Torvalds {
6101da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
611eea96364SMarcel Holtmann 	bdaddr_t *src = &sco_pi(sk)->src;
6121da177e4SLinus Torvalds 	int err = 0;
6131da177e4SLinus Torvalds 
6141da177e4SLinus Torvalds 	BT_DBG("sk %p backlog %d", sk, backlog);
6151da177e4SLinus Torvalds 
6161da177e4SLinus Torvalds 	lock_sock(sk);
6171da177e4SLinus Torvalds 
6187d5d775aSMarcel Holtmann 	if (sk->sk_state != BT_BOUND) {
6191da177e4SLinus Torvalds 		err = -EBADFD;
6201da177e4SLinus Torvalds 		goto done;
6211da177e4SLinus Torvalds 	}
6221da177e4SLinus Torvalds 
6237d5d775aSMarcel Holtmann 	if (sk->sk_type != SOCK_SEQPACKET) {
6247d5d775aSMarcel Holtmann 		err = -EINVAL;
6257d5d775aSMarcel Holtmann 		goto done;
6267d5d775aSMarcel Holtmann 	}
6277d5d775aSMarcel Holtmann 
628fb334059SMarcel Holtmann 	write_lock(&sco_sk_list.lock);
629fb334059SMarcel Holtmann 
630fb334059SMarcel Holtmann 	if (__sco_get_sock_listen_by_addr(src)) {
631fb334059SMarcel Holtmann 		err = -EADDRINUSE;
632fb334059SMarcel Holtmann 		goto unlock;
633fb334059SMarcel Holtmann 	}
634fb334059SMarcel Holtmann 
6351da177e4SLinus Torvalds 	sk->sk_max_ack_backlog = backlog;
6361da177e4SLinus Torvalds 	sk->sk_ack_backlog = 0;
637fb334059SMarcel Holtmann 
6381da177e4SLinus Torvalds 	sk->sk_state = BT_LISTEN;
6391da177e4SLinus Torvalds 
640fb334059SMarcel Holtmann unlock:
641fb334059SMarcel Holtmann 	write_unlock(&sco_sk_list.lock);
642fb334059SMarcel Holtmann 
6431da177e4SLinus Torvalds done:
6441da177e4SLinus Torvalds 	release_sock(sk);
6451da177e4SLinus Torvalds 	return err;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds 
sco_sock_accept(struct socket * sock,struct socket * newsock,int flags,bool kern)648c4297e8fSMarcel Holtmann static int sco_sock_accept(struct socket *sock, struct socket *newsock,
649cdfbabfbSDavid Howells 			   int flags, bool kern)
6501da177e4SLinus Torvalds {
651dfb2fae7SPeter Hurley 	DEFINE_WAIT_FUNC(wait, woken_wake_function);
6521da177e4SLinus Torvalds 	struct sock *sk = sock->sk, *ch;
6531da177e4SLinus Torvalds 	long timeo;
6541da177e4SLinus Torvalds 	int err = 0;
6551da177e4SLinus Torvalds 
6561da177e4SLinus Torvalds 	lock_sock(sk);
6571da177e4SLinus Torvalds 
6581da177e4SLinus Torvalds 	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
6591da177e4SLinus Torvalds 
6601da177e4SLinus Torvalds 	BT_DBG("sk %p timeo %ld", sk, timeo);
6611da177e4SLinus Torvalds 
6621da177e4SLinus Torvalds 	/* Wait for an incoming connection. (wake-one). */
663aa395145SEric Dumazet 	add_wait_queue_exclusive(sk_sleep(sk), &wait);
664552b0d3cSPeter Hurley 	while (1) {
6651da177e4SLinus Torvalds 		if (sk->sk_state != BT_LISTEN) {
6661da177e4SLinus Torvalds 			err = -EBADFD;
6671da177e4SLinus Torvalds 			break;
6681da177e4SLinus Torvalds 		}
6691da177e4SLinus Torvalds 
670552b0d3cSPeter Hurley 		ch = bt_accept_dequeue(sk, newsock);
671552b0d3cSPeter Hurley 		if (ch)
672552b0d3cSPeter Hurley 			break;
673552b0d3cSPeter Hurley 
674552b0d3cSPeter Hurley 		if (!timeo) {
675552b0d3cSPeter Hurley 			err = -EAGAIN;
676552b0d3cSPeter Hurley 			break;
677552b0d3cSPeter Hurley 		}
678552b0d3cSPeter Hurley 
6791da177e4SLinus Torvalds 		if (signal_pending(current)) {
6801da177e4SLinus Torvalds 			err = sock_intr_errno(timeo);
6811da177e4SLinus Torvalds 			break;
6821da177e4SLinus Torvalds 		}
683552b0d3cSPeter Hurley 
684552b0d3cSPeter Hurley 		release_sock(sk);
685dfb2fae7SPeter Hurley 
686dfb2fae7SPeter Hurley 		timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
687552b0d3cSPeter Hurley 		lock_sock(sk);
6881da177e4SLinus Torvalds 	}
689aa395145SEric Dumazet 	remove_wait_queue(sk_sleep(sk), &wait);
6901da177e4SLinus Torvalds 
6911da177e4SLinus Torvalds 	if (err)
6921da177e4SLinus Torvalds 		goto done;
6931da177e4SLinus Torvalds 
6941da177e4SLinus Torvalds 	newsock->state = SS_CONNECTED;
6951da177e4SLinus Torvalds 
6961da177e4SLinus Torvalds 	BT_DBG("new socket %p", ch);
6971da177e4SLinus Torvalds 
6981da177e4SLinus Torvalds done:
6991da177e4SLinus Torvalds 	release_sock(sk);
7001da177e4SLinus Torvalds 	return err;
7011da177e4SLinus Torvalds }
7021da177e4SLinus Torvalds 
sco_sock_getname(struct socket * sock,struct sockaddr * addr,int peer)703c4297e8fSMarcel Holtmann static int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
7049b2c45d4SDenys Vlasenko 			    int peer)
7051da177e4SLinus Torvalds {
7061da177e4SLinus Torvalds 	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
7071da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
7081da177e4SLinus Torvalds 
7091da177e4SLinus Torvalds 	BT_DBG("sock %p, sk %p", sock, sk);
7101da177e4SLinus Torvalds 
7111da177e4SLinus Torvalds 	addr->sa_family = AF_BLUETOOTH;
7121da177e4SLinus Torvalds 
7131da177e4SLinus Torvalds 	if (peer)
714eea96364SMarcel Holtmann 		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->dst);
7151da177e4SLinus Torvalds 	else
716eea96364SMarcel Holtmann 		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->src);
7171da177e4SLinus Torvalds 
7189b2c45d4SDenys Vlasenko 	return sizeof(struct sockaddr_sco);
7191da177e4SLinus Torvalds }
7201da177e4SLinus Torvalds 
sco_sock_sendmsg(struct socket * sock,struct msghdr * msg,size_t len)7211b784140SYing Xue static int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg,
7221b784140SYing Xue 			    size_t len)
7231da177e4SLinus Torvalds {
7241da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
7250771cbb3SLuiz Augusto von Dentz 	struct sk_buff *skb;
726b9dbdbc1SGustavo F. Padovan 	int err;
7271da177e4SLinus Torvalds 
7281da177e4SLinus Torvalds 	BT_DBG("sock %p, sk %p", sock, sk);
7291da177e4SLinus Torvalds 
730c1cbe4b7SBenjamin LaHaise 	err = sock_error(sk);
731c1cbe4b7SBenjamin LaHaise 	if (err)
732c1cbe4b7SBenjamin LaHaise 		return err;
7331da177e4SLinus Torvalds 
7341da177e4SLinus Torvalds 	if (msg->msg_flags & MSG_OOB)
7351da177e4SLinus Torvalds 		return -EOPNOTSUPP;
7361da177e4SLinus Torvalds 
7370771cbb3SLuiz Augusto von Dentz 	skb = bt_skb_sendmsg(sk, msg, len, len, 0, 0);
738266191aaSLuiz Augusto von Dentz 	if (IS_ERR(skb))
7390771cbb3SLuiz Augusto von Dentz 		return PTR_ERR(skb);
74099c23da0STakashi Iwai 
7411da177e4SLinus Torvalds 	lock_sock(sk);
7421da177e4SLinus Torvalds 
7431da177e4SLinus Torvalds 	if (sk->sk_state == BT_CONNECTED)
7440771cbb3SLuiz Augusto von Dentz 		err = sco_send_frame(sk, skb);
7451da177e4SLinus Torvalds 	else
7461da177e4SLinus Torvalds 		err = -ENOTCONN;
7471da177e4SLinus Torvalds 
7481da177e4SLinus Torvalds 	release_sock(sk);
749037ce005SLuiz Augusto von Dentz 
750037ce005SLuiz Augusto von Dentz 	if (err < 0)
7510771cbb3SLuiz Augusto von Dentz 		kfree_skb(skb);
7521da177e4SLinus Torvalds 	return err;
7531da177e4SLinus Torvalds }
7541da177e4SLinus Torvalds 
sco_conn_defer_accept(struct hci_conn * conn,u16 setting)7552f69a82aSFrédéric Dalleau static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting)
756fa5513beSFrédéric Dalleau {
757fa5513beSFrédéric Dalleau 	struct hci_dev *hdev = conn->hdev;
758fa5513beSFrédéric Dalleau 
759fa5513beSFrédéric Dalleau 	BT_DBG("conn %p", conn);
760fa5513beSFrédéric Dalleau 
761fa5513beSFrédéric Dalleau 	conn->state = BT_CONFIG;
762fa5513beSFrédéric Dalleau 
763fa5513beSFrédéric Dalleau 	if (!lmp_esco_capable(hdev)) {
764fa5513beSFrédéric Dalleau 		struct hci_cp_accept_conn_req cp;
765fa5513beSFrédéric Dalleau 
766fa5513beSFrédéric Dalleau 		bacpy(&cp.bdaddr, &conn->dst);
76733f24048SFrédéric Dalleau 		cp.role = 0x00; /* Ignored */
768fa5513beSFrédéric Dalleau 
769fa5513beSFrédéric Dalleau 		hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
770fa5513beSFrédéric Dalleau 	} else {
771fa5513beSFrédéric Dalleau 		struct hci_cp_accept_sync_conn_req cp;
772fa5513beSFrédéric Dalleau 
773fa5513beSFrédéric Dalleau 		bacpy(&cp.bdaddr, &conn->dst);
774fa5513beSFrédéric Dalleau 		cp.pkt_type = cpu_to_le16(conn->pkt_type);
775fa5513beSFrédéric Dalleau 
776dcf4adbfSJoe Perches 		cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
777dcf4adbfSJoe Perches 		cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
7782f69a82aSFrédéric Dalleau 		cp.content_format = cpu_to_le16(setting);
7792f69a82aSFrédéric Dalleau 
7802f69a82aSFrédéric Dalleau 		switch (setting & SCO_AIRMODE_MASK) {
7812f69a82aSFrédéric Dalleau 		case SCO_AIRMODE_TRANSP:
7822f69a82aSFrédéric Dalleau 			if (conn->pkt_type & ESCO_2EV3)
783dcf4adbfSJoe Perches 				cp.max_latency = cpu_to_le16(0x0008);
7842f69a82aSFrédéric Dalleau 			else
785dcf4adbfSJoe Perches 				cp.max_latency = cpu_to_le16(0x000D);
7862f69a82aSFrédéric Dalleau 			cp.retrans_effort = 0x02;
7872f69a82aSFrédéric Dalleau 			break;
7882f69a82aSFrédéric Dalleau 		case SCO_AIRMODE_CVSD:
789dcf4adbfSJoe Perches 			cp.max_latency = cpu_to_le16(0xffff);
790fa5513beSFrédéric Dalleau 			cp.retrans_effort = 0xff;
7912f69a82aSFrédéric Dalleau 			break;
79259da0b38SDan Carpenter 		default:
79359da0b38SDan Carpenter 			/* use CVSD settings as fallback */
79459da0b38SDan Carpenter 			cp.max_latency = cpu_to_le16(0xffff);
79559da0b38SDan Carpenter 			cp.retrans_effort = 0xff;
79659da0b38SDan Carpenter 			break;
7972f69a82aSFrédéric Dalleau 		}
798fa5513beSFrédéric Dalleau 
799fa5513beSFrédéric Dalleau 		hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
800fa5513beSFrédéric Dalleau 			     sizeof(cp), &cp);
801fa5513beSFrédéric Dalleau 	}
802fa5513beSFrédéric Dalleau }
803fa5513beSFrédéric Dalleau 
sco_sock_recvmsg(struct socket * sock,struct msghdr * msg,size_t len,int flags)8041b784140SYing Xue static int sco_sock_recvmsg(struct socket *sock, struct msghdr *msg,
8051b784140SYing Xue 			    size_t len, int flags)
80620714bfeSFrédéric Dalleau {
80720714bfeSFrédéric Dalleau 	struct sock *sk = sock->sk;
80820714bfeSFrédéric Dalleau 	struct sco_pinfo *pi = sco_pi(sk);
80920714bfeSFrédéric Dalleau 
81020714bfeSFrédéric Dalleau 	lock_sock(sk);
81120714bfeSFrédéric Dalleau 
81220714bfeSFrédéric Dalleau 	if (sk->sk_state == BT_CONNECT2 &&
81320714bfeSFrédéric Dalleau 	    test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
8142f69a82aSFrédéric Dalleau 		sco_conn_defer_accept(pi->conn->hcon, pi->setting);
81520714bfeSFrédéric Dalleau 		sk->sk_state = BT_CONFIG;
81620714bfeSFrédéric Dalleau 
81720714bfeSFrédéric Dalleau 		release_sock(sk);
81820714bfeSFrédéric Dalleau 		return 0;
81920714bfeSFrédéric Dalleau 	}
82020714bfeSFrédéric Dalleau 
82120714bfeSFrédéric Dalleau 	release_sock(sk);
82220714bfeSFrédéric Dalleau 
8231b784140SYing Xue 	return bt_sock_recvmsg(sock, msg, len, flags);
82420714bfeSFrédéric Dalleau }
82520714bfeSFrédéric Dalleau 
sco_sock_setsockopt(struct socket * sock,int level,int optname,sockptr_t optval,unsigned int optlen)826c4297e8fSMarcel Holtmann static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
827a7b75c5aSChristoph Hellwig 			       sockptr_t optval, unsigned int optlen)
8281da177e4SLinus Torvalds {
8291da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
83072473db9SLuiz Augusto von Dentz 	int err = 0;
831ad10b1a4SFrédéric Dalleau 	struct bt_voice voice;
832b96e9c67SFrédéric Dalleau 	u32 opt;
833f6873401SKiran K 	struct bt_codecs *codecs;
834f6873401SKiran K 	struct hci_dev *hdev;
835f6873401SKiran K 	__u8 buffer[255];
8361da177e4SLinus Torvalds 
8371da177e4SLinus Torvalds 	BT_DBG("sk %p", sk);
8381da177e4SLinus Torvalds 
8391da177e4SLinus Torvalds 	lock_sock(sk);
8401da177e4SLinus Torvalds 
8411da177e4SLinus Torvalds 	switch (optname) {
842b96e9c67SFrédéric Dalleau 
843b96e9c67SFrédéric Dalleau 	case BT_DEFER_SETUP:
844b96e9c67SFrédéric Dalleau 		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
845b96e9c67SFrédéric Dalleau 			err = -EINVAL;
846b96e9c67SFrédéric Dalleau 			break;
847b96e9c67SFrédéric Dalleau 		}
848b96e9c67SFrédéric Dalleau 
84972473db9SLuiz Augusto von Dentz 		err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
85072473db9SLuiz Augusto von Dentz 		if (err)
851b96e9c67SFrédéric Dalleau 			break;
852b96e9c67SFrédéric Dalleau 
853b96e9c67SFrédéric Dalleau 		if (opt)
854b96e9c67SFrédéric Dalleau 			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
855b96e9c67SFrédéric Dalleau 		else
856b96e9c67SFrédéric Dalleau 			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
857b96e9c67SFrédéric Dalleau 		break;
858b96e9c67SFrédéric Dalleau 
859ad10b1a4SFrédéric Dalleau 	case BT_VOICE:
860ad10b1a4SFrédéric Dalleau 		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
861ad10b1a4SFrédéric Dalleau 		    sk->sk_state != BT_CONNECT2) {
862ad10b1a4SFrédéric Dalleau 			err = -EINVAL;
863ad10b1a4SFrédéric Dalleau 			break;
864ad10b1a4SFrédéric Dalleau 		}
865ad10b1a4SFrédéric Dalleau 
866ad10b1a4SFrédéric Dalleau 		voice.setting = sco_pi(sk)->setting;
867ad10b1a4SFrédéric Dalleau 
86872473db9SLuiz Augusto von Dentz 		err = bt_copy_from_sockptr(&voice, sizeof(voice), optval,
86972473db9SLuiz Augusto von Dentz 					   optlen);
87072473db9SLuiz Augusto von Dentz 		if (err)
871ad10b1a4SFrédéric Dalleau 			break;
872ad10b1a4SFrédéric Dalleau 
873ad10b1a4SFrédéric Dalleau 		/* Explicitly check for these values */
874ad10b1a4SFrédéric Dalleau 		if (voice.setting != BT_VOICE_TRANSPARENT &&
875ad10b1a4SFrédéric Dalleau 		    voice.setting != BT_VOICE_CVSD_16BIT) {
876ad10b1a4SFrédéric Dalleau 			err = -EINVAL;
877ad10b1a4SFrédéric Dalleau 			break;
878ad10b1a4SFrédéric Dalleau 		}
879ad10b1a4SFrédéric Dalleau 
880ad10b1a4SFrédéric Dalleau 		sco_pi(sk)->setting = voice.setting;
881b2af264aSKiran K 		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
882b2af264aSKiran K 				     BDADDR_BREDR);
883b2af264aSKiran K 		if (!hdev) {
884b2af264aSKiran K 			err = -EBADFD;
885b2af264aSKiran K 			break;
886b2af264aSKiran K 		}
88705abad85SLuiz Augusto von Dentz 		if (enhanced_sync_conn_capable(hdev) &&
888b2af264aSKiran K 		    voice.setting == BT_VOICE_TRANSPARENT)
889b2af264aSKiran K 			sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
890b2af264aSKiran K 		hci_dev_put(hdev);
891ad10b1a4SFrédéric Dalleau 		break;
892ad10b1a4SFrédéric Dalleau 
89300398e1dSAlain Michaud 	case BT_PKT_STATUS:
89472473db9SLuiz Augusto von Dentz 		err = bt_copy_from_sockptr(&opt, sizeof(opt), optval, optlen);
89572473db9SLuiz Augusto von Dentz 		if (err)
89600398e1dSAlain Michaud 			break;
89700398e1dSAlain Michaud 
89800398e1dSAlain Michaud 		if (opt)
8993f19ffb2SLuiz Augusto von Dentz 			set_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
90000398e1dSAlain Michaud 		else
9013f19ffb2SLuiz Augusto von Dentz 			clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
90200398e1dSAlain Michaud 		break;
90300398e1dSAlain Michaud 
904f6873401SKiran K 	case BT_CODEC:
905f6873401SKiran K 		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
906f6873401SKiran K 		    sk->sk_state != BT_CONNECT2) {
907f6873401SKiran K 			err = -EINVAL;
908f6873401SKiran K 			break;
909f6873401SKiran K 		}
910f6873401SKiran K 
911f6873401SKiran K 		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
912f6873401SKiran K 				     BDADDR_BREDR);
913f6873401SKiran K 		if (!hdev) {
914f6873401SKiran K 			err = -EBADFD;
915f6873401SKiran K 			break;
916f6873401SKiran K 		}
917f6873401SKiran K 
918f6873401SKiran K 		if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
919f6873401SKiran K 			hci_dev_put(hdev);
920f6873401SKiran K 			err = -EOPNOTSUPP;
921f6873401SKiran K 			break;
922f6873401SKiran K 		}
923f6873401SKiran K 
924f6873401SKiran K 		if (!hdev->get_data_path_id) {
925f6873401SKiran K 			hci_dev_put(hdev);
926f6873401SKiran K 			err = -EOPNOTSUPP;
927f6873401SKiran K 			break;
928f6873401SKiran K 		}
929f6873401SKiran K 
930f6873401SKiran K 		if (optlen < sizeof(struct bt_codecs) ||
931f6873401SKiran K 		    optlen > sizeof(buffer)) {
932f6873401SKiran K 			hci_dev_put(hdev);
933f6873401SKiran K 			err = -EINVAL;
934f6873401SKiran K 			break;
935f6873401SKiran K 		}
936f6873401SKiran K 
93772473db9SLuiz Augusto von Dentz 		err = bt_copy_from_sockptr(buffer, optlen, optval, optlen);
93872473db9SLuiz Augusto von Dentz 		if (err) {
939f6873401SKiran K 			hci_dev_put(hdev);
940f6873401SKiran K 			break;
941f6873401SKiran K 		}
942f6873401SKiran K 
943f6873401SKiran K 		codecs = (void *)buffer;
944f6873401SKiran K 
945f6873401SKiran K 		if (codecs->num_codecs > 1) {
946f6873401SKiran K 			hci_dev_put(hdev);
947f6873401SKiran K 			err = -EINVAL;
948f6873401SKiran K 			break;
949f6873401SKiran K 		}
950f6873401SKiran K 
951f6873401SKiran K 		sco_pi(sk)->codec = codecs->codecs[0];
952f6873401SKiran K 		hci_dev_put(hdev);
953f6873401SKiran K 		break;
954f6873401SKiran K 
9551da177e4SLinus Torvalds 	default:
9561da177e4SLinus Torvalds 		err = -ENOPROTOOPT;
9571da177e4SLinus Torvalds 		break;
9581da177e4SLinus Torvalds 	}
9591da177e4SLinus Torvalds 
9601da177e4SLinus Torvalds 	release_sock(sk);
9611da177e4SLinus Torvalds 	return err;
9621da177e4SLinus Torvalds }
9631da177e4SLinus Torvalds 
sco_sock_getsockopt_old(struct socket * sock,int optname,char __user * optval,int __user * optlen)964c4297e8fSMarcel Holtmann static int sco_sock_getsockopt_old(struct socket *sock, int optname,
965c4297e8fSMarcel Holtmann 				   char __user *optval, int __user *optlen)
9661da177e4SLinus Torvalds {
9671da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
9681da177e4SLinus Torvalds 	struct sco_options opts;
9691da177e4SLinus Torvalds 	struct sco_conninfo cinfo;
9704eb706b1SNathan Chancellor 	int err = 0;
9714eb706b1SNathan Chancellor 	size_t len;
9721da177e4SLinus Torvalds 
9731da177e4SLinus Torvalds 	BT_DBG("sk %p", sk);
9741da177e4SLinus Torvalds 
9751da177e4SLinus Torvalds 	if (get_user(len, optlen))
9761da177e4SLinus Torvalds 		return -EFAULT;
9771da177e4SLinus Torvalds 
9781da177e4SLinus Torvalds 	lock_sock(sk);
9791da177e4SLinus Torvalds 
9801da177e4SLinus Torvalds 	switch (optname) {
9811da177e4SLinus Torvalds 	case SCO_OPTIONS:
9829d225d22SJohan Hedberg 		if (sk->sk_state != BT_CONNECTED &&
9839d225d22SJohan Hedberg 		    !(sk->sk_state == BT_CONNECT2 &&
9849d225d22SJohan Hedberg 		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
9851da177e4SLinus Torvalds 			err = -ENOTCONN;
9861da177e4SLinus Torvalds 			break;
9871da177e4SLinus Torvalds 		}
9881da177e4SLinus Torvalds 
9891da177e4SLinus Torvalds 		opts.mtu = sco_pi(sk)->conn->mtu;
9901da177e4SLinus Torvalds 
99179dbeafeSKai Ye 		BT_DBG("mtu %u", opts.mtu);
9921da177e4SLinus Torvalds 
9934eb706b1SNathan Chancellor 		len = min(len, sizeof(opts));
9941da177e4SLinus Torvalds 		if (copy_to_user(optval, (char *)&opts, len))
9951da177e4SLinus Torvalds 			err = -EFAULT;
9961da177e4SLinus Torvalds 
9971da177e4SLinus Torvalds 		break;
9981da177e4SLinus Torvalds 
9991da177e4SLinus Torvalds 	case SCO_CONNINFO:
10009d225d22SJohan Hedberg 		if (sk->sk_state != BT_CONNECTED &&
10019d225d22SJohan Hedberg 		    !(sk->sk_state == BT_CONNECT2 &&
10029d225d22SJohan Hedberg 		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
10031da177e4SLinus Torvalds 			err = -ENOTCONN;
10041da177e4SLinus Torvalds 			break;
10051da177e4SLinus Torvalds 		}
10061da177e4SLinus Torvalds 
1007c4c896e1SVasiliy Kulikov 		memset(&cinfo, 0, sizeof(cinfo));
10081da177e4SLinus Torvalds 		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
10091da177e4SLinus Torvalds 		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
10101da177e4SLinus Torvalds 
10114eb706b1SNathan Chancellor 		len = min(len, sizeof(cinfo));
10121da177e4SLinus Torvalds 		if (copy_to_user(optval, (char *)&cinfo, len))
10131da177e4SLinus Torvalds 			err = -EFAULT;
10141da177e4SLinus Torvalds 
10151da177e4SLinus Torvalds 		break;
10161da177e4SLinus Torvalds 
10171da177e4SLinus Torvalds 	default:
10181da177e4SLinus Torvalds 		err = -ENOPROTOOPT;
10191da177e4SLinus Torvalds 		break;
10201da177e4SLinus Torvalds 	}
10211da177e4SLinus Torvalds 
10221da177e4SLinus Torvalds 	release_sock(sk);
10231da177e4SLinus Torvalds 	return err;
10241da177e4SLinus Torvalds }
10251da177e4SLinus Torvalds 
sco_sock_getsockopt(struct socket * sock,int level,int optname,char __user * optval,int __user * optlen)1026c4297e8fSMarcel Holtmann static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
1027c4297e8fSMarcel Holtmann 			       char __user *optval, int __user *optlen)
1028d58daf42SMarcel Holtmann {
1029d58daf42SMarcel Holtmann 	struct sock *sk = sock->sk;
1030d58daf42SMarcel Holtmann 	int len, err = 0;
1031ad10b1a4SFrédéric Dalleau 	struct bt_voice voice;
1032eab2404bSLuiz Augusto von Dentz 	u32 phys;
1033248733e8SKiran K 	int buf_len;
1034248733e8SKiran K 	struct codec_list *c;
1035248733e8SKiran K 	u8 num_codecs, i, __user *ptr;
1036248733e8SKiran K 	struct hci_dev *hdev;
1037248733e8SKiran K 	struct hci_codec_caps *caps;
1038248733e8SKiran K 	struct bt_codec codec;
1039d58daf42SMarcel Holtmann 
1040d58daf42SMarcel Holtmann 	BT_DBG("sk %p", sk);
1041d58daf42SMarcel Holtmann 
1042d58daf42SMarcel Holtmann 	if (level == SOL_SCO)
1043d58daf42SMarcel Holtmann 		return sco_sock_getsockopt_old(sock, optname, optval, optlen);
1044d58daf42SMarcel Holtmann 
1045d58daf42SMarcel Holtmann 	if (get_user(len, optlen))
1046d58daf42SMarcel Holtmann 		return -EFAULT;
1047d58daf42SMarcel Holtmann 
1048d58daf42SMarcel Holtmann 	lock_sock(sk);
1049d58daf42SMarcel Holtmann 
1050d58daf42SMarcel Holtmann 	switch (optname) {
1051b96e9c67SFrédéric Dalleau 
1052b96e9c67SFrédéric Dalleau 	case BT_DEFER_SETUP:
1053b96e9c67SFrédéric Dalleau 		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
1054b96e9c67SFrédéric Dalleau 			err = -EINVAL;
1055b96e9c67SFrédéric Dalleau 			break;
1056b96e9c67SFrédéric Dalleau 		}
1057b96e9c67SFrédéric Dalleau 
1058b96e9c67SFrédéric Dalleau 		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
1059b96e9c67SFrédéric Dalleau 			     (u32 __user *)optval))
1060b96e9c67SFrédéric Dalleau 			err = -EFAULT;
1061b96e9c67SFrédéric Dalleau 
1062b96e9c67SFrédéric Dalleau 		break;
1063b96e9c67SFrédéric Dalleau 
1064ad10b1a4SFrédéric Dalleau 	case BT_VOICE:
1065ad10b1a4SFrédéric Dalleau 		voice.setting = sco_pi(sk)->setting;
1066ad10b1a4SFrédéric Dalleau 
1067ad10b1a4SFrédéric Dalleau 		len = min_t(unsigned int, len, sizeof(voice));
1068ad10b1a4SFrédéric Dalleau 		if (copy_to_user(optval, (char *)&voice, len))
1069ad10b1a4SFrédéric Dalleau 			err = -EFAULT;
1070ad10b1a4SFrédéric Dalleau 
1071ad10b1a4SFrédéric Dalleau 		break;
1072ad10b1a4SFrédéric Dalleau 
1073eab2404bSLuiz Augusto von Dentz 	case BT_PHY:
1074a2a8b0b4SLuiz Augusto von Dentz 		if (sk->sk_state != BT_CONNECTED) {
1075eab2404bSLuiz Augusto von Dentz 			err = -ENOTCONN;
1076eab2404bSLuiz Augusto von Dentz 			break;
1077eab2404bSLuiz Augusto von Dentz 		}
1078eab2404bSLuiz Augusto von Dentz 
1079eab2404bSLuiz Augusto von Dentz 		phys = hci_conn_get_phy(sco_pi(sk)->conn->hcon);
1080eab2404bSLuiz Augusto von Dentz 
1081eab2404bSLuiz Augusto von Dentz 		if (put_user(phys, (u32 __user *) optval))
1082eab2404bSLuiz Augusto von Dentz 			err = -EFAULT;
1083eab2404bSLuiz Augusto von Dentz 		break;
1084eab2404bSLuiz Augusto von Dentz 
108500398e1dSAlain Michaud 	case BT_PKT_STATUS:
10863f19ffb2SLuiz Augusto von Dentz 		if (put_user(test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags),
10873f19ffb2SLuiz Augusto von Dentz 			     (int __user *)optval))
108800398e1dSAlain Michaud 			err = -EFAULT;
108900398e1dSAlain Michaud 		break;
109000398e1dSAlain Michaud 
10910fc1a726SJoseph Hwang 	case BT_SNDMTU:
10920fc1a726SJoseph Hwang 	case BT_RCVMTU:
1093f6b8c6b5SWei Yongjun 		if (sk->sk_state != BT_CONNECTED) {
1094f6b8c6b5SWei Yongjun 			err = -ENOTCONN;
1095f6b8c6b5SWei Yongjun 			break;
1096f6b8c6b5SWei Yongjun 		}
1097f6b8c6b5SWei Yongjun 
10980fc1a726SJoseph Hwang 		if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval))
10990fc1a726SJoseph Hwang 			err = -EFAULT;
11000fc1a726SJoseph Hwang 		break;
11010fc1a726SJoseph Hwang 
1102248733e8SKiran K 	case BT_CODEC:
1103248733e8SKiran K 		num_codecs = 0;
1104248733e8SKiran K 		buf_len = 0;
1105248733e8SKiran K 
1106248733e8SKiran K 		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
1107248733e8SKiran K 		if (!hdev) {
1108248733e8SKiran K 			err = -EBADFD;
1109248733e8SKiran K 			break;
1110248733e8SKiran K 		}
1111248733e8SKiran K 
1112248733e8SKiran K 		if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
1113248733e8SKiran K 			hci_dev_put(hdev);
1114248733e8SKiran K 			err = -EOPNOTSUPP;
1115248733e8SKiran K 			break;
1116248733e8SKiran K 		}
1117248733e8SKiran K 
1118248733e8SKiran K 		if (!hdev->get_data_path_id) {
1119248733e8SKiran K 			hci_dev_put(hdev);
1120248733e8SKiran K 			err = -EOPNOTSUPP;
1121248733e8SKiran K 			break;
1122248733e8SKiran K 		}
1123248733e8SKiran K 
1124975abc0cSLuiz Augusto von Dentz 		release_sock(sk);
1125975abc0cSLuiz Augusto von Dentz 
1126248733e8SKiran K 		/* find total buffer size required to copy codec + caps */
1127248733e8SKiran K 		hci_dev_lock(hdev);
1128248733e8SKiran K 		list_for_each_entry(c, &hdev->local_codecs, list) {
1129248733e8SKiran K 			if (c->transport != HCI_TRANSPORT_SCO_ESCO)
1130248733e8SKiran K 				continue;
1131248733e8SKiran K 			num_codecs++;
1132248733e8SKiran K 			for (i = 0, caps = c->caps; i < c->num_caps; i++) {
1133248733e8SKiran K 				buf_len += 1 + caps->len;
1134248733e8SKiran K 				caps = (void *)&caps->data[caps->len];
1135248733e8SKiran K 			}
1136248733e8SKiran K 			buf_len += sizeof(struct bt_codec);
1137248733e8SKiran K 		}
1138248733e8SKiran K 		hci_dev_unlock(hdev);
1139248733e8SKiran K 
1140248733e8SKiran K 		buf_len += sizeof(struct bt_codecs);
1141248733e8SKiran K 		if (buf_len > len) {
1142248733e8SKiran K 			hci_dev_put(hdev);
1143975abc0cSLuiz Augusto von Dentz 			return -ENOBUFS;
1144248733e8SKiran K 		}
1145248733e8SKiran K 		ptr = optval;
1146248733e8SKiran K 
1147248733e8SKiran K 		if (put_user(num_codecs, ptr)) {
1148248733e8SKiran K 			hci_dev_put(hdev);
1149975abc0cSLuiz Augusto von Dentz 			return -EFAULT;
1150248733e8SKiran K 		}
1151248733e8SKiran K 		ptr += sizeof(num_codecs);
1152248733e8SKiran K 
1153248733e8SKiran K 		/* Iterate all the codecs supported over SCO and populate
1154248733e8SKiran K 		 * codec data
1155248733e8SKiran K 		 */
1156248733e8SKiran K 		hci_dev_lock(hdev);
1157248733e8SKiran K 		list_for_each_entry(c, &hdev->local_codecs, list) {
1158248733e8SKiran K 			if (c->transport != HCI_TRANSPORT_SCO_ESCO)
1159248733e8SKiran K 				continue;
1160248733e8SKiran K 
1161248733e8SKiran K 			codec.id = c->id;
1162248733e8SKiran K 			codec.cid = c->cid;
1163248733e8SKiran K 			codec.vid = c->vid;
1164248733e8SKiran K 			err = hdev->get_data_path_id(hdev, &codec.data_path);
1165248733e8SKiran K 			if (err < 0)
1166248733e8SKiran K 				break;
1167248733e8SKiran K 			codec.num_caps = c->num_caps;
1168248733e8SKiran K 			if (copy_to_user(ptr, &codec, sizeof(codec))) {
1169248733e8SKiran K 				err = -EFAULT;
1170248733e8SKiran K 				break;
1171248733e8SKiran K 			}
1172248733e8SKiran K 			ptr += sizeof(codec);
1173248733e8SKiran K 
1174248733e8SKiran K 			/* find codec capabilities data length */
1175248733e8SKiran K 			len = 0;
1176248733e8SKiran K 			for (i = 0, caps = c->caps; i < c->num_caps; i++) {
1177248733e8SKiran K 				len += 1 + caps->len;
1178248733e8SKiran K 				caps = (void *)&caps->data[caps->len];
1179248733e8SKiran K 			}
1180248733e8SKiran K 
1181248733e8SKiran K 			/* copy codec capabilities data */
1182248733e8SKiran K 			if (len && copy_to_user(ptr, c->caps, len)) {
1183248733e8SKiran K 				err = -EFAULT;
1184248733e8SKiran K 				break;
1185248733e8SKiran K 			}
1186248733e8SKiran K 			ptr += len;
1187248733e8SKiran K 		}
1188248733e8SKiran K 
1189248733e8SKiran K 		hci_dev_unlock(hdev);
1190248733e8SKiran K 		hci_dev_put(hdev);
1191248733e8SKiran K 
1192975abc0cSLuiz Augusto von Dentz 		lock_sock(sk);
1193975abc0cSLuiz Augusto von Dentz 
1194975abc0cSLuiz Augusto von Dentz 		if (!err && put_user(buf_len, optlen))
1195975abc0cSLuiz Augusto von Dentz 			err = -EFAULT;
1196975abc0cSLuiz Augusto von Dentz 
1197248733e8SKiran K 		break;
1198248733e8SKiran K 
1199d58daf42SMarcel Holtmann 	default:
1200d58daf42SMarcel Holtmann 		err = -ENOPROTOOPT;
1201d58daf42SMarcel Holtmann 		break;
1202d58daf42SMarcel Holtmann 	}
1203d58daf42SMarcel Holtmann 
1204d58daf42SMarcel Holtmann 	release_sock(sk);
1205d58daf42SMarcel Holtmann 	return err;
1206d58daf42SMarcel Holtmann }
1207d58daf42SMarcel Holtmann 
sco_sock_shutdown(struct socket * sock,int how)1208fd0b3ff7SMarcel Holtmann static int sco_sock_shutdown(struct socket *sock, int how)
1209fd0b3ff7SMarcel Holtmann {
1210fd0b3ff7SMarcel Holtmann 	struct sock *sk = sock->sk;
1211fd0b3ff7SMarcel Holtmann 	int err = 0;
1212fd0b3ff7SMarcel Holtmann 
1213fd0b3ff7SMarcel Holtmann 	BT_DBG("sock %p, sk %p", sock, sk);
1214fd0b3ff7SMarcel Holtmann 
1215fd0b3ff7SMarcel Holtmann 	if (!sk)
1216fd0b3ff7SMarcel Holtmann 		return 0;
1217fd0b3ff7SMarcel Holtmann 
12181da5537eSKuba Pawlak 	sock_hold(sk);
1219fd0b3ff7SMarcel Holtmann 	lock_sock(sk);
12201da5537eSKuba Pawlak 
1221fd0b3ff7SMarcel Holtmann 	if (!sk->sk_shutdown) {
1222fd0b3ff7SMarcel Holtmann 		sk->sk_shutdown = SHUTDOWN_MASK;
1223fd0b3ff7SMarcel Holtmann 		sco_sock_clear_timer(sk);
1224fd0b3ff7SMarcel Holtmann 		__sco_sock_close(sk);
1225fd0b3ff7SMarcel Holtmann 
1226093facf3SVladimir Davydov 		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
1227093facf3SVladimir Davydov 		    !(current->flags & PF_EXITING))
1228fd0b3ff7SMarcel Holtmann 			err = bt_sock_wait_state(sk, BT_CLOSED,
1229fd0b3ff7SMarcel Holtmann 						 sk->sk_lingertime);
1230fd0b3ff7SMarcel Holtmann 	}
12311da5537eSKuba Pawlak 
1232fd0b3ff7SMarcel Holtmann 	release_sock(sk);
12331da5537eSKuba Pawlak 	sock_put(sk);
12341da5537eSKuba Pawlak 
1235fd0b3ff7SMarcel Holtmann 	return err;
1236fd0b3ff7SMarcel Holtmann }
1237fd0b3ff7SMarcel Holtmann 
sco_sock_release(struct socket * sock)12381da177e4SLinus Torvalds static int sco_sock_release(struct socket *sock)
12391da177e4SLinus Torvalds {
12401da177e4SLinus Torvalds 	struct sock *sk = sock->sk;
12411da177e4SLinus Torvalds 	int err = 0;
12421da177e4SLinus Torvalds 
12431da177e4SLinus Torvalds 	BT_DBG("sock %p, sk %p", sock, sk);
12441da177e4SLinus Torvalds 
12451da177e4SLinus Torvalds 	if (!sk)
12461da177e4SLinus Torvalds 		return 0;
12471da177e4SLinus Torvalds 
12481da177e4SLinus Torvalds 	sco_sock_close(sk);
12491da177e4SLinus Torvalds 
1250bc1fb82aSEric Dumazet 	if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
1251093facf3SVladimir Davydov 	    !(current->flags & PF_EXITING)) {
12521da177e4SLinus Torvalds 		lock_sock(sk);
12531da177e4SLinus Torvalds 		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
12541da177e4SLinus Torvalds 		release_sock(sk);
12551da177e4SLinus Torvalds 	}
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	sock_orphan(sk);
12581da177e4SLinus Torvalds 	sco_sock_kill(sk);
12591da177e4SLinus Torvalds 	return err;
12601da177e4SLinus Torvalds }
12611da177e4SLinus Torvalds 
sco_conn_ready(struct sco_conn * conn)12621da177e4SLinus Torvalds static void sco_conn_ready(struct sco_conn *conn)
12631da177e4SLinus Torvalds {
1264735cbc47SAndrei Emeltchenko 	struct sock *parent;
1265735cbc47SAndrei Emeltchenko 	struct sock *sk = conn->sk;
12661da177e4SLinus Torvalds 
12671da177e4SLinus Torvalds 	BT_DBG("conn %p", conn);
12681da177e4SLinus Torvalds 
1269735cbc47SAndrei Emeltchenko 	if (sk) {
127027c24fdaSDesmond Cheong Zhi Xi 		lock_sock(sk);
12713f2c89fbSDesmond Cheong Zhi Xi 		sco_sock_clear_timer(sk);
12721da177e4SLinus Torvalds 		sk->sk_state = BT_CONNECTED;
12731da177e4SLinus Torvalds 		sk->sk_state_change(sk);
127427c24fdaSDesmond Cheong Zhi Xi 		release_sock(sk);
12751da177e4SLinus Torvalds 	} else {
127640528088SAndre Guedes 		sco_conn_lock(conn);
127740528088SAndre Guedes 
12782c501cddSKuba Pawlak 		if (!conn->hcon) {
12792c501cddSKuba Pawlak 			sco_conn_unlock(conn);
12802c501cddSKuba Pawlak 			return;
12812c501cddSKuba Pawlak 		}
12822c501cddSKuba Pawlak 
1283041987cfSMarcel Holtmann 		parent = sco_get_sock_listen(&conn->hcon->src);
128440528088SAndre Guedes 		if (!parent) {
128540528088SAndre Guedes 			sco_conn_unlock(conn);
128640528088SAndre Guedes 			return;
128740528088SAndre Guedes 		}
12881da177e4SLinus Torvalds 
128927c24fdaSDesmond Cheong Zhi Xi 		lock_sock(parent);
12901da177e4SLinus Torvalds 
1291b9dbdbc1SGustavo F. Padovan 		sk = sco_sock_alloc(sock_net(parent), NULL,
129211aa9c28SEric W. Biederman 				    BTPROTO_SCO, GFP_ATOMIC, 0);
12931da177e4SLinus Torvalds 		if (!sk) {
129427c24fdaSDesmond Cheong Zhi Xi 			release_sock(parent);
129540528088SAndre Guedes 			sco_conn_unlock(conn);
129640528088SAndre Guedes 			return;
12971da177e4SLinus Torvalds 		}
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds 		sco_sock_init(sk, parent);
13001da177e4SLinus Torvalds 
1301eea96364SMarcel Holtmann 		bacpy(&sco_pi(sk)->src, &conn->hcon->src);
1302eea96364SMarcel Holtmann 		bacpy(&sco_pi(sk)->dst, &conn->hcon->dst);
13031da177e4SLinus Torvalds 
13041da177e4SLinus Torvalds 		hci_conn_hold(conn->hcon);
13051da177e4SLinus Torvalds 		__sco_chan_add(conn, sk, parent);
13061da177e4SLinus Torvalds 
130720714bfeSFrédéric Dalleau 		if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
130820714bfeSFrédéric Dalleau 			sk->sk_state = BT_CONNECT2;
130920714bfeSFrédéric Dalleau 		else
13101da177e4SLinus Torvalds 			sk->sk_state = BT_CONNECTED;
13111da177e4SLinus Torvalds 
13121da177e4SLinus Torvalds 		/* Wake up parent */
1313676d2369SDavid S. Miller 		parent->sk_data_ready(parent);
13141da177e4SLinus Torvalds 
131527c24fdaSDesmond Cheong Zhi Xi 		release_sock(parent);
13161da177e4SLinus Torvalds 
13171da177e4SLinus Torvalds 		sco_conn_unlock(conn);
13181da177e4SLinus Torvalds 	}
131940528088SAndre Guedes }
13201da177e4SLinus Torvalds 
13211da177e4SLinus Torvalds /* ----- SCO interface with lower layer (HCI) ----- */
sco_connect_ind(struct hci_dev * hdev,bdaddr_t * bdaddr,__u8 * flags)132220714bfeSFrédéric Dalleau int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
13231da177e4SLinus Torvalds {
1324fc5fef61SGustavo Padovan 	struct sock *sk;
132571aeeaa1SMarcel Holtmann 	int lm = 0;
132671aeeaa1SMarcel Holtmann 
13276ed93dc6SAndrei Emeltchenko 	BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
13281da177e4SLinus Torvalds 
132971aeeaa1SMarcel Holtmann 	/* Find listening sockets */
133071aeeaa1SMarcel Holtmann 	read_lock(&sco_sk_list.lock);
1331b67bfe0dSSasha Levin 	sk_for_each(sk, &sco_sk_list.head) {
133271aeeaa1SMarcel Holtmann 		if (sk->sk_state != BT_LISTEN)
133371aeeaa1SMarcel Holtmann 			continue;
133471aeeaa1SMarcel Holtmann 
1335eea96364SMarcel Holtmann 		if (!bacmp(&sco_pi(sk)->src, &hdev->bdaddr) ||
1336eea96364SMarcel Holtmann 		    !bacmp(&sco_pi(sk)->src, BDADDR_ANY)) {
133771aeeaa1SMarcel Holtmann 			lm |= HCI_LM_ACCEPT;
133820714bfeSFrédéric Dalleau 
133920714bfeSFrédéric Dalleau 			if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
134020714bfeSFrédéric Dalleau 				*flags |= HCI_PROTO_DEFER;
134171aeeaa1SMarcel Holtmann 			break;
134271aeeaa1SMarcel Holtmann 		}
134371aeeaa1SMarcel Holtmann 	}
134471aeeaa1SMarcel Holtmann 	read_unlock(&sco_sk_list.lock);
134571aeeaa1SMarcel Holtmann 
134671aeeaa1SMarcel Holtmann 	return lm;
13471da177e4SLinus Torvalds }
13481da177e4SLinus Torvalds 
sco_connect_cfm(struct hci_conn * hcon,__u8 status)1349539c496dSJohan Hedberg static void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
13501da177e4SLinus Torvalds {
1351539c496dSJohan Hedberg 	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
1352539c496dSJohan Hedberg 		return;
1353539c496dSJohan Hedberg 
135479dbeafeSKai Ye 	BT_DBG("hcon %p bdaddr %pMR status %u", hcon, &hcon->dst, status);
1355539c496dSJohan Hedberg 
13561da177e4SLinus Torvalds 	if (!status) {
13571da177e4SLinus Torvalds 		struct sco_conn *conn;
13581da177e4SLinus Torvalds 
1359519e42b3SLukasz Rymanowski 		conn = sco_conn_add(hcon);
13601da177e4SLinus Torvalds 		if (conn)
13611da177e4SLinus Torvalds 			sco_conn_ready(conn);
13621da177e4SLinus Torvalds 	} else
1363e175072fSJoe Perches 		sco_conn_del(hcon, bt_to_errno(status));
13641da177e4SLinus Torvalds }
13651da177e4SLinus Torvalds 
sco_disconn_cfm(struct hci_conn * hcon,__u8 reason)13663a6d576bSJohan Hedberg static void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
13671da177e4SLinus Torvalds {
13683a6d576bSJohan Hedberg 	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
13693a6d576bSJohan Hedberg 		return;
13703a6d576bSJohan Hedberg 
13711da177e4SLinus Torvalds 	BT_DBG("hcon %p reason %d", hcon, reason);
13721da177e4SLinus Torvalds 
1373e175072fSJoe Perches 	sco_conn_del(hcon, bt_to_errno(reason));
13741da177e4SLinus Torvalds }
13751da177e4SLinus Torvalds 
sco_recv_scodata(struct hci_conn * hcon,struct sk_buff * skb)13769b4c3336SArron Wang void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
13771da177e4SLinus Torvalds {
13781da177e4SLinus Torvalds 	struct sco_conn *conn = hcon->sco_data;
13791da177e4SLinus Torvalds 
13801da177e4SLinus Torvalds 	if (!conn)
13811da177e4SLinus Torvalds 		goto drop;
13821da177e4SLinus Torvalds 
138379dbeafeSKai Ye 	BT_DBG("conn %p len %u", conn, skb->len);
13841da177e4SLinus Torvalds 
13851da177e4SLinus Torvalds 	if (skb->len) {
13861da177e4SLinus Torvalds 		sco_recv_frame(conn, skb);
13879b4c3336SArron Wang 		return;
13881da177e4SLinus Torvalds 	}
13891da177e4SLinus Torvalds 
13901da177e4SLinus Torvalds drop:
13911da177e4SLinus Torvalds 	kfree_skb(skb);
13921da177e4SLinus Torvalds }
13931da177e4SLinus Torvalds 
1394539c496dSJohan Hedberg static struct hci_cb sco_cb = {
1395539c496dSJohan Hedberg 	.name		= "SCO",
1396539c496dSJohan Hedberg 	.connect_cfm	= sco_connect_cfm,
13973a6d576bSJohan Hedberg 	.disconn_cfm	= sco_disconn_cfm,
1398539c496dSJohan Hedberg };
1399539c496dSJohan Hedberg 
sco_debugfs_show(struct seq_file * f,void * p)1400aef7d97cSMarcel Holtmann static int sco_debugfs_show(struct seq_file *f, void *p)
14011da177e4SLinus Torvalds {
14021da177e4SLinus Torvalds 	struct sock *sk;
14031da177e4SLinus Torvalds 
1404ee65d19eSGustavo F. Padovan 	read_lock(&sco_sk_list.lock);
14051da177e4SLinus Torvalds 
1406b67bfe0dSSasha Levin 	sk_for_each(sk, &sco_sk_list.head) {
1407eea96364SMarcel Holtmann 		seq_printf(f, "%pMR %pMR %d\n", &sco_pi(sk)->src,
1408eea96364SMarcel Holtmann 			   &sco_pi(sk)->dst, sk->sk_state);
14091da177e4SLinus Torvalds 	}
14101da177e4SLinus Torvalds 
1411ee65d19eSGustavo F. Padovan 	read_unlock(&sco_sk_list.lock);
1412be9d1227SMarcel Holtmann 
1413aef7d97cSMarcel Holtmann 	return 0;
14141da177e4SLinus Torvalds }
14151da177e4SLinus Torvalds 
14168e2924e3SYangtao Li DEFINE_SHOW_ATTRIBUTE(sco_debugfs);
1417aef7d97cSMarcel Holtmann 
1418aef7d97cSMarcel Holtmann static struct dentry *sco_debugfs;
14191da177e4SLinus Torvalds 
142090ddc4f0SEric Dumazet static const struct proto_ops sco_sock_ops = {
14211da177e4SLinus Torvalds 	.family		= PF_BLUETOOTH,
14221da177e4SLinus Torvalds 	.owner		= THIS_MODULE,
14231da177e4SLinus Torvalds 	.release	= sco_sock_release,
14241da177e4SLinus Torvalds 	.bind		= sco_sock_bind,
14251da177e4SLinus Torvalds 	.connect	= sco_sock_connect,
14261da177e4SLinus Torvalds 	.listen		= sco_sock_listen,
14271da177e4SLinus Torvalds 	.accept		= sco_sock_accept,
14281da177e4SLinus Torvalds 	.getname	= sco_sock_getname,
14291da177e4SLinus Torvalds 	.sendmsg	= sco_sock_sendmsg,
143020714bfeSFrédéric Dalleau 	.recvmsg	= sco_sock_recvmsg,
1431a11e1d43SLinus Torvalds 	.poll		= bt_sock_poll,
14323241ad82SMarcel Holtmann 	.ioctl		= bt_sock_ioctl,
1433c7cbdbf2SArnd Bergmann 	.gettstamp	= sock_gettstamp,
14341da177e4SLinus Torvalds 	.mmap		= sock_no_mmap,
14351da177e4SLinus Torvalds 	.socketpair	= sock_no_socketpair,
1436fd0b3ff7SMarcel Holtmann 	.shutdown	= sco_sock_shutdown,
14371da177e4SLinus Torvalds 	.setsockopt	= sco_sock_setsockopt,
14381da177e4SLinus Torvalds 	.getsockopt	= sco_sock_getsockopt
14391da177e4SLinus Torvalds };
14401da177e4SLinus Torvalds 
1441ec1b4cf7SStephen Hemminger static const struct net_proto_family sco_sock_family_ops = {
14421da177e4SLinus Torvalds 	.family	= PF_BLUETOOTH,
14431da177e4SLinus Torvalds 	.owner	= THIS_MODULE,
14441da177e4SLinus Torvalds 	.create	= sco_sock_create,
14451da177e4SLinus Torvalds };
14461da177e4SLinus Torvalds 
sco_init(void)144764274518SGustavo F. Padovan int __init sco_init(void)
14481da177e4SLinus Torvalds {
14491da177e4SLinus Torvalds 	int err;
14501da177e4SLinus Torvalds 
145115762fa7SMarcel Holtmann 	BUILD_BUG_ON(sizeof(struct sockaddr_sco) > sizeof(struct sockaddr));
145215762fa7SMarcel Holtmann 
14531da177e4SLinus Torvalds 	err = proto_register(&sco_proto, 0);
14541da177e4SLinus Torvalds 	if (err < 0)
14551da177e4SLinus Torvalds 		return err;
14561da177e4SLinus Torvalds 
14571da177e4SLinus Torvalds 	err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
14581da177e4SLinus Torvalds 	if (err < 0) {
14591da177e4SLinus Torvalds 		BT_ERR("SCO socket registration failed");
14601da177e4SLinus Torvalds 		goto error;
14611da177e4SLinus Torvalds 	}
14621da177e4SLinus Torvalds 
1463b0316615SAl Viro 	err = bt_procfs_init(&init_net, "sco", &sco_sk_list, NULL);
1464de9b9212SMasatake YAMATO 	if (err < 0) {
1465de9b9212SMasatake YAMATO 		BT_ERR("Failed to create SCO proc file");
1466de9b9212SMasatake YAMATO 		bt_sock_unregister(BTPROTO_SCO);
1467de9b9212SMasatake YAMATO 		goto error;
1468de9b9212SMasatake YAMATO 	}
1469de9b9212SMasatake YAMATO 
14701120e4bfSMarcel Holtmann 	BT_INFO("SCO socket layer initialized");
14711120e4bfSMarcel Holtmann 
1472539c496dSJohan Hedberg 	hci_register_cb(&sco_cb);
1473539c496dSJohan Hedberg 
14741120e4bfSMarcel Holtmann 	if (IS_ERR_OR_NULL(bt_debugfs))
14751120e4bfSMarcel Holtmann 		return 0;
14761120e4bfSMarcel Holtmann 
1477be7c2b99SGustavo Padovan 	sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
1478be7c2b99SGustavo Padovan 					  NULL, &sco_debugfs_fops);
14791da177e4SLinus Torvalds 
14801da177e4SLinus Torvalds 	return 0;
14811da177e4SLinus Torvalds 
14821da177e4SLinus Torvalds error:
14831da177e4SLinus Torvalds 	proto_unregister(&sco_proto);
14841da177e4SLinus Torvalds 	return err;
14851da177e4SLinus Torvalds }
14861da177e4SLinus Torvalds 
sco_exit(void)14870402d9f2SAlexander Aring void sco_exit(void)
14881da177e4SLinus Torvalds {
1489de9b9212SMasatake YAMATO 	bt_procfs_cleanup(&init_net, "sco");
1490de9b9212SMasatake YAMATO 
1491aef7d97cSMarcel Holtmann 	debugfs_remove(sco_debugfs);
14921da177e4SLinus Torvalds 
1493539c496dSJohan Hedberg 	hci_unregister_cb(&sco_cb);
1494539c496dSJohan Hedberg 
14955e9d7f86SDavid Herrmann 	bt_sock_unregister(BTPROTO_SCO);
14961da177e4SLinus Torvalds 
14971da177e4SLinus Torvalds 	proto_unregister(&sco_proto);
14981da177e4SLinus Torvalds }
14991da177e4SLinus Torvalds 
15007cb127d5SMarcel Holtmann module_param(disable_esco, bool, 0644);
15017cb127d5SMarcel Holtmann MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
1502