2013-01-17 12:39:44

by Frédéric DALLEAU

[permalink] [raw]
Subject: [PATCH 0/5] sco: SCO socket option for mode

Hi,

This is the patch version of the socket option for enabling transparent SCO
sockets. RFC didn't generate feedback, so if we consider that people only
complains when something is wrong, this patch is fine ;)
In between, the patch series has been simplified, the most visible change is
that RFC was declaring HCI_CONN_SCO_T1_SETTINGS and removing it
later, plus some __cpu_to_le16 conversion were added.

The initial mode corresponding to current behavior is SCO_MODE_CVSD.
SCO_MODE_TRANSPARENT is the mode for setting up transparent sockets.
SCO_MODE_ENHANCED is targeted at CSA2. It is only declared and not
implemented.

Let me know what you think.
Best regards,

Frédéric


Frédéric Dalleau (5):
Bluetooth: Add option for SCO socket mode
Bluetooth: Add setsockopt for SCO socket mode
Bluetooth: Use mode when accepting SCO connection
Bluetooth: Parameters for outgoing SCO connections
Bluetooth: Fallback transparent SCO from T2 to T1

include/net/bluetooth/hci_core.h | 5 +++-
include/net/bluetooth/sco.h | 20 ++++++++++++++
net/bluetooth/hci_conn.c | 36 +++++++++++++++++++++-----
net/bluetooth/hci_event.c | 22 +++++++++++++---
net/bluetooth/sco.c | 53 +++++++++++++++++++++++++++++++++++---
5 files changed, 121 insertions(+), 15 deletions(-)

--
1.7.9.5



2013-01-17 15:36:18

by Dalleau, Frederic

[permalink] [raw]
Subject: Re: [PATCH 1/5] Bluetooth: Add option for SCO socket mode

On Thu, Jan 17, 2013 at 06:09:32AM -0800, Marcel Holtmann wrote:
Hi Marcel,
> I do not like this enhanced magic. How is this suppose to work? And it
> is also not explained in the commit message. Or used in this patch.

sco_options_enhanced is not definitive, this patch is meant to describe
different parameters for the socket option that could be selected based on the
mode field. To ensure compatibility accross versions, the size of the socket
options structure can be checked.

The idea is to read supported codecs list using mgmt API. Then,it is possible
to select some codecs and the enhanced accept/setup sync conn are sent.

It does not make sense to get this option since the codec is negociated
externally.

If this mode is removed, we fallback on version 1 of RFC (except at this time,
sco_options.mode was sco_options.codec). And it is it is easy to add new modes
to select latency, or packet types without breaking existing API.

Thanks,
Fr?d?ric

2013-01-17 14:17:04

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 4/5] Bluetooth: Parameters for outgoing SCO connections

Hi Fred,

> In order to establish a transparent SCO connection, the correct settings must
> be specified in the SetupSynchronousConnection request. For that, a bit is set
> in ACL connection flags to set up the desired parameters. If this bit is not
> set, a legacy SCO connection will be requested.
> This patch uses T2 settings.
> ---
> include/net/bluetooth/hci_core.h | 3 +++
> net/bluetooth/hci_conn.c | 27 ++++++++++++++++++++-------
> net/bluetooth/sco.c | 4 ++--
> 3 files changed, 25 insertions(+), 9 deletions(-)
>
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index cb5d131..9ef7fe0 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_TRANSPARENT,
> };
>
> 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..e3f1fad 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -175,13 +175,22 @@ 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;
> +
> + if (test_and_clear_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
> + cp.pkt_type = __constant_cpu_to_le16(EDR_ESCO_MASK &
> + ~ESCO_2EV3);
> + cp.max_latency = __constant_cpu_to_le16(0x000d);
> + cp.voice_setting = __constant_cpu_to_le16(0x0003);
> + cp.retrans_effort = 0x02;
> + } else {
> + cp.pkt_type = cpu_to_le16(conn->pkt_type);
> + cp.max_latency = __constant_cpu_to_le16(0xffff);
> + cp.voice_setting = cpu_to_le16(hdev->voice_setting);
> + cp.retrans_effort = 0xff;
> + }
>
> hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
> }
> @@ -551,8 +560,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 +585,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_TRANSPARENT, &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 +618,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 we start doing this, then the security requirements for SCO channels
are pointless. They do not exists.

Regards

Marcel



2013-01-17 14:15:06

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 3/5] Bluetooth: Use mode when accepting SCO connection

Hi Fred,

> When an incoming SCO connection is requested, check the selected mode, and
> reply appropriately. Mode 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 defered setup enabled.
> ---
> 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..afa0104 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;
>
> @@ -2074,9 +2074,22 @@ void hci_conn_accept(struct hci_conn *conn, int mask)
>
> 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.content_format = cpu_to_le16(hdev->voice_setting);
> + cp.retrans_effort = 0xff;
> + break;
> + case 1:
> + if (conn->pkt_type & ESCO_2EV3)
> + cp.max_latency = __constant_cpu_to_le16(0x0008);
> + else
> + cp.max_latency = __constant_cpu_to_le16(0x000D);
> + cp.content_format = __constant_cpu_to_le16(0x0003);
> + cp.retrans_effort = 0x02;
> + break;
> + }

so what happens if someone sets mode == 0x02, then we just send some
random data. This reminds me, we need to do range checks for the
setsockopt call. Only valid modes are suppose to be allowed.
>
> 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);

Regards

Marcel



2013-01-17 14:12:10

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 2/5] Bluetooth: Add setsockopt for SCO socket mode

Hi Fred,

> This patch implements setsockopt().

not acceptable commit message.

> ---
> 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;

