* [RFC v2 1/5] Bluetooth: Add option for SCO socket mode
2012-12-11 16:53 [RFC v2 0/5] sco: SCO socket option for mode Frédéric Dalleau
@ 2012-12-11 16:53 ` Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 2/5] Bluetooth: Add setsockopt " Frédéric Dalleau
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Frédéric Dalleau @ 2012-12-11 16:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
This patch extends the current SCO socket option to add a 'mode' field. This
field is intended to choose data type at runtime. Current modes are CVSD and
transparent SCO, but adding new modes could allow support for CSA2 and fine
tuning a sco connection, for example latency, bandwith, voice setting. Incoming
connections will be setup during defered setup. Outgoing connections have to
be setup before connect(). The selected type is stored in the sco socket info.
This patch declares needed members and implements getsockopt().
---
include/net/bluetooth/sco.h | 19 +++++++++++++++++++
net/bluetooth/sco.c | 3 +++
2 files changed, 22 insertions(+)
diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
index 1e35c43..1798fd3 100644
--- a/include/net/bluetooth/sco.h
+++ b/include/net/bluetooth/sco.h
@@ -41,8 +41,26 @@ struct sockaddr_sco {
/* SCO socket options */
#define SCO_OPTIONS 0x01
+
+#define SCO_MODE_CVSD 0x00
+#define SCO_MODE_TRANSPARENT 0x01
+#define SCO_MODE_ENHANCED 0x02
struct sco_options {
__u16 mtu;
+ __u8 mode;
+};
+
+struct sco_coding {
+ __u8 format;
+ __u16 vid;
+ __u16 cid;
+};
+
+struct sco_options_enhanced {
+ __u16 mtu;
+ __u8 mode;
+ struct sco_coding host;
+ struct sco_coding air;
};
#define SCO_CONNINFO 0x02
@@ -73,6 +91,7 @@ struct sco_conn {
struct sco_pinfo {
struct bt_sock bt;
__u32 flags;
+ __u8 mode;
struct sco_conn *conn;
};
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 531a93d..bdb21b2 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -418,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)->mode = SCO_MODE_CVSD;
+
setup_timer(&sk->sk_timer, sco_sock_timeout, (unsigned long)sk);
bt_sock_link(&sco_sk_list, sk);
@@ -736,6 +738,7 @@ static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user
}
opts.mtu = sco_pi(sk)->conn->mtu;
+ opts.mode = sco_pi(sk)->mode;
BT_DBG("mtu %d", opts.mtu);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC v2 2/5] Bluetooth: Add setsockopt for SCO socket mode
2012-12-11 16:53 [RFC v2 0/5] sco: SCO socket option for mode Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 1/5] Bluetooth: Add option for SCO socket mode Frédéric Dalleau
@ 2012-12-11 16:53 ` Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 3/5] Bluetooth: Use codec to create SCO connection Frédéric Dalleau
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Frédéric Dalleau @ 2012-12-11 16:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
This patch implements setsockopt().
---
net/bluetooth/sco.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index bdb21b2..22ad5fa 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -678,6 +678,47 @@ static int sco_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
}
+static int sco_sock_setsockopt_old(struct socket *sock, int optname,
+ char __user *optval, unsigned int optlen)
+{
+ struct sock *sk = sock->sk;
+ struct sco_options opts;
+ int len, err = 0;
+
+ BT_DBG("sk %p", sk);
+
+ lock_sock(sk);
+
+ switch (optname) {
+ case SCO_OPTIONS:
+ if (sk->sk_state != BT_OPEN &&
+ sk->sk_state != BT_BOUND &&
+ sk->sk_state != BT_CONNECT2) {
+ err = -EINVAL;
+ break;
+ }
+
+ opts.mode = SCO_MODE_CVSD;
+
+ len = min_t(unsigned int, sizeof(opts), optlen);
+ if (copy_from_user((char *) &opts, optval, len)) {
+ err = -EFAULT;
+ break;
+ }
+
+ sco_pi(sk)->mode = opts.mode;
+ BT_DBG("mode %d", opts.mode);
+ break;
+
+ default:
+ err = -ENOPROTOOPT;
+ break;
+ }
+
+ release_sock(sk);
+ return err;
+}
+
static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
{
struct sock *sk = sock->sk;
@@ -686,6 +727,9 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
BT_DBG("sk %p", sk);
+ if (level == SOL_SCO)
+ return sco_sock_setsockopt_old(sock, optname, optval, optlen);
+
lock_sock(sk);
switch (optname) {
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC v2 3/5] Bluetooth: Use codec to create SCO connection
2012-12-11 16:53 [RFC v2 0/5] sco: SCO socket option for mode Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 1/5] Bluetooth: Add option for SCO socket mode Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 2/5] Bluetooth: Add setsockopt " Frédéric Dalleau
@ 2012-12-11 16:53 ` Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 4/5] Bluetooth: Set parameters for outgoing connections Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 5/5] Bluetooth: Fallback transparent SCO from T2 to T1 Frédéric Dalleau
4 siblings, 0 replies; 6+ messages in thread
From: Frédéric Dalleau @ 2012-12-11 16:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
When an incoming SCO connection is requested, check the selected codec, and
reply appropriately. Codec should have been negotiated previously.
Note that this patch only changes replies for defered setup.
---
include/net/bluetooth/hci_core.h | 2 +-
net/bluetooth/hci_event.c | 21 +++++++++++++++++----
net/bluetooth/sco.c | 2 +-
3 files changed, 19 insertions(+), 6 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 014a2ea..cb5d131 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -577,7 +577,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst);
int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
-void hci_conn_accept(struct hci_conn *conn, int mask);
+void hci_conn_accept(struct hci_conn *conn, int mask, int mode);
struct hci_chan *hci_chan_create(struct hci_conn *conn);
void hci_chan_del(struct hci_chan *chan);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 705078a..175d23d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2047,7 +2047,7 @@ unlock:
hci_conn_check_pending(hdev);
}
-void hci_conn_accept(struct hci_conn *conn, int mask)
+void hci_conn_accept(struct hci_conn *conn, int mask, int mode)
{
struct hci_dev *hdev = conn->hdev;
@@ -2070,13 +2070,26 @@ void hci_conn_accept(struct hci_conn *conn, int mask)
struct hci_cp_accept_sync_conn_req cp;
bacpy(&cp.bdaddr, &conn->dst);
- cp.pkt_type = cpu_to_le16(conn->pkt_type);
+ 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.content_format = cpu_to_le16(hdev->voice_setting);
- cp.retrans_effort = 0xff;
+
+ switch (mode) {
+ case 0:
+ cp.max_latency = __constant_cpu_to_le16(0xffff);
+ cp.retrans_effort = 0xff;
+ break;
+ case 1:
+ cp.content_format |= cpu_to_le16(3);
+ 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;
+ }
hci_send_cmd(hdev, HCI_OP_ACCEPT_SYNC_CONN_REQ,
sizeof(cp), &cp);
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 22ad5fa..6a957a3 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -666,7 +666,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)) {
- hci_conn_accept(pi->conn->hcon, 0);
+ hci_conn_accept(pi->conn->hcon, 0, pi->mode);
sk->sk_state = BT_CONFIG;
release_sock(sk);
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC v2 4/5] Bluetooth: Set parameters for outgoing connections
2012-12-11 16:53 [RFC v2 0/5] sco: SCO socket option for mode Frédéric Dalleau
` (2 preceding siblings ...)
2012-12-11 16:53 ` [RFC v2 3/5] Bluetooth: Use codec to create SCO connection Frédéric Dalleau
@ 2012-12-11 16:53 ` Frédéric Dalleau
2012-12-11 16:53 ` [RFC v2 5/5] Bluetooth: Fallback transparent SCO from T2 to T1 Frédéric Dalleau
4 siblings, 0 replies; 6+ messages in thread
From: Frédéric Dalleau @ 2012-12-11 16:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
In order to establish the connection, the outgoing connection must also
request the codec. Here we need to set a bit in ACL connection flag to set up
the desired parameters if ACL is not up yet.
---
include/net/bluetooth/hci_core.h | 3 +++
net/bluetooth/hci_conn.c | 21 ++++++++++++++++-----
net/bluetooth/sco.c | 4 ++--
3 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index cb5d131..7b9902a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -438,6 +438,7 @@ enum {
HCI_CONN_SSP_ENABLED,
HCI_CONN_POWER_SAVE,
HCI_CONN_REMOTE_OOB,
+ HCI_CONN_SCO_T2_SETTINGS,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
@@ -586,6 +587,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,
+ u8 sec_level, u8 auth_type, u8 codec);
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 25bfce0..4bba2fb 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -179,9 +179,16 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
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;
+
+ if (test_and_clear_bit(HCI_CONN_SCO_T2_SETTINGS, &conn->flags)) {
+ cp.voice_setting |= 3;
+ cp.max_latency = __constant_cpu_to_le16(0x000d);
+ cp.retrans_effort = 0x02;
+ } else {
+ cp.max_latency = __constant_cpu_to_le16(0xffff);
+ cp.retrans_effort = 0xff;
+ }
hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
}
@@ -551,8 +558,9 @@ 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, u8 sec_level,
+ u8 auth_type, u8 codec)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -575,6 +583,9 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
hci_conn_hold(sco);
+ if (codec)
+ set_bit(HCI_CONN_SCO_T2_SETTINGS, &sco->flags);
+
if (acl->state == BT_CONNECTED &&
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
set_bit(HCI_CONN_POWER_SAVE, &acl->flags);
@@ -605,7 +616,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
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 hci_connect_sco(hdev, type, dst, sec_level, auth_type, 0);
}
return ERR_PTR(-EINVAL);
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 6a957a3..bee0b5c 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -176,8 +176,8 @@ 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, BT_SECURITY_LOW,
+ HCI_AT_NO_BONDING, sco_pi(sk)->mode);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto done;
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread* [RFC v2 5/5] Bluetooth: Fallback transparent SCO from T2 to T1
2012-12-11 16:53 [RFC v2 0/5] sco: SCO socket option for mode Frédéric Dalleau
` (3 preceding siblings ...)
2012-12-11 16:53 ` [RFC v2 4/5] Bluetooth: Set parameters for outgoing connections Frédéric Dalleau
@ 2012-12-11 16:53 ` Frédéric Dalleau
4 siblings, 0 replies; 6+ messages in thread
From: Frédéric Dalleau @ 2012-12-11 16:53 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Frédéric Dalleau
When initiating an eSCO connection, force use of T2 settings at first try.
T2 is the recommended settings from HFP 1.6 WideBand Speech so we only do that
on an transparent eSCO request. Upon connection failure, try T1 settings.
To know which of T2 or T1 should be used, we use the connection attempt index.
T2 failure is detected if Synchronous Connection Complete Event fails with
error 0x0d. This error code has been found experimentally by sending a T2
request to a T1 only SCO listener. It means "Connection Rejected due to
Limited resource".
---
include/net/bluetooth/hci_core.h | 2 +-
net/bluetooth/hci_conn.c | 13 +++++++++++--
net/bluetooth/hci_event.c | 1 +
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 7b9902a..9ef7fe0 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -438,7 +438,7 @@ enum {
HCI_CONN_SSP_ENABLED,
HCI_CONN_POWER_SAVE,
HCI_CONN_REMOTE_OOB,
- HCI_CONN_SCO_T2_SETTINGS,
+ HCI_CONN_SCO_TRANSPARENT,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 4bba2fb..87c2fa4 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -181,10 +181,19 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
cp.voice_setting = cpu_to_le16(hdev->voice_setting);
- if (test_and_clear_bit(HCI_CONN_SCO_T2_SETTINGS, &conn->flags)) {
+ if (conn->attempt == 1 &&
+ test_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
+ cp.pkt_type = cpu_to_le16(EDR_ESCO_MASK & ~ESCO_2EV3);
cp.voice_setting |= 3;
cp.max_latency = __constant_cpu_to_le16(0x000d);
cp.retrans_effort = 0x02;
+ } else if (conn->attempt == 2 &&
+ test_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
+ cp.pkt_type = cpu_to_le16(ESCO_EV3 | EDR_ESCO_MASK);
+ cp.voice_setting |= 3;
+ cp.max_latency = __constant_cpu_to_le16(0x0007);
+ cp.retrans_effort = 0x02;
+ clear_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags);
} else {
cp.max_latency = __constant_cpu_to_le16(0xffff);
cp.retrans_effort = 0xff;
@@ -584,7 +593,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
hci_conn_hold(sco);
if (codec)
- set_bit(HCI_CONN_SCO_T2_SETTINGS, &sco->flags);
+ set_bit(HCI_CONN_SCO_TRANSPARENT, &sco->flags);
if (acl->state == BT_CONNECTED &&
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 175d23d..762ec1d 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3319,6 +3319,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
hci_conn_add_sysfs(conn);
break;
+ case 0x0d: /* No resource available */
case 0x11: /* Unsupported Feature or Parameter Value */
case 0x1c: /* SCO interval rejected */
case 0x1a: /* Unsupported Remote Feature */
--
1.7.9.5
^ permalink raw reply related [flat|nested] 6+ messages in thread