2021-07-27 08:45:38

by Kiran K

[permalink] [raw]
Subject: [PATCH v11 01/10] Bluetooth: Enumerate local supported codec and cache details

Move reading of supported local codecs into a separate init function,
query codecs capabilities and cache the data

Signed-off-by: Kiran K <[email protected]>
Signed-off-by: Chethan T N <[email protected]>
Signed-off-by: Srivatsa Ravishankar <[email protected]>
---
* changes in v11:
- Remove Kconfig related changes
- Address minor review comments
- Move codec related functions to new file hci_codec.c

* changes in v10:
- define Kconfig to control offload feature at build time
- fix review comments

* changes in v9:
- use shortname vnd instead of ven

* changes in v8:
- add comments
- split __u8 codec_id[5] into {__u8 id; __le16 cid, vid }
- address review comment related codec caps structure

* changes in v7:
- keep codec enumeration call in hci_init instead of having a separate
function
- Remove unused bitmasks defined for LE transports

* changes in v6:
- fix compiler warning reported for ARCH=arc

* changes in v5:
- fix review comments
- move code used to read standard/vendor codecs caps into single function

* changes in v4:
- convert reading of codecs and codecs caps calls from async to sync

* changes in v3
move codec enumeration into a new init function

* changes in v2
add skb length check before accessing data

include/net/bluetooth/hci.h | 41 +++++++
include/net/bluetooth/hci_core.h | 17 +++
net/bluetooth/Makefile | 2 +-
net/bluetooth/hci_codec.c | 194 +++++++++++++++++++++++++++++++
net/bluetooth/hci_codec.h | 6 +
net/bluetooth/hci_core.c | 12 +-
6 files changed, 266 insertions(+), 6 deletions(-)
create mode 100644 net/bluetooth/hci_codec.c
create mode 100644 net/bluetooth/hci_codec.h

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b80415011dcd..f76849c8eafd 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1307,6 +1307,28 @@ struct hci_rp_read_data_block_size {
} __packed;

#define HCI_OP_READ_LOCAL_CODECS 0x100b
+struct hci_std_codecs {
+ __u8 num;
+ __u8 codec[];
+} __packed;
+
+struct hci_vnd_codec {
+ /* company id */
+ __le16 cid;
+ /* vendor codec id */
+ __le16 vid;
+} __packed;
+
+struct hci_vnd_codecs {
+ __u8 num;
+ struct hci_vnd_codec codec[];
+} __packed;
+
+struct hci_rp_read_local_supported_codecs {
+ __u8 status;
+ struct hci_std_codecs std_codecs;
+ struct hci_vnd_codecs vnd_codecs;
+} __packed;

#define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
struct hci_rp_read_local_pairing_opts {
@@ -1315,6 +1337,25 @@ struct hci_rp_read_local_pairing_opts {
__u8 max_key_size;
} __packed;

+#define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e
+struct hci_op_read_local_codec_caps {
+ __u8 id;
+ __le16 cid;
+ __le16 vid;
+ __u8 transport;
+ __u8 direction;
+} __packed;
+
+struct hci_codec_caps {
+ __u8 len;
+ __u8 data[];
+} __packed;
+
+struct hci_rp_read_local_codec_caps {
+ __u8 status;
+ __u8 num_caps;
+} __packed;
+
#define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
struct hci_rp_read_page_scan_activity {
__u8 status;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index a53e94459ecd..6742e6ad7b37 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -131,6 +131,17 @@ struct bdaddr_list {
u8 bdaddr_type;
};

+struct codec_list {
+ struct list_head list;
+ u8 id;
+ __u16 cid;
+ __u16 vid;
+ u8 transport;
+ u8 num_caps;
+ u32 len;
+ struct hci_codec_caps caps[];
+};
+
struct bdaddr_list_with_irk {
struct list_head list;
bdaddr_t bdaddr;
@@ -535,6 +546,7 @@ struct hci_dev {
struct list_head pend_le_conns;
struct list_head pend_le_reports;
struct list_head blocked_keys;
+ struct list_head local_codecs;

struct hci_dev_stats stat;

@@ -1849,4 +1861,9 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
#define SCO_AIRMODE_CVSD 0x0000
#define SCO_AIRMODE_TRANSP 0x0003

+#define LOCAL_CODEC_ACL_MASK BIT(0)
+#define LOCAL_CODEC_SCO_MASK BIT(1)
+
+#define TRANSPORT_TYPE_MAX 0x04
+
#endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index cc0995301f93..f3e439d98b85 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -14,7 +14,7 @@ bluetooth_6lowpan-y := 6lowpan.o

bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
- ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o
+ ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o

bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
new file mode 100644
index 000000000000..205f3b04c172
--- /dev/null
+++ b/net/bluetooth/hci_codec.c
@@ -0,0 +1,194 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2021 Intel Corporation */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+static int hci_codec_list_add(struct list_head *list,
+ struct hci_op_read_local_codec_caps *sent,
+ struct hci_rp_read_local_codec_caps *rp,
+ void *caps,
+ __u32 len)
+{
+ struct codec_list *entry;
+
+ entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->id = sent->id;
+ if (sent->id == 0xFF) {
+ entry->cid = __le16_to_cpu(sent->cid);
+ entry->vid = __le16_to_cpu(sent->vid);
+ }
+ entry->transport = sent->transport;
+ entry->len = len;
+ entry->num_caps = rp->num_caps;
+ if (rp->num_caps)
+ memcpy(entry->caps, caps, len);
+ list_add(&entry->list, list);
+
+ return 0;
+}
+
+void hci_codec_list_clear(struct list_head *codec_list)
+{
+ struct codec_list *c, *n;
+
+ list_for_each_entry_safe(c, n, codec_list, list) {
+ list_del(&c->list);
+ kfree(c);
+ }
+}
+
+static void hci_read_codec_capabilities(struct hci_dev *hdev, void *codec_id,
+ __u8 transport, bool is_vnd_codec)
+{
+ struct hci_op_read_local_codec_caps cmd;
+ __u8 i;
+
+ memset(&cmd, 0, sizeof(cmd));
+
+ if (is_vnd_codec) {
+ struct hci_vnd_codec *vnd_codec;
+
+ vnd_codec = codec_id;
+ cmd.id = 0xFF;
+ cmd.cid = vnd_codec->cid;
+ cmd.vid = vnd_codec->vid;
+ } else {
+ cmd.id = *(__u8 *)codec_id;
+ }
+
+ cmd.direction = 0x00;
+
+ for (i = 0; i < TRANSPORT_TYPE_MAX; i++) {
+ if (transport & BIT(i)) {
+ struct hci_rp_read_local_codec_caps *rp;
+ struct hci_codec_caps *caps;
+ struct sk_buff *skb;
+ __u8 j;
+ __u32 len;
+
+ cmd.transport = i;
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
+ sizeof(cmd), &cmd,
+ HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb)) {
+ bt_dev_err(hdev, "Failed to read codec capabilities (%ld)",
+ PTR_ERR(skb));
+ continue;
+ }
+
+ if (skb->len < sizeof(*rp))
+ goto error;
+
+ rp = (void *)skb->data;
+
+ if (rp->status)
+ goto error;
+
+ if (!rp->num_caps) {
+ len = 0;
+ /* this codec doesn't have capabilities */
+ goto skip_caps_parse;
+ }
+
+ skb_pull(skb, sizeof(*rp));
+
+ for (j = 0, len = 0; j < rp->num_caps; j++) {
+ caps = (void *)skb->data;
+ if (skb->len < sizeof(*caps))
+ goto error;
+ if (skb->len < caps->len)
+ goto error;
+ len += sizeof(caps->len) + caps->len;
+ skb_pull(skb, sizeof(caps->len) + caps->len);
+ }
+
+skip_caps_parse:
+ hci_dev_lock(hdev);
+ hci_codec_list_add(&hdev->local_codecs, &cmd, rp,
+ (__u8 *)rp + sizeof(*rp), len);
+ hci_dev_unlock(hdev);
+error:
+ kfree_skb(skb);
+ }
+ }
+}
+
+static void hci_codec_list_parse(struct hci_dev *hdev, __u8 num_codecs,
+ void *codec_list, bool is_vnd_codec)
+{
+ __u8 i;
+
+ for (i = 0; i < num_codecs; i++) {
+ if (!is_vnd_codec) {
+ struct hci_std_codecs *codecs = codec_list;
+
+ hci_read_codec_capabilities(hdev, &codecs->codec[i],
+ LOCAL_CODEC_ACL_MASK,
+ is_vnd_codec);
+ } else {
+ struct hci_vnd_codecs *codecs = codec_list;
+
+ hci_read_codec_capabilities(hdev, &codecs->codec[i],
+ LOCAL_CODEC_ACL_MASK,
+ is_vnd_codec);
+ }
+ }
+}
+
+void hci_read_supported_codecs(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ struct hci_rp_read_local_supported_codecs *rp;
+ struct hci_std_codecs *std_codecs;
+ struct hci_vnd_codecs *vnd_codecs;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
+ HCI_CMD_TIMEOUT);
+
+ if (IS_ERR(skb)) {
+ bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
+ PTR_ERR(skb));
+ return;
+ }
+
+ if (skb->len < sizeof(*rp))
+ goto error;
+
+ rp = (void *)skb->data;
+
+ if (rp->status)
+ goto error;
+
+ skb_pull(skb, sizeof(rp->status));
+
+ std_codecs = (void *)skb->data;
+
+ /* validate codecs length before accessing */
+ if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
+ + sizeof(std_codecs->num))
+ goto error;
+
+ /* enumerate codec capabilities of standard codecs */
+ hci_codec_list_parse(hdev, std_codecs->num, std_codecs, false);
+
+ skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
+ + sizeof(std_codecs->num));
+
+ vnd_codecs = (void *)skb->data;
+
+ /* validate vendor codecs length before accessing */
+ if (skb->len <
+ flex_array_size(vnd_codecs, codec, vnd_codecs->num)
+ + sizeof(vnd_codecs->num))
+ goto error;
+
+ /* enumerate vendor codec capabilities */
+ hci_codec_list_parse(hdev, vnd_codecs->num, vnd_codecs, true);
+
+error:
+ kfree_skb(skb);
+}
diff --git a/net/bluetooth/hci_codec.h b/net/bluetooth/hci_codec.h
new file mode 100644
index 000000000000..e5e594933d07
--- /dev/null
+++ b/net/bluetooth/hci_codec.h
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+/* Copyright (C) 2021 Intel Corporation */
+
+void hci_read_supported_codecs(struct hci_dev *hdev);
+void hci_codec_list_clear(struct list_head *codec_list);
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2560ed2f144d..212d5066d413 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -45,6 +45,7 @@
#include "leds.h"
#include "msft.h"
#include "aosp.h"
+#include "hci_codec.h"

static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
@@ -838,10 +839,6 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
if (hdev->commands[22] & 0x04)
hci_set_event_mask_page_2(req);

- /* Read local codec list if the HCI command is supported */
- if (hdev->commands[29] & 0x20)
- hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);
-
/* Read local pairing options if the HCI command is supported */
if (hdev->commands[41] & 0x08)
hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL);
@@ -937,6 +934,10 @@ static int __hci_init(struct hci_dev *hdev)
if (err < 0)
return err;

+ /* Read local codec list if the HCI command is supported */
+ if (hdev->commands[29] & 0x20)
+ hci_read_supported_codecs(hdev);
+
/* This function is only called when the controller is actually in
* configured state. When the controller is marked as unconfigured,
* this initialization procedure is not run.
@@ -1841,6 +1842,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
memset(hdev->eir, 0, sizeof(hdev->eir));
memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
bacpy(&hdev->random_addr, BDADDR_ANY);
+ hci_codec_list_clear(&hdev->local_codecs);

hci_req_sync_unlock(hdev);

@@ -3842,7 +3844,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->conn_hash.list);
INIT_LIST_HEAD(&hdev->adv_instances);
INIT_LIST_HEAD(&hdev->blocked_keys);
-
+ INIT_LIST_HEAD(&hdev->local_codecs);
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
INIT_WORK(&hdev->tx_work, hci_tx_work);
--
2.17.1



2021-07-27 08:45:38

by Kiran K

[permalink] [raw]
Subject: [PATCH v11 04/10] Bluetooth: Allow querying of supported offload codecs over SCO socket

Add BT_CODEC option for getsockopt systemcall to get the details
of offload codecs supported over SCO socket

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
* changes in v11:
- Remove Kconfig related changes
* changes in v10:
- In getsockopt, prepare data in advance and call copy_to_user
istead of calling put_user on each field of struct bt_codec

include/net/bluetooth/bluetooth.h | 20 +++++++
include/net/bluetooth/hci.h | 4 ++
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/sco.c | 91 +++++++++++++++++++++++++++++++
4 files changed, 116 insertions(+)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 9125effbf448..64cddff0c9c4 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -153,6 +153,26 @@ struct bt_voice {

#define BT_SCM_PKT_STATUS 0x03

+#define BT_CODEC 19
+
+struct bt_codec_caps {
+ __u8 len;
+ __u8 data[];
+} __packed;
+
+struct bt_codec {
+ __u8 id;
+ __u16 cid;
+ __u16 vid;
+ __u8 data_path;
+ __u8 num_caps;
+} __packed;
+
+struct bt_codecs {
+ __u8 num_codecs;
+ struct bt_codec codecs[];
+} __packed;
+
__printf(1, 2)
void bt_info(const char *fmt, ...);
__printf(1, 2)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b4e35cf5f4b1..22e872e60ff8 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -2621,6 +2621,10 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
#define hci_iso_data_len(h) ((h) & 0x3fff)
#define hci_iso_data_flags(h) ((h) >> 14)

+/* codec transport types */
+#define TRANSPORT_ACL 0x00
+#define TRANSPORT_SCO_ESCO 0x01
+
/* le24 support */
static inline void hci_cpu_to_le24(__u32 val, __u8 dst[3])
{
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 6742e6ad7b37..71c409c8ab34 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -617,6 +617,7 @@ struct hci_dev {
int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
void (*cmd_timeout)(struct hci_dev *hdev);
bool (*prevent_wake)(struct hci_dev *hdev);
+ int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
};

#define HCI_PHY_HANDLE(handle) (handle & 0xff)
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index ffa2a77a3e4c..2f32693f09c1 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -953,6 +953,12 @@ 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);