Don't we need to set a opts.mtu here as well? This is user input. So we
need to be 100% sure to verify it.

Regards

Marcel



2013-01-17 14:09:32

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH 1/5] Bluetooth: Add option for SCO socket mode

Hi Fred,

> 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 | 20 ++++++++++++++++++++
> net/bluetooth/sco.c | 3 +++
> 2 files changed, 23 insertions(+)
>
> diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
> index 1e35c43..bc5d3d6 100644
> --- a/include/net/bluetooth/sco.h
> +++ b/include/net/bluetooth/sco.h
> @@ -41,8 +41,27 @@ 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
> +

I do not like this enhanced magic. How is this suppose to work? And it
is also not explained in the commit message. Or used in this patch.

Regards

Marcel



2013-01-17 12:39:49

by Frédéric DALLEAU

[permalink] [raw]
Subject: [PATCH 5/5] Bluetooth: Fallback transparent SCO from T2 to T1

When initiating a transparent eSCO connection, make use of T2 settings at
first try. T2 is the recommended settings from HFP 1.6 WideBand Speech. Upon
connection failure, try T1 settings.
To know which of T2 or T1 should be used, the connection attempt index is used.
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".
---
net/bluetooth/hci_conn.c | 11 ++++++++++-
net/bluetooth/hci_event.c | 1 +
2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index e3f1fad..d08f001 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -179,12 +179,21 @@ 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);

- if (test_and_clear_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
+ if (conn->attempt == 1 &&
+ test_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
cp.pkt_type = __constant_cpu_to_le16(EDR_ESCO_MASK &
~ESCO_2EV3);
cp.max_latency = __constant_cpu_to_le16(0x000d);
cp.voice_setting = __constant_cpu_to_le16(0x0003);
cp.retrans_effort = 0x02;
+ } else if (conn->attempt == 2 &&
+ test_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
+ cp.pkt_type = __constant_cpu_to_le16(EDR_ESCO_MASK |
+ ESCO_EV3);
+ cp.max_latency = __constant_cpu_to_le16(0x0007);
+ cp.voice_setting = __constant_cpu_to_le16(0x0003);
+ cp.retrans_effort = 0x02;
+ clear_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags);
} else {
cp.pkt_type = cpu_to_le16(conn->pkt_type);
cp.max_latency = __constant_cpu_to_le16(0xffff);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index afa0104..ba4af46 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


2013-01-17 12:39:48

by Frédéric DALLEAU

[permalink] [raw]
Subject: [PATCH 4/5] Bluetooth: Parameters for outgoing SCO connections

In order to establish a transparent SCO connection, the correct settings must
be specified in the SetupSynchronousConnection request. For that, a bit is set
in ACL connection flags to set up the desired parameters. If this bit is not
set, a legacy SCO connection will be requested.
This patch uses T2 settings.
---
include/net/bluetooth/hci_core.h | 3 +++
net/bluetooth/hci_conn.c | 27 ++++++++++++++++++++-------
net/bluetooth/sco.c | 4 ++--
3 files changed, 25 insertions(+), 9 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index cb5d131..9ef7fe0 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_TRANSPARENT,
};

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..e3f1fad 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -175,13 +175,22 @@ 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;
+
+ if (test_and_clear_bit(HCI_CONN_SCO_TRANSPARENT, &conn->flags)) {
+ cp.pkt_type = __constant_cpu_to_le16(EDR_ESCO_MASK &
+ ~ESCO_2EV3);
+ cp.max_latency = __constant_cpu_to_le16(0x000d);
+ cp.voice_setting = __constant_cpu_to_le16(0x0003);
+ cp.retrans_effort = 0x02;
+ } else {
+ cp.pkt_type = cpu_to_le16(conn->pkt_type);
+ cp.max_latency = __constant_cpu_to_le16(0xffff);
+ cp.voice_setting = cpu_to_le16(hdev->voice_setting);
+ cp.retrans_effort = 0xff;
+ }

hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
}
@@ -551,8 +560,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 +585,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_TRANSPARENT, &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 +618,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


2013-01-17 12:39:47

by Frédéric DALLEAU

[permalink] [raw]
Subject: [PATCH 3/5] Bluetooth: Use mode when accepting SCO connection

When an incoming SCO connection is requested, check the selected mode, and
reply appropriately. Mode 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 defered setup enabled.
---
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..afa0104 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;

@@ -2074,9 +2074,22 @@ void hci_conn_accept(struct hci_conn *conn, int mask)

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.content_format = cpu_to_le16(hdev->voice_setting);
+ cp.retrans_effort = 0xff;
+ break;
+ case 1:
+ if (conn->pkt_type & ESCO_2EV3)
+ cp.max_latency = __constant_cpu_to_le16(0x0008);
+ else
+ cp.max_latency = __constant_cpu_to_le16(0x000D);
+ cp.content_format = __constant_cpu_to_le16(0x0003);
+ 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


2013-01-17 12:39:46

by Frédéric DALLEAU

[permalink] [raw]
Subject: [PATCH 2/5] Bluetooth: Add setsockopt for SCO socket mode

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


2013-01-17 12:39:45

by Frédéric DALLEAU

[permalink] [raw]
Subject: [PATCH 1/5] Bluetooth: Add option for SCO socket mode

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 | 20 ++++++++++++++++++++
net/bluetooth/sco.c | 3 +++
2 files changed, 23 insertions(+)

diff --git a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h
index 1e35c43..bc5d3d6 100644
--- a/include/net/bluetooth/sco.h
+++ b/include/net/bluetooth/sco.h
@@ -41,8 +41,27 @@ 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 +92,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