162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci   BlueZ - Bluetooth protocol stack for Linux
362306a36Sopenharmony_ci   Copyright (C) 2000-2001 Qualcomm Incorporated
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci   This program is free software; you can redistribute it and/or modify
862306a36Sopenharmony_ci   it under the terms of the GNU General Public License version 2 as
962306a36Sopenharmony_ci   published by the Free Software Foundation;
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1262306a36Sopenharmony_ci   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1362306a36Sopenharmony_ci   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
1462306a36Sopenharmony_ci   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
1562306a36Sopenharmony_ci   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
1662306a36Sopenharmony_ci   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1762306a36Sopenharmony_ci   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1862306a36Sopenharmony_ci   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
2162306a36Sopenharmony_ci   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
2262306a36Sopenharmony_ci   SOFTWARE IS DISCLAIMED.
2362306a36Sopenharmony_ci*/
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci/* Bluetooth SCO sockets. */
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/module.h>
2862306a36Sopenharmony_ci#include <linux/debugfs.h>
2962306a36Sopenharmony_ci#include <linux/seq_file.h>
3062306a36Sopenharmony_ci#include <linux/sched/signal.h>
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
3362306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
3462306a36Sopenharmony_ci#include <net/bluetooth/sco.h>
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic bool disable_esco;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic const struct proto_ops sco_sock_ops;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic struct bt_sock_list sco_sk_list = {
4162306a36Sopenharmony_ci	.lock = __RW_LOCK_UNLOCKED(sco_sk_list.lock)
4262306a36Sopenharmony_ci};
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/* ---- SCO connections ---- */
4562306a36Sopenharmony_cistruct sco_conn {
4662306a36Sopenharmony_ci	struct hci_conn	*hcon;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	spinlock_t	lock;
4962306a36Sopenharmony_ci	struct sock	*sk;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	struct delayed_work	timeout_work;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	unsigned int    mtu;
5462306a36Sopenharmony_ci};
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define sco_conn_lock(c)	spin_lock(&c->lock)
5762306a36Sopenharmony_ci#define sco_conn_unlock(c)	spin_unlock(&c->lock)
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic void sco_sock_close(struct sock *sk);
6062306a36Sopenharmony_cistatic void sco_sock_kill(struct sock *sk);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/* ----- SCO socket info ----- */
6362306a36Sopenharmony_ci#define sco_pi(sk) ((struct sco_pinfo *) sk)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistruct sco_pinfo {
6662306a36Sopenharmony_ci	struct bt_sock	bt;
6762306a36Sopenharmony_ci	bdaddr_t	src;
6862306a36Sopenharmony_ci	bdaddr_t	dst;
6962306a36Sopenharmony_ci	__u32		flags;
7062306a36Sopenharmony_ci	__u16		setting;
7162306a36Sopenharmony_ci	struct bt_codec codec;
7262306a36Sopenharmony_ci	struct sco_conn	*conn;
7362306a36Sopenharmony_ci};
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci/* ---- SCO timers ---- */
7662306a36Sopenharmony_ci#define SCO_CONN_TIMEOUT	(HZ * 40)
7762306a36Sopenharmony_ci#define SCO_DISCONN_TIMEOUT	(HZ * 2)
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic void sco_sock_timeout(struct work_struct *work)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct sco_conn *conn = container_of(work, struct sco_conn,
8262306a36Sopenharmony_ci					     timeout_work.work);
8362306a36Sopenharmony_ci	struct sock *sk;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	sco_conn_lock(conn);
8662306a36Sopenharmony_ci	sk = conn->sk;
8762306a36Sopenharmony_ci	if (sk)
8862306a36Sopenharmony_ci		sock_hold(sk);
8962306a36Sopenharmony_ci	sco_conn_unlock(conn);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (!sk)
9262306a36Sopenharmony_ci		return;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	BT_DBG("sock %p state %d", sk, sk->sk_state);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	lock_sock(sk);
9762306a36Sopenharmony_ci	sk->sk_err = ETIMEDOUT;
9862306a36Sopenharmony_ci	sk->sk_state_change(sk);
9962306a36Sopenharmony_ci	release_sock(sk);
10062306a36Sopenharmony_ci	sock_put(sk);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic void sco_sock_set_timer(struct sock *sk, long timeout)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	if (!sco_pi(sk)->conn)
10662306a36Sopenharmony_ci		return;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout);
10962306a36Sopenharmony_ci	cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
11062306a36Sopenharmony_ci	schedule_delayed_work(&sco_pi(sk)->conn->timeout_work, timeout);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic void sco_sock_clear_timer(struct sock *sk)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	if (!sco_pi(sk)->conn)
11662306a36Sopenharmony_ci		return;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	BT_DBG("sock %p state %d", sk, sk->sk_state);
11962306a36Sopenharmony_ci	cancel_delayed_work(&sco_pi(sk)->conn->timeout_work);
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/* ---- SCO connections ---- */
12362306a36Sopenharmony_cistatic struct sco_conn *sco_conn_add(struct hci_conn *hcon)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	struct hci_dev *hdev = hcon->hdev;
12662306a36Sopenharmony_ci	struct sco_conn *conn = hcon->sco_data;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	if (conn) {
12962306a36Sopenharmony_ci		if (!conn->hcon)
13062306a36Sopenharmony_ci			conn->hcon = hcon;
13162306a36Sopenharmony_ci		return conn;
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);
13562306a36Sopenharmony_ci	if (!conn)
13662306a36Sopenharmony_ci		return NULL;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	spin_lock_init(&conn->lock);
13962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&conn->timeout_work, sco_sock_timeout);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	hcon->sco_data = conn;
14262306a36Sopenharmony_ci	conn->hcon = hcon;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (hdev->sco_mtu > 0)
14562306a36Sopenharmony_ci		conn->mtu = hdev->sco_mtu;
14662306a36Sopenharmony_ci	else
14762306a36Sopenharmony_ci		conn->mtu = 60;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	BT_DBG("hcon %p conn %p", hcon, conn);
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return conn;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/* Delete channel.
15562306a36Sopenharmony_ci * Must be called on the locked socket. */
15662306a36Sopenharmony_cistatic void sco_chan_del(struct sock *sk, int err)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct sco_conn *conn;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	conn = sco_pi(sk)->conn;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	BT_DBG("sk %p, conn %p, err %d", sk, conn, err);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (conn) {
16562306a36Sopenharmony_ci		sco_conn_lock(conn);
16662306a36Sopenharmony_ci		conn->sk = NULL;
16762306a36Sopenharmony_ci		sco_pi(sk)->conn = NULL;
16862306a36Sopenharmony_ci		sco_conn_unlock(conn);
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		if (conn->hcon)
17162306a36Sopenharmony_ci			hci_conn_drop(conn->hcon);
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	sk->sk_state = BT_CLOSED;
17562306a36Sopenharmony_ci	sk->sk_err   = err;
17662306a36Sopenharmony_ci	sk->sk_state_change(sk);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	sock_set_flag(sk, SOCK_ZAPPED);
17962306a36Sopenharmony_ci}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic void sco_conn_del(struct hci_conn *hcon, int err)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	struct sco_conn *conn = hcon->sco_data;
18462306a36Sopenharmony_ci	struct sock *sk;
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (!conn)
18762306a36Sopenharmony_ci		return;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* Kill socket */
19262306a36Sopenharmony_ci	sco_conn_lock(conn);
19362306a36Sopenharmony_ci	sk = conn->sk;
19462306a36Sopenharmony_ci	if (sk)
19562306a36Sopenharmony_ci		sock_hold(sk);
19662306a36Sopenharmony_ci	sco_conn_unlock(conn);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	if (sk) {
19962306a36Sopenharmony_ci		lock_sock(sk);
20062306a36Sopenharmony_ci		sco_sock_clear_timer(sk);
20162306a36Sopenharmony_ci		sco_chan_del(sk, err);
20262306a36Sopenharmony_ci		release_sock(sk);
20362306a36Sopenharmony_ci		sock_put(sk);
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	/* Ensure no more work items will run before freeing conn. */
20762306a36Sopenharmony_ci	cancel_delayed_work_sync(&conn->timeout_work);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	hcon->sco_data = NULL;
21062306a36Sopenharmony_ci	kfree(conn);
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic void __sco_chan_add(struct sco_conn *conn, struct sock *sk,
21462306a36Sopenharmony_ci			   struct sock *parent)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	BT_DBG("conn %p", conn);
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	sco_pi(sk)->conn = conn;
21962306a36Sopenharmony_ci	conn->sk = sk;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	if (parent)
22262306a36Sopenharmony_ci		bt_accept_enqueue(parent, sk, true);
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_cistatic int sco_chan_add(struct sco_conn *conn, struct sock *sk,
22662306a36Sopenharmony_ci			struct sock *parent)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	int err = 0;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	sco_conn_lock(conn);
23162306a36Sopenharmony_ci	if (conn->sk)
23262306a36Sopenharmony_ci		err = -EBUSY;
23362306a36Sopenharmony_ci	else
23462306a36Sopenharmony_ci		__sco_chan_add(conn, sk, parent);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	sco_conn_unlock(conn);
23762306a36Sopenharmony_ci	return err;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_cistatic int sco_connect(struct sock *sk)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct sco_conn *conn;
24362306a36Sopenharmony_ci	struct hci_conn *hcon;
24462306a36Sopenharmony_ci	struct hci_dev  *hdev;
24562306a36Sopenharmony_ci	int err, type;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst);
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
25062306a36Sopenharmony_ci	if (!hdev)
25162306a36Sopenharmony_ci		return -EHOSTUNREACH;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	hci_dev_lock(hdev);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (lmp_esco_capable(hdev) && !disable_esco)
25662306a36Sopenharmony_ci		type = ESCO_LINK;
25762306a36Sopenharmony_ci	else
25862306a36Sopenharmony_ci		type = SCO_LINK;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	if (sco_pi(sk)->setting == BT_VOICE_TRANSPARENT &&
26162306a36Sopenharmony_ci	    (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev))) {
26262306a36Sopenharmony_ci		err = -EOPNOTSUPP;
26362306a36Sopenharmony_ci		goto unlock;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
26762306a36Sopenharmony_ci			       sco_pi(sk)->setting, &sco_pi(sk)->codec);
26862306a36Sopenharmony_ci	if (IS_ERR(hcon)) {
26962306a36Sopenharmony_ci		err = PTR_ERR(hcon);
27062306a36Sopenharmony_ci		goto unlock;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	conn = sco_conn_add(hcon);
27462306a36Sopenharmony_ci	if (!conn) {
27562306a36Sopenharmony_ci		hci_conn_drop(hcon);
27662306a36Sopenharmony_ci		err = -ENOMEM;
27762306a36Sopenharmony_ci		goto unlock;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	lock_sock(sk);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	err = sco_chan_add(conn, sk, NULL);
28362306a36Sopenharmony_ci	if (err) {
28462306a36Sopenharmony_ci		release_sock(sk);
28562306a36Sopenharmony_ci		goto unlock;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* Update source addr of the socket */
28962306a36Sopenharmony_ci	bacpy(&sco_pi(sk)->src, &hcon->src);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	if (hcon->state == BT_CONNECTED) {
29262306a36Sopenharmony_ci		sco_sock_clear_timer(sk);
29362306a36Sopenharmony_ci		sk->sk_state = BT_CONNECTED;
29462306a36Sopenharmony_ci	} else {
29562306a36Sopenharmony_ci		sk->sk_state = BT_CONNECT;
29662306a36Sopenharmony_ci		sco_sock_set_timer(sk, sk->sk_sndtimeo);
29762306a36Sopenharmony_ci	}
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	release_sock(sk);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciunlock:
30262306a36Sopenharmony_ci	hci_dev_unlock(hdev);
30362306a36Sopenharmony_ci	hci_dev_put(hdev);
30462306a36Sopenharmony_ci	return err;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic int sco_send_frame(struct sock *sk, struct sk_buff *skb)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct sco_conn *conn = sco_pi(sk)->conn;
31062306a36Sopenharmony_ci	int len = skb->len;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/* Check outgoing MTU */
31362306a36Sopenharmony_ci	if (len > conn->mtu)
31462306a36Sopenharmony_ci		return -EINVAL;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	BT_DBG("sk %p len %d", sk, len);
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	hci_send_sco(conn->hcon, skb);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return len;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	struct sock *sk;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	sco_conn_lock(conn);
32862306a36Sopenharmony_ci	sk = conn->sk;
32962306a36Sopenharmony_ci	sco_conn_unlock(conn);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	if (!sk)
33262306a36Sopenharmony_ci		goto drop;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	BT_DBG("sk %p len %u", sk, skb->len);
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (sk->sk_state != BT_CONNECTED)
33762306a36Sopenharmony_ci		goto drop;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (!sock_queue_rcv_skb(sk, skb))
34062306a36Sopenharmony_ci		return;
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cidrop:
34362306a36Sopenharmony_ci	kfree_skb(skb);
34462306a36Sopenharmony_ci}
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci/* -------- Socket interface ---------- */
34762306a36Sopenharmony_cistatic struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct sock *sk;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	sk_for_each(sk, &sco_sk_list.head) {
35262306a36Sopenharmony_ci		if (sk->sk_state != BT_LISTEN)
35362306a36Sopenharmony_ci			continue;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci		if (!bacmp(&sco_pi(sk)->src, ba))
35662306a36Sopenharmony_ci			return sk;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return NULL;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci/* Find socket listening on source bdaddr.
36362306a36Sopenharmony_ci * Returns closest match.
36462306a36Sopenharmony_ci */
36562306a36Sopenharmony_cistatic struct sock *sco_get_sock_listen(bdaddr_t *src)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct sock *sk = NULL, *sk1 = NULL;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	read_lock(&sco_sk_list.lock);
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	sk_for_each(sk, &sco_sk_list.head) {
37262306a36Sopenharmony_ci		if (sk->sk_state != BT_LISTEN)
37362306a36Sopenharmony_ci			continue;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci		/* Exact match. */
37662306a36Sopenharmony_ci		if (!bacmp(&sco_pi(sk)->src, src))
37762306a36Sopenharmony_ci			break;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		/* Closest match */
38062306a36Sopenharmony_ci		if (!bacmp(&sco_pi(sk)->src, BDADDR_ANY))
38162306a36Sopenharmony_ci			sk1 = sk;
38262306a36Sopenharmony_ci	}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	read_unlock(&sco_sk_list.lock);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	return sk ? sk : sk1;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic void sco_sock_destruct(struct sock *sk)
39062306a36Sopenharmony_ci{
39162306a36Sopenharmony_ci	BT_DBG("sk %p", sk);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	skb_queue_purge(&sk->sk_receive_queue);
39462306a36Sopenharmony_ci	skb_queue_purge(&sk->sk_write_queue);
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic void sco_sock_cleanup_listen(struct sock *parent)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	struct sock *sk;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	BT_DBG("parent %p", parent);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/* Close not yet accepted channels */
40462306a36Sopenharmony_ci	while ((sk = bt_accept_dequeue(parent, NULL))) {
40562306a36Sopenharmony_ci		sco_sock_close(sk);
40662306a36Sopenharmony_ci		sco_sock_kill(sk);
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	parent->sk_state  = BT_CLOSED;
41062306a36Sopenharmony_ci	sock_set_flag(parent, SOCK_ZAPPED);
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/* Kill socket (only if zapped and orphan)
41462306a36Sopenharmony_ci * Must be called on unlocked socket.
41562306a36Sopenharmony_ci */
41662306a36Sopenharmony_cistatic void sco_sock_kill(struct sock *sk)
41762306a36Sopenharmony_ci{
41862306a36Sopenharmony_ci	if (!sock_flag(sk, SOCK_ZAPPED) || sk->sk_socket)
41962306a36Sopenharmony_ci		return;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	BT_DBG("sk %p state %d", sk, sk->sk_state);
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* Kill poor orphan */
42462306a36Sopenharmony_ci	bt_sock_unlink(&sco_sk_list, sk);
42562306a36Sopenharmony_ci	sock_set_flag(sk, SOCK_DEAD);
42662306a36Sopenharmony_ci	sock_put(sk);
42762306a36Sopenharmony_ci}
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_cistatic void __sco_sock_close(struct sock *sk)
43062306a36Sopenharmony_ci{
43162306a36Sopenharmony_ci	BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	switch (sk->sk_state) {
43462306a36Sopenharmony_ci	case BT_LISTEN:
43562306a36Sopenharmony_ci		sco_sock_cleanup_listen(sk);
43662306a36Sopenharmony_ci		break;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	case BT_CONNECTED:
43962306a36Sopenharmony_ci	case BT_CONFIG:
44062306a36Sopenharmony_ci		if (sco_pi(sk)->conn->hcon) {
44162306a36Sopenharmony_ci			sk->sk_state = BT_DISCONN;
44262306a36Sopenharmony_ci			sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT);
44362306a36Sopenharmony_ci			sco_conn_lock(sco_pi(sk)->conn);
44462306a36Sopenharmony_ci			hci_conn_drop(sco_pi(sk)->conn->hcon);
44562306a36Sopenharmony_ci			sco_pi(sk)->conn->hcon = NULL;
44662306a36Sopenharmony_ci			sco_conn_unlock(sco_pi(sk)->conn);
44762306a36Sopenharmony_ci		} else
44862306a36Sopenharmony_ci			sco_chan_del(sk, ECONNRESET);
44962306a36Sopenharmony_ci		break;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	case BT_CONNECT2:
45262306a36Sopenharmony_ci	case BT_CONNECT:
45362306a36Sopenharmony_ci	case BT_DISCONN:
45462306a36Sopenharmony_ci		sco_chan_del(sk, ECONNRESET);
45562306a36Sopenharmony_ci		break;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	default:
45862306a36Sopenharmony_ci		sock_set_flag(sk, SOCK_ZAPPED);
45962306a36Sopenharmony_ci		break;
46062306a36Sopenharmony_ci	}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci}
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci/* Must be called on unlocked socket. */
46562306a36Sopenharmony_cistatic void sco_sock_close(struct sock *sk)
46662306a36Sopenharmony_ci{
46762306a36Sopenharmony_ci	lock_sock(sk);
46862306a36Sopenharmony_ci	sco_sock_clear_timer(sk);
46962306a36Sopenharmony_ci	__sco_sock_close(sk);
47062306a36Sopenharmony_ci	release_sock(sk);
47162306a36Sopenharmony_ci}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_cistatic void sco_sock_init(struct sock *sk, struct sock *parent)
47462306a36Sopenharmony_ci{
47562306a36Sopenharmony_ci	BT_DBG("sk %p", sk);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	if (parent) {
47862306a36Sopenharmony_ci		sk->sk_type = parent->sk_type;
47962306a36Sopenharmony_ci		bt_sk(sk)->flags = bt_sk(parent)->flags;
48062306a36Sopenharmony_ci		security_sk_clone(parent, sk);
48162306a36Sopenharmony_ci	}
48262306a36Sopenharmony_ci}
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_cistatic struct proto sco_proto = {
48562306a36Sopenharmony_ci	.name		= "SCO",
48662306a36Sopenharmony_ci	.owner		= THIS_MODULE,
48762306a36Sopenharmony_ci	.obj_size	= sizeof(struct sco_pinfo)
48862306a36Sopenharmony_ci};
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_cistatic struct sock *sco_sock_alloc(struct net *net, struct socket *sock,
49162306a36Sopenharmony_ci				   int proto, gfp_t prio, int kern)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	struct sock *sk;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	sk = bt_sock_alloc(net, sock, &sco_proto, proto, prio, kern);
49662306a36Sopenharmony_ci	if (!sk)
49762306a36Sopenharmony_ci		return NULL;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	sk->sk_destruct = sco_sock_destruct;
50062306a36Sopenharmony_ci	sk->sk_sndtimeo = SCO_CONN_TIMEOUT;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT;
50362306a36Sopenharmony_ci	sco_pi(sk)->codec.id = BT_CODEC_CVSD;
50462306a36Sopenharmony_ci	sco_pi(sk)->codec.cid = 0xffff;
50562306a36Sopenharmony_ci	sco_pi(sk)->codec.vid = 0xffff;
50662306a36Sopenharmony_ci	sco_pi(sk)->codec.data_path = 0x00;
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	bt_sock_link(&sco_sk_list, sk);
50962306a36Sopenharmony_ci	return sk;
51062306a36Sopenharmony_ci}
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_cistatic int sco_sock_create(struct net *net, struct socket *sock, int protocol,
51362306a36Sopenharmony_ci			   int kern)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	struct sock *sk;
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	BT_DBG("sock %p", sock);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	sock->state = SS_UNCONNECTED;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	if (sock->type != SOCK_SEQPACKET)
52262306a36Sopenharmony_ci		return -ESOCKTNOSUPPORT;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	sock->ops = &sco_sock_ops;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	sk = sco_sock_alloc(net, sock, protocol, GFP_ATOMIC, kern);
52762306a36Sopenharmony_ci	if (!sk)
52862306a36Sopenharmony_ci		return -ENOMEM;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	sco_sock_init(sk, NULL);
53162306a36Sopenharmony_ci	return 0;
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_cistatic int sco_sock_bind(struct socket *sock, struct sockaddr *addr,
53562306a36Sopenharmony_ci			 int addr_len)
53662306a36Sopenharmony_ci{
53762306a36Sopenharmony_ci	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
53862306a36Sopenharmony_ci	struct sock *sk = sock->sk;
53962306a36Sopenharmony_ci	int err = 0;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (!addr || addr_len < sizeof(struct sockaddr_sco) ||
54262306a36Sopenharmony_ci	    addr->sa_family != AF_BLUETOOTH)
54362306a36Sopenharmony_ci		return -EINVAL;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	lock_sock(sk);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (sk->sk_state != BT_OPEN) {
55062306a36Sopenharmony_ci		err = -EBADFD;
55162306a36Sopenharmony_ci		goto done;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	if (sk->sk_type != SOCK_SEQPACKET) {
55562306a36Sopenharmony_ci		err = -EINVAL;
55662306a36Sopenharmony_ci		goto done;
55762306a36Sopenharmony_ci	}
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	bacpy(&sco_pi(sk)->src, &sa->sco_bdaddr);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	sk->sk_state = BT_BOUND;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_cidone:
56462306a36Sopenharmony_ci	release_sock(sk);
56562306a36Sopenharmony_ci	return err;
56662306a36Sopenharmony_ci}
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_cistatic int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
56962306a36Sopenharmony_ci{
57062306a36Sopenharmony_ci	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
57162306a36Sopenharmony_ci	struct sock *sk = sock->sk;
57262306a36Sopenharmony_ci	int err;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	BT_DBG("sk %p", sk);
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	if (alen < sizeof(struct sockaddr_sco) ||
57762306a36Sopenharmony_ci	    addr->sa_family != AF_BLUETOOTH)
57862306a36Sopenharmony_ci		return -EINVAL;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND)
58162306a36Sopenharmony_ci		return -EBADFD;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	if (sk->sk_type != SOCK_SEQPACKET)
58462306a36Sopenharmony_ci		err = -EINVAL;
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	lock_sock(sk);
58762306a36Sopenharmony_ci	/* Set destination address and psm */
58862306a36Sopenharmony_ci	bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr);
58962306a36Sopenharmony_ci	release_sock(sk);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	err = sco_connect(sk);
59262306a36Sopenharmony_ci	if (err)
59362306a36Sopenharmony_ci		return err;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	lock_sock(sk);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	err = bt_sock_wait_state(sk, BT_CONNECTED,
59862306a36Sopenharmony_ci				 sock_sndtimeo(sk, flags & O_NONBLOCK));
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	release_sock(sk);
60162306a36Sopenharmony_ci	return err;
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic int sco_sock_listen(struct socket *sock, int backlog)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct sock *sk = sock->sk;
60762306a36Sopenharmony_ci	bdaddr_t *src = &sco_pi(sk)->src;
60862306a36Sopenharmony_ci	int err = 0;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	BT_DBG("sk %p backlog %d", sk, backlog);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	lock_sock(sk);
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	if (sk->sk_state != BT_BOUND) {
61562306a36Sopenharmony_ci		err = -EBADFD;
61662306a36Sopenharmony_ci		goto done;
61762306a36Sopenharmony_ci	}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	if (sk->sk_type != SOCK_SEQPACKET) {
62062306a36Sopenharmony_ci		err = -EINVAL;
62162306a36Sopenharmony_ci		goto done;
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	write_lock(&sco_sk_list.lock);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (__sco_get_sock_listen_by_addr(src)) {
62762306a36Sopenharmony_ci		err = -EADDRINUSE;
62862306a36Sopenharmony_ci		goto unlock;
62962306a36Sopenharmony_ci	}
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	sk->sk_max_ack_backlog = backlog;
63262306a36Sopenharmony_ci	sk->sk_ack_backlog = 0;
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	sk->sk_state = BT_LISTEN;
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ciunlock:
63762306a36Sopenharmony_ci	write_unlock(&sco_sk_list.lock);
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_cidone:
64062306a36Sopenharmony_ci	release_sock(sk);
64162306a36Sopenharmony_ci	return err;
64262306a36Sopenharmony_ci}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_cistatic int sco_sock_accept(struct socket *sock, struct socket *newsock,
64562306a36Sopenharmony_ci			   int flags, bool kern)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	DEFINE_WAIT_FUNC(wait, woken_wake_function);
64862306a36Sopenharmony_ci	struct sock *sk = sock->sk, *ch;
64962306a36Sopenharmony_ci	long timeo;
65062306a36Sopenharmony_ci	int err = 0;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	lock_sock(sk);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci	BT_DBG("sk %p timeo %ld", sk, timeo);
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/* Wait for an incoming connection. (wake-one). */
65962306a36Sopenharmony_ci	add_wait_queue_exclusive(sk_sleep(sk), &wait);
66062306a36Sopenharmony_ci	while (1) {
66162306a36Sopenharmony_ci		if (sk->sk_state != BT_LISTEN) {
66262306a36Sopenharmony_ci			err = -EBADFD;
66362306a36Sopenharmony_ci			break;
66462306a36Sopenharmony_ci		}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		ch = bt_accept_dequeue(sk, newsock);
66762306a36Sopenharmony_ci		if (ch)
66862306a36Sopenharmony_ci			break;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		if (!timeo) {
67162306a36Sopenharmony_ci			err = -EAGAIN;
67262306a36Sopenharmony_ci			break;
67362306a36Sopenharmony_ci		}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci		if (signal_pending(current)) {
67662306a36Sopenharmony_ci			err = sock_intr_errno(timeo);
67762306a36Sopenharmony_ci			break;
67862306a36Sopenharmony_ci		}
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci		release_sock(sk);
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci		timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo);
68362306a36Sopenharmony_ci		lock_sock(sk);
68462306a36Sopenharmony_ci	}
68562306a36Sopenharmony_ci	remove_wait_queue(sk_sleep(sk), &wait);
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (err)
68862306a36Sopenharmony_ci		goto done;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	newsock->state = SS_CONNECTED;
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	BT_DBG("new socket %p", ch);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_cidone:
69562306a36Sopenharmony_ci	release_sock(sk);
69662306a36Sopenharmony_ci	return err;
69762306a36Sopenharmony_ci}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_cistatic int sco_sock_getname(struct socket *sock, struct sockaddr *addr,
70062306a36Sopenharmony_ci			    int peer)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;
70362306a36Sopenharmony_ci	struct sock *sk = sock->sk;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	BT_DBG("sock %p, sk %p", sock, sk);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	addr->sa_family = AF_BLUETOOTH;
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	if (peer)
71062306a36Sopenharmony_ci		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->dst);
71162306a36Sopenharmony_ci	else
71262306a36Sopenharmony_ci		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->src);
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	return sizeof(struct sockaddr_sco);
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic int sco_sock_sendmsg(struct socket *sock, struct msghdr *msg,
71862306a36Sopenharmony_ci			    size_t len)
71962306a36Sopenharmony_ci{
72062306a36Sopenharmony_ci	struct sock *sk = sock->sk;
72162306a36Sopenharmony_ci	struct sk_buff *skb;
72262306a36Sopenharmony_ci	int err;
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	BT_DBG("sock %p, sk %p", sock, sk);
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	err = sock_error(sk);
72762306a36Sopenharmony_ci	if (err)
72862306a36Sopenharmony_ci		return err;
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	if (msg->msg_flags & MSG_OOB)
73162306a36Sopenharmony_ci		return -EOPNOTSUPP;
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	skb = bt_skb_sendmsg(sk, msg, len, len, 0, 0);
73462306a36Sopenharmony_ci	if (IS_ERR(skb))
73562306a36Sopenharmony_ci		return PTR_ERR(skb);
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	lock_sock(sk);
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	if (sk->sk_state == BT_CONNECTED)
74062306a36Sopenharmony_ci		err = sco_send_frame(sk, skb);
74162306a36Sopenharmony_ci	else
74262306a36Sopenharmony_ci		err = -ENOTCONN;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	release_sock(sk);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (err < 0)
74762306a36Sopenharmony_ci		kfree_skb(skb);
74862306a36Sopenharmony_ci	return err;
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_cistatic void sco_conn_defer_accept(struct hci_conn *conn, u16 setting)
75262306a36Sopenharmony_ci{
75362306a36Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
75462306a36Sopenharmony_ci
75562306a36Sopenharmony_ci	BT_DBG("conn %p", conn);
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	conn->state = BT_CONFIG;
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci	if (!lmp_esco_capable(hdev)) {
76062306a36Sopenharmony_ci		struct hci_cp_accept_conn_req cp;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci		bacpy(&cp.bdaddr, &conn->dst);
76362306a36Sopenharmony_ci		cp.role = 0x00; /* Ignored */
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci		hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp);
76662306a36Sopenharmony_ci	} else {
76762306a36Sopenharmony_ci		struct hci_cp_accept_sync_conn_req cp;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci		bacpy(&cp.bdaddr, &conn->dst);
77062306a36Sopenharmony_ci		cp.pkt_type = cpu_to_le16(conn->pkt_type);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci		cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
77362306a36Sopenharmony_ci		cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
77462306a36Sopenharmony_ci		cp.content_format = cpu_to_le16(setting);
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci		switch (setting & SCO_AIRMODE_MASK) {
77762306a36Sopenharmony_ci		case SCO_AIRMODE_TRANSP:
77862306a36Sopenharmony_ci			if (conn->pkt_type & ESCO_2EV3)
77962306a36Sopenharmony_ci				cp.max_latency = cpu_to_le16(0x0008);
78062306a36Sopenharmony_ci			else
78162306a36Sopenharmony_ci				cp.max_latency = cpu_to_le16(0x000D);
78262306a36Sopenharmony_ci			cp.retrans_effort = 0x02;
78362306a36Sopenharmony_ci			break;
78462306a36Sopenharmony_ci		case SCO_AIRMODE_CVSD:
78562306a36Sopenharmony_ci			cp.max_latency = cpu_to_le16(0xffff);
78662306a36Sopenharmony_ci			cp.retrans_effort = 0xff;
78762306a36Sopenharmony_ci			break;
78862306a36Sopenharmony_ci		default:
78962306a36Sopenharmony_ci			/* use CVSD settings as fallback */
79062306a36Sopenharmony_ci			cp.max_latency = cpu_to_le16(0xffff);
79162306a36Sopenharmony_ci			cp.retrans_effort = 0xff;
79262306a36Sopenharmony_ci			break;
79362306a36Sopenharmony_ci		}
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
79662306a36Sopenharmony_ci			     sizeof(cp), &cp);
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cistatic int sco_sock_recvmsg(struct socket *sock, struct msghdr *msg,
80162306a36Sopenharmony_ci			    size_t len, int flags)
80262306a36Sopenharmony_ci{
80362306a36Sopenharmony_ci	struct sock *sk = sock->sk;
80462306a36Sopenharmony_ci	struct sco_pinfo *pi = sco_pi(sk);
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	lock_sock(sk);
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	if (sk->sk_state == BT_CONNECT2 &&
80962306a36Sopenharmony_ci	    test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) {
81062306a36Sopenharmony_ci		sco_conn_defer_accept(pi->conn->hcon, pi->setting);
81162306a36Sopenharmony_ci		sk->sk_state = BT_CONFIG;
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		release_sock(sk);
81462306a36Sopenharmony_ci		return 0;
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	release_sock(sk);
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	return bt_sock_recvmsg(sock, msg, len, flags);
82062306a36Sopenharmony_ci}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_cistatic int sco_sock_setsockopt(struct socket *sock, int level, int optname,
82362306a36Sopenharmony_ci			       sockptr_t optval, unsigned int optlen)
82462306a36Sopenharmony_ci{
82562306a36Sopenharmony_ci	struct sock *sk = sock->sk;
82662306a36Sopenharmony_ci	int len, err = 0;
82762306a36Sopenharmony_ci	struct bt_voice voice;
82862306a36Sopenharmony_ci	u32 opt;
82962306a36Sopenharmony_ci	struct bt_codecs *codecs;
83062306a36Sopenharmony_ci	struct hci_dev *hdev;
83162306a36Sopenharmony_ci	__u8 buffer[255];
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	BT_DBG("sk %p", sk);
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci	lock_sock(sk);
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	switch (optname) {
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	case BT_DEFER_SETUP:
84062306a36Sopenharmony_ci		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
84162306a36Sopenharmony_ci			err = -EINVAL;
84262306a36Sopenharmony_ci			break;
84362306a36Sopenharmony_ci		}
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci		if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
84662306a36Sopenharmony_ci			err = -EFAULT;
84762306a36Sopenharmony_ci			break;
84862306a36Sopenharmony_ci		}
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci		if (opt)
85162306a36Sopenharmony_ci			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
85262306a36Sopenharmony_ci		else
85362306a36Sopenharmony_ci			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags);
85462306a36Sopenharmony_ci		break;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	case BT_VOICE:
85762306a36Sopenharmony_ci		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
85862306a36Sopenharmony_ci		    sk->sk_state != BT_CONNECT2) {
85962306a36Sopenharmony_ci			err = -EINVAL;
86062306a36Sopenharmony_ci			break;
86162306a36Sopenharmony_ci		}
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci		voice.setting = sco_pi(sk)->setting;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		len = min_t(unsigned int, sizeof(voice), optlen);
86662306a36Sopenharmony_ci		if (copy_from_sockptr(&voice, optval, len)) {
86762306a36Sopenharmony_ci			err = -EFAULT;
86862306a36Sopenharmony_ci			break;
86962306a36Sopenharmony_ci		}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci		/* Explicitly check for these values */
87262306a36Sopenharmony_ci		if (voice.setting != BT_VOICE_TRANSPARENT &&
87362306a36Sopenharmony_ci		    voice.setting != BT_VOICE_CVSD_16BIT) {
87462306a36Sopenharmony_ci			err = -EINVAL;
87562306a36Sopenharmony_ci			break;
87662306a36Sopenharmony_ci		}
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci		sco_pi(sk)->setting = voice.setting;
87962306a36Sopenharmony_ci		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
88062306a36Sopenharmony_ci				     BDADDR_BREDR);
88162306a36Sopenharmony_ci		if (!hdev) {
88262306a36Sopenharmony_ci			err = -EBADFD;
88362306a36Sopenharmony_ci			break;
88462306a36Sopenharmony_ci		}
88562306a36Sopenharmony_ci		if (enhanced_sync_conn_capable(hdev) &&
88662306a36Sopenharmony_ci		    voice.setting == BT_VOICE_TRANSPARENT)
88762306a36Sopenharmony_ci			sco_pi(sk)->codec.id = BT_CODEC_TRANSPARENT;
88862306a36Sopenharmony_ci		hci_dev_put(hdev);
88962306a36Sopenharmony_ci		break;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_ci	case BT_PKT_STATUS:
89262306a36Sopenharmony_ci		if (copy_from_sockptr(&opt, optval, sizeof(u32))) {
89362306a36Sopenharmony_ci			err = -EFAULT;
89462306a36Sopenharmony_ci			break;
89562306a36Sopenharmony_ci		}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci		if (opt)
89862306a36Sopenharmony_ci			set_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
89962306a36Sopenharmony_ci		else
90062306a36Sopenharmony_ci			clear_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags);
90162306a36Sopenharmony_ci		break;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	case BT_CODEC:
90462306a36Sopenharmony_ci		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND &&
90562306a36Sopenharmony_ci		    sk->sk_state != BT_CONNECT2) {
90662306a36Sopenharmony_ci			err = -EINVAL;
90762306a36Sopenharmony_ci			break;
90862306a36Sopenharmony_ci		}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
91162306a36Sopenharmony_ci				     BDADDR_BREDR);
91262306a36Sopenharmony_ci		if (!hdev) {
91362306a36Sopenharmony_ci			err = -EBADFD;
91462306a36Sopenharmony_ci			break;
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci		if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
91862306a36Sopenharmony_ci			hci_dev_put(hdev);
91962306a36Sopenharmony_ci			err = -EOPNOTSUPP;
92062306a36Sopenharmony_ci			break;
92162306a36Sopenharmony_ci		}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci		if (!hdev->get_data_path_id) {
92462306a36Sopenharmony_ci			hci_dev_put(hdev);
92562306a36Sopenharmony_ci			err = -EOPNOTSUPP;
92662306a36Sopenharmony_ci			break;
92762306a36Sopenharmony_ci		}
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci		if (optlen < sizeof(struct bt_codecs) ||
93062306a36Sopenharmony_ci		    optlen > sizeof(buffer)) {
93162306a36Sopenharmony_ci			hci_dev_put(hdev);
93262306a36Sopenharmony_ci			err = -EINVAL;
93362306a36Sopenharmony_ci			break;
93462306a36Sopenharmony_ci		}
93562306a36Sopenharmony_ci
93662306a36Sopenharmony_ci		if (copy_from_sockptr(buffer, optval, optlen)) {
93762306a36Sopenharmony_ci			hci_dev_put(hdev);
93862306a36Sopenharmony_ci			err = -EFAULT;
93962306a36Sopenharmony_ci			break;
94062306a36Sopenharmony_ci		}
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci		codecs = (void *)buffer;
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_ci		if (codecs->num_codecs > 1) {
94562306a36Sopenharmony_ci			hci_dev_put(hdev);
94662306a36Sopenharmony_ci			err = -EINVAL;
94762306a36Sopenharmony_ci			break;
94862306a36Sopenharmony_ci		}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci		sco_pi(sk)->codec = codecs->codecs[0];
95162306a36Sopenharmony_ci		hci_dev_put(hdev);
95262306a36Sopenharmony_ci		break;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	default:
95562306a36Sopenharmony_ci		err = -ENOPROTOOPT;
95662306a36Sopenharmony_ci		break;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci	release_sock(sk);
96062306a36Sopenharmony_ci	return err;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_cistatic int sco_sock_getsockopt_old(struct socket *sock, int optname,
96462306a36Sopenharmony_ci				   char __user *optval, int __user *optlen)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct sock *sk = sock->sk;
96762306a36Sopenharmony_ci	struct sco_options opts;
96862306a36Sopenharmony_ci	struct sco_conninfo cinfo;
96962306a36Sopenharmony_ci	int len, err = 0;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	BT_DBG("sk %p", sk);
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	if (get_user(len, optlen))
97462306a36Sopenharmony_ci		return -EFAULT;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	lock_sock(sk);
97762306a36Sopenharmony_ci
97862306a36Sopenharmony_ci	switch (optname) {
97962306a36Sopenharmony_ci	case SCO_OPTIONS:
98062306a36Sopenharmony_ci		if (sk->sk_state != BT_CONNECTED &&
98162306a36Sopenharmony_ci		    !(sk->sk_state == BT_CONNECT2 &&
98262306a36Sopenharmony_ci		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
98362306a36Sopenharmony_ci			err = -ENOTCONN;
98462306a36Sopenharmony_ci			break;
98562306a36Sopenharmony_ci		}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		opts.mtu = sco_pi(sk)->conn->mtu;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci		BT_DBG("mtu %u", opts.mtu);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci		len = min_t(unsigned int, len, sizeof(opts));
99262306a36Sopenharmony_ci		if (copy_to_user(optval, (char *)&opts, len))
99362306a36Sopenharmony_ci			err = -EFAULT;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci		break;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	case SCO_CONNINFO:
99862306a36Sopenharmony_ci		if (sk->sk_state != BT_CONNECTED &&
99962306a36Sopenharmony_ci		    !(sk->sk_state == BT_CONNECT2 &&
100062306a36Sopenharmony_ci		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {
100162306a36Sopenharmony_ci			err = -ENOTCONN;
100262306a36Sopenharmony_ci			break;
100362306a36Sopenharmony_ci		}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci		memset(&cinfo, 0, sizeof(cinfo));
100662306a36Sopenharmony_ci		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;
100762306a36Sopenharmony_ci		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci		len = min_t(unsigned int, len, sizeof(cinfo));
101062306a36Sopenharmony_ci		if (copy_to_user(optval, (char *)&cinfo, len))
101162306a36Sopenharmony_ci			err = -EFAULT;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci		break;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	default:
101662306a36Sopenharmony_ci		err = -ENOPROTOOPT;
101762306a36Sopenharmony_ci		break;
101862306a36Sopenharmony_ci	}
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	release_sock(sk);
102162306a36Sopenharmony_ci	return err;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_cistatic int sco_sock_getsockopt(struct socket *sock, int level, int optname,
102562306a36Sopenharmony_ci			       char __user *optval, int __user *optlen)
102662306a36Sopenharmony_ci{
102762306a36Sopenharmony_ci	struct sock *sk = sock->sk;
102862306a36Sopenharmony_ci	int len, err = 0;
102962306a36Sopenharmony_ci	struct bt_voice voice;
103062306a36Sopenharmony_ci	u32 phys;
103162306a36Sopenharmony_ci	int buf_len;
103262306a36Sopenharmony_ci	struct codec_list *c;
103362306a36Sopenharmony_ci	u8 num_codecs, i, __user *ptr;
103462306a36Sopenharmony_ci	struct hci_dev *hdev;
103562306a36Sopenharmony_ci	struct hci_codec_caps *caps;
103662306a36Sopenharmony_ci	struct bt_codec codec;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	BT_DBG("sk %p", sk);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	if (level == SOL_SCO)
104162306a36Sopenharmony_ci		return sco_sock_getsockopt_old(sock, optname, optval, optlen);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (get_user(len, optlen))
104462306a36Sopenharmony_ci		return -EFAULT;
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_ci	lock_sock(sk);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	switch (optname) {
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	case BT_DEFER_SETUP:
105162306a36Sopenharmony_ci		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
105262306a36Sopenharmony_ci			err = -EINVAL;
105362306a36Sopenharmony_ci			break;
105462306a36Sopenharmony_ci		}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags),
105762306a36Sopenharmony_ci			     (u32 __user *)optval))
105862306a36Sopenharmony_ci			err = -EFAULT;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		break;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	case BT_VOICE:
106362306a36Sopenharmony_ci		voice.setting = sco_pi(sk)->setting;
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_ci		len = min_t(unsigned int, len, sizeof(voice));
106662306a36Sopenharmony_ci		if (copy_to_user(optval, (char *)&voice, len))
106762306a36Sopenharmony_ci			err = -EFAULT;
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci		break;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	case BT_PHY:
107262306a36Sopenharmony_ci		if (sk->sk_state != BT_CONNECTED) {
107362306a36Sopenharmony_ci			err = -ENOTCONN;
107462306a36Sopenharmony_ci			break;
107562306a36Sopenharmony_ci		}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_ci		phys = hci_conn_get_phy(sco_pi(sk)->conn->hcon);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci		if (put_user(phys, (u32 __user *) optval))
108062306a36Sopenharmony_ci			err = -EFAULT;
108162306a36Sopenharmony_ci		break;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	case BT_PKT_STATUS:
108462306a36Sopenharmony_ci		if (put_user(test_bit(BT_SK_PKT_STATUS, &bt_sk(sk)->flags),
108562306a36Sopenharmony_ci			     (int __user *)optval))
108662306a36Sopenharmony_ci			err = -EFAULT;
108762306a36Sopenharmony_ci		break;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	case BT_SNDMTU:
109062306a36Sopenharmony_ci	case BT_RCVMTU:
109162306a36Sopenharmony_ci		if (sk->sk_state != BT_CONNECTED) {
109262306a36Sopenharmony_ci			err = -ENOTCONN;
109362306a36Sopenharmony_ci			break;
109462306a36Sopenharmony_ci		}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci		if (put_user(sco_pi(sk)->conn->mtu, (u32 __user *)optval))
109762306a36Sopenharmony_ci			err = -EFAULT;
109862306a36Sopenharmony_ci		break;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	case BT_CODEC:
110162306a36Sopenharmony_ci		num_codecs = 0;
110262306a36Sopenharmony_ci		buf_len = 0;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci		hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
110562306a36Sopenharmony_ci		if (!hdev) {
110662306a36Sopenharmony_ci			err = -EBADFD;
110762306a36Sopenharmony_ci			break;
110862306a36Sopenharmony_ci		}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
111162306a36Sopenharmony_ci			hci_dev_put(hdev);
111262306a36Sopenharmony_ci			err = -EOPNOTSUPP;
111362306a36Sopenharmony_ci			break;
111462306a36Sopenharmony_ci		}
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci		if (!hdev->get_data_path_id) {
111762306a36Sopenharmony_ci			hci_dev_put(hdev);
111862306a36Sopenharmony_ci			err = -EOPNOTSUPP;
111962306a36Sopenharmony_ci			break;
112062306a36Sopenharmony_ci		}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci		release_sock(sk);
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci		/* find total buffer size required to copy codec + caps */
112562306a36Sopenharmony_ci		hci_dev_lock(hdev);
112662306a36Sopenharmony_ci		list_for_each_entry(c, &hdev->local_codecs, list) {
112762306a36Sopenharmony_ci			if (c->transport != HCI_TRANSPORT_SCO_ESCO)
112862306a36Sopenharmony_ci				continue;
112962306a36Sopenharmony_ci			num_codecs++;
113062306a36Sopenharmony_ci			for (i = 0, caps = c->caps; i < c->num_caps; i++) {
113162306a36Sopenharmony_ci				buf_len += 1 + caps->len;
113262306a36Sopenharmony_ci				caps = (void *)&caps->data[caps->len];
113362306a36Sopenharmony_ci			}
113462306a36Sopenharmony_ci			buf_len += sizeof(struct bt_codec);
113562306a36Sopenharmony_ci		}
113662306a36Sopenharmony_ci		hci_dev_unlock(hdev);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci		buf_len += sizeof(struct bt_codecs);
113962306a36Sopenharmony_ci		if (buf_len > len) {
114062306a36Sopenharmony_ci			hci_dev_put(hdev);
114162306a36Sopenharmony_ci			return -ENOBUFS;
114262306a36Sopenharmony_ci		}
114362306a36Sopenharmony_ci		ptr = optval;
114462306a36Sopenharmony_ci
114562306a36Sopenharmony_ci		if (put_user(num_codecs, ptr)) {
114662306a36Sopenharmony_ci			hci_dev_put(hdev);
114762306a36Sopenharmony_ci			return -EFAULT;
114862306a36Sopenharmony_ci		}
114962306a36Sopenharmony_ci		ptr += sizeof(num_codecs);
115062306a36Sopenharmony_ci
115162306a36Sopenharmony_ci		/* Iterate all the codecs supported over SCO and populate
115262306a36Sopenharmony_ci		 * codec data
115362306a36Sopenharmony_ci		 */
115462306a36Sopenharmony_ci		hci_dev_lock(hdev);
115562306a36Sopenharmony_ci		list_for_each_entry(c, &hdev->local_codecs, list) {
115662306a36Sopenharmony_ci			if (c->transport != HCI_TRANSPORT_SCO_ESCO)
115762306a36Sopenharmony_ci				continue;
115862306a36Sopenharmony_ci
115962306a36Sopenharmony_ci			codec.id = c->id;
116062306a36Sopenharmony_ci			codec.cid = c->cid;
116162306a36Sopenharmony_ci			codec.vid = c->vid;
116262306a36Sopenharmony_ci			err = hdev->get_data_path_id(hdev, &codec.data_path);
116362306a36Sopenharmony_ci			if (err < 0)
116462306a36Sopenharmony_ci				break;
116562306a36Sopenharmony_ci			codec.num_caps = c->num_caps;
116662306a36Sopenharmony_ci			if (copy_to_user(ptr, &codec, sizeof(codec))) {
116762306a36Sopenharmony_ci				err = -EFAULT;
116862306a36Sopenharmony_ci				break;
116962306a36Sopenharmony_ci			}
117062306a36Sopenharmony_ci			ptr += sizeof(codec);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci			/* find codec capabilities data length */
117362306a36Sopenharmony_ci			len = 0;
117462306a36Sopenharmony_ci			for (i = 0, caps = c->caps; i < c->num_caps; i++) {
117562306a36Sopenharmony_ci				len += 1 + caps->len;
117662306a36Sopenharmony_ci				caps = (void *)&caps->data[caps->len];
117762306a36Sopenharmony_ci			}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci			/* copy codec capabilities data */
118062306a36Sopenharmony_ci			if (len && copy_to_user(ptr, c->caps, len)) {
118162306a36Sopenharmony_ci				err = -EFAULT;
118262306a36Sopenharmony_ci				break;
118362306a36Sopenharmony_ci			}
118462306a36Sopenharmony_ci			ptr += len;
118562306a36Sopenharmony_ci		}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci		hci_dev_unlock(hdev);
118862306a36Sopenharmony_ci		hci_dev_put(hdev);
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci		lock_sock(sk);
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci		if (!err && put_user(buf_len, optlen))
119362306a36Sopenharmony_ci			err = -EFAULT;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci		break;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	default:
119862306a36Sopenharmony_ci		err = -ENOPROTOOPT;
119962306a36Sopenharmony_ci		break;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	release_sock(sk);
120362306a36Sopenharmony_ci	return err;
120462306a36Sopenharmony_ci}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_cistatic int sco_sock_shutdown(struct socket *sock, int how)
120762306a36Sopenharmony_ci{
120862306a36Sopenharmony_ci	struct sock *sk = sock->sk;
120962306a36Sopenharmony_ci	int err = 0;
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci	BT_DBG("sock %p, sk %p", sock, sk);
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	if (!sk)
121462306a36Sopenharmony_ci		return 0;
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	sock_hold(sk);
121762306a36Sopenharmony_ci	lock_sock(sk);
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci	if (!sk->sk_shutdown) {
122062306a36Sopenharmony_ci		sk->sk_shutdown = SHUTDOWN_MASK;
122162306a36Sopenharmony_ci		sco_sock_clear_timer(sk);
122262306a36Sopenharmony_ci		__sco_sock_close(sk);
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime &&
122562306a36Sopenharmony_ci		    !(current->flags & PF_EXITING))
122662306a36Sopenharmony_ci			err = bt_sock_wait_state(sk, BT_CLOSED,
122762306a36Sopenharmony_ci						 sk->sk_lingertime);
122862306a36Sopenharmony_ci	}
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	release_sock(sk);
123162306a36Sopenharmony_ci	sock_put(sk);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	return err;
123462306a36Sopenharmony_ci}
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_cistatic int sco_sock_release(struct socket *sock)
123762306a36Sopenharmony_ci{
123862306a36Sopenharmony_ci	struct sock *sk = sock->sk;
123962306a36Sopenharmony_ci	int err = 0;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	BT_DBG("sock %p, sk %p", sock, sk);
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	if (!sk)
124462306a36Sopenharmony_ci		return 0;
124562306a36Sopenharmony_ci
124662306a36Sopenharmony_ci	sco_sock_close(sk);
124762306a36Sopenharmony_ci
124862306a36Sopenharmony_ci	if (sock_flag(sk, SOCK_LINGER) && READ_ONCE(sk->sk_lingertime) &&
124962306a36Sopenharmony_ci	    !(current->flags & PF_EXITING)) {
125062306a36Sopenharmony_ci		lock_sock(sk);
125162306a36Sopenharmony_ci		err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
125262306a36Sopenharmony_ci		release_sock(sk);
125362306a36Sopenharmony_ci	}
125462306a36Sopenharmony_ci
125562306a36Sopenharmony_ci	sock_orphan(sk);
125662306a36Sopenharmony_ci	sco_sock_kill(sk);
125762306a36Sopenharmony_ci	return err;
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic void sco_conn_ready(struct sco_conn *conn)
126162306a36Sopenharmony_ci{
126262306a36Sopenharmony_ci	struct sock *parent;
126362306a36Sopenharmony_ci	struct sock *sk = conn->sk;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	BT_DBG("conn %p", conn);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	if (sk) {
126862306a36Sopenharmony_ci		lock_sock(sk);
126962306a36Sopenharmony_ci		sco_sock_clear_timer(sk);
127062306a36Sopenharmony_ci		sk->sk_state = BT_CONNECTED;
127162306a36Sopenharmony_ci		sk->sk_state_change(sk);
127262306a36Sopenharmony_ci		release_sock(sk);
127362306a36Sopenharmony_ci	} else {
127462306a36Sopenharmony_ci		sco_conn_lock(conn);
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci		if (!conn->hcon) {
127762306a36Sopenharmony_ci			sco_conn_unlock(conn);
127862306a36Sopenharmony_ci			return;
127962306a36Sopenharmony_ci		}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci		parent = sco_get_sock_listen(&conn->hcon->src);
128262306a36Sopenharmony_ci		if (!parent) {
128362306a36Sopenharmony_ci			sco_conn_unlock(conn);
128462306a36Sopenharmony_ci			return;
128562306a36Sopenharmony_ci		}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci		lock_sock(parent);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci		sk = sco_sock_alloc(sock_net(parent), NULL,
129062306a36Sopenharmony_ci				    BTPROTO_SCO, GFP_ATOMIC, 0);
129162306a36Sopenharmony_ci		if (!sk) {
129262306a36Sopenharmony_ci			release_sock(parent);
129362306a36Sopenharmony_ci			sco_conn_unlock(conn);
129462306a36Sopenharmony_ci			return;
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci
129762306a36Sopenharmony_ci		sco_sock_init(sk, parent);
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci		bacpy(&sco_pi(sk)->src, &conn->hcon->src);
130062306a36Sopenharmony_ci		bacpy(&sco_pi(sk)->dst, &conn->hcon->dst);
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		hci_conn_hold(conn->hcon);
130362306a36Sopenharmony_ci		__sco_chan_add(conn, sk, parent);
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci		if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags))
130662306a36Sopenharmony_ci			sk->sk_state = BT_CONNECT2;
130762306a36Sopenharmony_ci		else
130862306a36Sopenharmony_ci			sk->sk_state = BT_CONNECTED;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci		/* Wake up parent */
131162306a36Sopenharmony_ci		parent->sk_data_ready(parent);
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ci		release_sock(parent);
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_ci		sco_conn_unlock(conn);
131662306a36Sopenharmony_ci	}
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci/* ----- SCO interface with lower layer (HCI) ----- */
132062306a36Sopenharmony_ciint sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	struct sock *sk;
132362306a36Sopenharmony_ci	int lm = 0;
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci	BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ci	/* Find listening sockets */
132862306a36Sopenharmony_ci	read_lock(&sco_sk_list.lock);
132962306a36Sopenharmony_ci	sk_for_each(sk, &sco_sk_list.head) {
133062306a36Sopenharmony_ci		if (sk->sk_state != BT_LISTEN)
133162306a36Sopenharmony_ci			continue;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci		if (!bacmp(&sco_pi(sk)->src, &hdev->bdaddr) ||
133462306a36Sopenharmony_ci		    !bacmp(&sco_pi(sk)->src, BDADDR_ANY)) {
133562306a36Sopenharmony_ci			lm |= HCI_LM_ACCEPT;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci			if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))
133862306a36Sopenharmony_ci				*flags |= HCI_PROTO_DEFER;
133962306a36Sopenharmony_ci			break;
134062306a36Sopenharmony_ci		}
134162306a36Sopenharmony_ci	}
134262306a36Sopenharmony_ci	read_unlock(&sco_sk_list.lock);
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	return lm;
134562306a36Sopenharmony_ci}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_cistatic void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
134862306a36Sopenharmony_ci{
134962306a36Sopenharmony_ci	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
135062306a36Sopenharmony_ci		return;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	BT_DBG("hcon %p bdaddr %pMR status %u", hcon, &hcon->dst, status);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	if (!status) {
135562306a36Sopenharmony_ci		struct sco_conn *conn;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci		conn = sco_conn_add(hcon);
135862306a36Sopenharmony_ci		if (conn)
135962306a36Sopenharmony_ci			sco_conn_ready(conn);
136062306a36Sopenharmony_ci	} else
136162306a36Sopenharmony_ci		sco_conn_del(hcon, bt_to_errno(status));
136262306a36Sopenharmony_ci}
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_cistatic void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
136762306a36Sopenharmony_ci		return;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	BT_DBG("hcon %p reason %d", hcon, reason);
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	sco_conn_del(hcon, bt_to_errno(reason));
137262306a36Sopenharmony_ci}
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_civoid sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
137562306a36Sopenharmony_ci{
137662306a36Sopenharmony_ci	struct sco_conn *conn = hcon->sco_data;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	if (!conn)
137962306a36Sopenharmony_ci		goto drop;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	BT_DBG("conn %p len %u", conn, skb->len);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	if (skb->len) {
138462306a36Sopenharmony_ci		sco_recv_frame(conn, skb);
138562306a36Sopenharmony_ci		return;
138662306a36Sopenharmony_ci	}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cidrop:
138962306a36Sopenharmony_ci	kfree_skb(skb);
139062306a36Sopenharmony_ci}
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_cistatic struct hci_cb sco_cb = {
139362306a36Sopenharmony_ci	.name		= "SCO",
139462306a36Sopenharmony_ci	.connect_cfm	= sco_connect_cfm,
139562306a36Sopenharmony_ci	.disconn_cfm	= sco_disconn_cfm,
139662306a36Sopenharmony_ci};
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_cistatic int sco_debugfs_show(struct seq_file *f, void *p)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	struct sock *sk;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	read_lock(&sco_sk_list.lock);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci	sk_for_each(sk, &sco_sk_list.head) {
140562306a36Sopenharmony_ci		seq_printf(f, "%pMR %pMR %d\n", &sco_pi(sk)->src,
140662306a36Sopenharmony_ci			   &sco_pi(sk)->dst, sk->sk_state);
140762306a36Sopenharmony_ci	}
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	read_unlock(&sco_sk_list.lock);
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	return 0;
141262306a36Sopenharmony_ci}
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(sco_debugfs);
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_cistatic struct dentry *sco_debugfs;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_cistatic const struct proto_ops sco_sock_ops = {
141962306a36Sopenharmony_ci	.family		= PF_BLUETOOTH,
142062306a36Sopenharmony_ci	.owner		= THIS_MODULE,
142162306a36Sopenharmony_ci	.release	= sco_sock_release,
142262306a36Sopenharmony_ci	.bind		= sco_sock_bind,
142362306a36Sopenharmony_ci	.connect	= sco_sock_connect,
142462306a36Sopenharmony_ci	.listen		= sco_sock_listen,
142562306a36Sopenharmony_ci	.accept		= sco_sock_accept,
142662306a36Sopenharmony_ci	.getname	= sco_sock_getname,
142762306a36Sopenharmony_ci	.sendmsg	= sco_sock_sendmsg,
142862306a36Sopenharmony_ci	.recvmsg	= sco_sock_recvmsg,
142962306a36Sopenharmony_ci	.poll		= bt_sock_poll,
143062306a36Sopenharmony_ci	.ioctl		= bt_sock_ioctl,
143162306a36Sopenharmony_ci	.gettstamp	= sock_gettstamp,
143262306a36Sopenharmony_ci	.mmap		= sock_no_mmap,
143362306a36Sopenharmony_ci	.socketpair	= sock_no_socketpair,
143462306a36Sopenharmony_ci	.shutdown	= sco_sock_shutdown,
143562306a36Sopenharmony_ci	.setsockopt	= sco_sock_setsockopt,
143662306a36Sopenharmony_ci	.getsockopt	= sco_sock_getsockopt
143762306a36Sopenharmony_ci};
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_cistatic const struct net_proto_family sco_sock_family_ops = {
144062306a36Sopenharmony_ci	.family	= PF_BLUETOOTH,
144162306a36Sopenharmony_ci	.owner	= THIS_MODULE,
144262306a36Sopenharmony_ci	.create	= sco_sock_create,
144362306a36Sopenharmony_ci};
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ciint __init sco_init(void)
144662306a36Sopenharmony_ci{
144762306a36Sopenharmony_ci	int err;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct sockaddr_sco) > sizeof(struct sockaddr));
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	err = proto_register(&sco_proto, 0);
145262306a36Sopenharmony_ci	if (err < 0)
145362306a36Sopenharmony_ci		return err;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	err = bt_sock_register(BTPROTO_SCO, &sco_sock_family_ops);
145662306a36Sopenharmony_ci	if (err < 0) {
145762306a36Sopenharmony_ci		BT_ERR("SCO socket registration failed");
145862306a36Sopenharmony_ci		goto error;
145962306a36Sopenharmony_ci	}
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	err = bt_procfs_init(&init_net, "sco", &sco_sk_list, NULL);
146262306a36Sopenharmony_ci	if (err < 0) {
146362306a36Sopenharmony_ci		BT_ERR("Failed to create SCO proc file");
146462306a36Sopenharmony_ci		bt_sock_unregister(BTPROTO_SCO);
146562306a36Sopenharmony_ci		goto error;
146662306a36Sopenharmony_ci	}
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	BT_INFO("SCO socket layer initialized");
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	hci_register_cb(&sco_cb);
147162306a36Sopenharmony_ci
147262306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(bt_debugfs))
147362306a36Sopenharmony_ci		return 0;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci	sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
147662306a36Sopenharmony_ci					  NULL, &sco_debugfs_fops);
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	return 0;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_cierror:
148162306a36Sopenharmony_ci	proto_unregister(&sco_proto);
148262306a36Sopenharmony_ci	return err;
148362306a36Sopenharmony_ci}
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_civoid sco_exit(void)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	bt_procfs_cleanup(&init_net, "sco");
148862306a36Sopenharmony_ci
148962306a36Sopenharmony_ci	debugfs_remove(sco_debugfs);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	hci_unregister_cb(&sco_cb);
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	bt_sock_unregister(BTPROTO_SCO);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	proto_unregister(&sco_proto);
149662306a36Sopenharmony_ci}
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_cimodule_param(disable_esco, bool, 0644);
149962306a36Sopenharmony_ciMODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation");
1500