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