2021-11-19 08:14:58

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 01/14] Bluetooth: Refactor code to read supported codecs in getsockopt

This patch moves reading of supported codecs from cache to a new
function to reuse over L2CAP sockets to be used in a2dp offload
use case.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/hci_codec.c | 83 +++++++++++++++++++++++++++++++++++
net/bluetooth/hci_codec.h | 2 +
net/bluetooth/sco.c | 91 +++------------------------------------
3 files changed, 91 insertions(+), 85 deletions(-)

diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
index 38201532f58e..1e486aca3002 100644
--- a/net/bluetooth/hci_codec.c
+++ b/net/bluetooth/hci_codec.c
@@ -250,3 +250,86 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
error:
kfree_skb(skb);
}
+
+int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
+ int __user *optlen, int len)
+{
+ int n = 0, buf_len = 0, err = 0;
+ struct hci_codec_caps *caps;
+ struct bt_codec codec;
+ u8 num_codecs = 0, i, __user *ptr;
+ struct codec_list *c;
+
+ if (!hdev->get_data_path_id) {
+ err = -EOPNOTSUPP;
+ goto error;
+ }
+
+ /* find total buffer size required to copy codec + capabilities */
+ hci_dev_lock(hdev);
+ list_for_each_entry(c, &hdev->local_codecs, list) {
+ if (c->transport != type)
+ continue;
+ num_codecs++;
+ for (i = 0, caps = c->caps; i < c->num_caps; i++) {
+ buf_len += 1 + caps->len;
+ caps = (void *)&caps->data[caps->len];
+ }
+ buf_len += sizeof(struct bt_codec);
+ }
+ hci_dev_unlock(hdev);
+
+ buf_len += sizeof(struct bt_codecs);
+ if (buf_len > len) {
+ err = -ENOBUFS;
+ goto error;
+ }
+ ptr = optval;
+
+ if (put_user(num_codecs, ptr)) {
+ err = -EFAULT;
+ goto error;
+ }
+ ptr += sizeof(num_codecs);
+
+ /* Iterate over all the codecs on required transport */
+ hci_dev_lock(hdev);
+ list_for_each_entry(c, &hdev->local_codecs, list) {
+ if (c->transport != type)
+ continue;
+
+ codec.id = c->id;
+ codec.cid = c->cid;
+ codec.vid = c->vid;
+ err = hdev->get_data_path_id(hdev, &codec.data_path);
+ if (err < 0)
+ break;
+ codec.num_caps = c->num_caps;
+ if (copy_to_user(ptr, &codec, sizeof(codec))) {
+ err = -EFAULT;
+ break;
+ }
+ ptr += sizeof(codec);
+
+ /* find codec capabilities data length */
+ n = 0;
+ for (i = 0, caps = c->caps; i < c->num_caps; i++) {
+ n += 1 + caps->len;
+ caps = (void *)&caps->data[caps->len];
+ }
+
+ /* copy codec capabilities data */
+ if (n && copy_to_user(ptr, c->caps, n)) {
+ err = -EFAULT;
+ break;
+ }
+ ptr += n;
+ }
+ hci_dev_unlock(hdev);
+
+ if (!err && put_user(buf_len, optlen))
+ err = -EFAULT;
+
+error:
+ return err;
+}
diff --git a/net/bluetooth/hci_codec.h b/net/bluetooth/hci_codec.h
index a2751930f123..6e849c7d75b9 100644
--- a/net/bluetooth/hci_codec.h
+++ b/net/bluetooth/hci_codec.h
@@ -5,3 +5,5 @@
void hci_read_supported_codecs(struct hci_dev *hdev);
void hci_read_supported_codecs_v2(struct hci_dev *hdev);
void hci_codec_list_clear(struct list_head *codec_list);
+int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
+ int __user *optlen, int len);
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 8eabf41b2993..6bb1b5dc0e60 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -33,6 +33,8 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/sco.h>

+#include "hci_codec.h"
+
static bool disable_esco;

static const struct proto_ops sco_sock_ops;
@@ -1032,12 +1034,7 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
struct bt_voice voice;
u32 phys;
int pkt_status;
- int buf_len;
- struct codec_list *c;
- u8 num_codecs, i, __user *ptr;
struct hci_dev *hdev;
- struct hci_codec_caps *caps;
- struct bt_codec codec;

BT_DBG("sk %p", sk);

@@ -1103,98 +1100,22 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
break;

case BT_CODEC:
- num_codecs = 0;
- buf_len = 0;
-
- hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
+ hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
+ BDADDR_BREDR);
if (!hdev) {
err = -EBADFD;
break;
}

if (!hci_dev_test_flag(hdev, HCI_OFFLOAD_CODECS_ENABLED)) {
- hci_dev_put(hdev);
err = -EOPNOTSUPP;
- break;
- }
-
- if (!hdev->get_data_path_id) {
- hci_dev_put(hdev);
- err = -EOPNOTSUPP;
- break;
- }
-
- /* find total buffer size required to copy codec + caps */
- hci_dev_lock(hdev);
- list_for_each_entry(c, &hdev->local_codecs, list) {
- if (c->transport != HCI_TRANSPORT_SCO_ESCO)
- continue;
- num_codecs++;
- for (i = 0, caps = c->caps; i < c->num_caps; i++) {
- buf_len += 1 + caps->len;
- caps = (void *)&caps->data[caps->len];
- }
- buf_len += sizeof(struct bt_codec);
- }
- hci_dev_unlock(hdev);
-
- buf_len += sizeof(struct bt_codecs);
- if (buf_len > len) {
hci_dev_put(hdev);
- err = -ENOBUFS;
break;
}
- ptr = optval;

- if (put_user(num_codecs, ptr)) {
- hci_dev_put(hdev);
- err = -EFAULT;
- break;
- }
- ptr += sizeof(num_codecs);
-
- /* Iterate all the codecs supported over SCO and populate
- * codec data
- */
- hci_dev_lock(hdev);
- list_for_each_entry(c, &hdev->local_codecs, list) {
- if (c->transport != HCI_TRANSPORT_SCO_ESCO)
- continue;
-
- codec.id = c->id;
- codec.cid = c->cid;
- codec.vid = c->vid;
- err = hdev->get_data_path_id(hdev, &codec.data_path);
- if (err < 0)
- break;
- codec.num_caps = c->num_caps;
- if (copy_to_user(ptr, &codec, sizeof(codec))) {
- err = -EFAULT;
- break;
- }
- ptr += sizeof(codec);
-
- /* find codec capabilities data length */
- len = 0;
- for (i = 0, caps = c->caps; i < c->num_caps; i++) {
- len += 1 + caps->len;
- caps = (void *)&caps->data[caps->len];
- }
-
- /* copy codec capabilities data */
- if (len && copy_to_user(ptr, c->caps, len)) {
- err = -EFAULT;
- break;
- }
- ptr += len;
- }
-
- if (!err && put_user(buf_len, optlen))
- err = -EFAULT;
-
- hci_dev_unlock(hdev);
+ err = hci_get_supported_codecs(hdev, HCI_TRANSPORT_SCO_ESCO,
+ optval, optlen, len);
hci_dev_put(hdev);
-
break;

default:
--
2.17.1



2021-11-19 08:15:00

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 02/14] Bluetooth: Support reading of codecs supported over l2cap socket

Codecs supported for A2DP offload use case are returned over l2cap
socket. Add BT_CODEC option to getsockopt to return the codecs.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
include/net/bluetooth/hci.h | 2 ++
net/bluetooth/l2cap_sock.c | 21 +++++++++++++++++++++
2 files changed, 23 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 84db6b275231..e52fd2f1e046 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -332,6 +332,7 @@ enum {
HCI_FORCE_NO_MITM,
HCI_QUALITY_REPORT,
HCI_OFFLOAD_CODECS_ENABLED,
+ HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED,

__HCI_NUM_FLAGS,
};
@@ -2667,6 +2668,7 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
#define hci_iso_data_flags(h) ((h) >> 14)

/* codec transport types */
+#define HCI_TRANSPORT_ACL 0x00
#define HCI_TRANSPORT_SCO_ESCO 0x01

/* le24 support */
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 4574c5cb1b59..3c293d6bd04b 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -36,6 +36,7 @@
#include <net/bluetooth/l2cap.h>

#include "smp.h"
+#include "hci_codec.h"

static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
@@ -568,6 +569,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
struct bt_power pwr;
u32 phys;
int len, mode, err = 0;
+ struct hci_dev *hdev;

