diff options
Diffstat (limited to 'net/bluetooth/sco.c')
| -rw-r--r-- | net/bluetooth/sco.c | 509 | 
1 files changed, 316 insertions, 193 deletions
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index d0927d1fdad..c06dbd3938e 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -25,34 +25,14 @@  /* Bluetooth SCO sockets. */  #include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/socket.h> -#include <linux/skbuff.h> -#include <linux/device.h>  #include <linux/debugfs.h>  #include <linux/seq_file.h> -#include <linux/list.h> -#include <net/sock.h> - -#include <asm/system.h> -#include <asm/uaccess.h>  #include <net/bluetooth/bluetooth.h>  #include <net/bluetooth/hci_core.h>  #include <net/bluetooth/sco.h> -#define VERSION "0.6" - -static int disable_esco = 0; +static bool disable_esco;  static const struct proto_ops sco_sock_ops; @@ -63,8 +43,6 @@ static struct bt_sock_list sco_sk_list = {  static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent);  static void sco_chan_del(struct sock *sk, int err); -static int  sco_conn_del(struct hci_conn *conn, int err); -  static void sco_sock_close(struct sock *sk);  static void sco_sock_kill(struct sock *sk); @@ -97,15 +75,15 @@ static void sco_sock_clear_timer(struct sock *sk)  }  /* ---- SCO connections ---- */ -static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) +static struct sco_conn *sco_conn_add(struct hci_conn *hcon)  {  	struct hci_dev *hdev = hcon->hdev;  	struct sco_conn *conn = hcon->sco_data; -	if (conn || status) +	if (conn)  		return conn; -	conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC); +	conn = kzalloc(sizeof(struct sco_conn), GFP_KERNEL);  	if (!conn)  		return NULL; @@ -114,9 +92,6 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)  	hcon->sco_data = conn;  	conn->hcon = hcon; -	conn->src = &hdev->bdaddr; -	conn->dst = &hcon->dst; -  	if (hdev->sco_mtu > 0)  		conn->mtu = hdev->sco_mtu;  	else @@ -127,7 +102,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status)  	return conn;  } -static inline struct sock *sco_chan_get(struct sco_conn *conn) +static struct sock *sco_chan_get(struct sco_conn *conn)  {  	struct sock *sk = NULL;  	sco_conn_lock(conn); @@ -138,16 +113,17 @@ static inline struct sock *sco_chan_get(struct sco_conn *conn)  static int sco_conn_del(struct hci_conn *hcon, int err)  { -	struct sco_conn *conn; +	struct sco_conn *conn = hcon->sco_data;  	struct sock *sk; -	if (!(conn = hcon->sco_data)) +	if (!conn)  		return 0;  	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);  	/* Kill socket */ -	if ((sk = sco_chan_get(conn))) { +	sk = sco_chan_get(conn); +	if (sk) {  		bh_lock_sock(sk);  		sco_sock_clear_timer(sk);  		sco_chan_del(sk, err); @@ -160,7 +136,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err)  	return 0;  } -static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +static int sco_chan_add(struct sco_conn *conn, struct sock *sk, +			struct sock *parent)  {  	int err = 0; @@ -176,39 +153,46 @@ static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct so  static int sco_connect(struct sock *sk)  { -	bdaddr_t *src = &bt_sk(sk)->src; -	bdaddr_t *dst = &bt_sk(sk)->dst;  	struct sco_conn *conn;  	struct hci_conn *hcon;  	struct hci_dev  *hdev;  	int err, type; -	BT_DBG("%s -> %s", batostr(src), batostr(dst)); +	BT_DBG("%pMR -> %pMR", &sco_pi(sk)->src, &sco_pi(sk)->dst); -	if (!(hdev = hci_get_route(dst, src))) +	hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src); +	if (!hdev)  		return -EHOSTUNREACH; -	hci_dev_lock_bh(hdev); - -	err = -ENOMEM; +	hci_dev_lock(hdev);  	if (lmp_esco_capable(hdev) && !disable_esco)  		type = ESCO_LINK;  	else  		type = SCO_LINK; -	hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); -	if (!hcon) +	if (sco_pi(sk)->setting == BT_VOICE_TRANSPARENT && +	    (!lmp_transp_capable(hdev) || !lmp_esco_capable(hdev))) { +		err = -EOPNOTSUPP; +		goto done; +	} + +	hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst, +			       sco_pi(sk)->setting); +	if (IS_ERR(hcon)) { +		err = PTR_ERR(hcon);  		goto done; +	} -	conn = sco_conn_add(hcon, 0); +	conn = sco_conn_add(hcon);  	if (!conn) { -		hci_conn_put(hcon); +		hci_conn_drop(hcon); +		err = -ENOMEM;  		goto done;  	}  	/* Update source addr of the socket */ -	bacpy(src, conn->src); +	bacpy(&sco_pi(sk)->src, &hcon->src);  	err = sco_chan_add(conn, sk, NULL);  	if (err) @@ -223,16 +207,16 @@ static int sco_connect(struct sock *sk)  	}  done: -	hci_dev_unlock_bh(hdev); +	hci_dev_unlock(hdev);  	hci_dev_put(hdev);  	return err;  } -static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) +static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)  {  	struct sco_conn *conn = sco_pi(sk)->conn;  	struct sk_buff *skb; -	int err, count; +	int err;  	/* Check outgoing MTU */  	if (len > conn->mtu) @@ -240,23 +224,21 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)  	BT_DBG("sk %p len %d", sk, len); -	count = min_t(unsigned int, conn->mtu, len); -	skb = bt_skb_send_alloc(sk, count, -			msg->msg_flags & MSG_DONTWAIT, &err); +	skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);  	if (!skb)  		return err; -	if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { +	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {  		kfree_skb(skb);  		return -EFAULT;  	}  	hci_send_sco(conn->hcon, skb); -	return count; +	return len;  } -static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) +static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)  {  	struct sock *sk = sco_chan_get(conn); @@ -276,17 +258,19 @@ drop:  }  /* -------- Socket interface ---------- */ -static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) +static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba)  {  	struct sock *sk; -	struct hlist_node *node; -	sk_for_each(sk, node, &sco_sk_list.head) -		if (!bacmp(&bt_sk(sk)->src, ba)) -			goto found; -	sk = NULL; -found: -	return sk; +	sk_for_each(sk, &sco_sk_list.head) { +		if (sk->sk_state != BT_LISTEN) +			continue; + +		if (!bacmp(&sco_pi(sk)->src, ba)) +			return sk; +	} + +	return NULL;  }  /* Find socket listening on source bdaddr. @@ -295,26 +279,25 @@ found:  static struct sock *sco_get_sock_listen(bdaddr_t *src)  {  	struct sock *sk = NULL, *sk1 = NULL; -	struct hlist_node *node;  	read_lock(&sco_sk_list.lock); -	sk_for_each(sk, node, &sco_sk_list.head) { +	sk_for_each(sk, &sco_sk_list.head) {  		if (sk->sk_state != BT_LISTEN)  			continue;  		/* Exact match. */ -		if (!bacmp(&bt_sk(sk)->src, src)) +		if (!bacmp(&sco_pi(sk)->src, src))  			break;  		/* Closest match */ -		if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) +		if (!bacmp(&sco_pi(sk)->src, BDADDR_ANY))  			sk1 = sk;  	}  	read_unlock(&sco_sk_list.lock); -	return node ? sk : sk1; +	return sk ? sk : sk1;  }  static void sco_sock_destruct(struct sock *sk) @@ -368,6 +351,16 @@ static void __sco_sock_close(struct sock *sk)  	case BT_CONNECTED:  	case BT_CONFIG: +		if (sco_pi(sk)->conn->hcon) { +			sk->sk_state = BT_DISCONN; +			sco_sock_set_timer(sk, SCO_DISCONN_TIMEOUT); +			hci_conn_drop(sco_pi(sk)->conn->hcon); +			sco_pi(sk)->conn->hcon = NULL; +		} else +			sco_chan_del(sk, ECONNRESET); +		break; + +	case BT_CONNECT2:  	case BT_CONNECT:  	case BT_DISCONN:  		sco_chan_del(sk, ECONNRESET); @@ -393,8 +386,11 @@ static void sco_sock_init(struct sock *sk, struct sock *parent)  {  	BT_DBG("sk %p", sk); -	if (parent) +	if (parent) {  		sk->sk_type = parent->sk_type; +		bt_sk(sk)->flags = bt_sk(parent)->flags; +		security_sk_clone(parent, sk); +	}  }  static struct proto sco_proto = { @@ -422,6 +418,8 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro  	sk->sk_protocol = proto;  	sk->sk_state    = BT_OPEN; +	sco_pi(sk)->setting = BT_VOICE_CVSD_16BIT; +  	setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk);  	bt_sock_link(&sco_sk_list, sk); @@ -454,10 +452,9 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le  {  	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;  	struct sock *sk = sock->sk; -	bdaddr_t *src = &sa->sco_bdaddr;  	int err = 0; -	BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); +	BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);  	if (!addr || addr->sa_family != AF_BLUETOOTH)  		return -EINVAL; @@ -469,17 +466,14 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le  		goto done;  	} -	write_lock_bh(&sco_sk_list.lock); - -	if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) { -		err = -EADDRINUSE; -	} else { -		/* Save source address */ -		bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); -		sk->sk_state = BT_BOUND; +	if (sk->sk_type != SOCK_SEQPACKET) { +		err = -EINVAL; +		goto done;  	} -	write_unlock_bh(&sco_sk_list.lock); +	bacpy(&sco_pi(sk)->src, &sa->sco_bdaddr); + +	sk->sk_state = BT_BOUND;  done:  	release_sock(sk); @@ -490,8 +484,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen  {  	struct sockaddr_sco *sa = (struct sockaddr_sco *) addr;  	struct sock *sk = sock->sk; -	int err = 0; - +	int err;  	BT_DBG("sk %p", sk); @@ -508,13 +501,14 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen  	lock_sock(sk);  	/* Set destination address and psm */ -	bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr); +	bacpy(&sco_pi(sk)->dst, &sa->sco_bdaddr); -	if ((err = sco_connect(sk))) +	err = sco_connect(sk); +	if (err)  		goto done;  	err = bt_sock_wait_state(sk, BT_CONNECTED, -			sock_sndtimeo(sk, flags & O_NONBLOCK)); +				 sock_sndtimeo(sk, flags & O_NONBLOCK));  done:  	release_sock(sk); @@ -524,21 +518,38 @@ done:  static int sco_sock_listen(struct socket *sock, int backlog)  {  	struct sock *sk = sock->sk; +	bdaddr_t *src = &sco_pi(sk)->src;  	int err = 0;  	BT_DBG("sk %p backlog %d", sk, backlog);  	lock_sock(sk); -	if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) { +	if (sk->sk_state != BT_BOUND) {  		err = -EBADFD;  		goto done;  	} +	if (sk->sk_type != SOCK_SEQPACKET) { +		err = -EINVAL; +		goto done; +	} + +	write_lock(&sco_sk_list.lock); + +	if (__sco_get_sock_listen_by_addr(src)) { +		err = -EADDRINUSE; +		goto unlock; +	} +  	sk->sk_max_ack_backlog = backlog;  	sk->sk_ack_backlog = 0; +  	sk->sk_state = BT_LISTEN; +unlock: +	write_unlock(&sco_sk_list.lock); +  done:  	release_sock(sk);  	return err; @@ -553,30 +564,26 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag  	lock_sock(sk); -	if (sk->sk_state != BT_LISTEN) { -		err = -EBADFD; -		goto done; -	} -  	timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK);  	BT_DBG("sk %p timeo %ld", sk, timeo);  	/* Wait for an incoming connection. (wake-one). */  	add_wait_queue_exclusive(sk_sleep(sk), &wait); -	while (!(ch = bt_accept_dequeue(sk, newsock))) { +	while (1) {  		set_current_state(TASK_INTERRUPTIBLE); -		if (!timeo) { -			err = -EAGAIN; + +		if (sk->sk_state != BT_LISTEN) { +			err = -EBADFD;  			break;  		} -		release_sock(sk); -		timeo = schedule_timeout(timeo); -		lock_sock(sk); +		ch = bt_accept_dequeue(sk, newsock); +		if (ch) +			break; -		if (sk->sk_state != BT_LISTEN) { -			err = -EBADFD; +		if (!timeo) { +			err = -EAGAIN;  			break;  		} @@ -584,8 +591,12 @@ static int sco_sock_accept(struct socket *sock, struct socket *newsock, int flag  			err = sock_intr_errno(timeo);  			break;  		} + +		release_sock(sk); +		timeo = schedule_timeout(timeo); +		lock_sock(sk);  	} -	set_current_state(TASK_RUNNING); +	__set_current_state(TASK_RUNNING);  	remove_wait_queue(sk_sleep(sk), &wait);  	if (err) @@ -611,9 +622,9 @@ static int sco_sock_getname(struct socket *sock, struct sockaddr *addr, int *len  	*len = sizeof(struct sockaddr_sco);  	if (peer) -		bacpy(&sa->sco_bdaddr, &bt_sk(sk)->dst); +		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->dst);  	else -		bacpy(&sa->sco_bdaddr, &bt_sk(sk)->src); +		bacpy(&sa->sco_bdaddr, &sco_pi(sk)->src);  	return 0;  } @@ -644,16 +655,127 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock,  	return err;  } +static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting) +{ +	struct hci_dev *hdev = conn->hdev; + +	BT_DBG("conn %p", conn); + +	conn->state = BT_CONFIG; + +	if (!lmp_esco_capable(hdev)) { +		struct hci_cp_accept_conn_req cp; + +		bacpy(&cp.bdaddr, &conn->dst); +		cp.role = 0x00; /* Ignored */ + +		hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); +	} else { +		struct hci_cp_accept_sync_conn_req cp; + +		bacpy(&cp.bdaddr, &conn->dst); +		cp.pkt_type = cpu_to_le16(conn->pkt_type); + +		cp.tx_bandwidth   = cpu_to_le32(0x00001f40); +		cp.rx_bandwidth   = cpu_to_le32(0x00001f40); +		cp.content_format = cpu_to_le16(setting); + +		switch (setting & SCO_AIRMODE_MASK) { +		case SCO_AIRMODE_TRANSP: +			if (conn->pkt_type & ESCO_2EV3) +				cp.max_latency = cpu_to_le16(0x0008); +			else +				cp.max_latency = cpu_to_le16(0x000D); +			cp.retrans_effort = 0x02; +			break; +		case SCO_AIRMODE_CVSD: +			cp.max_latency = cpu_to_le16(0xffff); +			cp.retrans_effort = 0xff; +			break; +		} + +		hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, +			     sizeof(cp), &cp); +	} +} + +static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, +			    struct msghdr *msg, size_t len, int flags) +{ +	struct sock *sk = sock->sk; +	struct sco_pinfo *pi = sco_pi(sk); + +	lock_sock(sk); + +	if (sk->sk_state == BT_CONNECT2 && +	    test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { +		sco_conn_defer_accept(pi->conn->hcon, pi->setting); +		sk->sk_state = BT_CONFIG; + +		release_sock(sk); +		return 0; +	} + +	release_sock(sk); + +	return bt_sock_recvmsg(iocb, sock, msg, len, flags); +} +  static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)  {  	struct sock *sk = sock->sk; -	int err = 0; +	int len, err = 0; +	struct bt_voice voice; +	u32 opt;  	BT_DBG("sk %p", sk);  	lock_sock(sk);  	switch (optname) { + +	case BT_DEFER_SETUP: +		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { +			err = -EINVAL; +			break; +		} + +		if (get_user(opt, (u32 __user *) optval)) { +			err = -EFAULT; +			break; +		} + +		if (opt) +			set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); +		else +			clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); +		break; + +	case BT_VOICE: +		if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND && +		    sk->sk_state != BT_CONNECT2) { +			err = -EINVAL; +			break; +		} + +		voice.setting = sco_pi(sk)->setting; + +		len = min_t(unsigned int, sizeof(voice), optlen); +		if (copy_from_user((char *) &voice, optval, len)) { +			err = -EFAULT; +			break; +		} + +		/* Explicitly check for these values */ +		if (voice.setting != BT_VOICE_TRANSPARENT && +		    voice.setting != BT_VOICE_CVSD_16BIT) { +			err = -EINVAL; +			break; +		} + +		sco_pi(sk)->setting = voice.setting; +		break; +  	default:  		err = -ENOPROTOOPT;  		break; @@ -679,7 +801,9 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user  	switch (optname) {  	case SCO_OPTIONS: -		if (sk->sk_state != BT_CONNECTED) { +		if (sk->sk_state != BT_CONNECTED && +		    !(sk->sk_state == BT_CONNECT2 && +		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {  			err = -ENOTCONN;  			break;  		} @@ -695,11 +819,14 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user  		break;  	case SCO_CONNINFO: -		if (sk->sk_state != BT_CONNECTED) { +		if (sk->sk_state != BT_CONNECTED && +		    !(sk->sk_state == BT_CONNECT2 && +		      test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) {  			err = -ENOTCONN;  			break;  		} +		memset(&cinfo, 0, sizeof(cinfo));  		cinfo.hci_handle = sco_pi(sk)->conn->hcon->handle;  		memcpy(cinfo.dev_class, sco_pi(sk)->conn->hcon->dev_class, 3); @@ -722,6 +849,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char  {  	struct sock *sk = sock->sk;  	int len, err = 0; +	struct bt_voice voice;  	BT_DBG("sk %p", sk); @@ -734,6 +862,28 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char  	lock_sock(sk);  	switch (optname) { + +	case BT_DEFER_SETUP: +		if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) { +			err = -EINVAL; +			break; +		} + +		if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), +			     (u32 __user *) optval)) +			err = -EFAULT; + +		break; + +	case BT_VOICE: +		voice.setting = sco_pi(sk)->setting; + +		len = min_t(unsigned int, len, sizeof(voice)); +		if (copy_to_user(optval, (char *)&voice, len)) +			err = -EFAULT; + +		break; +  	default:  		err = -ENOPROTOOPT;  		break; @@ -761,7 +911,7 @@ static int sco_sock_shutdown(struct socket *sock, int how)  		if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)  			err = bt_sock_wait_state(sk, BT_CLOSED, -							sk->sk_lingertime); +						 sk->sk_lingertime);  	}  	release_sock(sk);  	return err; @@ -816,7 +966,9 @@ static void sco_chan_del(struct sock *sk, int err)  		conn->sk = NULL;  		sco_pi(sk)->conn = NULL;  		sco_conn_unlock(conn); -		hci_conn_put(conn->hcon); + +		if (conn->hcon) +			hci_conn_drop(conn->hcon);  	}  	sk->sk_state = BT_CLOSED; @@ -828,73 +980,78 @@ static void sco_chan_del(struct sock *sk, int err)  static void sco_conn_ready(struct sco_conn *conn)  { -	struct sock *parent, *sk; +	struct sock *parent; +	struct sock *sk = conn->sk;  	BT_DBG("conn %p", conn); -	sco_conn_lock(conn); - -	if ((sk = conn->sk)) { +	if (sk) {  		sco_sock_clear_timer(sk);  		bh_lock_sock(sk);  		sk->sk_state = BT_CONNECTED;  		sk->sk_state_change(sk);  		bh_unlock_sock(sk);  	} else { -		parent = sco_get_sock_listen(conn->src); -		if (!parent) -			goto done; +		sco_conn_lock(conn); + +		parent = sco_get_sock_listen(&conn->hcon->src); +		if (!parent) { +			sco_conn_unlock(conn); +			return; +		}  		bh_lock_sock(parent);  		sk = sco_sock_alloc(sock_net(parent), NULL, -				BTPROTO_SCO, GFP_ATOMIC); +				    BTPROTO_SCO, GFP_ATOMIC);  		if (!sk) {  			bh_unlock_sock(parent); -			goto done; +			sco_conn_unlock(conn); +			return;  		}  		sco_sock_init(sk, parent); -		bacpy(&bt_sk(sk)->src, conn->src); -		bacpy(&bt_sk(sk)->dst, conn->dst); +		bacpy(&sco_pi(sk)->src, &conn->hcon->src); +		bacpy(&sco_pi(sk)->dst, &conn->hcon->dst);  		hci_conn_hold(conn->hcon);  		__sco_chan_add(conn, sk, parent); -		sk->sk_state = BT_CONNECTED; +		if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) +			sk->sk_state = BT_CONNECT2; +		else +			sk->sk_state = BT_CONNECTED;  		/* Wake up parent */ -		parent->sk_data_ready(parent, 1); +		parent->sk_data_ready(parent);  		bh_unlock_sock(parent); -	} -done: -	sco_conn_unlock(conn); +		sco_conn_unlock(conn); +	}  }  /* ----- SCO interface with lower layer (HCI) ----- */ -static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type) +int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags)  { -	register struct sock *sk; -	struct hlist_node *node; +	struct sock *sk;  	int lm = 0; -	if (type != SCO_LINK && type != ESCO_LINK) -		return 0; - -	BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); +	BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);  	/* Find listening sockets */  	read_lock(&sco_sk_list.lock); -	sk_for_each(sk, node, &sco_sk_list.head) { +	sk_for_each(sk, &sco_sk_list.head) {  		if (sk->sk_state != BT_LISTEN)  			continue; -		if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) || -				!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { +		if (!bacmp(&sco_pi(sk)->src, &hdev->bdaddr) || +		    !bacmp(&sco_pi(sk)->src, BDADDR_ANY)) {  			lm |= HCI_LM_ACCEPT; + +			if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) +				*flags |= HCI_PROTO_DEFER;  			break;  		}  	} @@ -903,38 +1060,27 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)  	return lm;  } -static int sco_connect_cfm(struct hci_conn *hcon, __u8 status) +void sco_connect_cfm(struct hci_conn *hcon, __u8 status)  { -	BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); - -	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) -		return 0; - +	BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);  	if (!status) {  		struct sco_conn *conn; -		conn = sco_conn_add(hcon, status); +		conn = sco_conn_add(hcon);  		if (conn)  			sco_conn_ready(conn);  	} else -		sco_conn_del(hcon, bt_err(status)); - -	return 0; +		sco_conn_del(hcon, bt_to_errno(status));  } -static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason) +void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)  {  	BT_DBG("hcon %p reason %d", hcon, reason); -	if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK) -		return 0; - -	sco_conn_del(hcon, bt_err(reason)); - -	return 0; +	sco_conn_del(hcon, bt_to_errno(reason));  } -static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) +int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)  {  	struct sco_conn *conn = hcon->sco_data; @@ -956,16 +1102,15 @@ drop:  static int sco_debugfs_show(struct seq_file *f, void *p)  {  	struct sock *sk; -	struct hlist_node *node; -	read_lock_bh(&sco_sk_list.lock); +	read_lock(&sco_sk_list.lock); -	sk_for_each(sk, node, &sco_sk_list.head) { -		seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src), -				batostr(&bt_sk(sk)->dst), sk->sk_state); +	sk_for_each(sk, &sco_sk_list.head) { +		seq_printf(f, "%pMR %pMR %d\n", &sco_pi(sk)->src, +			   &sco_pi(sk)->dst, sk->sk_state);  	} -	read_unlock_bh(&sco_sk_list.lock); +	read_unlock(&sco_sk_list.lock);  	return 0;  } @@ -994,7 +1139,7 @@ static const struct proto_ops sco_sock_ops = {  	.accept		= sco_sock_accept,  	.getname	= sco_sock_getname,  	.sendmsg	= sco_sock_sendmsg, -	.recvmsg	= bt_sock_recvmsg, +	.recvmsg	= sco_sock_recvmsg,  	.poll		= bt_sock_poll,  	.ioctl		= bt_sock_ioctl,  	.mmap		= sock_no_mmap, @@ -1010,16 +1155,7 @@ static const struct net_proto_family sco_sock_family_ops = {  	.create	= sco_sock_create,  }; -static struct hci_proto sco_hci_proto = { -	.name		= "SCO", -	.id		= HCI_PROTO_SCO, -	.connect_ind	= sco_connect_ind, -	.connect_cfm	= sco_connect_cfm, -	.disconn_cfm	= sco_disconn_cfm, -	.recv_scodata	= sco_recv_scodata -}; - -static int __init sco_init(void) +int __init sco_init(void)  {  	int err; @@ -1033,23 +1169,21 @@ static int __init sco_init(void)  		goto error;  	} -	err = hci_register_proto(&sco_hci_proto); +	err = bt_procfs_init(&init_net, "sco", &sco_sk_list, NULL);  	if (err < 0) { -		BT_ERR("SCO protocol registration failed"); +		BT_ERR("Failed to create SCO proc file");  		bt_sock_unregister(BTPROTO_SCO);  		goto error;  	} -	if (bt_debugfs) { -		sco_debugfs = debugfs_create_file("sco", 0444, -					bt_debugfs, NULL, &sco_debugfs_fops); -		if (!sco_debugfs) -			BT_ERR("Failed to create SCO debug file"); -	} - -	BT_INFO("SCO (Voice Link) ver %s", VERSION);  	BT_INFO("SCO socket layer initialized"); +	if (IS_ERR_OR_NULL(bt_debugfs)) +		return 0; + +	sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs, +					  NULL, &sco_debugfs_fops); +  	return 0;  error: @@ -1057,27 +1191,16 @@ error:  	return err;  } -static void __exit sco_exit(void) +void __exit sco_exit(void)  { -	debugfs_remove(sco_debugfs); +	bt_procfs_cleanup(&init_net, "sco"); -	if (bt_sock_unregister(BTPROTO_SCO) < 0) -		BT_ERR("SCO socket unregistration failed"); +	debugfs_remove(sco_debugfs); -	if (hci_unregister_proto(&sco_hci_proto) < 0) -		BT_ERR("SCO protocol unregistration failed"); +	bt_sock_unregister(BTPROTO_SCO);  	proto_unregister(&sco_proto);  } -module_init(sco_init); -module_exit(sco_exit); -  module_param(disable_esco, bool, 0644);  MODULE_PARM_DESC(disable_esco, "Disable eSCO connection creation"); - -MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); -MODULE_DESCRIPTION("Bluetooth SCO ver " VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("bt-proto-2");  | 
