2021-04-28 14:57:05

by K, Kiran

[permalink] [raw]
Subject: [PATCH v4 1/2] Bluetooth: enumerate local supported codec and cache details

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

Signed-off-by: Kiran K <[email protected]>
Signed-off-by: Chethan T N <[email protected]>
Signed-off-by: Srivatsa Ravishankar <[email protected]>
---
* changes in 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 | 18 ++++
include/net/bluetooth/hci_core.h | 23 +++++
net/bluetooth/hci_core.c | 144 ++++++++++++++++++++++++++++++-
3 files changed, 181 insertions(+), 4 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ea4ae551c426..2f7f8c6f7d63 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1314,6 +1314,24 @@ 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 codec_id[5];
+ __u8 transport;
+ __u8 direction;
+} __packed;
+
+struct hci_codec_caps {
+ __u8 len;
+ __u8 caps[];
+} __packed;
+
+struct hci_rp_read_local_codec_caps {
+ __u8 status;
+ __u8 num_caps;
+ struct hci_codec_caps 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 8f5f390363f5..b40c7ed38d18 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -131,6 +131,14 @@ struct bdaddr_list {
u8 bdaddr_type;
};

+struct codec_list {
+ struct list_head list;
+ u8 transport;
+ u8 codec_id[5];
+ u8 num_caps;
+ struct hci_codec_caps caps[];
+};
+
struct bdaddr_list_with_irk {
struct list_head list;
bdaddr_t bdaddr;
@@ -534,6 +542,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;

@@ -1843,9 +1852,23 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,

void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 *bdaddr_type);
+int hci_codec_list_add(struct list_head *list, struct hci_rp_read_local_codec_caps *rp,
+ __u32 len,
+ struct hci_op_read_local_codec_caps *sent);
+void hci_codec_list_clear(struct list_head *codec_list);

#define SCO_AIRMODE_MASK 0x0003
#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 LOCAL_CODEC_CIS_MASK BIT(2)
+#define LOCAL_CODEC_BIS_MASK BIT(3)
+
+#define LOCAL_CODEC_ACL 0x00
+#define LOCAL_CODEC_SCO 0x01
+#define LOCAL_CODEC_CIS 0x02
+#define LOCAL_CODEC_BIS 0x03
+
#endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index fd12f1652bdf..7201967b6e9c 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -838,10 +838,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);
@@ -907,6 +903,113 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
return 0;
}