BT_DBG("sk %p", sk);

@@ -704,6 +706,25 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
err = -EFAULT;
break;

+ case BT_CODEC:
+ hdev = hci_get_route(BDADDR_ANY, &chan->src, BDADDR_BREDR);
+ if (!hdev) {
+ err = -EBADFD;
+ break;
+ }
+
+ if (!hci_dev_test_flag(hdev,
+ HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED)) {
+ hci_dev_put(hdev);
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ err = hci_get_supported_codecs(hdev, HCI_TRANSPORT_ACL, optval,
+ optlen, len);
+ hci_dev_put(hdev);
+ break;
+
default:
err = -ENOPROTOOPT;
break;
--
2.17.1


2021-11-19 08:15:02

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 03/14] Bluetooth: btintel: cache offload use case data

Keep a copy of use cases preset information in
driver data. Use cases preset data can be re-used
later instead of reading from controller every time.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
drivers/bluetooth/btintel.c | 6 ++++++
drivers/bluetooth/btintel.h | 1 +
2 files changed, 7 insertions(+)

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 8f9109b40961..c8c5c7007094 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -2221,6 +2221,7 @@ static int btintel_configure_offload(struct hci_dev *hdev)
struct sk_buff *skb;
int err = 0;
struct intel_offload_use_cases *use_cases;
+ struct btintel_data *intel_data;

skb = __hci_cmd_sync(hdev, 0xfc86, 0, NULL, HCI_INIT_TIMEOUT);
if (IS_ERR(skb)) {
@@ -2241,10 +2242,15 @@ static int btintel_configure_offload(struct hci_dev *hdev)
goto error;
}

+ intel_data = hci_get_priv((hdev));
+
+ intel_data->use_cases = *use_cases;
+
if (use_cases->preset[0] & 0x03) {
hdev->get_data_path_id = btintel_get_data_path_id;
hdev->get_codec_config_data = btintel_get_codec_config_data;
}
+
error:
kfree_skb(skb);
return err;
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index e500c0d7a729..091528d75256 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -158,6 +158,7 @@ enum {

struct btintel_data {
DECLARE_BITMAP(flags, __INTEL_NUM_FLAGS);
+ struct intel_offload_use_cases use_cases;
};

#define btintel_set_flag(hdev, nr) \
--
2.17.1


2021-11-19 08:15:03

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 04/14] Bluetooth: Pass transport type in get_data_path_id

To support fetching of data path id for other transport types
like a2dp, le audio, pass an additional parameter to get_data_path_id
callback function.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
drivers/bluetooth/btintel.c | 19 +++++++++++++++----
drivers/bluetooth/hci_vhci.c | 6 +++++-
include/net/bluetooth/hci_core.h | 3 ++-
net/bluetooth/hci_codec.c | 9 ++++++---
net/bluetooth/hci_conn.c | 3 ++-
net/bluetooth/hci_request.c | 5 +++--
net/bluetooth/hci_request.h | 3 ++-
7 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index c8c5c7007094..4b6d7ea08425 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -2209,11 +2209,22 @@ static int btintel_get_codec_config_data(struct hci_dev *hdev,
return err;
}

-static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
+static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 transport,
+ __u8 *data_path_id)
{
- /* Intel uses 1 as data path id for all the usecases */
- *data_path_id = 1;
- return 0;
+ struct btintel_data *intel_data;
+
+ if (transport != HCI_TRANSPORT_SCO_ESCO)
+ return -EINVAL;
+
+ intel_data = hci_get_priv((hdev));
+
+ if (intel_data->use_cases.preset[0] & 0x03) {
+ /* Intel uses 1 as data path id for all the usecases */
+ *data_path_id = 1;
+ return 0;
+ }
+ return -EOPNOTSUPP;
}

static int btintel_configure_offload(struct hci_dev *hdev)
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 49ac884d996e..57f4d016fa89 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -80,8 +80,12 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}

-static int vhci_get_data_path_id(struct hci_dev *hdev, u8 *data_path_id)
+static int vhci_get_data_path_id(struct hci_dev *hdev, u8 transport,
+ u8 *data_path_id)
{
+ if (transport != HCI_TRANSPORT_SCO_ESCO)
+ return -EINVAL;
+
*data_path_id = 0;
return 0;
}
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 2560cfe80db8..b0c5eba20fd4 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -617,7 +617,8 @@ struct hci_dev {
void (*cmd_timeout)(struct hci_dev *hdev);
bool (*wakeup)(struct hci_dev *hdev);
int (*set_quality_report)(struct hci_dev *hdev, bool enable);
- int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
+ int (*get_data_path_id)(struct hci_dev *hdev, __u8 transport,
+ __u8 *data_path);
int (*get_codec_config_data)(struct hci_dev *hdev, __u8 type,
struct bt_codec *codec, __u8 *vnd_len,
__u8 **vnd_data);
diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
index 1e486aca3002..33b341104105 100644
--- a/net/bluetooth/hci_codec.c
+++ b/net/bluetooth/hci_codec.c
@@ -259,12 +259,17 @@ int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
struct bt_codec codec;
u8 num_codecs = 0, i, __user *ptr;
struct codec_list *c;
+ u8 data_path;

if (!hdev->get_data_path_id) {
err = -EOPNOTSUPP;
goto error;
}

+ err = hdev->get_data_path_id(hdev, type, &data_path);
+ if (err < 0)
+ goto error;
+
/* find total buffer size required to copy codec + capabilities */
hci_dev_lock(hdev);
list_for_each_entry(c, &hdev->local_codecs, list) {
@@ -301,9 +306,7 @@ int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
codec.id = c->id;
codec.cid = c->cid;
codec.vid = c->vid;
- err = hdev->get_data_path_id(hdev, &codec.data_path);
- if (err < 0)
- break;
+ codec.data_path = data_path;
codec.num_caps = c->num_caps;
if (copy_to_user(ptr, &codec, sizeof(codec))) {
err = -EFAULT;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cd6e1cf7e396..ce87692272b5 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -317,7 +317,8 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)

/* for offload use case, codec needs to configured before opening SCO */
if (conn->codec.data_path)
- hci_req_configure_datapath(hdev, &conn->codec);
+ hci_req_configure_datapath(hdev, HCI_TRANSPORT_SCO_ESCO,
+ &conn->codec);

conn->state = BT_CONNECT;
conn->out = true;
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 8b3205e4b23e..00460317dec0 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -2480,7 +2480,8 @@ static void config_data_path_complete(struct hci_dev *hdev, u8 status,
bt_dev_dbg(hdev, "status %u", status);
}

-int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec)
+int hci_req_configure_datapath(struct hci_dev *hdev, u8 transport,
+ struct bt_codec *codec)
{
struct hci_request req;
int err;
@@ -2500,7 +2501,7 @@ int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec)
goto error;
}

- err = hdev->get_data_path_id(hdev, &cmd->data_path_id);
+ err = hdev->get_data_path_id(hdev, transport, &cmd->data_path_id);
if (err < 0)
goto error;

diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index 5f8e8846ec74..e360085def98 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -111,7 +111,8 @@ void __hci_req_update_class(struct hci_request *req);
/* Returns true if HCI commands were queued */
bool hci_req_stop_discovery(struct hci_request *req);

-int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec);
+int hci_req_configure_datapath(struct hci_dev *hdev, u8 transport,
+ struct bt_codec *codec);

static inline void hci_req_update_scan(struct hci_dev *hdev)
{
--
2.17.1


2021-11-19 08:15:06

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 05/14] Bluetooth: btintel: Add support to fetch data path id for a2dp offload

During *setup*, when configuring offload, set get_data_path_id callback
function and support fetching of data path id for a2dp offload use case.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
drivers/bluetooth/btintel.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 4b6d7ea08425..1501376ccf72 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -2214,16 +2214,30 @@ static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 transport,
{
struct btintel_data *intel_data;

- if (transport != HCI_TRANSPORT_SCO_ESCO)
+ if (transport != HCI_TRANSPORT_SCO_ESCO &&
+ transport != HCI_TRANSPORT_ACL) {
+ bt_dev_err(hdev, "Invalid transport type %u", transport);
return -EINVAL;
+ }

intel_data = hci_get_priv((hdev));

- if (intel_data->use_cases.preset[0] & 0x03) {
- /* Intel uses 1 as data path id for all the usecases */
- *data_path_id = 1;
- return 0;
+ switch (transport) {
+ case HCI_TRANSPORT_SCO_ESCO:
+ if (intel_data->use_cases.preset[0] & 0x03) {
+ *data_path_id = 1;
+ return 0;
+ }
+ break;
+ case HCI_TRANSPORT_ACL:
+ if (intel_data->use_cases.preset[0] & 0x08) {
+ *data_path_id = 1;
+ return 0;
+ }
+ break;
}
+ bt_dev_err(hdev, "Required preset is not supported 0x%02x",
+ intel_data->use_cases.preset[0]);
return -EOPNOTSUPP;
}

@@ -2262,6 +2276,10 @@ static int btintel_configure_offload(struct hci_dev *hdev)
hdev->get_codec_config_data = btintel_get_codec_config_data;
}