@@ -1017,6 +1023,91 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
err = -EFAULT;
break;

+ case BT_CODEC:
+ num_codecs = 0;
+ buf_len = 0;
+
+ hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
+ if (!hdev) {
+ err = -EBADFD;
+ break;
+ }
+
+ if (!hdev->get_data_path_id) {
+ 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 != 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) {
+ err = -ENOBUFS;
+ break;
+ }
+ ptr = optval;
+
+ if (put_user(num_codecs, ptr)) {
+ 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 != 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);
+
+ break;
+
default:
err = -ENOPROTOOPT;
break;
--
2.17.1


2021-07-27 08:47:46

by Kiran K

[permalink] [raw]
Subject: [PATCH v11 05/10] Bluetooth: btintel: Define callback to fetch data_path_id

For Intel controllers supporting HFP offload usecase,
define a callback function to fetch data_path_id

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
* changes in v11:
- no changes
* changes in v10:
- new patch due to refactoring

drivers/bluetooth/btintel.c | 10 ++++++++++
1 file changed, 10 insertions(+)

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index a6b81914766e..49813f2d2e27 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -1272,6 +1272,13 @@ int btintel_set_debug_features(struct hci_dev *hdev,
}
EXPORT_SYMBOL_GPL(btintel_set_debug_features);

+static int btintel_get_data_path_id(struct hci_dev *hdev, __u8 *data_path_id)
+{
+ /* Intel uses 1 as data path id for all the usecases */
+ *data_path_id = 1;
+ return 0;
+}
+
int btintel_configure_offload_usecases(struct hci_dev *hdev)
{
struct sk_buff *skb;
@@ -1296,6 +1303,9 @@ int btintel_configure_offload_usecases(struct hci_dev *hdev)
err = -bt_to_errno(skb->data[0]);
goto error;
}
+
+ if (usecases->preset[0] & 0x03)
+ hdev->get_data_path_id = btintel_get_data_path_id;
error:
kfree_skb(skb);
return err;
--
2.17.1


2021-07-27 08:47:46

by Kiran K

[permalink] [raw]
Subject: [PATCH v11 09/10] Bluetooth: Add support for msbc coding format

In Enhanced_Setup_Synchronous_Command, add support for msbc
coding format

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
* changes in v11:
- Remove Kconfig

* changes on v10:
- Fix typos and unwanted chunks

include/net/bluetooth/bluetooth.h | 1 +
net/bluetooth/hci_conn.c | 25 +++++++++++++++++++++++++
2 files changed, 26 insertions(+)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index f2df8bb108d9..c1fa90fb7502 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -175,6 +175,7 @@ struct bt_codecs {

#define CODING_FORMAT_CVSD 0x02
#define CODING_FORMAT_TRANSPARENT 0x03
+#define CODING_FORMAT_MSBC 0x05

__printf(1, 2)
void bt_info(const char *fmt, ...);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 48943b01a356..95ffff4da885 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -328,6 +328,31 @@ static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
cp.rx_bandwidth = cpu_to_le32(0x00001f40);

switch (conn->codec.id) {
+ case CODING_FORMAT_MSBC:
+ if (!find_next_esco_param(conn, esco_param_msbc,
+ ARRAY_SIZE(esco_param_msbc)))
+ return false;
+
+ param = &esco_param_msbc[conn->attempt - 1];
+ cp.tx_coding_format.id = 0x05;
+ cp.rx_coding_format.id = 0x05;
+ cp.tx_codec_frame_size = __cpu_to_le16(60);
+ cp.rx_codec_frame_size = __cpu_to_le16(60);
+ cp.in_bandwidth = __cpu_to_le32(32000);
+ cp.out_bandwidth = __cpu_to_le32(32000);
+ cp.in_coding_format.id = 0x04;
+ cp.out_coding_format.id = 0x04;
+ cp.in_coded_data_size = __cpu_to_le16(16);
+ cp.out_coded_data_size = __cpu_to_le16(16);
+ cp.in_pcm_data_format = 2;
+ cp.out_pcm_data_format = 2;
+ cp.in_pcm_sample_payload_msb_pos = 0;
+ cp.out_pcm_sample_payload_msb_pos = 0;
+ cp.in_data_path = conn->codec.data_path;
+ cp.out_data_path = conn->codec.data_path;
+ cp.in_transport_unit_size = 1;
+ cp.out_transport_unit_size = 1;
+ break;
case CODING_FORMAT_TRANSPARENT:
if (!find_next_esco_param(conn, esco_param_msbc,
ARRAY_SIZE(esco_param_msbc)))
--
2.17.1


2021-07-27 08:49:39

by Kiran K

[permalink] [raw]
Subject: [PATCH v11 08/10] Bluetooth: Add support for HCI_Enhanced_Setup_Synchronous_Connection command

< HCI Command: Enhanced Setup Synchronous Connection (0x01|0x003d) plen 59
Handle: 256
Transmit bandwidth: 8000
Receive bandwidth: 8000
Max latency: 13
Packet type: 0x0380
3-EV3 may not be used
2-EV5 may not be used
3-EV5 may not be used
Retransmission effort: Optimize for link quality (0x02)
> HCI Event: Command Status (0x0f) plen 4
Enhanced Setup Synchronous Connection (0x01|0x003d) ncmd 1
Status: Success (0x00)
> HCI Event: Synchronous Connect Complete (0x2c) plen 17
Status: Success (0x00)
Handle: 257
Address: CC:98:8B:92:04:FD (SONY Visual Products Inc.)
Link type: eSCO (0x02)
Transmission interval: 0x0c
Retransmission window: 0x06
RX packet length: 60
TX packet length: 60
Air mode: Transparent (0x03)

Signed-off-by: Kiran K <[email protected]>
Reviewed-by: Chethan T N <[email protected]>
Reviewed-by: Srivatsa Ravishankar <[email protected]>
---
* changes in v11:
- Remove changes related to Kconfig
- s/use_enhanced_sco_conn/enhanced_sco_capable/g
- Minor review comments

* changes in v10:
- Fix typos and remove unwanted chunks
* changes in v9:
- Fix review comments, use bt_dev_dbg instead of BT_DBG

include/net/bluetooth/bluetooth.h | 3 +-
include/net/bluetooth/hci.h | 34 ++++++++++
include/net/bluetooth/hci_core.h | 6 +-
net/bluetooth/hci_conn.c | 105 +++++++++++++++++++++++++++++-
net/bluetooth/hci_event.c | 39 +++++++++++
net/bluetooth/sco.c | 11 +++-
6 files changed, 192 insertions(+), 6 deletions(-)

diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index 1a48b6732eef..f2df8bb108d9 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -173,7 +173,8 @@ struct bt_codecs {
struct bt_codec codecs[];
} __packed;

-#define CODING_FORMAT_CVSD 0x02
+#define CODING_FORMAT_CVSD 0x02
+#define CODING_FORMAT_TRANSPARENT 0x03

__printf(1, 2)
void bt_info(const char *fmt, ...);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c998607fc517..8af8892e18bc 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -871,6 +871,40 @@ struct hci_cp_logical_link_cancel {
__u8 flow_spec_id;
} __packed;

+#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
+struct hci_coding_format {
+ __u8 id;
+ __le16 cid;
+ __le16 vid;
+} __packed;
+
+struct hci_cp_enhanced_setup_sync_conn {
+ __le16 handle;
+ __le32 tx_bandwidth;
+ __le32 rx_bandwidth;
+ struct hci_coding_format tx_coding_format;
+ struct hci_coding_format rx_coding_format;
+ __le16 tx_codec_frame_size;
+ __le16 rx_codec_frame_size;
+ __le32 in_bandwidth;
+ __le32 out_bandwidth;
+ struct hci_coding_format in_coding_format;
+ struct hci_coding_format out_coding_format;
+ __le16 in_coded_data_size;
+ __le16 out_coded_data_size;
+ __u8 in_pcm_data_format;
+ __u8 out_pcm_data_format;
+ __u8 in_pcm_sample_payload_msb_pos;
+ __u8 out_pcm_sample_payload_msb_pos;
+ __u8 in_data_path;
+ __u8 out_data_path;
+ __u8 in_transport_unit_size;
+ __u8 out_transport_unit_size;
+ __le16 max_latency;
+ __le16 pkt_type;
+ __u8 retrans_effort;
+} __packed;
+
struct hci_rp_logical_link_cancel {
__u8 status;
__u8 phy_handle;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index eafa6f8114cb..4c310bd3e1c6 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -713,6 +713,7 @@ struct hci_conn {
struct amp_mgr *amp_mgr;

struct hci_conn *link;
+ struct bt_codec codec;

void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
void (*security_cfm_cb) (struct hci_conn *conn, u8 status);
@@ -1119,7 +1120,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
u8 sec_level, u8 auth_type,
enum conn_reasons conn_reason);
struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
- __u16 setting);
+ __u16 setting, struct bt_codec *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,
@@ -1440,6 +1441,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
/* Use LL Privacy based address resolution if supported */
#define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)

+/* Use enhanced synchronous connection if command is supported */
+#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
+
/* Use ext scanning if set ext scan param and ext scan enable is supported */
#define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
((dev)->commands[37] & 0x40))
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 2b5059a56cda..48943b01a356 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -307,13 +307,103 @@ static bool find_next_esco_param(struct hci_conn *conn,
return conn->attempt <= size;
}

-bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
+static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
+{
+ struct hci_dev *hdev = conn->hdev;
+ struct hci_cp_enhanced_setup_sync_conn cp;
+ const struct sco_param *param;
+
+ bt_dev_dbg(hdev, "hcon %p", conn);
+
+ conn->state = BT_CONNECT;
+ conn->out = true;
+
+ conn->attempt++;
+
+ memset(&cp, 0x00, sizeof(cp));
+
+ cp.handle = cpu_to_le16(handle);
+
+ cp.tx_bandwidth = cpu_to_le32(0x00001f40);
+ cp.rx_bandwidth = cpu_to_le32(0x00001f40);
+
+ switch (conn->codec.id) {
+ case CODING_FORMAT_TRANSPARENT:
+ if (!find_next_esco_param(conn, esco_param_msbc,
+ ARRAY_SIZE(esco_param_msbc)))
+ return false;
+ param = &esco_param_msbc[conn->attempt - 1];
+ cp.tx_coding_format.id = 0x03;
+ cp.rx_coding_format.id = 0x03;
+ cp.tx_codec_frame_size = __cpu_to_le16(60);
+ cp.rx_codec_frame_size = __cpu_to_le16(60);
+ cp.in_bandwidth = __cpu_to_le32(0x1f40);
+ cp.out_bandwidth = __cpu_to_le32(0x1f40);
+ cp.in_coding_format.id = 0x03;
+ cp.out_coding_format.id = 0x03;
+ cp.in_coded_data_size = __cpu_to_le16(16);
+ cp.out_coded_data_size = __cpu_to_le16(16);
+ cp.in_pcm_data_format = 2;
+ cp.out_pcm_data_format = 2;
+ cp.in_pcm_sample_payload_msb_pos = 0;
+ cp.out_pcm_sample_payload_msb_pos = 0;
+ cp.in_data_path = conn->codec.data_path;
+ cp.out_data_path = conn->codec.data_path;
+ cp.in_transport_unit_size = 1;
+ cp.out_transport_unit_size = 1;
+ break;
+
+ case CODING_FORMAT_CVSD:
+ if (lmp_esco_capable(conn->link)) {
+ if (!find_next_esco_param(conn, esco_param_cvsd,
+ ARRAY_SIZE(esco_param_cvsd)))
+ return false;
+ param = &esco_param_cvsd[conn->attempt - 1];
+ } else {
+ if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
+ return false;
+ param = &sco_param_cvsd[conn->attempt - 1];
+ }
+ cp.tx_coding_format.id = 2;
+ cp.rx_coding_format.id = 2;
+ cp.tx_codec_frame_size = __cpu_to_le16(60);
+ cp.rx_codec_frame_size = __cpu_to_le16(60);
+ cp.in_bandwidth = __cpu_to_le32(16000);
+ cp.out_bandwidth = __cpu_to_le32(16000);
+ cp.in_coding_format.id = 4;
+ cp.out_coding_format.id = 4;
+ cp.in_coded_data_size = __cpu_to_le16(16);
+ cp.out_coded_data_size = __cpu_to_le16(16);
+ cp.in_pcm_data_format = 2;
+ cp.out_pcm_data_format = 2;
+ cp.in_pcm_sample_payload_msb_pos = 0;
+ cp.out_pcm_sample_payload_msb_pos = 0;
+ cp.in_data_path = conn->codec.data_path;
+ cp.out_data_path = conn->codec.data_path;
+ cp.in_transport_unit_size = 16;
+ cp.out_transport_unit_size = 16;
+ break;
+ default:
+ return false;
+ }
+
+ cp.retrans_effort = param->retrans_effort;
+ cp.pkt_type = __cpu_to_le16(param->pkt_type);
+ cp.max_latency = __cpu_to_le16(param->max_latency);
+
+ if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
+ return false;
+
+ return true;
+}
+
+static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
{
struct hci_dev *hdev = conn->hdev;
struct hci_cp_setup_sync_conn cp;
const struct sco_param *param;

- BT_DBG("hcon %p", conn);
+ bt_dev_dbg(hdev, "hcon %p", conn);

conn->state = BT_CONNECT;
conn->out = true;
@@ -359,6 +449,14 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
return true;
}

+bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
+{
+ if (enhanced_sco_capable(conn->hdev))
+ return hci_enhanced_setup_sync_conn(conn, handle);
+
+ return hci_setup_sync_conn(conn, handle);
+}
+
u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
u16 to_multiplier)
{
@@ -1319,7 +1417,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
}

struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
- __u16 setting)
+ __u16 setting, struct bt_codec *codec)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -1344,6 +1442,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
hci_conn_hold(sco);

sco->setting = setting;
+ sco->codec = *codec;

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 1c3018202564..18985ac6a83f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2236,6 +2236,41 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
hci_dev_unlock(hdev);
}

+static void hci_cs_enhanced_setup_sync_conn(struct hci_dev *hdev, __u8 status)
+{
+ struct hci_cp_enhanced_setup_sync_conn *cp;
+ struct hci_conn *acl, *sco;
+ __u16 handle;
+
+ bt_dev_dbg(hdev, "status 0x%2.2x", status);
+
+ if (!status)
+ return;
+
+ cp = hci_sent_cmd_data(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN);
+ if (!cp)
+ return;
+
+ handle = __le16_to_cpu(cp->handle);
+
+ bt_dev_dbg(hdev, "handle 0x%4.4x", handle);
+
+ hci_dev_lock(hdev);
+
+ acl = hci_conn_hash_lookup_handle(hdev, handle);
+ if (acl) {
+ sco = acl->link;
+ if (sco) {
+ sco->state = BT_CLOSED;
+
+ hci_connect_cfm(sco, status);
+ hci_conn_del(sco);
+ }
+ }
+
+ hci_dev_unlock(hdev);
+}
+
static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
{
struct hci_cp_sniff_mode *cp;
@@ -3715,6 +3750,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cs_setup_sync_conn(hdev, ev->status);
break;

+ case HCI_OP_ENHANCED_SETUP_SYNC_CONN:
+ hci_cs_enhanced_setup_sync_conn(hdev, ev->status);
+ break;
+
case HCI_OP_SNIFF_MODE:
hci_cs_sniff_mode(hdev, ev->status);
break;
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 34541e971dc7..5ff06ac05fef 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -240,7 +240,7 @@ static int sco_connect(struct sock *sk)
}

hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
- sco_pi(sk)->setting);
+ sco_pi(sk)->setting, &sco_pi(sk)->codec);
if (IS_ERR(hcon)) {
err = PTR_ERR(hcon);
goto done;
@@ -927,6 +927,15 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
}

sco_pi(sk)->setting = voice.setting;
+ hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
+ BDADDR_BREDR);
+ if (!hdev) {
+ err = -EBADFD;
+ break;
+ }
+ if (enhanced_sco_capable(hdev) &&
+ voice.setting == BT_VOICE_TRANSPARENT)
+ sco_pi(sk)->codec.id = CODING_FORMAT_TRANSPARENT;
break;

case BT_PKT_STATUS:
--
2.17.1


2021-07-27 09:14:15

by bluez.test.bot

[permalink] [raw]
Subject: RE: [v11,01/10] Bluetooth: Enumerate local supported codec and cache details

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=521837

---Test result---

Test Summary:
CheckPatch FAIL 1.71 seconds
GitLint FAIL 1.01 seconds
BuildKernel PASS 651.06 seconds
TestRunner: Setup PASS 418.48 seconds
TestRunner: l2cap-tester PASS 3.03 seconds
TestRunner: bnep-tester PASS 2.21 seconds
TestRunner: mgmt-tester FAIL 32.55 seconds
TestRunner: rfcomm-tester PASS 2.44 seconds
TestRunner: sco-tester PASS 2.32 seconds
TestRunner: smp-tester FAIL 2.39 seconds
TestRunner: userchan-tester PASS 2.29 seconds

Details
##############################
Test: CheckPatch - FAIL - 1.71 seconds
Run checkpatch.pl script with rule in .checkpatch.conf
Bluetooth: Enumerate local supported codec and cache details
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#126:
new file mode 100644

total: 0 errors, 1 warnings, 0 checks, 336 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
mechanically convert to the typical style using --fix or --fix-inplace.

"[PATCH] Bluetooth: Enumerate local supported codec and cache details" has style problems, please review.

NOTE: If any of the errors are false positives, please report
them to the maintainer, see CHECKPATCH in MAINTAINERS.


##############################
Test: GitLint - FAIL - 1.01 seconds
Run gitlint with rule in .gitlint
Bluetooth: Add support for HCI_Enhanced_Setup_Synchronous_Connection command
1: T1 Title exceeds max length (76>72): "Bluetooth: Add support for HCI_Enhanced_Setup_Synchronous_Connection command"


##############################
Test: BuildKernel - PASS - 651.06 seconds
Build Kernel with minimal configuration supports Bluetooth


##############################
Test: TestRunner: Setup - PASS - 418.48 seconds
Setup environment for running Test Runner


##############################
Test: TestRunner: l2cap-tester - PASS - 3.03 seconds
Run test-runner with l2cap-tester
Total: 40, Passed: 40 (100.0%), Failed: 0, Not Run: 0

##############################
Test: TestRunner: bnep-tester - PASS - 2.21 seconds
Run test-runner with bnep-tester
Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0

##############################
Test: TestRunner: mgmt-tester - FAIL - 32.55 seconds
Run test-runner with mgmt-tester
Total: 448, Passed: 444 (99.1%), Failed: 1, Not Run: 3

Failed Test Cases
Read Exp Feature - Success Failed 0.012 seconds

##############################
Test: TestRunner: rfcomm-tester - PASS - 2.44 seconds
Run test-runner with rfcomm-tester
Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0

##############################
Test: TestRunner: sco-tester - PASS - 2.32 seconds
Run test-runner with sco-tester
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

##############################
Test: TestRunner: smp-tester - FAIL - 2.39 seconds
Run test-runner with smp-tester
Total: 8, Passed: 7 (87.5%), Failed: 1, Not Run: 0

Failed Test Cases
SMP Client - SC Request 2 Failed 0.025 seconds

##############################
Test: TestRunner: userchan-tester - PASS - 2.29 seconds
Run test-runner with userchan-tester
Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0



---
Regards,
Linux Bluetooth


Attachments:
l2cap-tester.log (50.36 kB)
bnep-tester.log (3.84 kB)
mgmt-tester.log (606.62 kB)
rfcomm-tester.log (14.44 kB)
sco-tester.log (9.71 kB)
smp-tester.log (11.47 kB)
userchan-tester.log (6.36 kB)
Download all attachments

2021-07-28 04:03:18

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v11 08/10] Bluetooth: Add support for HCI_Enhanced_Setup_Synchronous_Connection command

Hi Kiran,