+static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 *codec_id,
+ __u8 transport, bool is_vendor_codec)
+{
+ struct hci_op_read_local_codec_caps caps;
+ struct hci_rp_read_local_codec_caps *rp;
+ struct sk_buff *skb;
+
+ memset(&caps, 0, sizeof(caps));
+
+ if (is_vendor_codec) {
+ caps.codec_id[0] = 0xFF;
+ memcpy(&caps.codec_id[1], codec_id, 4);
+ } else {
+ caps.codec_id[0] = codec_id[0];
+ }
+
+ caps.direction = 0x00;
+ caps.transport = transport;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS, sizeof(caps),
+ &caps, HCI_CMD_TIMEOUT);
+ if (IS_ERR(skb)) {
+ bt_dev_err(hdev, "Failed to read local supported codecs v2 (%ld)",
+ PTR_ERR(skb));
+ return;
+ }
+
+ if (skb->len < sizeof(*rp))
+ goto error;
+
+ rp = (void *)skb->data;
+
+ if (rp->status)
+ goto error;
+
+ hci_dev_lock(hdev);
+ hci_codec_list_add(&hdev->local_codecs, rp, skb->len - 2, &caps);
+ hci_dev_unlock(hdev);
+
+error:
+ kfree_skb(skb);
+}
+
+static void hci_read_supported_codecs(struct hci_dev *hdev)
+{
+ struct sk_buff *skb;
+ __u8 num_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 < 1 || skb->data[0])
+ goto error;
+
+ skb_pull(skb, 1);
+
+ if (skb->len < 1)
+ goto error;
+
+ /* enumerate standard codecs */
+ num_codecs = skb->data[0];
+
+ skb_pull(skb, 1);
+
+ if (num_codecs && skb->len < num_codecs)
+ goto error;
+
+ while (num_codecs--) {
+ hci_read_codec_capabilities(hdev, skb->data, LOCAL_CODEC_ACL,
+ false);
+ skb_pull(skb, 1);
+ }
+
+ /* enumerate vendor specific codecs */
+ if (skb->len < 1)
+ goto error;
+
+ num_codecs = skb->data[0];
+
+ skb_pull(skb, 1);
+
+ if (num_codecs && skb->len < (num_codecs * 4))
+ goto error;
+
+ while (num_codecs--) {
+ hci_read_codec_capabilities(hdev, skb->data, LOCAL_CODEC_ACL,
+ true);
+ skb_pull(skb, 4);
+ }
+
+error:
+ kfree_skb(skb);
+}
+
+static void hci_init5_req(struct hci_dev *hdev)
+{
+ /* Read local codec list if the HCI command is supported */
+ if (hdev->commands[29] & 0x20)
+ hci_read_supported_codecs(hdev);
+}
+
static int __hci_init(struct hci_dev *hdev)
{
int err;
@@ -937,6 +1040,8 @@ static int __hci_init(struct hci_dev *hdev)
if (err < 0)
return err;

+ hci_init5_req(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.
@@ -3559,6 +3664,35 @@ void hci_conn_params_clear_disabled(struct hci_dev *hdev)
BT_DBG("All LE disabled connection parameters were removed");
}

+int hci_codec_list_add(struct list_head *list, struct hci_rp_read_local_codec_caps *rp,
+ __u32 len,
+ struct hci_op_read_local_codec_caps *sent)
+{
+ struct codec_list *entry;
+
+ entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ memcpy(entry->codec_id, sent->codec_id, 5);
+ entry->transport = sent->transport;
+ entry->num_caps = rp->num_caps;
+ if (rp->num_caps)
+ memcpy(entry->caps, rp->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);
+ }
+}
/* This function requires the caller holds hdev->lock */
static void hci_conn_params_clear_all(struct hci_dev *hdev)
{
@@ -3818,6 +3952,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);
@@ -4036,6 +4171,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_conn_params_clear_all(hdev);
hci_discovery_filter_clear(hdev);
hci_blocked_keys_clear(hdev);
+ hci_codec_list_clear(&hdev->local_codecs);
hci_dev_unlock(hdev);

hci_dev_put(hdev);
--
2.17.1


2021-04-28 15:07:56

by bluez.test.bot

[permalink] [raw]
Subject: RE: [v4,1/2] Bluetooth: enumerate local supported codec and cache details

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

Dear submitter,

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

---Test result---

##############################
Test: CheckPatch - PASS


##############################
Test: CheckGitLint - PASS


##############################
Test: CheckBuildK - PASS


##############################
Test: CheckTestRunner: Setup - PASS


##############################
Test: CheckTestRunner: l2cap-tester - PASS
Total: 40, Passed: 40 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: bnep-tester - PASS
Total: 1, Passed: 1 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: mgmt-tester - PASS
Total: 416, Passed: 403 (96.9%), Failed: 0, Not Run: 13

##############################
Test: CheckTestRunner: rfcomm-tester - PASS
Total: 9, Passed: 9 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: sco-tester - PASS
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: smp-tester - PASS
Total: 8, Passed: 8 (100.0%), Failed: 0, Not Run: 0

##############################
Test: CheckTestRunner: userchan-tester - PASS
Total: 3, Passed: 3 (100.0%), Failed: 0, Not Run: 0



---
Regards,
Linux Bluetooth


Attachments:
l2cap-tester.log (51.07 kB)
bnep-tester.log (3.85 kB)
mgmt-tester.log (538.61 kB)
rfcomm-tester.log (14.78 kB)
sco-tester.log (9.68 kB)
smp-tester.log (11.55 kB)
userchan-tester.log (6.46 kB)
Download all attachments

