2021-04-22 14:12:09

by Kiran K

[permalink] [raw]
Subject: [PATCH v3 3/3] Bluetooth: cache local supported codec capabilities

Cache the codec information in the driver and this data can
be exposed to user space audio modules via getsockopt

Signed-off-by: Kiran K <[email protected]>
Signed-off-by: Chethan T N <[email protected]>
Signed-off-by: Srivatsa Ravishankar <[email protected]>
---
* changes in v3
remove unwanted log

* changes in v2
add skb length check before accessing data

include/net/bluetooth/hci.h | 11 +++++++++++
include/net/bluetooth/hci_core.h | 13 +++++++++++++
net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 32 ++++++++++++++++++++++++++++++++
4 files changed, 87 insertions(+)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 34eb9f4b027f..6b4344639ff7 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1323,6 +1323,17 @@ struct hci_op_read_local_codec_caps {
__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 2c19b02a805d..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,6 +1852,10 @@ 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
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index fda7077d0d47..17dc342f4486 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -3569,6 +3569,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)
{
@@ -3828,6 +3857,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);
@@ -4046,6 +4076,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);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 7ca3535f30de..b55cd02abd02 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1057,6 +1057,34 @@ static void hci_cc_read_local_codecs_v2(struct hci_dev *hdev,
}
}

+static void hci_cc_read_local_codec_caps(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_op_read_local_codec_caps *sent;
+ struct hci_rp_read_local_codec_caps *rp;
+
+ if (skb->len < sizeof(*rp))
+ return;
+
+ rp = (void *)skb->data;
+
+ bt_dev_dbg(hdev, "status 0x%2.2x", rp->status);
+
+ if (rp->status)
+ return;
+
+ sent = hci_sent_cmd_data(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS);
+
+ if (!sent)
+ return;
+
+ hci_dev_lock(hdev);
+
+ hci_codec_list_add(&hdev->local_codecs, rp, skb->len - 2, sent);
+
+ hci_dev_unlock(hdev);
+}
+
static void hci_cc_read_clock(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_rp_read_clock *rp = (void *) skb->data;
@@ -3615,6 +3643,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
hci_cc_read_local_codecs_v2(hdev, skb);
break;

+ case HCI_OP_READ_LOCAL_CODEC_CAPS:
+ hci_cc_read_local_codec_caps(hdev, skb);
+ break;
+
case HCI_OP_READ_FLOW_CONTROL_MODE:
hci_cc_read_flow_control_mode(hdev, skb);
break;
--
2.17.1


2021-04-23 08:04:49

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] Bluetooth: cache local supported codec capabilities

Hi Kiran,

> Cache the codec information in the driver and this data can
> be exposed to user space audio modules via getsockopt
>
> Signed-off-by: Kiran K <[email protected]>
> Signed-off-by: Chethan T N <[email protected]>
> Signed-off-by: Srivatsa Ravishankar <[email protected]>
> ---
> * changes in v3
> remove unwanted log
>
> * changes in v2
> add skb length check before accessing data
>
> include/net/bluetooth/hci.h | 11 +++++++++++
> include/net/bluetooth/hci_core.h | 13 +++++++++++++
> net/bluetooth/hci_core.c | 31 +++++++++++++++++++++++++++++++
> net/bluetooth/hci_event.c | 32 ++++++++++++++++++++++++++++++++
> 4 files changed, 87 insertions(+)
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 34eb9f4b027f..6b4344639ff7 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -1323,6 +1323,17 @@ struct hci_op_read_local_codec_caps {
> __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 2c19b02a805d..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,6 +1852,10 @@ 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);

I think you need to redo the whole patch series, since 1/3 should have hci_codec_list_add in that it adds the codec id from reading the codec list.

And then reading the capabilities just updates the codec.

Our problem is that the whole init phase is rather async than sync in it procedure. And the reason for that is purely historic from the times when Linus had no work queues and we had to process everything in tasklets or spawn kthreads.

Frankly if we moved the whole init procedure to use __hci_cmd_sync we could fold the complete init{1-4} phases into one. And there is no reason we don’t do that. However one problem at a time.

Regards

Marcel