+ /* supports SBC codec for a2dp offload */
+ if (use_cases->preset[0] & 0x08)
+ hdev->get_data_path_id = btintel_get_data_path_id;
+
error:
kfree_skb(skb);
return err;
--
2.17.1


2021-11-19 08:15:11

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 06/14] Bluetooth: Remove unused member in struct hci_vnd_codec_v2

Remove unused "u8 id" member in struct hci_vnd_codec_v2. Vendor codec
is identifiable by Company Id and Vendor Id fields.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
include/net/bluetooth/hci.h | 1 -
1 file changed, 1 deletion(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index e52fd2f1e046..54fae19f3758 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1395,7 +1395,6 @@ struct hci_std_codecs_v2 {
} __packed;

struct hci_vnd_codec_v2 {
- __u8 id;
__le16 cid;
__le16 vid;
__u8 transport;
--
2.17.1


2021-11-19 08:15:11

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 07/14] Bluetooth: Read Output codec capabilities

When reading codec capabilities, read output (controller to host)
capabilities also along with input (host to controller) capabilities.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/hci_codec.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)

diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
index 33b341104105..854440872632 100644
--- a/net/bluetooth/hci_codec.c
+++ b/net/bluetooth/hci_codec.c
@@ -159,6 +159,9 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
caps.id = std_codecs->codec[i];
caps.direction = 0x00;
hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
+
+ caps.direction = 0x01;
+ hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
}

skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
@@ -179,6 +182,9 @@ void hci_read_supported_codecs(struct hci_dev *hdev)
caps.vid = vnd_codecs->codec[i].vid;
caps.direction = 0x00;
hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
+
+ caps.direction = 0x01;
+ hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps);
}

error:
@@ -224,6 +230,10 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)

for (i = 0; i < std_codecs->num; i++) {
caps.id = std_codecs->codec[i].id;
+ caps.direction = 0x00;
+ hci_read_codec_capabilities(hdev, std_codecs->codec[i].transport,
+ &caps);
+ caps.direction = 0x01;
hci_read_codec_capabilities(hdev, std_codecs->codec[i].transport,
&caps);
}
@@ -243,6 +253,10 @@ void hci_read_supported_codecs_v2(struct hci_dev *hdev)
caps.id = 0xFF;
caps.cid = vnd_codecs->codec[i].cid;
caps.vid = vnd_codecs->codec[i].vid;
+ caps.direction = 0x00;
+ hci_read_codec_capabilities(hdev, vnd_codecs->codec[i].transport,
+ &caps);
+ caps.direction = 0x01;
hci_read_codec_capabilities(hdev, vnd_codecs->codec[i].transport,
&caps);
}
--
2.17.1


2021-11-19 08:15:13

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 08/14] Bluetooth: Implement MSFT avdtp open command

In A2DP offload use case, controller needs to configured
with selected codec capabilities, dcid of media transport
channel and ACL connection handle.

Controller responds with avdtp handle which needs to be
sent in other avdtp commands like start, suspend and close.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
include/net/bluetooth/bluetooth.h | 2 +
net/bluetooth/l2cap_sock.c | 27 ++++++++
net/bluetooth/msft.c | 104 ++++++++++++++++++++++++++++++
net/bluetooth/msft.h | 3 +
4 files changed, 136 insertions(+)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 2f31e571f34c..6d5580316493 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -177,6 +177,8 @@ struct bt_codecs {
#define BT_CODEC_TRANSPARENT 0x03
#define BT_CODEC_MSBC 0x05

+#define BT_MSFT 20
+
__printf(1, 2)
void bt_info(const char *fmt, ...);
__printf(1, 2)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 3c293d6bd04b..6f8d8c189b41 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -37,6 +37,8 @@

#include "smp.h"
#include "hci_codec.h"
+#include "hci_request.h"
+#include "msft.h"

static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
@@ -916,6 +918,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
struct l2cap_conn *conn;
int len, err = 0;
u32 opt;
+ struct hci_dev *hdev;

BT_DBG("sk %p", sk);

@@ -1144,6 +1147,30 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,

break;

+ case BT_MSFT:
+ if (sk->sk_state != BT_CONNECTED) {
+ err = -ENOTCONN;
+ break;
+ }
+
+ hdev = hci_get_route(BDADDR_ANY, &chan->src, BDADDR_BREDR);
+ if (!hdev) {
+ err = -EBADFD;
+ break;
+ }
+
+ if (!hci_dev_test_flag(hdev,
+ HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED) ||
+ !hdev->get_data_path_id) {
+ err = -EOPNOTSUPP;
+ hci_dev_put(hdev);
+ break;
+ }
+
+ err = msft_avdtp_cmd(hdev, chan, optval, optlen);
+ hci_dev_put(hdev);
+ break;
+
default:
err = -ENOPROTOOPT;
break;
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 1122097e1e49..60ed08d65a06 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -6,6 +6,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h>
+#include <net/bluetooth/l2cap.h>

#include "hci_request.h"
#include "mgmt_util.h"
@@ -98,6 +99,28 @@ struct msft_data {
__u8 filter_enabled;
};

+#define MSFT_OP_AVDTP 0xfc1e
+struct msft_cp_avdtp {
+ __u8 sub_opcode;
+ __u8 len;
+ __u8 data[0];
+};
+
+#define MSFT_OP_AVDTP_OPEN 0x08
+struct hci_media_service_caps {
+ __u8 category;
+ __u8 len;
+ __u8 data[0];
+} __packed;
+
+struct msft_cp_avdtp_open {
+ __u8 sub_opcode;
+ __le16 handle;
+ __le16 dcid;
+ __le16 omtu;
+ __u8 caps[0];
+} __packed;
+
static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
@@ -812,3 +835,84 @@ bool msft_curve_validity(struct hci_dev *hdev)
{
return hdev->msft_curve_validity;
}
+
+static int msft_avdtp_open(struct hci_dev *hdev,
+ struct l2cap_chan *chan,
+ struct msft_cp_avdtp *cmd)
+{
+ struct msft_cp_avdtp_open *open_cmd;
+ struct hci_media_service_caps *caps;
+ int err = 0;
+
+ caps = (void *)cmd->data;
+
+ if (!caps || caps->category != 0x07) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ open_cmd = kzalloc(sizeof(*open_cmd) + caps->len, GFP_KERNEL);
+ if (!open_cmd) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ open_cmd->sub_opcode = MSFT_OP_AVDTP_OPEN;
+ open_cmd->handle = cpu_to_le16(chan->conn->hcon->handle);
+ open_cmd->dcid = cpu_to_le16(chan->dcid);
+ open_cmd->omtu = cpu_to_le16(chan->omtu);
+
+ /* copy codec capabilities */
+ memcpy(open_cmd->caps, caps, sizeof(*caps) + caps->len);
+
+ hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(*open_cmd) + cmd->len,
+ open_cmd);
+
+ /* wait until we get avdtp handle or timeout */
+fail:
+ kfree(open_cmd);
+ return err;
+}
+
+int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
+ sockptr_t optval, int optlen)
+{
+ int err = 0;
+ struct msft_cp_avdtp *cmd;
+ u8 buffer[255];
+
+ if (!optlen) {
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if (optlen > sizeof(buffer)) {
+ err = -ENOBUFS;
+ goto fail;
+ }
+
+ if (copy_from_sockptr(buffer, optval, optlen)) {
+ err = -EFAULT;
+ goto fail;
+ }
+
+ cmd = (void *)buffer;
+
+ switch (cmd->sub_opcode) {
+ case MSFT_OP_AVDTP_OPEN:
+ if (cmd->len > sizeof(buffer) - sizeof(*cmd)) {
+ err = -EINVAL;
+ break;
+ }
+ err = msft_avdtp_open(hdev, chan, cmd);
+ break;
+
+ default:
+ err = -EINVAL;
+ bt_dev_err(hdev, "Invalid MSFT avdtp sub opcode = 0x%2.2x",
+ cmd->sub_opcode);
+ break;
+ }
+fail:
+ return err;
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index b59b63dc0ea8..7628c87e6358 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -77,3 +77,6 @@ static inline bool msft_curve_validity(struct hci_dev *hdev)
}

#endif
+
+int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
+ sockptr_t optval, int optlen);
--
2.17.1