2021-04-28 22:12:25

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: [PATCH v4 1/2] Bluetooth: enumerate local supported codec and cache details

Hi Kiran,

On Wed, Apr 28, 2021 at 7:57 AM Kiran K <[email protected]> wrote:
>
> 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 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 | 18 ++++
> include/net/bluetooth/hci_core.h | 23 +++++
> net/bluetooth/hci_core.c | 144 ++++++++++++++++++++++++++++++-
> 3 files changed, 181 insertions(+), 4 deletions(-)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index ea4ae551c426..2f7f8c6f7d63 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1314,6 +1314,24 @@ 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 codec_id[5];
> + __u8 transport;
> + __u8 direction;
> +} __packed;
> +
> +struct hci_codec_caps {
> + __u8 len;
> + __u8 caps[];
> +} __packed;
> +
> +struct hci_rp_read_local_codec_caps {
> + __u8 status;
> + __u8 num_caps;
> + struct hci_codec_caps 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 8f5f390363f5..b40c7ed38d18 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -131,6 +131,14 @@ struct bdaddr_list {
> u8 bdaddr_type;
> };
>
> +struct codec_list {
> + struct list_head list;
> + u8 transport;
> + u8 codec_id[5];
> + u8 num_caps;
> + struct hci_codec_caps caps[];
> +};
> +
> struct bdaddr_list_with_irk {
> struct list_head list;
> bdaddr_t bdaddr;
> @@ -534,6 +542,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;
>
> @@ -1843,9 +1852,23 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand,
>
> void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
> u8 *bdaddr_type);
> +int hci_codec_list_add(struct list_head *list, struct hci_rp_read_local_codec_caps *rp,
> + __u32 len,
> + struct hci_op_read_local_codec_caps *sent);
> +void hci_codec_list_clear(struct list_head *codec_list);
>
> #define SCO_AIRMODE_MASK 0x0003
> #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 LOCAL_CODEC_CIS_MASK BIT(2)
> +#define LOCAL_CODEC_BIS_MASK BIT(3)
> +
> +#define LOCAL_CODEC_ACL 0x00
> +#define LOCAL_CODEC_SCO 0x01
> +#define LOCAL_CODEC_CIS 0x02
> +#define LOCAL_CODEC_BIS 0x03
> +
> #endif /* __HCI_CORE_H */
> diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
> index fd12f1652bdf..7201967b6e9c 100644
> --- a/net/bluetooth/hci_core.c
> +++ b/net/bluetooth/hci_core.c
> @@ -838,10 +838,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);
> @@ -907,6 +903,113 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
> return 0;
> }
>
> +static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 *codec_id,
> + __u8 transport, bool is_vendor_codec)
> +{
> + struct hci_op_read_local_codec_caps caps;
> + struct hci_rp_read_local_codec_caps *rp;
> + struct sk_buff *skb;
> +
> + memset(&caps, 0, sizeof(caps));
> +
> + if (is_vendor_codec) {
> + caps.codec_id[0] = 0xFF;
> + memcpy(&caps.codec_id[1], codec_id, 4);
> + } else {
> + caps.codec_id[0] = codec_id[0];
> + }
> +
> + caps.direction = 0x00;
> + caps.transport = transport;
> +
> + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS, sizeof(caps),
> + &caps, HCI_CMD_TIMEOUT);
> + if (IS_ERR(skb)) {
> + bt_dev_err(hdev, "Failed to read local supported codecs v2 (%ld)",
> + PTR_ERR(skb));
> + return;
> + }
> +
> + if (skb->len < sizeof(*rp))
> + goto error;
> +
> + rp = (void *)skb->data;
> +
> + if (rp->status)
> + goto error;
> +
> + hci_dev_lock(hdev);
> + hci_codec_list_add(&hdev->local_codecs, rp, skb->len - 2, &caps);
> + hci_dev_unlock(hdev);
> +
> +error:
> + kfree_skb(skb);
> +}
> +
> +static void hci_read_supported_codecs(struct hci_dev *hdev)
> +{
> + struct sk_buff *skb;
> + __u8 num_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 < 1 || skb->data[0])
> + goto error;
> +
> + skb_pull(skb, 1);