2021-04-28 14:57:05

by Kiran K

[permalink] [raw]
Subject: RE: [PATCH v3 3/3] Bluetooth: cache local supported codec capabilities

Hi Marcel,

> > +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);
>
> I think you need to redo the whole patch series, since 1/3 should have
> hci_codec_list_add in that it adds the codec id from reading the codec list.
>
Ack

> And then reading the capabilities just updates the codec.
>
With async calls converted to sync, can we add codec details to the list on reading codec caps as same codec can be supported on multiple transport types ?

> Our problem is that the whole init phase is rather async than sync in it
> procedure. And the reason for that is purely historic from the times when
> Linus had no work queues and we had to process everything in tasklets or
> spawn kthreads.
>
> Frankly if we moved the whole init procedure to use __hci_cmd_sync we
> could fold the complete init{1-4} phases into one. And there is no reason we
> don’t do that. However one problem at a time.
>
Ack. I will define init5 for reading codecs and codec caps using __hci_cmd_sync calls.

> Regards
>
> Marcel

Thanks,
Kiran

2021-04-28 14:58:00

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v3 3/3] Bluetooth: cache local supported codec capabilities

Hi Kiran,

>>> +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);
>>
>> I think you need to redo the whole patch series, since 1/3 should have
>> hci_codec_list_add in that it adds the codec id from reading the codec list.
>>
> Ack
>
>> And then reading the capabilities just updates the codec.
>>
> With async calls converted to sync, can we add codec details to the list on reading codec caps as same codec can be supported on multiple transport types ?
>
>> Our problem is that the whole init phase is rather async than sync in it
>> procedure. And the reason for that is purely historic from the times when
>> Linus had no work queues and we had to process everything in tasklets or
>> spawn kthreads.
>>
>> Frankly if we moved the whole init procedure to use __hci_cmd_sync we
>> could fold the complete init{1-4} phases into one. And there is no reason we
>> don’t do that. However one problem at a time.
>>
> Ack. I will define init5 for reading codecs and codec caps using __hci_cmd_sync calls.

I think this is too early. I only looked at the intermingling of hci_update_background_scan. I have not gotten the whole init handling. I suspect some looking issues that would have to be cleaned up first.

Regards

Marcel

2021-04-28 19:21:51

by Kiran K

[permalink] [raw]
Subject: RE: [PATCH v3 3/3] Bluetooth: cache local supported codec capabilities

Hi Marcel,

> -----Original Message-----
> From: Marcel Holtmann <[email protected]>
> Sent: Wednesday, April 28, 2021 8:20 PM
> To: K, Kiran <[email protected]>
> Cc: [email protected]; Tumkur Narayan, Chethan
> <[email protected]>; Srivatsa, Ravishankar
> <[email protected]>
> Subject: Re: [PATCH v3 3/3] Bluetooth: cache local supported codec
> capabilities
>
> Hi Kiran,
>
> >>> +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);
> >>
> >> I think you need to redo the whole patch series, since 1/3 should
> >> have hci_codec_list_add in that it adds the codec id from reading the
> codec list.
> >>
> > Ack
> >
> >> And then reading the capabilities just updates the codec.
> >>
> > With async calls converted to sync, can we add codec details to the list on
> reading codec caps as same codec can be supported on multiple transport
> types ?
> >
> >> Our problem is that the whole init phase is rather async than sync in
> >> it procedure. And the reason for that is purely historic from the
> >> times when Linus had no work queues and we had to process everything
> >> in tasklets or spawn kthreads.
> >>
> >> Frankly if we moved the whole init procedure to use __hci_cmd_sync we
> >> could fold the complete init{1-4} phases into one. And there is no
> >> reason we don’t do that. However one problem at a time.
> >>
> > Ack. I will define init5 for reading codecs and codec caps using
> __hci_cmd_sync calls.
>
> I think this is too early. I only looked at the intermingling of
> hci_update_background_scan. I have not gotten the whole init handling. I
> suspect some looking issues that would have to be cleaned up first.

In my test, I didn't see any issue. In that case, let me know how to proceed further. I am happy to amend as per your comments.

Thanks,
Kiran