2021-11-19 08:15:15

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 09/14] Bluetooth: Handle MSFT avdtp open event

Handle MSFT avdtp open event

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/hci_event.c | 4 +++
net/bluetooth/msft.c | 57 ++++++++++++++++++++++++++++++++++++++-
net/bluetooth/msft.h | 3 +++
3 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index efc5458b1345..70ee07e8f27e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3812,6 +3812,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cc_le_read_transmit_power(hdev, skb);
break;

+ case MSFT_OP_AVDTP:
+ msft_cc_avdtp(hdev, skb);
+ break;
+
default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, *opcode);
break;
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 60ed08d65a06..5953127b3521 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -99,7 +99,6 @@ struct msft_data {
__u8 filter_enabled;
};

-#define MSFT_OP_AVDTP 0xfc1e
struct msft_cp_avdtp {
__u8 sub_opcode;
__u8 len;
@@ -121,6 +120,13 @@ struct msft_cp_avdtp_open {
__u8 caps[0];
} __packed;

+struct msft_rp_avdtp_open {
+ __u8 status;
+ __u8 sub_opcode;
+ __le16 avdtp_handle;
+ __u8 audio_intf_param_cnt;
+} __packed;
+
static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
@@ -916,3 +922,52 @@ int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
fail:
return err;
}
+
+static void msft_cc_avdtp_open(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct msft_rp_avdtp_open *rp;
+ struct msft_cp_avdtp_open *sent;
+ struct hci_conn *hconn;
+
+ if (skb->len < sizeof(*rp))
+ return;
+
+ rp = (void *)skb->data;
+
+ sent = hci_sent_cmd_data(hdev, MSFT_OP_AVDTP);
+
+ hconn = hci_conn_hash_lookup_handle(hdev, le16_to_cpu(sent->handle));
+
+ if (!hconn)
+ return;
+
+ /* wake up the task waiting on avdtp handle */
+}
+
+void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ void *sent;
+ __u8 status;
+
+ if (skb->len < 2)
+ return;
+
+ status = skb->data[0];
+
+ bt_dev_dbg(hdev, "status 0x%2.2x", status);
+
+ sent = hci_sent_cmd_data(hdev, MSFT_OP_AVDTP);
+ if (!sent)
+ return;
+
+ switch (skb->data[1]) {
+ case MSFT_OP_AVDTP_OPEN:
+ msft_cc_avdtp_open(hdev, skb);
+ break;
+
+ default:
+ bt_dev_err(hdev, "Invalid MSFT sub opcode 0x%2.2x",
+ skb->data[1]);
+ break;
+ }
+}
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index 7628c87e6358..ba26c43431dc 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -10,6 +10,8 @@
#define MSFT_FEATURE_MASK_CURVE_VALIDITY BIT(4)
#define MSFT_FEATURE_MASK_CONCURRENT_ADV_MONITOR BIT(5)

+#define MSFT_OP_AVDTP 0xfc1e
+
#if IS_ENABLED(CONFIG_BT_MSFTEXT)

bool msft_monitor_supported(struct hci_dev *hdev);
@@ -80,3 +82,4 @@ static inline bool msft_curve_validity(struct hci_dev *hdev)

int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
sockptr_t optval, int optlen);
+void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb);
--
2.17.1


2021-11-19 08:15:18

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 10/14] Bluetooth: Handle MSFT avdtp open event

On receiving MSFT avdtp open event, cache avdtp handle and
signal the task waiting on avdtp handle.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
include/net/bluetooth/bluetooth.h | 3 +++
include/net/bluetooth/hci.h | 1 +
include/net/bluetooth/l2cap.h | 4 ++++
net/bluetooth/af_bluetooth.c | 36 +++++++++++++++++++++++++++++++
net/bluetooth/l2cap_core.c | 15 +++++++++++++
net/bluetooth/l2cap_sock.c | 16 +++++++++++++-
net/bluetooth/msft.c | 16 +++++++++++---
net/bluetooth/msft.h | 2 +-
8 files changed, 88 insertions(+), 5 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 6d5580316493..fb204f0089d5 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -317,6 +317,7 @@ struct bt_sock {
struct list_head accept_q;
struct sock *parent;
unsigned long flags;
+ u16 avdtp_handle;
void (*skb_msg_name)(struct sk_buff *, void *, int *);
void (*skb_put_cmsg)(struct sk_buff *, struct msghdr *, struct sock *);
};
@@ -324,6 +325,7 @@ struct bt_sock {
enum {
BT_SK_DEFER_SETUP,
BT_SK_SUSPEND,
+ BT_SK_AVDTP_PEND,
};

struct bt_sock_list {
@@ -346,6 +348,7 @@ __poll_t bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait);
int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo);
int bt_sock_wait_ready(struct sock *sk, unsigned long flags);
+int bt_sock_wait_for_avdtp_hndl(struct sock *sk, unsigned long timeo);

void bt_accept_enqueue(struct sock *parent, struct sock *sk, bool bh);
void bt_accept_unlink(struct sock *sk);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 54fae19f3758..2aeab94a30b7 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -348,6 +348,7 @@ enum {
#define HCI_POWER_OFF_TIMEOUT msecs_to_jiffies(5000) /* 5 seconds */
#define HCI_LE_CONN_TIMEOUT msecs_to_jiffies(20000) /* 20 seconds */
#define HCI_LE_AUTOCONN_TIMEOUT msecs_to_jiffies(4000) /* 4 seconds */
+#define MSFT_AVDTP_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */

/* HCI data types */
#define HCI_COMMAND_PKT 0x01
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 3c4f550e5a8b..62705273d2eb 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -669,6 +669,8 @@ struct l2cap_ops {
unsigned long len, int nb);
int (*filter) (struct l2cap_chan * chan,
struct sk_buff *skb);
+ void (*avdtp_wakeup) (struct l2cap_chan *chan,
+ u8 status, u16 handle);
};

struct l2cap_conn {
@@ -1001,6 +1003,8 @@ void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);

struct l2cap_conn *l2cap_conn_get(struct l2cap_conn *conn);
void l2cap_conn_put(struct l2cap_conn *conn);
+void l2cap_avdtp_wakeup(struct l2cap_conn *conn, u16 dcid, u8 status,
+ u16 handle);

int l2cap_register_user(struct l2cap_conn *conn, struct l2cap_user *user);
void l2cap_unregister_user(struct l2cap_conn *conn, struct l2cap_user *user);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 1661979b6a6e..62bfd88d05b2 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -607,6 +607,42 @@ int bt_sock_wait_ready(struct sock *sk, unsigned long flags)
}
EXPORT_SYMBOL(bt_sock_wait_ready);

+/* This function expects the sk lock to be held when called */
+int bt_sock_wait_for_avdtp_hndl(struct sock *sk, unsigned long timeo)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int err = 0;
+
+ BT_DBG("sk %p", sk);
+
+ add_wait_queue(sk_sleep(sk), &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (test_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags)) {
+ if (!timeo) {
+ err = -EINPROGRESS;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ err = sock_intr_errno(timeo);
+ break;
+ }
+
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ err = sock_error(sk);
+ if (err)
+ break;
+ }
+ __set_current_state(TASK_RUNNING);
+ remove_wait_queue(sk_sleep(sk), &wait);
+ return err;
+}
+EXPORT_SYMBOL(bt_sock_wait_for_avdtp_hndl);
+
#ifdef CONFIG_PROC_FS
static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(seq->private->l->lock)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4f8f37599962..32b69c9432aa 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -8507,6 +8507,21 @@ int __init l2cap_init(void)
return 0;
}

+void l2cap_avdtp_wakeup(struct l2cap_conn *conn, u16 cid, u8 status,
+ u16 handle)
+{
+ struct l2cap_chan *chan;
+
+ chan = l2cap_get_chan_by_dcid(conn, cid);
+
+ if (!chan)
+ return;
+
+ chan->ops->avdtp_wakeup(chan, status, handle);
+
+ l2cap_chan_unlock(chan);
+}
+
void l2cap_exit(void)
{
debugfs_remove(l2cap_debugfs);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 6f8d8c189b41..c50c22ae6731 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1167,7 +1167,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
break;
}