We better use a skb_pull with a sizeof of the struct we expect, here
you are probably reading the status but for someone else might not
understand what you doing here.

> +
> + if (skb->len < 1)
> + goto error;
> +
> + /* enumerate standard codecs */
> + num_codecs = skb->data[0];
> +
> + skb_pull(skb, 1);

Ditto, use skb_pull(sbk, sizeof(num_codecs)).

> +
> + if (num_codecs && skb->len < num_codecs)
> + goto error;

The check above might be easier if we use flex_array_size so we
perform the check for the entire array, and then on the while loop you
just access each element by index like Im doing in the patch bellow:

https://patchwork.kernel.org/project/bluetooth/patch/[email protected]/

> + while (num_codecs--) {
> + hci_read_codec_capabilities(hdev, skb->data, LOCAL_CODEC_ACL,
> + false);
> + skb_pull(skb, 1);
> + }

Same thing here.

> + /* enumerate vendor specific codecs */
> + if (skb->len < 1)
> + goto error;
> +
> + num_codecs = skb->data[0];
> +
> + skb_pull(skb, 1);
> +
> + if (num_codecs && skb->len < (num_codecs * 4))
> + goto error;
> +
> + while (num_codecs--) {
> + hci_read_codec_capabilities(hdev, skb->data, LOCAL_CODEC_ACL,
> + true);
> + skb_pull(skb, 4);
> + }

Btw, the code for reading vendor and standard seems exactly the same
so perhaps it is worth moving these lines above under another function
e.g. hci_codec_list_parse which can then take a boolean saying is
vendor or not and from there call hci_read_codec_capabilities.

> +error:
> + kfree_skb(skb);
> +}
> +
> +static void hci_init5_req(struct hci_dev *hdev)
> +{
> + /* Read local codec list if the HCI command is supported */
> + if (hdev->commands[29] & 0x20)
> + hci_read_supported_codecs(hdev);
> +}
> +
> static int __hci_init(struct hci_dev *hdev)
> {
> int err;
> @@ -937,6 +1040,8 @@ static int __hci_init(struct hci_dev *hdev)
> if (err < 0)
> return err;
>
> + hci_init5_req(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.
> @@ -3559,6 +3664,35 @@ void hci_conn_params_clear_disabled(struct hci_dev *hdev)
> BT_DBG("All LE disabled connection parameters were removed");
> }
>
> +int hci_codec_list_add(struct list_head *list, struct hci_rp_read_local_codec_caps *rp,
> + __u32 len,
> + struct hci_op_read_local_codec_caps *sent)
> +{
> + struct codec_list *entry;
> +
> + entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
> + if (!entry)
> + return -ENOMEM;
> +
> + memcpy(entry->codec_id, sent->codec_id, 5);
> + entry->transport = sent->transport;
> + entry->num_caps = rp->num_caps;
> + if (rp->num_caps)
> + memcpy(entry->caps, rp->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);
> + }
> +}
> /* This function requires the caller holds hdev->lock */
> static void hci_conn_params_clear_all(struct hci_dev *hdev)
> {
> @@ -3818,6 +3952,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);
> @@ -4036,6 +4171,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
> hci_conn_params_clear_all(hdev);
> hci_discovery_filter_clear(hdev);
> hci_blocked_keys_clear(hdev);
> + hci_codec_list_clear(&hdev->local_codecs);
> hci_dev_unlock(hdev);
>
> hci_dev_put(hdev);
> --
> 2.17.1
>


--
Luiz Augusto von Dentz

2021-05-02 09:10:14

by K, Kiran

[permalink] [raw]
Subject: RE: [PATCH v4 1/2] Bluetooth: enumerate local supported codec and cache details

Hi Luiz,

Thanks for the comments. I will make the suggested changes in next patch set - v5.