On Tue, Jul 27, 2021 at 1:45 AM Kiran K <[email protected]> wrote:
>
> < HCI Command: Enhanced Setup Synchronous Connection (0x01|0x003d) plen 59
> Handle: 256
> Transmit bandwidth: 8000
> Receive bandwidth: 8000
> Max latency: 13
> Packet type: 0x0380
> 3-EV3 may not be used
> 2-EV5 may not be used
> 3-EV5 may not be used
> Retransmission effort: Optimize for link quality (0x02)
> > HCI Event: Command Status (0x0f) plen 4
> Enhanced Setup Synchronous Connection (0x01|0x003d) ncmd 1
> Status: Success (0x00)
> > HCI Event: Synchronous Connect Complete (0x2c) plen 17
> Status: Success (0x00)
> Handle: 257
> Address: CC:98:8B:92:04:FD (SONY Visual Products Inc.)
> Link type: eSCO (0x02)
> Transmission interval: 0x0c
> Retransmission window: 0x06
> RX packet length: 60
> TX packet length: 60
> Air mode: Transparent (0x03)
>
> Signed-off-by: Kiran K <[email protected]>
> Reviewed-by: Chethan T N <[email protected]>
> Reviewed-by: Srivatsa Ravishankar <[email protected]>
> ---
> * changes in v11:
> - Remove changes related to Kconfig
> - s/use_enhanced_sco_conn/enhanced_sco_capable/g
> - Minor review comments
>
> * changes in v10:
> - Fix typos and remove unwanted chunks
> * changes in v9:
> - Fix review comments, use bt_dev_dbg instead of BT_DBG
>
> include/net/bluetooth/bluetooth.h | 3 +-
> include/net/bluetooth/hci.h | 34 ++++++++++
> include/net/bluetooth/hci_core.h | 6 +-
> net/bluetooth/hci_conn.c | 105 +++++++++++++++++++++++++++++-
> net/bluetooth/hci_event.c | 39 +++++++++++
> net/bluetooth/sco.c | 11 +++-
> 6 files changed, 192 insertions(+), 6 deletions(-)
>
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index 1a48b6732eef..f2df8bb108d9 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -173,7 +173,8 @@ struct bt_codecs {
> struct bt_codec codecs[];
> } __packed;
>
> -#define CODING_FORMAT_CVSD 0x02
> +#define CODING_FORMAT_CVSD 0x02
> +#define CODING_FORMAT_TRANSPARENT 0x03
>
> __printf(1, 2)
> void bt_info(const char *fmt, ...);
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index c998607fc517..8af8892e18bc 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -871,6 +871,40 @@ struct hci_cp_logical_link_cancel {
> __u8 flow_spec_id;
> } __packed;
>
> +#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
> +struct hci_coding_format {
> + __u8 id;
> + __le16 cid;
> + __le16 vid;
> +} __packed;
> +
> +struct hci_cp_enhanced_setup_sync_conn {
> + __le16 handle;
> + __le32 tx_bandwidth;
> + __le32 rx_bandwidth;
> + struct hci_coding_format tx_coding_format;
> + struct hci_coding_format rx_coding_format;
> + __le16 tx_codec_frame_size;
> + __le16 rx_codec_frame_size;
> + __le32 in_bandwidth;
> + __le32 out_bandwidth;
> + struct hci_coding_format in_coding_format;
> + struct hci_coding_format out_coding_format;
> + __le16 in_coded_data_size;
> + __le16 out_coded_data_size;
> + __u8 in_pcm_data_format;
> + __u8 out_pcm_data_format;
> + __u8 in_pcm_sample_payload_msb_pos;
> + __u8 out_pcm_sample_payload_msb_pos;
> + __u8 in_data_path;
> + __u8 out_data_path;
> + __u8 in_transport_unit_size;
> + __u8 out_transport_unit_size;
> + __le16 max_latency;
> + __le16 pkt_type;
> + __u8 retrans_effort;
> +} __packed;
> +
> struct hci_rp_logical_link_cancel {
> __u8 status;
> __u8 phy_handle;
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index eafa6f8114cb..4c310bd3e1c6 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -713,6 +713,7 @@ struct hci_conn {
> struct amp_mgr *amp_mgr;
>
> struct hci_conn *link;
> + struct bt_codec codec;
>
> void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
> void (*security_cfm_cb) (struct hci_conn *conn, u8 status);
> @@ -1119,7 +1120,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
> u8 sec_level, u8 auth_type,
> enum conn_reasons conn_reason);
> struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
> - __u16 setting);
> + __u16 setting, struct bt_codec *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,
> @@ -1440,6 +1441,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
> /* Use LL Privacy based address resolution if supported */
> #define use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
>
> +/* Use enhanced synchronous connection if command is supported */
> +#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
> +
> /* Use ext scanning if set ext scan param and ext scan enable is supported */
> #define use_ext_scan(dev) (((dev)->commands[37] & 0x20) && \
> ((dev)->commands[37] & 0x40))
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index 2b5059a56cda..48943b01a356 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -307,13 +307,103 @@ static bool find_next_esco_param(struct hci_conn *conn,
> return conn->attempt <= size;
> }
>
> -bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
> +static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16 handle)
> +{
> + struct hci_dev *hdev = conn->hdev;
> + struct hci_cp_enhanced_setup_sync_conn cp;
> + const struct sco_param *param;
> +
> + bt_dev_dbg(hdev, "hcon %p", conn);
> +
> + conn->state = BT_CONNECT;
> + conn->out = true;
> +
> + conn->attempt++;
> +
> + memset(&cp, 0x00, sizeof(cp));
> +
> + cp.handle = cpu_to_le16(handle);
> +
> + cp.tx_bandwidth = cpu_to_le32(0x00001f40);
> + cp.rx_bandwidth = cpu_to_le32(0x00001f40);
> +
> + switch (conn->codec.id) {
> + case CODING_FORMAT_TRANSPARENT:
> + if (!find_next_esco_param(conn, esco_param_msbc,
> + ARRAY_SIZE(esco_param_msbc)))
> + return false;
> + param = &esco_param_msbc[conn->attempt - 1];
> + cp.tx_coding_format.id = 0x03;
> + cp.rx_coding_format.id = 0x03;
> + cp.tx_codec_frame_size = __cpu_to_le16(60);
> + cp.rx_codec_frame_size = __cpu_to_le16(60);
> + cp.in_bandwidth = __cpu_to_le32(0x1f40);
> + cp.out_bandwidth = __cpu_to_le32(0x1f40);
> + cp.in_coding_format.id = 0x03;
> + cp.out_coding_format.id = 0x03;
> + cp.in_coded_data_size = __cpu_to_le16(16);
> + cp.out_coded_data_size = __cpu_to_le16(16);
> + cp.in_pcm_data_format = 2;
> + cp.out_pcm_data_format = 2;
> + cp.in_pcm_sample_payload_msb_pos = 0;
> + cp.out_pcm_sample_payload_msb_pos = 0;
> + cp.in_data_path = conn->codec.data_path;
> + cp.out_data_path = conn->codec.data_path;
> + cp.in_transport_unit_size = 1;
> + cp.out_transport_unit_size = 1;
> + break;
> +
> + case CODING_FORMAT_CVSD:
> + if (lmp_esco_capable(conn->link)) {
> + if (!find_next_esco_param(conn, esco_param_cvsd,
> + ARRAY_SIZE(esco_param_cvsd)))
> + return false;
> + param = &esco_param_cvsd[conn->attempt - 1];
> + } else {
> + if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
> + return false;
> + param = &sco_param_cvsd[conn->attempt - 1];
> + }
> + cp.tx_coding_format.id = 2;
> + cp.rx_coding_format.id = 2;
> + cp.tx_codec_frame_size = __cpu_to_le16(60);
> + cp.rx_codec_frame_size = __cpu_to_le16(60);
> + cp.in_bandwidth = __cpu_to_le32(16000);
> + cp.out_bandwidth = __cpu_to_le32(16000);
> + cp.in_coding_format.id = 4;
> + cp.out_coding_format.id = 4;
> + cp.in_coded_data_size = __cpu_to_le16(16);
> + cp.out_coded_data_size = __cpu_to_le16(16);
> + cp.in_pcm_data_format = 2;
> + cp.out_pcm_data_format = 2;
> + cp.in_pcm_sample_payload_msb_pos = 0;
> + cp.out_pcm_sample_payload_msb_pos = 0;
> + cp.in_data_path = conn->codec.data_path;
> + cp.out_data_path = conn->codec.data_path;
> + cp.in_transport_unit_size = 16;
> + cp.out_transport_unit_size = 16;
> + break;
> + default:
> + return false;
> + }
> +
> + cp.retrans_effort = param->retrans_effort;
> + cp.pkt_type = __cpu_to_le16(param->pkt_type);
> + cp.max_latency = __cpu_to_le16(param->max_latency);
> +
> + if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0)
> + return false;
> +
> + return true;
> +}
> +
> +static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
> {
> struct hci_dev *hdev = conn->hdev;
> struct hci_cp_setup_sync_conn cp;
> const struct sco_param *param;
>
> - BT_DBG("hcon %p", conn);
> + bt_dev_dbg(hdev, "hcon %p", conn);
>
> conn->state = BT_CONNECT;
> conn->out = true;
> @@ -359,6 +449,14 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
> return true;
> }
>
> +bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
> +{
> + if (enhanced_sco_capable(conn->hdev))
> + return hci_enhanced_setup_sync_conn(conn, handle);
> +
> + return hci_setup_sync_conn(conn, handle);
> +}
> +
> u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency,
> u16 to_multiplier)
> {
> @@ -1319,7 +1417,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
> }
>
> struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
> - __u16 setting)
> + __u16 setting, struct bt_codec *codec)
> {
> struct hci_conn *acl;
> struct hci_conn *sco;
> @@ -1344,6 +1442,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst,
> hci_conn_hold(sco);
>
> sco->setting = setting;
> + sco->codec = *codec;
>
> 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 1c3018202564..18985ac6a83f 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -2236,6 +2236,41 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status)
> hci_dev_unlock(hdev);
> }
>
> +static void hci_cs_enhanced_setup_sync_conn(struct hci_dev *hdev, __u8 status)
> +{
> + struct hci_cp_enhanced_setup_sync_conn *cp;
> + struct hci_conn *acl, *sco;
> + __u16 handle;
> +
> + bt_dev_dbg(hdev, "status 0x%2.2x", status);
> +
> + if (!status)
> + return;
> +
> + cp = hci_sent_cmd_data(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN);
> + if (!cp)
> + return;
> +
> + handle = __le16_to_cpu(cp->handle);
> +
> + bt_dev_dbg(hdev, "handle 0x%4.4x", handle);
> +
> + hci_dev_lock(hdev);
> +
> + acl = hci_conn_hash_lookup_handle(hdev, handle);
> + if (acl) {
> + sco = acl->link;
> + if (sco) {
> + sco->state = BT_CLOSED;
> +
> + hci_connect_cfm(sco, status);
> + hci_conn_del(sco);
> + }
> + }
> +
> + hci_dev_unlock(hdev);
> +}
> +
> static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status)
> {
> struct hci_cp_sniff_mode *cp;
> @@ -3715,6 +3750,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb,
> hci_cs_setup_sync_conn(hdev, ev->status);
> break;
>
> + case HCI_OP_ENHANCED_SETUP_SYNC_CONN:
> + hci_cs_enhanced_setup_sync_conn(hdev, ev->status);
> + break;
> +
> case HCI_OP_SNIFF_MODE:
> hci_cs_sniff_mode(hdev, ev->status);
> break;
> diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
> index 34541e971dc7..5ff06ac05fef 100644
> --- a/net/bluetooth/sco.c
> +++ b/net/bluetooth/sco.c
> @@ -240,7 +240,7 @@ static int sco_connect(struct sock *sk)
> }
>
> hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
> - sco_pi(sk)->setting);
> + sco_pi(sk)->setting, &sco_pi(sk)->codec);
> if (IS_ERR(hcon)) {
> err = PTR_ERR(hcon);
> goto done;
> @@ -927,6 +927,15 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname,
> }
>
> sco_pi(sk)->setting = voice.setting;
> + hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
> + BDADDR_BREDR);
> + if (!hdev) {
> + err = -EBADFD;
> + break;
> + }
> + if (enhanced_sco_capable(hdev) &&
> + voice.setting == BT_VOICE_TRANSPARENT)
> + sco_pi(sk)->codec.id = CODING_FORMAT_TRANSPARENT;


hci_get_route does call hci_dev_hold so you need hci_dev_put once you
are done with it.

> break;
>
> case BT_PKT_STATUS:
> --
> 2.17.1
>


--
Luiz Augusto von Dentz

2021-07-30 14:07:41

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v11 01/10] Bluetooth: Enumerate local supported codec and cache details

Hi Kiran,