- err = msft_avdtp_cmd(hdev, chan, optval, optlen);
+ err = msft_avdtp_cmd(hdev, chan, optval, optlen, sk);
hci_dev_put(hdev);
break;

@@ -1758,6 +1758,19 @@ static int l2cap_sock_filter(struct l2cap_chan *chan, struct sk_buff *skb)
return 0;
}

+static void l2cap_sock_avdtp_wakeup(struct l2cap_chan *chan, u8 status,
+ u16 handle)
+{
+ struct sock *sk = chan->data;
+
+ if (test_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags)) {
+ bt_sk(sk)->avdtp_handle = handle;
+ sk->sk_err = -bt_to_errno(status);
+ clear_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags);
+ sk->sk_state_change(sk);
+ }
+}
+
static const struct l2cap_ops l2cap_chan_ops = {
.name = "L2CAP Socket Interface",
.new_connection = l2cap_sock_new_connection_cb,
@@ -1774,6 +1787,7 @@ static const struct l2cap_ops l2cap_chan_ops = {
.get_peer_pid = l2cap_sock_get_peer_pid_cb,
.alloc_skb = l2cap_sock_alloc_skb_cb,
.filter = l2cap_sock_filter,
+ .avdtp_wakeup = l2cap_sock_avdtp_wakeup,
};

static void l2cap_sock_destruct(struct sock *sk)
diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index 5953127b3521..aca5cac7a87f 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -844,7 +844,8 @@ bool msft_curve_validity(struct hci_dev *hdev)

static int msft_avdtp_open(struct hci_dev *hdev,
struct l2cap_chan *chan,
- struct msft_cp_avdtp *cmd)
+ struct msft_cp_avdtp *cmd,
+ struct sock *sk)
{
struct msft_cp_avdtp_open *open_cmd;
struct hci_media_service_caps *caps;
@@ -874,14 +875,18 @@ static int msft_avdtp_open(struct hci_dev *hdev,
hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(*open_cmd) + cmd->len,
open_cmd);

+ set_bit(BT_SK_AVDTP_PEND, &bt_sk(sk)->flags);
/* wait until we get avdtp handle or timeout */
+ err = bt_sock_wait_for_avdtp_hndl(sk, MSFT_AVDTP_TIMEOUT);
+
fail:
kfree(open_cmd);
return err;
}

int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
- sockptr_t optval, int optlen)
+ sockptr_t optval, int optlen,
+ struct sock *sk)
{
int err = 0;
struct msft_cp_avdtp *cmd;
@@ -910,7 +915,7 @@ int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
err = -EINVAL;
break;
}
- err = msft_avdtp_open(hdev, chan, cmd);
+ err = msft_avdtp_open(hdev, chan, cmd, sk);
break;

default:
@@ -928,6 +933,7 @@ static void msft_cc_avdtp_open(struct hci_dev *hdev, struct sk_buff *skb)
struct msft_rp_avdtp_open *rp;
struct msft_cp_avdtp_open *sent;
struct hci_conn *hconn;
+ struct l2cap_conn *conn;

if (skb->len < sizeof(*rp))
return;
@@ -941,7 +947,11 @@ static void msft_cc_avdtp_open(struct hci_dev *hdev, struct sk_buff *skb)
if (!hconn)
return;

+ conn = hconn->l2cap_data;
+
/* wake up the task waiting on avdtp handle */
+ l2cap_avdtp_wakeup(conn, le16_to_cpu(sent->dcid), rp->status,
+ rp->status ? 0 : __le16_to_cpu(rp->avdtp_handle));
}

void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb)
diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
index ba26c43431dc..9e25fb28450c 100644
--- a/net/bluetooth/msft.h
+++ b/net/bluetooth/msft.h
@@ -81,5 +81,5 @@ static inline bool msft_curve_validity(struct hci_dev *hdev)
#endif

int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
- sockptr_t optval, int optlen);
+ sockptr_t optval, int optlen, struct sock *sk);
void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb);
--
2.17.1


2021-11-19 08:15:23

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 11/14] Bluetooth: Implment MSFT avdtp start command

In a2dp offload use case, after sending L2CAP AVDTP
start command, controller needs to sent MSFT avdtp start
command to trigger to let know the controller to start
streaming audio data. Allow BlueZ daemon to send
MSFT avdtp start command via setsockopt.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/msft.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index aca5cac7a87f..e3f7503070a6 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -127,6 +127,12 @@ struct msft_rp_avdtp_open {
__u8 audio_intf_param_cnt;
} __packed;

+#define MSFT_OP_AVDTP_START 0x09
+struct msft_cp_avdtp_start {
+ u8 sub_opcode;
+ __le16 avdtp_handle;
+} __packed;
+
static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
@@ -884,6 +890,19 @@ static int msft_avdtp_open(struct hci_dev *hdev,
return err;
}

+static int msft_avdtp_start(struct hci_dev *hdev, struct sock *sk)
+{
+ struct msft_cp_avdtp_start cmd;
+
+ if (!bt_sk(sk)->avdtp_handle)
+ return -EBADFD;
+
+ cmd.sub_opcode = MSFT_OP_AVDTP_START;
+ cmd.avdtp_handle = cpu_to_le16(bt_sk(sk)->avdtp_handle);
+
+ return hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(cmd), &cmd);
+}
+
int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
sockptr_t optval, int optlen,
struct sock *sk)
@@ -918,6 +937,10 @@ int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
err = msft_avdtp_open(hdev, chan, cmd, sk);
break;

+ case MSFT_OP_AVDTP_START:
+ err = msft_avdtp_start(hdev, sk);
+ break;
+
default:
err = -EINVAL;
bt_dev_err(hdev, "Invalid MSFT avdtp sub opcode = 0x%2.2x",
@@ -975,6 +998,9 @@ void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb)
msft_cc_avdtp_open(hdev, skb);
break;

+ case MSFT_OP_AVDTP_START:
+ break;
+
default:
bt_dev_err(hdev, "Invalid MSFT sub opcode 0x%2.2x",
skb->data[1]);
--
2.17.1


2021-11-19 08:15:24

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 12/14] Bluetooth: Implment MSFT avdtp suspend command

In a2dp offload use case, to suspend streaming,
controller needs to sent MSFT avdtp suspend command. Allow BlueZ
daemon to send MSFT avdtp suspend command via setsockopt.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/msft.c | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index e3f7503070a6..b505b32289f8 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -133,6 +133,12 @@ struct msft_cp_avdtp_start {
__le16 avdtp_handle;
} __packed;

+#define MSFT_OP_AVDTP_SUSPEND 0x0A
+struct msft_cp_avdtp_suspend {
+ u8 sub_opcode;
+ __le16 avdtp_handle;
+} __packed;
+
static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
@@ -903,6 +909,19 @@ static int msft_avdtp_start(struct hci_dev *hdev, struct sock *sk)
return hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(cmd), &cmd);
}

+static int msft_avdtp_suspend(struct hci_dev *hdev, struct sock *sk)
+{
+ struct msft_cp_avdtp_suspend cmd;
+
+ if (!bt_sk(sk)->avdtp_handle)
+ return -EBADFD;
+
+ cmd.sub_opcode = MSFT_OP_AVDTP_SUSPEND;
+ cmd.avdtp_handle = cpu_to_le16(bt_sk(sk)->avdtp_handle);
+
+ return hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(cmd), &cmd);
+}
+
int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
sockptr_t optval, int optlen,
struct sock *sk)
@@ -941,6 +960,10 @@ int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
err = msft_avdtp_start(hdev, sk);
break;

+ case MSFT_OP_AVDTP_SUSPEND:
+ err = msft_avdtp_suspend(hdev, sk);
+ break;
+
default:
err = -EINVAL;
bt_dev_err(hdev, "Invalid MSFT avdtp sub opcode = 0x%2.2x",
@@ -999,6 +1022,7 @@ void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb)
break;

case MSFT_OP_AVDTP_START:
+ case MSFT_OP_AVDTP_SUSPEND:
break;

default:
--
2.17.1


2021-11-19 08:15:24

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 13/14] Bluetooth: Implment MSFT avdtp close command

In a2dp offload use case, to tear down streaming,
controller needs to sent MSFT avdtp close command. Allow BlueZ
daemon to send MSFT avdtp close command via setsockopt.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/msft.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)

diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
index b505b32289f8..20638254a396 100644
--- a/net/bluetooth/msft.c
+++ b/net/bluetooth/msft.c
@@ -139,6 +139,12 @@ struct msft_cp_avdtp_suspend {
__le16 avdtp_handle;
} __packed;

+#define MSFT_OP_AVDTP_CLOSE 0x0B
+struct msft_cp_avdtp_close {
+ u8 sub_opcode;
+ __le16 avdtp_handle;
+} __packed;
+
static int __msft_add_monitor_pattern(struct hci_dev *hdev,
struct adv_monitor *monitor);
static int __msft_remove_monitor(struct hci_dev *hdev,
@@ -922,6 +928,21 @@ static int msft_avdtp_suspend(struct hci_dev *hdev, struct sock *sk)
return hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(cmd), &cmd);
}

+static int msft_avdtp_close(struct hci_dev *hdev, struct sock *sk)
+{
+ struct msft_cp_avdtp_close cmd;
+
+ if (!bt_sk(sk)->avdtp_handle)
+ return -EBADFD;
+
+ cmd.sub_opcode = MSFT_OP_AVDTP_CLOSE;
+ cmd.avdtp_handle = cpu_to_le16(bt_sk(sk)->avdtp_handle);
+
+ bt_sk(sk)->avdtp_handle = 0;
+
+ return hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(cmd), &cmd);
+}
+
int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
sockptr_t optval, int optlen,
struct sock *sk)
@@ -964,6 +985,10 @@ int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
err = msft_avdtp_suspend(hdev, sk);
break;

+ case MSFT_OP_AVDTP_CLOSE:
+ err = msft_avdtp_close(hdev, sk);
+ break;
+
default:
err = -EINVAL;
bt_dev_err(hdev, "Invalid MSFT avdtp sub opcode = 0x%2.2x",
@@ -1023,6 +1048,7 @@ void msft_cc_avdtp(struct hci_dev *hdev, struct sk_buff *skb)

case MSFT_OP_AVDTP_START:
case MSFT_OP_AVDTP_SUSPEND:
+ case MSFT_OP_AVDTP_CLOSE:
break;

default:
--
2.17.1


2021-11-19 08:15:28

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 14/14] Bluetooth: Add MSFT a2dp offload codec under experimental flag

Keep MSFT a2dp offload codecs feature under experimental flag.

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
net/bluetooth/mgmt.c | 94 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index f8f74d344297..913e2c66cdf6 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -3887,10 +3887,16 @@ static const u8 rpa_resolution_uuid[16] = {
0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15,
};

+/* 0cc2131f-96f0-4cd1-b313-b97e7cbc8335 */
+static const u8 msft_a2dp_offload_codecs_uuid[16] = {
+ 0x35, 0x83, 0xbc, 0x7c, 0x7e, 0xb9, 0x13, 0xb3,
+ 0xd1, 0x4c, 0xf0, 0x96, 0x1f, 0x13, 0xc2, 0x0c,
+};
+
static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
void *data, u16 data_len)
{
- char buf[102]; /* Enough space for 5 features: 2 + 20 * 5 */
+ char buf[122]; /* Enough space for 6 features: 2 + 20 * 6 */
struct mgmt_rp_read_exp_features_info *rp = (void *)buf;
u16 idx = 0;
u32 flags;
@@ -3957,6 +3963,17 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev,
idx++;
}

+ if (hdev && hdev->get_data_path_id) {
+ if (hci_dev_test_flag(hdev, HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED))
+ flags = BIT(0);
+ else
+ flags = 0;
+
+ memcpy(rp->features[idx].uuid, msft_a2dp_offload_codecs_uuid, 16);
+ rp->features[idx].flags = cpu_to_le32(flags);
+ idx++;
+ }
+
rp->feature_count = cpu_to_le16(idx);

