From 9d225d2208a6f17da5987ff4e7710b9e805cb5d6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 8 Aug 2013 14:53:56 +0300 Subject: Bluetooth: Fix getting SCO socket options in deferred state When a socket is in deferred state there does actually exist an underlying connection even though the connection state is not yet BT_CONNECTED. In the deferred state it should therefore be allowed to get socket options that usually depend on a connection, such as SCO_OPTIONS and SCO_CONNINFO. This patch fixes the behavior of some user space code that behaves as follows without it: $ sudo tools/btiotest -i 00:1B:DC:xx:xx:xx -d -s accept=2 reject=-1 discon=-1 defer=1 sec=0 update_sec=0 prio=0 voice=0x0000 Listening for SCO connections bt_io_get(OPT_DEST): getsockopt(SCO_OPTIONS): Transport endpoint is not connected (107) Accepting connection Successfully connected to 60:D8:19:xx:xx:xx. handle=43, class=000000 The conditions that the patch updates the if-statements to is taken from similar code in l2cap_sock.c which correctly handles the deferred state. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'net/bluetooth/sco.c') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index e7bd4eea575c..2de7150a6304 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -765,7 +765,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; } @@ -781,7 +783,9 @@ 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; } -- cgit v1.2.3 From e660ed6c70370dae0887e2b5224d8b6c1e138120 Mon Sep 17 00:00:00 2001 From: Frédéric Dalleau Date: Mon, 19 Aug 2013 14:23:54 +0200 Subject: Bluetooth: Use hci_connect_sco directly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hci_connect is a super function for connecting hci protocols. But the voice_setting parameter (introduced in subsequent patches) is only needed by SCO and security requirements are not needed for SCO channels. Thus, it makes sense to have a separate function for SCO. Signed-off-by: Frédéric Dalleau Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 2 ++ net/bluetooth/hci_conn.c | 8 ++------ net/bluetooth/sco.c | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/sco.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f77885ea78c2..307a19269020 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -584,6 +584,8 @@ struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 dst_type, __u8 sec_level, __u8 auth_type); +struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, + bdaddr_t *dst); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 6c7f36379722..5f1f448dd0f2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -560,13 +560,12 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, return acl; } -static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, - bdaddr_t *dst, u8 sec_level, u8 auth_type) +struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *acl; struct hci_conn *sco; - acl = hci_connect_acl(hdev, dst, sec_level, auth_type); + acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); if (IS_ERR(acl)) return acl; @@ -612,9 +611,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, return hci_connect_le(hdev, dst, dst_type, sec_level, auth_type); case ACL_LINK: return hci_connect_acl(hdev, dst, sec_level, auth_type); - case SCO_LINK: - case ESCO_LINK: - return hci_connect_sco(hdev, type, dst, sec_level, auth_type); } return ERR_PTR(-EINVAL); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 2de7150a6304..ab2502cbecfb 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -176,8 +176,7 @@ static int sco_connect(struct sock *sk) else type = SCO_LINK; - hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW, - HCI_AT_NO_BONDING); + hcon = hci_connect_sco(hdev, type, dst); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; -- cgit v1.2.3 From 33f2404823f000f9b5fc570b0a08b1008e241578 Mon Sep 17 00:00:00 2001 From: Frédéric Dalleau Date: Mon, 19 Aug 2013 14:23:55 +0200 Subject: Bluetooth: Remove unused mask parameter in sco_conn_defer_accept MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From Bluetooth Core v4.0 specification, 7.1.8 Accept Connection Request Command "When accepting synchronous connection request, the Role parameter is not used and will be ignored by the BR/EDR Controller." Signed-off-by: Frédéric Dalleau Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'net/bluetooth/sco.c') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index ab2502cbecfb..acdca68806db 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -651,7 +651,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; } -static void sco_conn_defer_accept(struct hci_conn *conn, int mask) +static void sco_conn_defer_accept(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; @@ -663,11 +663,7 @@ static void sco_conn_defer_accept(struct hci_conn *conn, int mask) struct hci_cp_accept_conn_req cp; bacpy(&cp.bdaddr, &conn->dst); - - if (lmp_rswitch_capable(hdev) && (mask & HCI_LM_MASTER)) - cp.role = 0x00; /* Become master */ - else - cp.role = 0x01; /* Remain slave */ + cp.role = 0x00; /* Ignored */ hci_send_cmd(hdev, HCI_OP_ACCEPT_CONN_REQ, sizeof(cp), &cp); } else { @@ -697,7 +693,7 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { - sco_conn_defer_accept(pi->conn->hcon, 0); + sco_conn_defer_accept(pi->conn->hcon); sk->sk_state = BT_CONFIG; msg->msg_namelen = 0; -- cgit v1.2.3 From ad10b1a48754b1381582d96f070a39832e41382d Mon Sep 17 00:00:00 2001 From: Frédéric Dalleau Date: Mon, 19 Aug 2013 14:23:56 +0200 Subject: Bluetooth: Add Bluetooth socket voice option MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch extends the current Bluetooth socket options with BT_VOICE. This is intended to choose voice data type at runtime. It only applies to SCO sockets. Incoming connections shall be setup during deferred setup. Outgoing connections shall be setup before connect(). The desired setting is stored in the SCO socket info. This patch declares needed members, modifies getsockopt() and setsockopt(). Signed-off-by: Frédéric Dalleau Acked-by: Marcel Holtmann Signed-off-by: Johan Hedberg Signed-off-by: Gustavo Padovan --- include/net/bluetooth/bluetooth.h | 8 ++++++++ include/net/bluetooth/sco.h | 1 + net/bluetooth/sco.c | 40 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 48 insertions(+), 1 deletion(-) (limited to 'net/bluetooth/sco.c') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 10eb9b389014..10d43d8c7037 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -107,6 +107,14 @@ struct bt_power { */ #define BT_CHANNEL_POLICY_AMP_PREFERRED 2 +#define BT_VOICE 11 +struct bt_voice { + __u16 setting; +}; + +#define BT_VOICE_TRANSPARENT 0x0003 +#define BT_VOICE_CVSD_16BIT 0x0060 + __printf(1, 2) int bt_info(const char *fmt, ...); __printf(1, 2) diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h index 1e35c43657c8..e252a31ee6b6 100644 --- a/include/net/bluetooth/sco.h +++ b/include/net/bluetooth/sco.h @@ -73,6 +73,7 @@ struct sco_conn { struct sco_pinfo { struct bt_sock bt; __u32 flags; + __u16 setting; struct sco_conn *conn; }; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index acdca68806db..678747e2e389 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -416,6 +416,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); @@ -709,7 +711,8 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, 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); @@ -735,6 +738,31 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char 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; @@ -808,6 +836,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); @@ -833,6 +862,15 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char 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; -- cgit v1.2.3 From 2f69a82acf6f971a9e184dd32b24c79a14388a6c Mon Sep 17 00:00:00 2001 From: Frédéric Dalleau Date: Mon, 19 Aug 2013 14:23:58 +0200 Subject: Bluetooth: Use voice setting in deferred SCO connection request MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an incoming eSCO connection is requested, check the selected voice setting and reply appropriately. Voice setting should have been negotiated previously. For example, in case of HFP, the codec is negotiated using AT commands on the RFCOMM channel. This patch only changes replies for socket with deferred setup enabled. Signed-off-by: Frédéric Dalleau Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) (limited to 'net/bluetooth/sco.c') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 678747e2e389..b1016c82c908 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -653,7 +653,7 @@ static int sco_sock_sendmsg(struct kiocb *iocb, struct socket *sock, return err; } -static void sco_conn_defer_accept(struct hci_conn *conn) +static void sco_conn_defer_accept(struct hci_conn *conn, u16 setting) { struct hci_dev *hdev = conn->hdev; @@ -676,9 +676,21 @@ static void sco_conn_defer_accept(struct hci_conn *conn) cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); - cp.max_latency = __constant_cpu_to_le16(0xffff); - cp.content_format = cpu_to_le16(hdev->voice_setting); - cp.retrans_effort = 0xff; + 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 = __constant_cpu_to_le16(0x0008); + else + cp.max_latency = __constant_cpu_to_le16(0x000D); + cp.retrans_effort = 0x02; + break; + case SCO_AIRMODE_CVSD: + cp.max_latency = __constant_cpu_to_le16(0xffff); + cp.retrans_effort = 0xff; + break; + } hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ, sizeof(cp), &cp); @@ -695,7 +707,7 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock, if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { - sco_conn_defer_accept(pi->conn->hcon); + sco_conn_defer_accept(pi->conn->hcon, pi->setting); sk->sk_state = BT_CONFIG; msg->msg_namelen = 0; -- cgit v1.2.3 From 10c62ddc6f032c3a096401ca3ce7e5b2d5780859 Mon Sep 17 00:00:00 2001 From: Frédéric Dalleau Date: Mon, 19 Aug 2013 14:23:59 +0200 Subject: Bluetooth: Parameters for outgoing SCO connections MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to establish a transparent SCO connection, the correct settings must be specified in the Setup Synchronous Connection request. For that, a setting field is added to ACL connection data to set up the desired parameters. The patch also removes usage of hdev->voice_setting in CVSD connection and makes use of T2 parameters for transparent data. Signed-off-by: Frédéric Dalleau Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- include/net/bluetooth/hci_core.h | 5 +++-- net/bluetooth/hci_conn.c | 24 +++++++++++++++++++----- net/bluetooth/sco.c | 2 +- 3 files changed, 23 insertions(+), 8 deletions(-) (limited to 'net/bluetooth/sco.c') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f403509b4d12..61ca2ce5b063 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -320,6 +320,7 @@ struct hci_conn { __u32 passkey_notify; __u8 passkey_entered; __u16 disc_timeout; + __u16 setting; unsigned long flags; __u8 remote_cap; @@ -584,8 +585,8 @@ struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 dst_type, __u8 sec_level, __u8 auth_type); -struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, - bdaddr_t *dst); +struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u16 setting); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5f1f448dd0f2..c0e56a512ff3 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -185,13 +185,24 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) conn->attempt++; cp.handle = cpu_to_le16(handle); - cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); - cp.max_latency = __constant_cpu_to_le16(0xffff); - cp.voice_setting = cpu_to_le16(hdev->voice_setting); - cp.retrans_effort = 0xff; + cp.voice_setting = cpu_to_le16(conn->setting); + + switch (conn->setting & SCO_AIRMODE_MASK) { + case SCO_AIRMODE_TRANSP: + cp.pkt_type = __constant_cpu_to_le16(EDR_ESCO_MASK & + ~ESCO_2EV3); + cp.max_latency = __constant_cpu_to_le16(0x000d); + cp.retrans_effort = 0x02; + break; + case SCO_AIRMODE_CVSD: + cp.pkt_type = cpu_to_le16(conn->pkt_type); + cp.max_latency = __constant_cpu_to_le16(0xffff); + cp.retrans_effort = 0xff; + break; + } hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); } @@ -560,7 +571,8 @@ static struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, return acl; } -struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst) +struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u16 setting) { struct hci_conn *acl; struct hci_conn *sco; @@ -583,6 +595,8 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst) hci_conn_hold(sco); + sco->setting = setting; + if (acl->state == BT_CONNECTED && (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { set_bit(HCI_CONN_POWER_SAVE, &acl->flags); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index b1016c82c908..ed581b41e034 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -176,7 +176,7 @@ static int sco_connect(struct sock *sk) else type = SCO_LINK; - hcon = hci_connect_sco(hdev, type, dst); + hcon = hci_connect_sco(hdev, type, dst, sco_pi(sk)->setting); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; -- cgit v1.2.3 From 79dc0087c33f06a8c35d8c9e37ea6307b790bc4c Mon Sep 17 00:00:00 2001 From: Frédéric Dalleau Date: Mon, 19 Aug 2013 14:24:01 +0200 Subject: Bluetooth: Prevent transparent SCO on older devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older Bluetooth devices may not support Setup Synchronous Connection or SCO transparent data. This is indicated by the corresponding LMP feature bits. It is not possible to know if the adapter support these features before setting BT_VOICE option since the socket is not bound to an adapter. An adapter can also be added after the socket is created. The socket can be bound to an address before adapter is plugged in. Thus, on a such adapters, if user request BT_VOICE_TRANSPARENT, outgoing connections fail on connect() and returns -EOPNOTSUPP. Incoming connections do not fail. However, they should only be allowed depending on what was specified in Write_Voice_Settings command. EOPNOTSUPP is choosen because connect() system call is failing after selecting route but before any connection attempt. Signed-off-by: Frédéric Dalleau Signed-off-by: Johan Hedberg Acked-by: Marcel Holtmann Signed-off-by: Gustavo Padovan --- net/bluetooth/sco.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'net/bluetooth/sco.c') diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index ed581b41e034..96bd388d93a4 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -176,6 +176,12 @@ static int sco_connect(struct sock *sk) else type = SCO_LINK; + 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, dst, sco_pi(sk)->setting); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); -- cgit v1.2.3