> Move reading of supported local codecs into a separate init function,
> query codecs capabilities and cache the data
>
> Signed-off-by: Kiran K <[email protected]>
> Signed-off-by: Chethan T N <[email protected]>
> Signed-off-by: Srivatsa Ravishankar <[email protected]>
> ---
> * changes in v11:
> - Remove Kconfig related changes
> - Address minor review comments
> - Move codec related functions to new file hci_codec.c
>
> * changes in v10:
> - define Kconfig to control offload feature at build time
> - fix review comments
>
> * changes in v9:
> - use shortname vnd instead of ven
>
> * changes in v8:
> - add comments
> - split __u8 codec_id[5] into {__u8 id; __le16 cid, vid }
> - address review comment related codec caps structure
>
> * changes in v7:
> - keep codec enumeration call in hci_init instead of having a separate
> function
> - Remove unused bitmasks defined for LE transports
>
> * changes in v6:
> - fix compiler warning reported for ARCH=arc
>
> * changes in v5:
> - fix review comments
> - move code used to read standard/vendor codecs caps into single function
>
> * changes in v4:
> - convert reading of codecs and codecs caps calls from async to sync
>
> * changes in v3
> move codec enumeration into a new init function
>
> * changes in v2
> add skb length check before accessing data
>
> include/net/bluetooth/hci.h | 41 +++++++
> include/net/bluetooth/hci_core.h | 17 +++
> net/bluetooth/Makefile | 2 +-
> net/bluetooth/hci_codec.c | 194 +++++++++++++++++++++++++++++++
> net/bluetooth/hci_codec.h | 6 +
> net/bluetooth/hci_core.c | 12 +-
> 6 files changed, 266 insertions(+), 6 deletions(-)
> create mode 100644 net/bluetooth/hci_codec.c
> create mode 100644 net/bluetooth/hci_codec.h
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index b80415011dcd..f76849c8eafd 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1307,6 +1307,28 @@ struct hci_rp_read_data_block_size {
> } __packed;
>
> #define HCI_OP_READ_LOCAL_CODECS 0x100b
> +struct hci_std_codecs {
> + __u8 num;
> + __u8 codec[];
> +} __packed;
> +
> +struct hci_vnd_codec {
> + /* company id */
> + __le16 cid;
> + /* vendor codec id */
> + __le16 vid;
> +} __packed;
> +
> +struct hci_vnd_codecs {
> + __u8 num;
> + struct hci_vnd_codec codec[];
> +} __packed;
> +
> +struct hci_rp_read_local_supported_codecs {
> + __u8 status;
> + struct hci_std_codecs std_codecs;
> + struct hci_vnd_codecs vnd_codecs;
> +} __packed;
>
> #define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
> struct hci_rp_read_local_pairing_opts {
> @@ -1315,6 +1337,25 @@ struct hci_rp_read_local_pairing_opts {
> __u8 max_key_size;
> } __packed;
>
> +#define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e
> +struct hci_op_read_local_codec_caps {
> + __u8 id;
> + __le16 cid;
> + __le16 vid;
> + __u8 transport;
> + __u8 direction;
> +} __packed;
> +
> +struct hci_codec_caps {
> + __u8 len;
> + __u8 data[];
> +} __packed;
> +
> +struct hci_rp_read_local_codec_caps {
> + __u8 status;
> + __u8 num_caps;
> +} __packed;
> +
> #define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
> struct hci_rp_read_page_scan_activity {
> __u8 status;
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index a53e94459ecd..6742e6ad7b37 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -131,6 +131,17 @@ struct bdaddr_list {
> u8 bdaddr_type;
> };
>
> +struct codec_list {
> + struct list_head list;
> + u8 id;
> + __u16 cid;
> + __u16 vid;
> + u8 transport;
> + u8 num_caps;
> + u32 len;
> + struct hci_codec_caps caps[];
> +};
> +
> struct bdaddr_list_with_irk {
> struct list_head list;
> bdaddr_t bdaddr;
> @@ -535,6 +546,7 @@ struct hci_dev {
> struct list_head pend_le_conns;
> struct list_head pend_le_reports;
> struct list_head blocked_keys;
> + struct list_head local_codecs;
>
> struct hci_dev_stats stat;
>
> @@ -1849,4 +1861,9 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
> #define SCO_AIRMODE_CVSD 0x0000
> #define SCO_AIRMODE_TRANSP 0x0003
>
> +#define LOCAL_CODEC_ACL_MASK BIT(0)
> +#define LOCAL_CODEC_SCO_MASK BIT(1)
> +
> +#define TRANSPORT_TYPE_MAX 0x04
> +
> #endif /* __HCI_CORE_H */
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index cc0995301f93..f3e439d98b85 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -14,7 +14,7 @@ bluetooth_6lowpan-y := 6lowpan.o
>
> bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
> hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
> - ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o
> + ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o
>
> bluetooth-$(CONFIG_BT_BREDR) += sco.o
> bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
> diff --git a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c
> new file mode 100644
> index 000000000000..205f3b04c172
> --- /dev/null
> +++ b/net/bluetooth/hci_codec.c
> @@ -0,0 +1,194 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (C) 2021 Intel Corporation */
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +static int hci_codec_list_add(struct list_head *list,
> + struct hci_op_read_local_codec_caps *sent,
> + struct hci_rp_read_local_codec_caps *rp,
> + void *caps,
> + __u32 len)
> +{
> + struct codec_list *entry;
> +
> + entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
> + if (!entry)
> + return -ENOMEM;
> +
> + entry->id = sent->id;
> + if (sent->id == 0xFF) {
> + entry->cid = __le16_to_cpu(sent->cid);
> + entry->vid = __le16_to_cpu(sent->vid);
> + }
> + entry->transport = sent->transport;
> + entry->len = len;
> + entry->num_caps = rp->num_caps;
> + if (rp->num_caps)
> + memcpy(entry->caps, caps, len);
> + list_add(&entry->list, list);
> +
> + return 0;
> +}
> +
> +void hci_codec_list_clear(struct list_head *codec_list)
> +{
> + struct codec_list *c, *n;
> +
> + list_for_each_entry_safe(c, n, codec_list, list) {
> + list_del(&c->list);
> + kfree(c);
> + }
> +}
> +
> +static void hci_read_codec_capabilities(struct hci_dev *hdev, void *codec_id,
> + __u8 transport, bool is_vnd_codec)
> +{
> + struct hci_op_read_local_codec_caps cmd;
> + __u8 i;
> +
> + memset(&cmd, 0, sizeof(cmd));
> +
> + if (is_vnd_codec) {
> + struct hci_vnd_codec *vnd_codec;
> +
> + vnd_codec = codec_id;
> + cmd.id = 0xFF;
> + cmd.cid = vnd_codec->cid;
> + cmd.vid = vnd_codec->vid;
> + } else {
> + cmd.id = *(__u8 *)codec_id;
> + }
> +
> + cmd.direction = 0x00;
> +
> + for (i = 0; i < TRANSPORT_TYPE_MAX; i++) {
> + if (transport & BIT(i)) {
> + struct hci_rp_read_local_codec_caps *rp;
> + struct hci_codec_caps *caps;
> + struct sk_buff *skb;
> + __u8 j;
> + __u32 len;
> +
> + cmd.transport = i;
> + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS,
> + sizeof(cmd), &cmd,
> + HCI_CMD_TIMEOUT);
> + if (IS_ERR(skb)) {
> + bt_dev_err(hdev, "Failed to read codec capabilities (%ld)",
> + PTR_ERR(skb));
> + continue;
> + }
> +
> + if (skb->len < sizeof(*rp))
> + goto error;
> +
> + rp = (void *)skb->data;
> +
> + if (rp->status)
> + goto error;
> +
> + if (!rp->num_caps) {
> + len = 0;
> + /* this codec doesn't have capabilities */
> + goto skip_caps_parse;
> + }
> +
> + skb_pull(skb, sizeof(*rp));
> +
> + for (j = 0, len = 0; j < rp->num_caps; j++) {
> + caps = (void *)skb->data;
> + if (skb->len < sizeof(*caps))
> + goto error;
> + if (skb->len < caps->len)
> + goto error;
> + len += sizeof(caps->len) + caps->len;
> + skb_pull(skb, sizeof(caps->len) + caps->len);
> + }
> +
> +skip_caps_parse:
> + hci_dev_lock(hdev);
> + hci_codec_list_add(&hdev->local_codecs, &cmd, rp,
> + (__u8 *)rp + sizeof(*rp), len);
> + hci_dev_unlock(hdev);
> +error:
> + kfree_skb(skb);
> + }
> + }
> +}
> +
> +static void hci_codec_list_parse(struct hci_dev *hdev, __u8 num_codecs,
> + void *codec_list, bool is_vnd_codec)
> +{
> + __u8 i;
> +
> + for (i = 0; i < num_codecs; i++) {
> + if (!is_vnd_codec) {
> + struct hci_std_codecs *codecs = codec_list;
> +
> + hci_read_codec_capabilities(hdev, &codecs->codec[i],
> + LOCAL_CODEC_ACL_MASK,
> + is_vnd_codec);
> + } else {
> + struct hci_vnd_codecs *codecs = codec_list;
> +
> + hci_read_codec_capabilities(hdev, &codecs->codec[i],
> + LOCAL_CODEC_ACL_MASK,
> + is_vnd_codec);
> + }
> + }
> +}

I said before that I don’t like it this way. The is_vnd_codec part is pointless and you are trickling this through. I really mean that I am not wanting to it this way upstream.

So first of all,

if (is_vnd_codec) {
int i;

for (i = 0; i < num_codecs; i++) {
struct hci_vnd_codecs *codecs = codec_list;
hci_read_codec_capabilities(hdev, &codecs->codec[i],
LOCAL_CODEC_ACL_MASK, true);
}
} else {
int I;

for (i = 0; i < num_codecs; i++) {
struct hci_std_codecs *codecs = codec_list;
hci_read_codec_capabilities(hdev, &codecs->codec[i],
LOCAL_CODEC_ACL_MASK, false);
}
}

This is just by definition more efficient code. Now as caller you already know if you are a vendor codec list or not.

static void hci_codec_list_parse_std(struct hci_dev *hdev, __u8 num_codecs,
struct hci_std_codecs *codecs)
{
int i;

for (i = 0; i < num_codecs; i++)
hci_read_codec_capabilities(hdev, &codecs->codec[i],
LOCAL_CODEC_ACL_MASK, false);
}

static void hci_codec_list_parse_vnd(struct hci_dev *hdev, __u8 num_codecs,
struct hci_vnd_codecs *codecs)
{
..
}


This is already less code and easier to understand. Also it is type safer since the parameter is not a void pointer.

Now on to the LOCAL_CODEC_ACL_MASK transport setting and the hci_read_codec_capabilities. I have no idea why this is done this way. I can not follow this code since it is spaghetti left and right. This needs to be untangled.

I am not going to review hci_read_codec_capabilities right now, please look through it and come up with simpler solution.

> +
> +void hci_read_supported_codecs(struct hci_dev *hdev)
> +{
> + struct sk_buff *skb;
> + struct hci_rp_read_local_supported_codecs *rp;
> + struct hci_std_codecs *std_codecs;
> + struct hci_vnd_codecs *vnd_codecs;
> +
> + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
> + HCI_CMD_TIMEOUT);
> +
> + if (IS_ERR(skb)) {
> + bt_dev_err(hdev, "Failed to read local supported codecs (%ld)",
> + PTR_ERR(skb));
> + return;
> + }
> +
> + if (skb->len < sizeof(*rp))
> + goto error;
> +
> + rp = (void *)skb->data;
> +
> + if (rp->status)
> + goto error;
> +
> + skb_pull(skb, sizeof(rp->status));
> +
> + std_codecs = (void *)skb->data;
> +
> + /* validate codecs length before accessing */
> + if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
> + + sizeof(std_codecs->num))
> + goto error;
> +
> + /* enumerate codec capabilities of standard codecs */
> + hci_codec_list_parse(hdev, std_codecs->num, std_codecs, false);


for (i = 0; i < std_codecs->num; i++)
hci_read_codec_capabilities(hdev, &std_codecs->codec[i],
LOCAL_CODEC_ACL_MASK, false);

Now I am saving the function above and only need 2 extra lines. This is more readable since it is easier to follow.

> +
> + skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
> + + sizeof(std_codecs->num));
> +
> + vnd_codecs = (void *)skb->data;
> +
> + /* validate vendor codecs length before accessing */
> + if (skb->len <
> + flex_array_size(vnd_codecs, codec, vnd_codecs->num)
> + + sizeof(vnd_codecs->num))
> + goto error;
> +
> + /* enumerate vendor codec capabilities */
> + hci_codec_list_parse(hdev, vnd_codecs->num, vnd_codecs, true);
> +
> +error:
> + kfree_skb(skb);
> +}
> diff --git a/net/bluetooth/hci_codec.h b/net/bluetooth/hci_codec.h
> new file mode 100644
> index 000000000000..e5e594933d07
> --- /dev/null
> +++ b/net/bluetooth/hci_codec.h
> @@ -0,0 +1,6 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +/* Copyright (C) 2021 Intel Corporation */
> +
> +void hci_read_supported_codecs(struct hci_dev *hdev);
> +void hci_codec_list_clear(struct list_head *codec_list);
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index 2560ed2f144d..212d5066d413 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -45,6 +45,7 @@
> #include "leds.h"
> #include "msft.h"
> #include "aosp.h"
> +#include "hci_codec.h"
>
> static void hci_rx_work(struct work_struct *work);
> static void hci_cmd_work(struct work_struct *work);
> @@ -838,10 +839,6 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
> if (hdev->commands[22] & 0x04)
> hci_set_event_mask_page_2(req);
>
> - /* Read local codec list if the HCI command is supported */
> - if (hdev->commands[29] & 0x20)
> - hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);
> -
> /* Read local pairing options if the HCI command is supported */
> if (hdev->commands[41] & 0x08)
> hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL);
> @@ -937,6 +934,10 @@ static int __hci_init(struct hci_dev *hdev)
> if (err < 0)
> return err;
>
> + /* Read local codec list if the HCI command is supported */
> + if (hdev->commands[29] & 0x20)
> + hci_read_supported_codecs(hdev);
> +
> /* This function is only called when the controller is actually in
> * configured state. When the controller is marked as unconfigured,
> * this initialization procedure is not run.
> @@ -1841,6 +1842,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
> memset(hdev->eir, 0, sizeof(hdev->eir));
> memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
> bacpy(&hdev->random_addr, BDADDR_ANY);
> + hci_codec_list_clear(&hdev->local_codecs);
>
> hci_req_sync_unlock(hdev);
>
> @@ -3842,7 +3844,7 @@ struct hci_dev *hci_alloc_dev(void)
> INIT_LIST_HEAD(&hdev->conn_hash.list);
> INIT_LIST_HEAD(&hdev->adv_instances);
> INIT_LIST_HEAD(&hdev->blocked_keys);
> -
> + INIT_LIST_HEAD(&hdev->local_codecs);
> INIT_WORK(&hdev->rx_work, hci_rx_work);
> INIT_WORK(&hdev->cmd_work, hci_cmd_work);
> INIT_WORK(&hdev->tx_work, hci_tx_work);

This kind of style changes by removing an on purpose place empty line as separator are not acceptable. Please avoid them.

Regards

Marcel


2021-07-30 14:16:21

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v11 04/10] Bluetooth: Allow querying of supported offload codecs over SCO socket

Hi Kiran,

> Add BT_CODEC option for getsockopt systemcall to get the details
> of offload codecs supported over SCO socket
>
> Signed-off-by: Kiran K <[email protected]>
> Reviewed-by: Chethan T N <[email protected]>
> Reviewed-by: Srivatsa Ravishankar <[email protected]>
> ---
> * changes in v11:
> - Remove Kconfig related changes
> * changes in v10:
> - In getsockopt, prepare data in advance and call copy_to_user
> istead of calling put_user on each field of struct bt_codec
>
> include/net/bluetooth/bluetooth.h | 20 +++++++
> include/net/bluetooth/hci.h | 4 ++
> include/net/bluetooth/hci_core.h | 1 +
> net/bluetooth/sco.c | 91 +++++++++++++++++++++++++++++++
> 4 files changed, 116 insertions(+)
>
> diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
> index 9125effbf448..64cddff0c9c4 100644
> --- a/include/net/bluetooth/bluetooth.h
> +++ b/include/net/bluetooth/bluetooth.h
> @@ -153,6 +153,26 @@ struct bt_voice {
>
> #define BT_SCM_PKT_STATUS 0x03
>
> +#define BT_CODEC 19
> +
> +struct bt_codec_caps {
> + __u8 len;
> + __u8 data[];
> +} __packed;
> +
> +struct bt_codec {
> + __u8 id;
> + __u16 cid;
> + __u16 vid;
> + __u8 data_path;
> + __u8 num_caps;
> +} __packed;
> +
> +struct bt_codecs {
> + __u8 num_codecs;
> + struct bt_codec codecs[];
> +} __packed;
> +
> __printf(1, 2)
> void bt_info(const char *fmt, ...);
> __printf(1, 2)
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index b4e35cf5f4b1..22e872e60ff8 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -2621,6 +2621,10 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
> #define hci_iso_data_len(h) ((h) & 0x3fff)
> #define hci_iso_data_flags(h) ((h) >> 14)
>
> +/* codec transport types */
> +#define TRANSPORT_ACL 0x00
> +#define TRANSPORT_SCO_ESCO 0x01
> +
> /* le24 support */
> static inline void hci_cpu_to_le24(__u32 val, __u8 dst[3])
> {
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 6742e6ad7b37..71c409c8ab34 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -617,6 +617,7 @@ struct hci_dev {
> int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
> void (*cmd_timeout)(struct hci_dev *hdev);
> bool (*prevent_wake)(struct hci_dev *hdev);
> + int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
> };
>
> #define HCI_PHY_HANDLE(handle) (handle & 0xff)
> diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
> index ffa2a77a3e4c..2f32693f09c1 100644
> --- a/net/bluetooth/sco.c
> +++ b/net/bluetooth/sco.c
> @@ -953,6 +953,12 @@ 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);
>
> @@ -1017,6 +1023,91 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname,
> err = -EFAULT;
> break;
>
> + case BT_CODEC:
> + num_codecs = 0;
> + buf_len = 0;
> +
> + hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src, BDADDR_BREDR);
> + if (!hdev) {
> + err = -EBADFD;
> + break;
> + }
> +
> + if (!hdev->get_data_path_id) {
> + err = -EOPNOTSUPP;
> + break;
> + }

so I did say that this needs to be put behind an experimental feature setting. I am not committing to an userspace API until we have more feedback.

Regards

Marcel


2021-08-02 00:25:04

by Kiran K

[permalink] [raw]
Subject: RE: [PATCH v11 01/10] Bluetooth: Enumerate local supported codec and cache details

Hi Marcel,