/* After reading the experimental features information, enable
@@ -4256,6 +4273,20 @@ static int exp_offload_codec_feature_changed(bool enabled, struct hci_dev *hdev,
HCI_MGMT_EXP_FEATURE_EVENTS, skip);
}

+static int exp_msft_a2dp_offload_codec_feature_changed(bool enabled,
+ struct sock *skip)
+{
+ struct mgmt_ev_exp_feature_changed ev;
+
+ memset(&ev, 0, sizeof(ev));
+ memcpy(ev.uuid, msft_a2dp_offload_codecs_uuid, 16);
+ ev.flags = cpu_to_le32(enabled ? BIT(0) : 0);
+
+ return mgmt_limited_event(MGMT_EV_EXP_FEATURE_CHANGED, NULL,
+ &ev, sizeof(ev),
+ HCI_MGMT_EXP_FEATURE_EVENTS, skip);
+}
+
static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
struct mgmt_cp_set_exp_feature *cp,
u16 data_len)
@@ -4314,6 +4345,66 @@ static int set_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
return err;
}

+static int set_msft_a2dp_offload_codec_func(struct sock *sk, struct hci_dev *hdev,
+ struct mgmt_cp_set_exp_feature *cp,
+ u16 data_len)
+{
+ bool val, changed;
+ int err;
+ struct mgmt_rp_set_exp_feature rp;
+
+ /* Command requires to use a valid controller index */
+ if (!hdev)
+ return mgmt_cmd_status(sk, MGMT_INDEX_NONE,
+ MGMT_OP_SET_EXP_FEATURE,
+ MGMT_STATUS_INVALID_INDEX);
+
+ /* Parameters are limited to a single octet */
+ if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1)
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_EXP_FEATURE,
+ MGMT_STATUS_INVALID_PARAMS);
+
+ /* Only boolean on/off is supported */
+ if (cp->param[0] != 0x00 && cp->param[0] != 0x01)
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_EXP_FEATURE,
+ MGMT_STATUS_INVALID_PARAMS);
+
+ val = !!cp->param[0];
+ changed = (val != hci_dev_test_flag(hdev,
+ HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED));
+
+ if (!hdev->get_data_path_id) {
+ return mgmt_cmd_status(sk, hdev->id,
+ MGMT_OP_SET_EXP_FEATURE,
+ MGMT_STATUS_NOT_SUPPORTED);
+ }
+
+ if (changed) {
+ if (val)
+ hci_dev_set_flag(hdev,
+ HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED);
+ else
+ hci_dev_clear_flag(hdev,
+ HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED);
+ }
+
+ bt_dev_info(hdev, "msft offload codecs enable %d changed %d",
+ val, changed);
+
+ memcpy(rp.uuid, msft_a2dp_offload_codecs_uuid, 16);
+ rp.flags = cpu_to_le32(val ? BIT(0) : 0);
+ hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS);
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_SET_EXP_FEATURE, 0,
+ &rp, sizeof(rp));
+
+ if (changed)
+ exp_msft_a2dp_offload_codec_feature_changed(val, sk);
+
+ return err;
+}
static const struct mgmt_exp_feature {
const u8 *uuid;
int (*set_func)(struct sock *sk, struct hci_dev *hdev,
@@ -4326,6 +4417,7 @@ static const struct mgmt_exp_feature {
EXP_FEAT(rpa_resolution_uuid, set_rpa_resolution_func),
EXP_FEAT(quality_report_uuid, set_quality_report_func),
EXP_FEAT(offload_codecs_uuid, set_offload_codec_func),
+ EXP_FEAT(msft_a2dp_offload_codecs_uuid, set_msft_a2dp_offload_codec_func),

/* end with a null feature */
EXP_FEAT(NULL, NULL)
--
2.17.1


2021-11-23 23:43:40

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v4 04/14] Bluetooth: Pass transport type in get_data_path_id

Hi Kiran,

On Fri, Nov 19, 2021 at 12:15 AM Kiran K <[email protected]> wrote:
>
> To support fetching of data path id for other transport types
> like a2dp, le audio, pass an additional parameter to get_data_path_id
> callback function.
>
> Signed-off-by: Kiran K <[email protected]>
> Reviewed-by: Chethan T N <[email protected]>
> Reviewed-by: Srivatsa Ravishankar <[email protected]>
> ---
> drivers/bluetooth/btintel.c | 19 +++++++++++++++----
> drivers/bluetooth/hci_vhci.c | 6 +++++-
> include/net/bluetooth/hci_core.h | 3 ++-
> net/bluetooth/hci_codec.c | 9 ++++++---
> net/bluetooth/hci_conn.c | 3 ++-
> net/bluetooth/hci_request.c | 5 +++--
> net/bluetooth/hci_request.h | 3 ++-
> 7 files changed, 35 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index c8c5c7007094..4b6d7ea08425 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -2209,11 +2209,22 @@ static int btintel_get_codec_config_data(struct hci_dev *hdev,
> return err;
> }
>
> -static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
> +static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 transport,
> + __u8 *data_path_id)
> {
> - /* Intel uses 1 as data path id for all the usecases */
> - *data_path_id = 1;
> - return 0;
> + struct btintel_data *intel_data;
> +
> + if (transport != HCI_TRANSPORT_SCO_ESCO)
> + return -EINVAL;
> +
> + intel_data = hci_get_priv((hdev));
> +
> + if (intel_data->use_cases.preset[0] & 0x03) {
> + /* Intel uses 1 as data path id for all the usecases */
> + *data_path_id = 1;
> + return 0;
> + }
> + return -EOPNOTSUPP;
> }
>
> static int btintel_configure_offload(struct hci_dev *hdev)
> diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
> index 49ac884d996e..57f4d016fa89 100644
> --- a/drivers/bluetooth/hci_vhci.c
> +++ b/drivers/bluetooth/hci_vhci.c
> @@ -80,8 +80,12 @@ static int vhci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
> return 0;
> }
>
> -static int vhci_get_data_path_id(struct hci_dev *hdev, u8 *data_path_id)
> +static int vhci_get_data_path_id(struct hci_dev *hdev, u8 transport,
> + u8 *data_path_id)
> {
> + if (transport != HCI_TRANSPORT_SCO_ESCO)
> + return -EINVAL;
> +
> *data_path_id = 0;
> return 0;
> }
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 2560cfe80db8..b0c5eba20fd4 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -617,7 +617,8 @@ struct hci_dev {
> void (*cmd_timeout)(struct hci_dev *hdev);
> bool (*wakeup)(struct hci_dev *hdev);
> int (*set_quality_report)(struct hci_dev *hdev, bool enable);
> - int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
> + int (*get_data_path_id)(struct hci_dev *hdev, __u8 transport,
> + __u8 *data_path);
> int (*get_codec_config_data)(struct hci_dev *hdev, __u8 type,
> struct bt_codec *codec, __u8 *vnd_len,
> __u8 **vnd_data);
> diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
> index 1e486aca3002..33b341104105 100644
> --- a/net/bluetooth/hci_codec.c
> +++ b/net/bluetooth/hci_codec.c
> @@ -259,12 +259,17 @@ int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
> struct bt_codec codec;
> u8 num_codecs = 0, i, __user *ptr;
> struct codec_list *c;
> + u8 data_path;
>
> if (!hdev->get_data_path_id) {
> err = -EOPNOTSUPP;
> goto error;
> }
>
> + err = hdev->get_data_path_id(hdev, type, &data_path);
> + if (err < 0)
> + goto error;
> +
> /* find total buffer size required to copy codec + capabilities */
> hci_dev_lock(hdev);
> list_for_each_entry(c, &hdev->local_codecs, list) {
> @@ -301,9 +306,7 @@ int hci_get_supported_codecs(struct hci_dev *hdev, u8 type, char __user *optval,
> codec.id = c->id;
> codec.cid = c->cid;
> codec.vid = c->vid;
> - err = hdev->get_data_path_id(hdev, &codec.data_path);
> - if (err < 0)
> - break;
> + codec.data_path = data_path;
> codec.num_caps = c->num_caps;
> if (copy_to_user(ptr, &codec, sizeof(codec))) {
> err = -EFAULT;
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index cd6e1cf7e396..ce87692272b5 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -317,7 +317,8 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
>
> /* for offload use case, codec needs to configured before opening SCO */
> if (conn->codec.data_path)
> - hci_req_configure_datapath(hdev, &conn->codec);
> + hci_req_configure_datapath(hdev, HCI_TRANSPORT_SCO_ESCO,
> + &conn->codec);
>
> conn->state = BT_CONNECT;
> conn->out = true;
> diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
> index 8b3205e4b23e..00460317dec0 100644
> --- a/net/bluetooth/hci_request.c
> +++ b/net/bluetooth/hci_request.c
> @@ -2480,7 +2480,8 @@ static void config_data_path_complete(struct hci_dev *hdev, u8 status,
> bt_dev_dbg(hdev, "status %u", status);
> }
>
> -int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec)
> +int hci_req_configure_datapath(struct hci_dev *hdev, u8 transport,
> + struct bt_codec *codec)
> {
> struct hci_request req;
> int err;
> @@ -2500,7 +2501,7 @@ int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec)
> goto error;
> }
>
> - err = hdev->get_data_path_id(hdev, &cmd->data_path_id);
> + err = hdev->get_data_path_id(hdev, transport, &cmd->data_path_id);
> if (err < 0)
> goto error;
>
> diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
> index 5f8e8846ec74..e360085def98 100644
> --- a/net/bluetooth/hci_request.h
> +++ b/net/bluetooth/hci_request.h
> @@ -111,7 +111,8 @@ void __hci_req_update_class(struct hci_request *req);
> /* Returns true if HCI commands were queued */
> bool hci_req_stop_discovery(struct hci_request *req);
>
> -int hci_req_configure_datapath(struct hci_dev *hdev, struct bt_codec *codec);
> +int hci_req_configure_datapath(struct hci_dev *hdev, u8 transport,
> + struct bt_codec *codec);

We are moving away from the hci_req* design, instead one should either
use a sync version if that could block or queue a command callback.

> static inline void hci_req_update_scan(struct hci_dev *hdev)
> {
> --
> 2.17.1
>


--
Luiz Augusto von Dentz

2021-11-23 23:49:55

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v4 05/14] Bluetooth: btintel: Add support to fetch data path id for a2dp offload

Hi Kiran,

On Fri, Nov 19, 2021 at 12:16 AM Kiran K <[email protected]> wrote:
>
> During *setup*, when configuring offload, set get_data_path_id callback
> function and support fetching of data path id for a2dp offload use case.
>
> Signed-off-by: Kiran K <[email protected]>
> Reviewed-by: Chethan T N <[email protected]>
> Reviewed-by: Srivatsa Ravishankar <[email protected]>
> ---
> drivers/bluetooth/btintel.c | 28 +++++++++++++++++++++++-----
> 1 file changed, 23 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 4b6d7ea08425..1501376ccf72 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -2214,16 +2214,30 @@ static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 transport,
> {
> struct btintel_data *intel_data;
>
> - if (transport != HCI_TRANSPORT_SCO_ESCO)
> + if (transport != HCI_TRANSPORT_SCO_ESCO &&
> + transport != HCI_TRANSPORT_ACL) {
> + bt_dev_err(hdev, "Invalid transport type %u", transport);
> return -EINVAL;
> + }
>
> intel_data = hci_get_priv((hdev));
>
> - if (intel_data->use_cases.preset[0] & 0x03) {
> - /* Intel uses 1 as data path id for all the usecases */
> - *data_path_id = 1;
> - return 0;
> + switch (transport) {
> + case HCI_TRANSPORT_SCO_ESCO:
> + if (intel_data->use_cases.preset[0] & 0x03) {
> + *data_path_id = 1;
> + return 0;
> + }
> + break;
> + case HCI_TRANSPORT_ACL:
> + if (intel_data->use_cases.preset[0] & 0x08) {
> + *data_path_id = 1;
> + return 0;
> + }

I would suggest adding the bits of use_cases as defines using BIT
macro, it may also be a good idea to check if the preset should
actually be a bitmap and then use the likes of test_bit, etc.

> + break;
> }
> + bt_dev_err(hdev, "Required preset is not supported 0x%02x",
> + intel_data->use_cases.preset[0]);
> return -EOPNOTSUPP;
> }
>
> @@ -2262,6 +2276,10 @@ static int btintel_configure_offload(struct hci_dev *hdev)
> hdev->get_codec_config_data = btintel_get_codec_config_data;
> }
>
> + /* supports SBC codec for a2dp offload */
> + if (use_cases->preset[0] & 0x08)
> + hdev->get_data_path_id = btintel_get_data_path_id;

This seems to be checking only for one of the use cases. How about
SCO/ESCO, doesn't that use get_data_path_id as well?

> error:
> kfree_skb(skb);
> return err;
> --
> 2.17.1
>


--
Luiz Augusto von Dentz

2021-11-23 23:52:44

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v4 06/14] Bluetooth: Remove unused member in struct hci_vnd_codec_v2

Hi Kiran,

On Fri, Nov 19, 2021 at 12:16 AM Kiran K <[email protected]> wrote:
>
> Remove unused "u8 id" member in struct hci_vnd_codec_v2. Vendor codec
> is identifiable by Company Id and Vendor Id fields.
>
> Signed-off-by: Kiran K <[email protected]>
> Reviewed-by: Chethan T N <[email protected]>
> Reviewed-by: Srivatsa Ravishankar <[email protected]>
> ---
> include/net/bluetooth/hci.h | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index e52fd2f1e046..54fae19f3758 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1395,7 +1395,6 @@ struct hci_std_codecs_v2 {
> } __packed;
>
> struct hci_vnd_codec_v2 {
> - __u8 id;
> __le16 cid;
> __le16 vid;
> __u8 transport;
> --
> 2.17.1

Not following this change, afaik LC3 for example should be id 0x06
cid/vid 0x0000 as that is not a vendor, or this is never used for
codecs defined in the spec?


--
Luiz Augusto von Dentz

2021-11-24 01:26:47

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v4 08/14] Bluetooth: Implement MSFT avdtp open command

Hi Kiran,

On Fri, Nov 19, 2021 at 12:16 AM Kiran K <[email protected]> wrote:
>
> In A2DP offload use case, controller needs to configured
> with selected codec capabilities, dcid of media transport
> channel and ACL connection handle.
>
> Controller responds with avdtp handle which needs to be
> sent in other avdtp commands like start, suspend and close.
>
> Signed-off-by: Kiran K <[email protected]>
> Reviewed-by: Chethan T N <[email protected]>
> Reviewed-by: Srivatsa Ravishankar <[email protected]>
> ---
> include/net/bluetooth/bluetooth.h | 2 +
> net/bluetooth/l2cap_sock.c | 27 ++++++++
> net/bluetooth/msft.c | 104 ++++++++++++++++++++++++++++++
> net/bluetooth/msft.h | 3 +
> 4 files changed, 136 insertions(+)
>
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index 2f31e571f34c..6d5580316493 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -177,6 +177,8 @@ struct bt_codecs {
> #define BT_CODEC_TRANSPARENT 0x03
> #define BT_CODEC_MSBC 0x05
>
> +#define BT_MSFT 20
> +
> __printf(1, 2)
> void bt_info(const char *fmt, ...);
> __printf(1, 2)
> diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
> index 3c293d6bd04b..6f8d8c189b41 100644
> --- a/net/bluetooth/l2cap_sock.c
> +++ b/net/bluetooth/l2cap_sock.c
> @@ -37,6 +37,8 @@
>
> #include "smp.h"
> #include "hci_codec.h"
> +#include "hci_request.h"
> +#include "msft.h"
>
> static struct bt_sock_list l2cap_sk_list = {
> .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
> @@ -916,6 +918,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
> struct l2cap_conn *conn;
> int len, err = 0;
> u32 opt;
> + struct hci_dev *hdev;
>
> BT_DBG("sk %p", sk);
>
> @@ -1144,6 +1147,30 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
>
> break;
>
> + case BT_MSFT:
> + if (sk->sk_state != BT_CONNECTED) {
> + err = -ENOTCONN;
> + break;
> + }
> +
> + hdev = hci_get_route(BDADDR_ANY, &chan->src, BDADDR_BREDR);
> + if (!hdev) {
> + err = -EBADFD;
> + break;
> + }
> +
> + if (!hci_dev_test_flag(hdev,
> + HCI_MSFT_A2DP_OFFLOAD_CODECS_ENABLED) ||
> + !hdev->get_data_path_id) {
> + err = -EOPNOTSUPP;
> + hci_dev_put(hdev);
> + break;
> + }
> +
> + err = msft_avdtp_cmd(hdev, chan, optval, optlen);
> + hci_dev_put(hdev);
> + break;
> +
> default:
> err = -ENOPROTOOPT;
> break;
> diff --git a/net/bluetooth/msft.c b/net/bluetooth/msft.c
> index 1122097e1e49..60ed08d65a06 100644
> --- a/net/bluetooth/msft.c
> +++ b/net/bluetooth/msft.c
> @@ -6,6 +6,7 @@
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/mgmt.h>
> +#include <net/bluetooth/l2cap.h>
>
> #include "hci_request.h"
> #include "mgmt_util.h"
> @@ -98,6 +99,28 @@ struct msft_data {
> __u8 filter_enabled;
> };
>
> +#define MSFT_OP_AVDTP 0xfc1e

Is this different than the opcode used in other commands? Afaik all
MSFT command share the same opcode or is this different for AVDTP?

> +struct msft_cp_avdtp {
> + __u8 sub_opcode;
> + __u8 len;
> + __u8 data[0];
> +};
> +
> +#define MSFT_OP_AVDTP_OPEN 0x08
> +struct hci_media_service_caps {
> + __u8 category;
> + __u8 len;
> + __u8 data[0];
> +} __packed;
> +
> +struct msft_cp_avdtp_open {
> + __u8 sub_opcode;
> + __le16 handle;
> + __le16 dcid;
> + __le16 omtu;
> + __u8 caps[0];
> +} __packed;
> +
> static int __msft_add_monitor_pattern(struct hci_dev *hdev,
> struct adv_monitor *monitor);
> static int __msft_remove_monitor(struct hci_dev *hdev,
> @@ -812,3 +835,84 @@ bool msft_curve_validity(struct hci_dev *hdev)
> {
> return hdev->msft_curve_validity;
> }
> +
> +static int msft_avdtp_open(struct hci_dev *hdev,
> + struct l2cap_chan *chan,
> + struct msft_cp_avdtp *cmd)
> +{
> + struct msft_cp_avdtp_open *open_cmd;
> + struct hci_media_service_caps *caps;
> + int err = 0;
> +
> + caps = (void *)cmd->data;
> +
> + if (!caps || caps->category != 0x07) {
> + err = -EINVAL;
> + goto fail;
> + }
> +
> + open_cmd = kzalloc(sizeof(*open_cmd) + caps->len, GFP_KERNEL);
> + if (!open_cmd) {
> + err = -ENOMEM;
> + goto fail;
> + }
> +
> + open_cmd->sub_opcode = MSFT_OP_AVDTP_OPEN;
> + open_cmd->handle = cpu_to_le16(chan->conn->hcon->handle);
> + open_cmd->dcid = cpu_to_le16(chan->dcid);
> + open_cmd->omtu = cpu_to_le16(chan->omtu);
> +
> + /* copy codec capabilities */
> + memcpy(open_cmd->caps, caps, sizeof(*caps) + caps->len);
> +
> + hci_send_cmd(hdev, MSFT_OP_AVDTP, sizeof(*open_cmd) + cmd->len,
> + open_cmd);
> +
> + /* wait until we get avdtp handle or timeout */
> +fail:
> + kfree(open_cmd);
> + return err;
> +}
> +
> +int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
> + sockptr_t optval, int optlen)
> +{
> + int err = 0;
> + struct msft_cp_avdtp *cmd;
> + u8 buffer[255];
> +
> + if (!optlen) {
> + err = -EINVAL;
> + goto fail;
> + }
> +
> + if (optlen > sizeof(buffer)) {
> + err = -ENOBUFS;
> + goto fail;
> + }
> +
> + if (copy_from_sockptr(buffer, optval, optlen)) {
> + err = -EFAULT;
> + goto fail;
> + }
> +
> + cmd = (void *)buffer;
> +
> + switch (cmd->sub_opcode) {
> + case MSFT_OP_AVDTP_OPEN:
> + if (cmd->len > sizeof(buffer) - sizeof(*cmd)) {
> + err = -EINVAL;
> + break;
> + }
> + err = msft_avdtp_open(hdev, chan, cmd);
> + break;
> +
> + default:
> + err = -EINVAL;
> + bt_dev_err(hdev, "Invalid MSFT avdtp sub opcode = 0x%2.2x",
> + cmd->sub_opcode);
> + break;
> + }
> +fail:
> + return err;
> +}
> diff --git a/net/bluetooth/msft.h b/net/bluetooth/msft.h
> index b59b63dc0ea8..7628c87e6358 100644
> --- a/net/bluetooth/msft.h
> +++ b/net/bluetooth/msft.h
> @@ -77,3 +77,6 @@ static inline bool msft_curve_validity(struct hci_dev *hdev)
> }
>
> #endif
> +
> +int msft_avdtp_cmd(struct hci_dev *hdev, struct l2cap_chan *chan,
> + sockptr_t optval, int optlen);
> --
> 2.17.1
>


--
Luiz Augusto von Dentz