> > +static void hci_read_supported_codecs(struct hci_dev *hdev) {
> > + struct sk_buff *skb;
> > + __u8 num_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 < 1 || skb->data[0])
> > + goto error;
> > +
> > + skb_pull(skb, 1);
>
> We better use a skb_pull with a sizeof of the struct we expect, here you are
> probably reading the status but for someone else might not understand what
> you doing here.
>

Ack

> > +
> > + if (skb->len < 1)
> > + goto error;
> > +
> > + /* enumerate standard codecs */
> > + num_codecs = skb->data[0];
> > +
> > + skb_pull(skb, 1);
>
> Ditto, use skb_pull(sbk, sizeof(num_codecs)).
>
> > +
> > + if (num_codecs && skb->len < num_codecs)
> > + goto error;
>
> The check above might be easier if we use flex_array_size so we perform the
> check for the entire array, and then on the while loop you just access each
> element by index like Im doing in the patch bellow:
>
> https://patchwork.kernel.org/project/bluetooth/patch/20210419171257.386
> [email protected]/

Ack

>
> > + while (num_codecs--) {
> > + hci_read_codec_capabilities(hdev, skb->data,
> LOCAL_CODEC_ACL,
> > + false);
> > + skb_pull(skb, 1);
> > + }
>
> Same thing here.
>
> > + /* enumerate vendor specific codecs */
> > + if (skb->len < 1)
> > + goto error;
> > +
> > + num_codecs = skb->data[0];
> > +
> > + skb_pull(skb, 1);
> > +
> > + if (num_codecs && skb->len < (num_codecs * 4))
> > + goto error;
> > +
> > + while (num_codecs--) {
> > + hci_read_codec_capabilities(hdev, skb->data,
> LOCAL_CODEC_ACL,
> > + true);
> > + skb_pull(skb, 4);
> > + }
>
> Btw, the code for reading vendor and standard seems exactly the same so
> perhaps it is worth moving these lines above under another function e.g.
> hci_codec_list_parse which can then take a boolean saying is vendor or not
> and from there call hci_read_codec_capabilities.
>

Ack

> > +error:
> > + kfree_skb(skb);
> > +}
> > +
> > +static void hci_init5_req(struct hci_dev *hdev) {
> > + /* Read local codec list if the HCI command is supported */
> > + if (hdev->commands[29] & 0x20)
> > + hci_read_supported_codecs(hdev); }
> > +
> > static int __hci_init(struct hci_dev *hdev) {
> > int err;
> > @@ -937,6 +1040,8 @@ static int __hci_init(struct hci_dev *hdev)
> > if (err < 0)
> > return err;
> >
> > + hci_init5_req(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.
> > @@ -3559,6 +3664,35 @@ void hci_conn_params_clear_disabled(struct
> hci_dev *hdev)
> > BT_DBG("All LE disabled connection parameters were removed");
> > }
> >
> > +int hci_codec_list_add(struct list_head *list, struct
> hci_rp_read_local_codec_caps *rp,
> > + __u32 len,
> > + struct hci_op_read_local_codec_caps *sent) {
> > + struct codec_list *entry;
> > +
> > + entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL);
> > + if (!entry)
> > + return -ENOMEM;
> > +
> > + memcpy(entry->codec_id, sent->codec_id, 5);
> > + entry->transport = sent->transport;
> > + entry->num_caps = rp->num_caps;
> > + if (rp->num_caps)
> > + memcpy(entry->caps, rp->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);
> > + }
> > +}
> > /* This function requires the caller holds hdev->lock */ static void
> > hci_conn_params_clear_all(struct hci_dev *hdev) { @@ -3818,6 +3952,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); @@ -4036,6 +4171,7
> > @@ void hci_unregister_dev(struct hci_dev *hdev)
> > hci_conn_params_clear_all(hdev);
> > hci_discovery_filter_clear(hdev);
> > hci_blocked_keys_clear(hdev);
> > + hci_codec_list_clear(&hdev->local_codecs);
> > hci_dev_unlock(hdev);
> >
> > hci_dev_put(hdev);
> > --
> > 2.17.1
> >
>
>
> --
> Luiz Augusto von Dentz

Thanks,
Kiran