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