> -----Original Message-----
> From: Marcel Holtmann <[email protected]>
> Sent: Friday, July 30, 2021 7:36 PM
> To: K, Kiran <[email protected]>
> Cc: BlueZ <[email protected]>; Srivatsa, Ravishankar
> <[email protected]>; Tumkur Narayan, Chethan
> <[email protected]>
> Subject: Re: [PATCH v11 01/10] Bluetooth: Enumerate local supported codec
> and cache details
>
> Hi Kiran,
>
> > Move reading of supported local codecs into a separate init function,
> > query codecs capabilities and cache the data
> >
> > Signed-off-by: Kiran K <[email protected]>
> > Signed-off-by: Chethan T N <[email protected]>
> > Signed-off-by: Srivatsa Ravishankar <[email protected]>
> > ---
> > * changes in v11:
> > - Remove Kconfig related changes
> > - Address minor review comments
> > - Move codec related functions to new file hci_codec.c
> >
> > * changes in v10:
> > - define Kconfig to control offload feature at build time
> > - fix review comments
> >
> > * changes in v9:
> > - use shortname vnd instead of ven
> >
> > * changes in v8:
> > - add comments
> > - split __u8 codec_id[5] into {__u8 id; __le16 cid, vid }
> > - address review comment related codec caps structure
> >
> > * changes in v7:
> > - keep codec enumeration call in hci_init instead of having a separate
> > function
> > - Remove unused bitmasks defined for LE transports
> >
> > * changes in v6:
> > - fix compiler warning reported for ARCH=arc
> >
> > * changes in v5:
> > - fix review comments
> > - move code used to read standard/vendor codecs caps into single
> > function
> >
> > * changes in v4:
> > - convert reading of codecs and codecs caps calls from async to sync
> >
> > * changes in v3
> > move codec enumeration into a new init function
> >
> > * changes in v2
> > add skb length check before accessing data
> >
> > include/net/bluetooth/hci.h | 41 +++++++
> > include/net/bluetooth/hci_core.h | 17 +++
> > net/bluetooth/Makefile | 2 +-
> > net/bluetooth/hci_codec.c | 194 +++++++++++++++++++++++++++++++
> > net/bluetooth/hci_codec.h | 6 +
> > net/bluetooth/hci_core.c | 12 +-
> > 6 files changed, 266 insertions(+), 6 deletions(-) create mode 100644
> > net/bluetooth/hci_codec.c create mode 100644 net/bluetooth/hci_codec.h
> >
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index b80415011dcd..f76849c8eafd 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -1307,6 +1307,28 @@ struct hci_rp_read_data_block_size { }
> > __packed;
> >
> > #define HCI_OP_READ_LOCAL_CODECS 0x100b
> > +struct hci_std_codecs {
> > + __u8 num;
> > + __u8 codec[];
> > +} __packed;
> > +
> > +struct hci_vnd_codec {
> > + /* company id */
> > + __le16 cid;
> > + /* vendor codec id */
> > + __le16 vid;
> > +} __packed;
> > +
> > +struct hci_vnd_codecs {
> > + __u8 num;
> > + struct hci_vnd_codec codec[];
> > +} __packed;
> > +
> > +struct hci_rp_read_local_supported_codecs {
> > + __u8 status;
> > + struct hci_std_codecs std_codecs;
> > + struct hci_vnd_codecs vnd_codecs;
> > +} __packed;
> >
> > #define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c
> > struct hci_rp_read_local_pairing_opts { @@ -1315,6 +1337,25 @@ struct
> > hci_rp_read_local_pairing_opts {
> > __u8 max_key_size;
> > } __packed;
> >
> > +#define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e
> > +struct hci_op_read_local_codec_caps {
> > + __u8 id;
> > + __le16 cid;
> > + __le16 vid;
> > + __u8 transport;
> > + __u8 direction;
> > +} __packed;
> > +
> > +struct hci_codec_caps {
> > + __u8 len;
> > + __u8 data[];
> > +} __packed;
> > +
> > +struct hci_rp_read_local_codec_caps {
> > + __u8 status;
> > + __u8 num_caps;
> > +} __packed;
> > +
> > #define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
> > struct hci_rp_read_page_scan_activity {
> > __u8 status;
> > diff --git a/include/net/bluetooth/hci_core.h
> > b/include/net/bluetooth/hci_core.h
> > index a53e94459ecd..6742e6ad7b37 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -131,6 +131,17 @@ struct bdaddr_list {
> > u8 bdaddr_type;
> > };
> >
> > +struct codec_list {
> > + struct list_head list;
> > + u8 id;
> > + __u16 cid;
> > + __u16 vid;
> > + u8 transport;
> > + u8 num_caps;
> > + u32 len;
> > + struct hci_codec_caps caps[];
> > +};
> > +
> > struct bdaddr_list_with_irk {
> > struct list_head list;
> > bdaddr_t bdaddr;
> > @@ -535,6 +546,7 @@ struct hci_dev {
> > struct list_head pend_le_conns;
> > struct list_head pend_le_reports;
> > struct list_head blocked_keys;
> > + struct list_head local_codecs;
> >
> > struct hci_dev_stats stat;
> >
> > @@ -1849,4 +1861,9 @@ void hci_copy_identity_address(struct hci_dev
> *hdev, bdaddr_t *bdaddr,
> > #define SCO_AIRMODE_CVSD 0x0000
> > #define SCO_AIRMODE_TRANSP 0x0003
> >
> > +#define LOCAL_CODEC_ACL_MASK BIT(0)
> > +#define LOCAL_CODEC_SCO_MASK BIT(1)
> > +
> > +#define TRANSPORT_TYPE_MAX 0x04
> > +
> > #endif /* __HCI_CORE_H */
> > diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index
> > cc0995301f93..f3e439d98b85 100644
> > --- a/net/bluetooth/Makefile
> > +++ b/net/bluetooth/Makefile
> > @@ -14,7 +14,7 @@ bluetooth_6lowpan-y := 6lowpan.o
> >
> > bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
> > hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \
> > - ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o
> > + ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o
> >
> > bluetooth-$(CONFIG_BT_BREDR) += sco.o
> > bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o diff --git
> > a/net/bluetooth/hci_codec.c b/net/bluetooth/hci_codec.c new file mode
> > 100644 index 000000000000..205f3b04c172
> > --- /dev/null
> > +++ b/net/bluetooth/hci_codec.c
> > @@ -0,0 +1,194 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/* Copyright (C) 2021 Intel Corporation */
> > +
> > +#include <net/bluetooth/bluetooth.h>
> > +#include <net/bluetooth/hci_core.h>
> > +
> > +static int hci_codec_list_add(struct list_head *list,
> > + struct hci_op_read_local_codec_caps *sent,
> > + struct hci_rp_read_local_codec_caps *rp,
> > + void *caps,
> > + __u32 len)
> > +{
> > + struct codec_list *entry;
> > +
> > + entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
> > + if (!entry)
> > + return -ENOMEM;
> > +
> > + entry->id = sent->id;
> > + if (sent->id == 0xFF) {
> > + entry->cid = __le16_to_cpu(sent->cid);
> > + entry->vid = __le16_to_cpu(sent->vid);
> > + }
> > + entry->transport = sent->transport;
> > + entry->len = len;
> > + entry->num_caps = rp->num_caps;
> > + if (rp->num_caps)
> > + memcpy(entry->caps, caps, len);
> > + list_add(&entry->list, list);
> > +
> > + return 0;
> > +}
> > +
> > +void hci_codec_list_clear(struct list_head *codec_list) {
> > + struct codec_list *c, *n;
> > +
> > + list_for_each_entry_safe(c, n, codec_list, list) {
> > + list_del(&c->list);
> > + kfree(c);
> > + }
> > +}
> > +
> > +static void hci_read_codec_capabilities(struct hci_dev *hdev, void
> *codec_id,
> > + __u8 transport, bool is_vnd_codec) {
> > + struct hci_op_read_local_codec_caps cmd;
> > + __u8 i;
> > +
> > + memset(&cmd, 0, sizeof(cmd));
> > +
> > + if (is_vnd_codec) {
> > + struct hci_vnd_codec *vnd_codec;
> > +
> > + vnd_codec = codec_id;
> > + cmd.id = 0xFF;
> > + cmd.cid = vnd_codec->cid;
> > + cmd.vid = vnd_codec->vid;
> > + } else {
> > + cmd.id = *(__u8 *)codec_id;
> > + }
> > +
> > + cmd.direction = 0x00;
> > +
> > + for (i = 0; i < TRANSPORT_TYPE_MAX; i++) {
> > + if (transport & BIT(i)) {
> > + struct hci_rp_read_local_codec_caps *rp;
> > + struct hci_codec_caps *caps;
> > + struct sk_buff *skb;
> > + __u8 j;
> > + __u32 len;
> > +
> > + cmd.transport = i;
> > + skb = __hci_cmd_sync(hdev,
> HCI_OP_READ_LOCAL_CODEC_CAPS,
> > + sizeof(cmd), &cmd,
> > + HCI_CMD_TIMEOUT);
> > + if (IS_ERR(skb)) {
> > + bt_dev_err(hdev, "Failed to read codec
> capabilities (%ld)",
> > + PTR_ERR(skb));
> > + continue;
> > + }
> > +
> > + if (skb->len < sizeof(*rp))
> > + goto error;
> > +
> > + rp = (void *)skb->data;
> > +
> > + if (rp->status)
> > + goto error;
> > +
> > + if (!rp->num_caps) {
> > + len = 0;
> > + /* this codec doesn't have capabilities */
> > + goto skip_caps_parse;
> > + }
> > +
> > + skb_pull(skb, sizeof(*rp));
> > +
> > + for (j = 0, len = 0; j < rp->num_caps; j++) {
> > + caps = (void *)skb->data;
> > + if (skb->len < sizeof(*caps))
> > + goto error;
> > + if (skb->len < caps->len)
> > + goto error;
> > + len += sizeof(caps->len) + caps->len;
> > + skb_pull(skb, sizeof(caps->len) + caps->len);
> > + }
> > +
> > +skip_caps_parse:
> > + hci_dev_lock(hdev);
> > + hci_codec_list_add(&hdev->local_codecs, &cmd, rp,
> > + (__u8 *)rp + sizeof(*rp), len);
> > + hci_dev_unlock(hdev);
> > +error:
> > + kfree_skb(skb);
> > + }
> > + }
> > +}
> > +
> > +static void hci_codec_list_parse(struct hci_dev *hdev, __u8 num_codecs,
> > + void *codec_list, bool is_vnd_codec) {
> > + __u8 i;
> > +
> > + for (i = 0; i < num_codecs; i++) {
> > + if (!is_vnd_codec) {
> > + struct hci_std_codecs *codecs = codec_list;
> > +
> > + hci_read_codec_capabilities(hdev, &codecs-
> >codec[i],
> > + LOCAL_CODEC_ACL_MASK,
> > + is_vnd_codec);
> > + } else {
> > + struct hci_vnd_codecs *codecs = codec_list;
> > +
> > + hci_read_codec_capabilities(hdev, &codecs-
> >codec[i],
> > + LOCAL_CODEC_ACL_MASK,
> > + is_vnd_codec);
> > + }
> > + }
> > +}
>
> I said before that I don’t like it this way. The is_vnd_codec part is pointless
> and you are trickling this through. I really mean that I am not wanting to it
> this way upstream.
>
> So first of all,
>
> if (is_vnd_codec) {
> int i;
>
> for (i = 0; i < num_codecs; i++) {
> struct hci_vnd_codecs *codecs = codec_list;
> hci_read_codec_capabilities(hdev, &codecs-
> >codec[i],
> LOCAL_CODEC_ACL_MASK,
> true);
> }
> } else {
> int I;
>
> for (i = 0; i < num_codecs; i++) {
> struct hci_std_codecs *codecs = codec_list;
> hci_read_codec_capabilities(hdev, &codecs-
> >codec[i],
> LOCAL_CODEC_ACL_MASK,
> false);
> }
> }
>
> This is just by definition more efficient code. Now as caller you already know
> if you are a vendor codec list or not.
>
> static void hci_codec_list_parse_std(struct hci_dev *hdev, __u8
> num_codecs,
> struct hci_std_codecs *codecs)
> {
> int i;
>
> for (i = 0; i < num_codecs; i++)
> hci_read_codec_capabilities(hdev, &codecs-
> >codec[i],
> LOCAL_CODEC_ACL_MASK,
> false);
> }
>
> static void hci_codec_list_parse_vnd(struct hci_dev *hdev, __u8
> num_codecs,
> struct hci_vnd_codecs *codecs)
> {
> ..
> }
>
>
> This is already less code and easier to understand. Also it is type safer since
> the parameter is not a void pointer.

Ack.

>
> Now on to the LOCAL_CODEC_ACL_MASK transport setting and the
> hci_read_codec_capabilities. I have no idea why this is done this way. I can
> not follow this code since it is spaghetti left and right. This needs to be
> untangled.
>

HCI_READ_LOCAL_SUPPORTED_CODEC_CAPABILITIES command requires transport type to be specified. In HCI_READ_LOCAL_SUPPORTED_CODECS_V1, by default transport type is BREDR_ACL. Hence in this patch, caller is explicitly passing LOCAL_CODEC_ACL_MASK.

In patch 02/10, transport bit mask received in HCI_READ_LOCAL_SUPPORTED_CODECS_V2, is passed.

> I am not going to review hci_read_codec_capabilities right now, please look
> through it and come up with simpler solution.
>
> > +
> > +void hci_read_supported_codecs(struct hci_dev *hdev) {
> > + struct sk_buff *skb;
> > + struct hci_rp_read_local_supported_codecs *rp;
> > + struct hci_std_codecs *std_codecs;
> > + struct hci_vnd_codecs *vnd_codecs;
> > +
> > + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL,
> > + HCI_CMD_TIMEOUT);
> > +
> > + if (IS_ERR(skb)) {
> > + bt_dev_err(hdev, "Failed to read local supported codecs
> (%ld)",
> > + PTR_ERR(skb));
> > + return;
> > + }
> > +
> > + if (skb->len < sizeof(*rp))
> > + goto error;
> > +
> > + rp = (void *)skb->data;
> > +
> > + if (rp->status)
> > + goto error;
> > +
> > + skb_pull(skb, sizeof(rp->status));
> > +
> > + std_codecs = (void *)skb->data;
> > +
> > + /* validate codecs length before accessing */
> > + if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num)
> > + + sizeof(std_codecs->num))
> > + goto error;
> > +
> > + /* enumerate codec capabilities of standard codecs */
> > + hci_codec_list_parse(hdev, std_codecs->num, std_codecs, false);
>
>
> for (i = 0; i < std_codecs->num; i++)
> hci_read_codec_capabilities(hdev, &std_codecs->codec[i],
> LOCAL_CODEC_ACL_MASK, false);
>
> Now I am saving the function above and only need 2 extra lines. This is more
> readable since it is easier to follow.
>
> > +
> > + skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num)
> > + + sizeof(std_codecs->num));
> > +
> > + vnd_codecs = (void *)skb->data;
> > +
> > + /* validate vendor codecs length before accessing */
> > + if (skb->len <
> > + flex_array_size(vnd_codecs, codec, vnd_codecs->num)
> > + + sizeof(vnd_codecs->num))
> > + goto error;
> > +
> > + /* enumerate vendor codec capabilities */
> > + hci_codec_list_parse(hdev, vnd_codecs->num, vnd_codecs, true);
> > +
> > +error:
> > + kfree_skb(skb);
> > +}
> > diff --git a/net/bluetooth/hci_codec.h b/net/bluetooth/hci_codec.h new
> > file mode 100644 index 000000000000..e5e594933d07
> > --- /dev/null
> > +++ b/net/bluetooth/hci_codec.h
> > @@ -0,0 +1,6 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +/* Copyright (C) 2021 Intel Corporation */
> > +
> > +void hci_read_supported_codecs(struct hci_dev *hdev); void
> > +hci_codec_list_clear(struct list_head *codec_list);
> > diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index
> > 2560ed2f144d..212d5066d413 100644
> > --- a/net/bluetooth/hci_core.c
> > +++ b/net/bluetooth/hci_core.c
> > @@ -45,6 +45,7 @@
> > #include "leds.h"
> > #include "msft.h"
> > #include "aosp.h"
> > +#include "hci_codec.h"
> >
> > static void hci_rx_work(struct work_struct *work); static void
> > hci_cmd_work(struct work_struct *work); @@ -838,10 +839,6 @@ static
> > int hci_init4_req(struct hci_request *req, unsigned long opt)
> > if (hdev->commands[22] & 0x04)
> > hci_set_event_mask_page_2(req);
> >
> > - /* Read local codec list if the HCI command is supported */
> > - if (hdev->commands[29] & 0x20)
> > - hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL);
> > -
> > /* Read local pairing options if the HCI command is supported */
> > if (hdev->commands[41] & 0x08)
> > hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0,
> NULL); @@ -937,6
> > +934,10 @@ static int __hci_init(struct hci_dev *hdev)
> > if (err < 0)
> > return err;
> >
> > + /* Read local codec list if the HCI command is supported */
> > + if (hdev->commands[29] & 0x20)
> > + hci_read_supported_codecs(hdev);
> > +
> > /* This function is only called when the controller is actually in
> > * configured state. When the controller is marked as unconfigured,
> > * this initialization procedure is not run.
> > @@ -1841,6 +1842,7 @@ int hci_dev_do_close(struct hci_dev *hdev)
> > memset(hdev->eir, 0, sizeof(hdev->eir));
> > memset(hdev->dev_class, 0, sizeof(hdev->dev_class));
> > bacpy(&hdev->random_addr, BDADDR_ANY);
> > + hci_codec_list_clear(&hdev->local_codecs);
> >
> > hci_req_sync_unlock(hdev);
> >
> > @@ -3842,7 +3844,7 @@ struct hci_dev *hci_alloc_dev(void)
> > INIT_LIST_HEAD(&hdev->conn_hash.list);
> > INIT_LIST_HEAD(&hdev->adv_instances);
> > INIT_LIST_HEAD(&hdev->blocked_keys);
> > -
> > + INIT_LIST_HEAD(&hdev->local_codecs);
> > INIT_WORK(&hdev->rx_work, hci_rx_work);
> > INIT_WORK(&hdev->cmd_work, hci_cmd_work);
> > INIT_WORK(&hdev->tx_work, hci_tx_work);
>
> This kind of style changes by removing an on purpose place empty line as
> separator are not acceptable. Please avoid them.

Ack

>
> Regards
>
> Marcel

Regards,
Kiran

2021-08-14 06:37:59

by Kiran K

[permalink] [raw]
Subject: RE: [PATCH v11 04/10] Bluetooth: Allow querying of supported offload codecs over SCO socket

Hi Marcel,

> -----Original Message-----
> From: Marcel Holtmann <[email protected]>
> Sent: Friday, July 30, 2021 7:44 PM
> To: K, Kiran <[email protected]>
> Cc: [email protected]; Srivatsa, Ravishankar
> <[email protected]>; Tumkur Narayan, Chethan
> <[email protected]>
> Subject: Re: [PATCH v11 04/10] Bluetooth: Allow querying of supported
> offload codecs over SCO socket
>
> Hi Kiran,
>
> > Add BT_CODEC option for getsockopt systemcall to get the details of
> > offload codecs supported over SCO socket
> >
> > Signed-off-by: Kiran K <[email protected]>
> > Reviewed-by: Chethan T N <[email protected]>
> > Reviewed-by: Srivatsa Ravishankar <[email protected]>
> > ---
> > * changes in v11:
> > - Remove Kconfig related changes
> > * changes in v10:
> > - In getsockopt, prepare data in advance and call copy_to_user
> > istead of calling put_user on each field of struct bt_codec
> >
> > include/net/bluetooth/bluetooth.h | 20 +++++++
> > include/net/bluetooth/hci.h | 4 ++
> > include/net/bluetooth/hci_core.h | 1 +
> > net/bluetooth/sco.c | 91 +++++++++++++++++++++++++++++++
> > 4 files changed, 116 insertions(+)
> >
> > diff --git a/include/net/bluetooth/bluetooth.h
> > b/include/net/bluetooth/bluetooth.h
> > index 9125effbf448..64cddff0c9c4 100644
> > --- a/include/net/bluetooth/bluetooth.h
> > +++ b/include/net/bluetooth/bluetooth.h
> > @@ -153,6 +153,26 @@ struct bt_voice {
> >
> > #define BT_SCM_PKT_STATUS 0x03
> >
> > +#define BT_CODEC 19
> > +
> > +struct bt_codec_caps {
> > + __u8 len;
> > + __u8 data[];
> > +} __packed;
> > +
> > +struct bt_codec {
> > + __u8 id;
> > + __u16 cid;
> > + __u16 vid;
> > + __u8 data_path;
> > + __u8 num_caps;
> > +} __packed;
> > +
> > +struct bt_codecs {
> > + __u8 num_codecs;
> > + struct bt_codec codecs[];
> > +} __packed;
> > +
> > __printf(1, 2)
> > void bt_info(const char *fmt, ...);
> > __printf(1, 2)
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index b4e35cf5f4b1..22e872e60ff8 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -2621,6 +2621,10 @@ static inline struct hci_sco_hdr
> *hci_sco_hdr(const struct sk_buff *skb)
> > #define hci_iso_data_len(h) ((h) & 0x3fff)
> > #define hci_iso_data_flags(h) ((h) >> 14)
> >
> > +/* codec transport types */
> > +#define TRANSPORT_ACL 0x00
> > +#define TRANSPORT_SCO_ESCO 0x01
> > +
> > /* le24 support */
> > static inline void hci_cpu_to_le24(__u32 val, __u8 dst[3]) { diff
> > --git a/include/net/bluetooth/hci_core.h
> > b/include/net/bluetooth/hci_core.h
> > index 6742e6ad7b37..71c409c8ab34 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -617,6 +617,7 @@ struct hci_dev {
> > int (*set_bdaddr)(struct hci_dev *hdev, const bdaddr_t *bdaddr);
> > void (*cmd_timeout)(struct hci_dev *hdev);
> > bool (*prevent_wake)(struct hci_dev *hdev);
> > + int (*get_data_path_id)(struct hci_dev *hdev, __u8 *data_path);
> > };
> >
> > #define HCI_PHY_HANDLE(handle) (handle & 0xff)
> > diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index
> > ffa2a77a3e4c..2f32693f09c1 100644
> > --- a/net/bluetooth/sco.c
> > +++ b/net/bluetooth/sco.c
> > @@ -953,6 +953,12 @@ 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);
> >
> > @@ -1017,6 +1023,91 @@ static int sco_sock_getsockopt(struct socket
> *sock, int level, int optname,
> > err = -EFAULT;
> > break;
> >
> > + case BT_CODEC:
> > + num_codecs = 0;
> > + buf_len = 0;
> > +
> > + hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
> BDADDR_BREDR);
> > + if (!hdev) {
> > + err = -EBADFD;
> > + break;
> > + }
> > +
> > + if (!hdev->get_data_path_id) {
> > + err = -EOPNOTSUPP;
> > + break;
> > + }
>
> so I did say that this needs to be put behind an experimental feature setting.
> I am not committing to an userspace API until we have more feedback.

Ack.
>
> Regards
>
> Marcel

Regards,
Kiran


2021-08-14 06:44:57

by Kiran K

[permalink] [raw]
Subject: RE: [PATCH v11 08/10] Bluetooth: Add support for HCI_Enhanced_Setup_Synchronous_Connection command

Hi Luiz,

> -----Original Message-----
> From: Luiz Augusto von Dentz <[email protected]>
> Sent: Wednesday, July 28, 2021 9:30 AM
> To: K, Kiran <[email protected]>
> Cc: [email protected]; Srivatsa, Ravishankar
> <[email protected]>; Tumkur Narayan, Chethan
> <[email protected]>
> Subject: Re: [PATCH v11 08/10] Bluetooth: Add support for
> HCI_Enhanced_Setup_Synchronous_Connection command
>
> Hi Kiran,
>
> On Tue, Jul 27, 2021 at 1:45 AM Kiran K <[email protected]> wrote:
> >
> > < HCI Command: Enhanced Setup Synchronous Connection (0x01|0x003d)
> plen 59
> > Handle: 256
> > Transmit bandwidth: 8000
> > Receive bandwidth: 8000
> > Max latency: 13
> > Packet type: 0x0380
> > 3-EV3 may not be used
> > 2-EV5 may not be used
> > 3-EV5 may not be used
> > Retransmission effort: Optimize for link quality (0x02)
> > > HCI Event: Command Status (0x0f) plen 4
> > Enhanced Setup Synchronous Connection (0x01|0x003d) ncmd 1
> > Status: Success (0x00)
> > > HCI Event: Synchronous Connect Complete (0x2c) plen 17
> > Status: Success (0x00)
> > Handle: 257
> > Address: CC:98:8B:92:04:FD (SONY Visual Products Inc.)
> > Link type: eSCO (0x02)
> > Transmission interval: 0x0c
> > Retransmission window: 0x06
> > RX packet length: 60
> > TX packet length: 60
> > Air mode: Transparent (0x03)
> >
> > Signed-off-by: Kiran K <[email protected]>
> > Reviewed-by: Chethan T N <[email protected]>
> > Reviewed-by: Srivatsa Ravishankar <[email protected]>
> > ---
> > * changes in v11:
> > - Remove changes related to Kconfig
> > - s/use_enhanced_sco_conn/enhanced_sco_capable/g
> > - Minor review comments
> >
> > * changes in v10:
> > - Fix typos and remove unwanted chunks
> > * changes in v9:
> > - Fix review comments, use bt_dev_dbg instead of BT_DBG
> >
> > include/net/bluetooth/bluetooth.h | 3 +-
> > include/net/bluetooth/hci.h | 34 ++++++++++
> > include/net/bluetooth/hci_core.h | 6 +-
> > net/bluetooth/hci_conn.c | 105 +++++++++++++++++++++++++++++-
> > net/bluetooth/hci_event.c | 39 +++++++++++
> > net/bluetooth/sco.c | 11 +++-
> > 6 files changed, 192 insertions(+), 6 deletions(-)
> >
> > diff --git a/include/net/bluetooth/bluetooth.h
> > b/include/net/bluetooth/bluetooth.h
> > index 1a48b6732eef..f2df8bb108d9 100644
> > --- a/include/net/bluetooth/bluetooth.h
> > +++ b/include/net/bluetooth/bluetooth.h
> > @@ -173,7 +173,8 @@ struct bt_codecs {
> > struct bt_codec codecs[];
> > } __packed;
> >
> > -#define CODING_FORMAT_CVSD 0x02
> > +#define CODING_FORMAT_CVSD 0x02
> > +#define CODING_FORMAT_TRANSPARENT 0x03
> >
> > __printf(1, 2)
> > void bt_info(const char *fmt, ...);
> > diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> > index c998607fc517..8af8892e18bc 100644
> > --- a/include/net/bluetooth/hci.h
> > +++ b/include/net/bluetooth/hci.h
> > @@ -871,6 +871,40 @@ struct hci_cp_logical_link_cancel {
> > __u8 flow_spec_id;
> > } __packed;
> >
> > +#define HCI_OP_ENHANCED_SETUP_SYNC_CONN 0x043d
> > +struct hci_coding_format {
> > + __u8 id;
> > + __le16 cid;
> > + __le16 vid;
> > +} __packed;
> > +
> > +struct hci_cp_enhanced_setup_sync_conn {
> > + __le16 handle;
> > + __le32 tx_bandwidth;
> > + __le32 rx_bandwidth;
> > + struct hci_coding_format tx_coding_format;
> > + struct hci_coding_format rx_coding_format;
> > + __le16 tx_codec_frame_size;
> > + __le16 rx_codec_frame_size;
> > + __le32 in_bandwidth;
> > + __le32 out_bandwidth;
> > + struct hci_coding_format in_coding_format;
> > + struct hci_coding_format out_coding_format;
> > + __le16 in_coded_data_size;
> > + __le16 out_coded_data_size;
> > + __u8 in_pcm_data_format;
> > + __u8 out_pcm_data_format;
> > + __u8 in_pcm_sample_payload_msb_pos;
> > + __u8 out_pcm_sample_payload_msb_pos;
> > + __u8 in_data_path;
> > + __u8 out_data_path;
> > + __u8 in_transport_unit_size;
> > + __u8 out_transport_unit_size;
> > + __le16 max_latency;
> > + __le16 pkt_type;
> > + __u8 retrans_effort;
> > +} __packed;
> > +
> > struct hci_rp_logical_link_cancel {
> > __u8 status;
> > __u8 phy_handle;
> > diff --git a/include/net/bluetooth/hci_core.h
> > b/include/net/bluetooth/hci_core.h
> > index eafa6f8114cb..4c310bd3e1c6 100644
> > --- a/include/net/bluetooth/hci_core.h
> > +++ b/include/net/bluetooth/hci_core.h
> > @@ -713,6 +713,7 @@ struct hci_conn {
> > struct amp_mgr *amp_mgr;
> >
> > struct hci_conn *link;
> > + struct bt_codec codec;
> >
> > void (*connect_cfm_cb) (struct hci_conn *conn, u8 status);
> > void (*security_cfm_cb) (struct hci_conn *conn, u8 status); @@
> > -1119,7 +1120,7 @@ struct hci_conn *hci_connect_acl(struct hci_dev
> *hdev, bdaddr_t *dst,
> > u8 sec_level, u8 auth_type,
> > enum conn_reasons conn_reason);
> > struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t
> *dst,
> > - __u16 setting);
> > + __u16 setting, struct bt_codec
> > + *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, @@ -1440,6 +1441,9 @@ void hci_conn_del_sysfs(struct
> > hci_conn *conn);
> > /* Use LL Privacy based address resolution if supported */ #define
> > use_ll_privacy(dev) ((dev)->le_features[0] & HCI_LE_LL_PRIVACY)
> >
> > +/* Use enhanced synchronous connection if command is supported */
> > +#define enhanced_sco_capable(dev) ((dev)->commands[29] & 0x08)
> > +
> > /* Use ext scanning if set ext scan param and ext scan enable is
> > supported */ #define use_ext_scan(dev) (((dev)->commands[37] & 0x20)
> && \
> > ((dev)->commands[37] & 0x40)) diff --git
> > a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index
> > 2b5059a56cda..48943b01a356 100644
> > --- a/net/bluetooth/hci_conn.c
> > +++ b/net/bluetooth/hci_conn.c
> > @@ -307,13 +307,103 @@ static bool find_next_esco_param(struct
> hci_conn *conn,
> > return conn->attempt <= size;
> > }
> >
> > -bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
> > +static bool hci_enhanced_setup_sync_conn(struct hci_conn *conn, __u16
> > +handle) {
> > + struct hci_dev *hdev = conn->hdev;
> > + struct hci_cp_enhanced_setup_sync_conn cp;
> > + const struct sco_param *param;
> > +
> > + bt_dev_dbg(hdev, "hcon %p", conn);
> > +
> > + conn->state = BT_CONNECT;
> > + conn->out = true;
> > +
> > + conn->attempt++;
> > +
> > + memset(&cp, 0x00, sizeof(cp));
> > +
> > + cp.handle = cpu_to_le16(handle);
> > +
> > + cp.tx_bandwidth = cpu_to_le32(0x00001f40);
> > + cp.rx_bandwidth = cpu_to_le32(0x00001f40);
> > +
> > + switch (conn->codec.id) {
> > + case CODING_FORMAT_TRANSPARENT:
> > + if (!find_next_esco_param(conn, esco_param_msbc,
> > + ARRAY_SIZE(esco_param_msbc)))
> > + return false;
> > + param = &esco_param_msbc[conn->attempt - 1];
> > + cp.tx_coding_format.id = 0x03;
> > + cp.rx_coding_format.id = 0x03;
> > + cp.tx_codec_frame_size = __cpu_to_le16(60);
> > + cp.rx_codec_frame_size = __cpu_to_le16(60);
> > + cp.in_bandwidth = __cpu_to_le32(0x1f40);
> > + cp.out_bandwidth = __cpu_to_le32(0x1f40);
> > + cp.in_coding_format.id = 0x03;
> > + cp.out_coding_format.id = 0x03;
> > + cp.in_coded_data_size = __cpu_to_le16(16);
> > + cp.out_coded_data_size = __cpu_to_le16(16);
> > + cp.in_pcm_data_format = 2;
> > + cp.out_pcm_data_format = 2;
> > + cp.in_pcm_sample_payload_msb_pos = 0;
> > + cp.out_pcm_sample_payload_msb_pos = 0;
> > + cp.in_data_path = conn->codec.data_path;
> > + cp.out_data_path = conn->codec.data_path;
> > + cp.in_transport_unit_size = 1;
> > + cp.out_transport_unit_size = 1;
> > + break;
> > +
> > + case CODING_FORMAT_CVSD:
> > + if (lmp_esco_capable(conn->link)) {
> > + if (!find_next_esco_param(conn, esco_param_cvsd,
> > + ARRAY_SIZE(esco_param_cvsd)))
> > + return false;
> > + param = &esco_param_cvsd[conn->attempt - 1];
> > + } else {
> > + if (conn->attempt > ARRAY_SIZE(sco_param_cvsd))
> > + return false;
> > + param = &sco_param_cvsd[conn->attempt - 1];
> > + }
> > + cp.tx_coding_format.id = 2;
> > + cp.rx_coding_format.id = 2;
> > + cp.tx_codec_frame_size = __cpu_to_le16(60);
> > + cp.rx_codec_frame_size = __cpu_to_le16(60);
> > + cp.in_bandwidth = __cpu_to_le32(16000);
> > + cp.out_bandwidth = __cpu_to_le32(16000);
> > + cp.in_coding_format.id = 4;
> > + cp.out_coding_format.id = 4;
> > + cp.in_coded_data_size = __cpu_to_le16(16);
> > + cp.out_coded_data_size = __cpu_to_le16(16);
> > + cp.in_pcm_data_format = 2;
> > + cp.out_pcm_data_format = 2;
> > + cp.in_pcm_sample_payload_msb_pos = 0;
> > + cp.out_pcm_sample_payload_msb_pos = 0;
> > + cp.in_data_path = conn->codec.data_path;
> > + cp.out_data_path = conn->codec.data_path;
> > + cp.in_transport_unit_size = 16;
> > + cp.out_transport_unit_size = 16;
> > + break;
> > + default:
> > + return false;
> > + }
> > +
> > + cp.retrans_effort = param->retrans_effort;
> > + cp.pkt_type = __cpu_to_le16(param->pkt_type);
> > + cp.max_latency = __cpu_to_le16(param->max_latency);
> > +
> > + if (hci_send_cmd(hdev, HCI_OP_ENHANCED_SETUP_SYNC_CONN,
> sizeof(cp), &cp) < 0)
> > + return false;
> > +
> > + return true;
> > +}
> > +
> > +static bool hci_setup_sync_conn(struct hci_conn *conn, __u16 handle)
> > {
> > struct hci_dev *hdev = conn->hdev;
> > struct hci_cp_setup_sync_conn cp;
> > const struct sco_param *param;
> >
> > - BT_DBG("hcon %p", conn);
> > + bt_dev_dbg(hdev, "hcon %p", conn);
> >
> > conn->state = BT_CONNECT;
> > conn->out = true;
> > @@ -359,6 +449,14 @@ bool hci_setup_sync(struct hci_conn *conn, __u16
> handle)
> > return true;
> > }
> >
> > +bool hci_setup_sync(struct hci_conn *conn, __u16 handle) {
> > + if (enhanced_sco_capable(conn->hdev))
> > + return hci_enhanced_setup_sync_conn(conn, handle);
> > +
> > + return hci_setup_sync_conn(conn, handle); }
> > +
> > u8 hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16
> latency,
> > u16 to_multiplier) { @@ -1319,7 +1417,7 @@
> > struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst,
> > }
> >
> > struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t
> *dst,
> > - __u16 setting)
> > + __u16 setting, struct bt_codec
> > + *codec)
> > {
> > struct hci_conn *acl;
> > struct hci_conn *sco;
> > @@ -1344,6 +1442,7 @@ struct hci_conn *hci_connect_sco(struct hci_dev
> *hdev, int type, bdaddr_t *dst,
> > hci_conn_hold(sco);
> >
> > sco->setting = setting;
> > + sco->codec = *codec;
> >
> > 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
> > 1c3018202564..18985ac6a83f 100644
> > --- a/net/bluetooth/hci_event.c
> > +++ b/net/bluetooth/hci_event.c
> > @@ -2236,6 +2236,41 @@ static void hci_cs_setup_sync_conn(struct
> hci_dev *hdev, __u8 status)
> > hci_dev_unlock(hdev);
> > }
> >
> > +static void hci_cs_enhanced_setup_sync_conn(struct hci_dev *hdev,
> > +__u8 status) {
> > + struct hci_cp_enhanced_setup_sync_conn *cp;
> > + struct hci_conn *acl, *sco;
> > + __u16 handle;
> > +
> > + bt_dev_dbg(hdev, "status 0x%2.2x", status);
> > +
> > + if (!status)
> > + return;
> > +
> > + cp = hci_sent_cmd_data(hdev,
> HCI_OP_ENHANCED_SETUP_SYNC_CONN);
> > + if (!cp)
> > + return;
> > +
> > + handle = __le16_to_cpu(cp->handle);
> > +
> > + bt_dev_dbg(hdev, "handle 0x%4.4x", handle);
> > +
> > + hci_dev_lock(hdev);
> > +
> > + acl = hci_conn_hash_lookup_handle(hdev, handle);
> > + if (acl) {
> > + sco = acl->link;
> > + if (sco) {
> > + sco->state = BT_CLOSED;
> > +
> > + hci_connect_cfm(sco, status);
> > + hci_conn_del(sco);
> > + }
> > + }
> > +
> > + hci_dev_unlock(hdev);
> > +}
> > +
> > static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) {
> > struct hci_cp_sniff_mode *cp;
> > @@ -3715,6 +3750,10 @@ static void hci_cmd_status_evt(struct hci_dev
> *hdev, struct sk_buff *skb,
> > hci_cs_setup_sync_conn(hdev, ev->status);
> > break;
> >
> > + case HCI_OP_ENHANCED_SETUP_SYNC_CONN:
> > + hci_cs_enhanced_setup_sync_conn(hdev, ev->status);
> > + break;
> > +
> > case HCI_OP_SNIFF_MODE:
> > hci_cs_sniff_mode(hdev, ev->status);
> > break;
> > diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index
> > 34541e971dc7..5ff06ac05fef 100644
> > --- a/net/bluetooth/sco.c
> > +++ b/net/bluetooth/sco.c
> > @@ -240,7 +240,7 @@ static int sco_connect(struct sock *sk)
> > }
> >
> > hcon = hci_connect_sco(hdev, type, &sco_pi(sk)->dst,
> > - sco_pi(sk)->setting);
> > + sco_pi(sk)->setting,
> > + &sco_pi(sk)->codec);
> > if (IS_ERR(hcon)) {
> > err = PTR_ERR(hcon);
> > goto done;
> > @@ -927,6 +927,15 @@ static int sco_sock_setsockopt(struct socket *sock,
> int level, int optname,
> > }
> >
> > sco_pi(sk)->setting = voice.setting;
> > + hdev = hci_get_route(&sco_pi(sk)->dst, &sco_pi(sk)->src,
> > + BDADDR_BREDR);
> > + if (!hdev) {
> > + err = -EBADFD;
> > + break;
> > + }
> > + if (enhanced_sco_capable(hdev) &&
> > + voice.setting == BT_VOICE_TRANSPARENT)
> > + sco_pi(sk)->codec.id =
> > + CODING_FORMAT_TRANSPARENT;
>
>
> hci_get_route does call hci_dev_hold so you need hci_dev_put once you are
> done with it.

Ack. I think same comment is relevant in 04/10 and 06/10 patch. I will send an updated version.
>
> > break;
> >
> > case BT_PKT_STATUS:
> > --
> > 2.17.1
> >
>
>
> --
> Luiz Augusto von Dentz

Thanks,
Kiran