Bluetooth: CAP: Add verification of CCIDs as the initiator

When the initiator provides CCID in the metadata, we verify
that the CCIDs exist on the device.

Signed-off-by: Emil Gydesen <emil.gydesen@nordicsemi.no>
This commit is contained in:
Emil Gydesen 2023-10-11 10:09:46 +02:00 committed by Carles Cufí
parent a422e1d8fb
commit 779f725db3
4 changed files with 92 additions and 10 deletions

View File

@ -10,6 +10,7 @@
#include <zephyr/bluetooth/audio/cap.h>
#include <zephyr/bluetooth/audio/tbs.h>
#include "cap_internal.h"
#include "ccid_internal.h"
#include "csip_internal.h"
#include "bap_endpoint.h"
@ -38,9 +39,14 @@ int bt_cap_initiator_register_cb(const struct bt_cap_initiator_cb *cb)
return 0;
}
struct valid_metadata_param {
bool stream_context_found;
bool valid;
};
static bool data_func_cb(struct bt_data *data, void *user_data)
{
bool *stream_context_found = (bool *)user_data;
struct valid_metadata_param *metadata_param = (struct valid_metadata_param *)user_data;
LOG_DBG("type %u len %u data %s", data->type, data->data_len,
bt_hex(data->data, data->data_len));
@ -50,8 +56,21 @@ static bool data_func_cb(struct bt_data *data, void *user_data)
return false;
}
*stream_context_found = true;
return false;
metadata_param->stream_context_found = true;
} else if (IS_ENABLED(CONFIG_BT_CCID) && data->type == BT_AUDIO_METADATA_TYPE_CCID_LIST) {
/* If the application supplies a CCID list, we verify that the CCIDs exist on our
* device
*/
for (uint8_t i = 0U; i < data->data_len; i++) {
const uint8_t ccid = data->data[i];
if (bt_ccid_find_attr(ccid) == NULL) {
LOG_DBG("Unknown characterstic for CCID 0x%02X", ccid);
metadata_param->valid = false;
return false;
}
}
}
return true;
@ -59,21 +78,24 @@ static bool data_func_cb(struct bt_data *data, void *user_data)
static bool cap_initiator_valid_metadata(const uint8_t meta[], size_t meta_len)
{
bool stream_context_found = false;
struct valid_metadata_param metadata_param = {
.stream_context_found = false,
.valid = true,
};
int err;
LOG_DBG("meta %p len %zu", meta, meta_len);
err = bt_audio_data_parse(meta, meta_len, data_func_cb, &stream_context_found);
err = bt_audio_data_parse(meta, meta_len, data_func_cb, &metadata_param);
if (err != 0 && err != -ECANCELED) {
return false;
}
if (!stream_context_found) {
if (!metadata_param.stream_context_found) {
LOG_DBG("No streaming context supplied");
}
return stream_context_found;
return metadata_param.stream_context_found && metadata_param.valid;
}
#if defined(CONFIG_BT_BAP_BROADCAST_SOURCE)

View File

@ -6,6 +6,9 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/att.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
#include "ccid_internal.h"
@ -23,3 +26,41 @@ uint8_t bt_ccid_get_value(void)
return ccid_value++;
}
struct ccid_search_param {
const struct bt_gatt_attr *attr;
uint8_t ccid;
};
static uint8_t ccid_attr_cb(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data)
{
struct ccid_search_param *search_param = user_data;
if (attr->read != NULL) {
uint8_t ccid = 0U;
ssize_t res;
res = attr->read(NULL, attr, &ccid, sizeof(ccid), 0);
if (res == sizeof(ccid) && search_param->ccid == ccid) {
search_param->attr = attr;
return BT_GATT_ITER_STOP;
}
}
return BT_GATT_ITER_CONTINUE;
}
const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid)
{
struct ccid_search_param search_param = {
.attr = NULL,
.ccid = ccid,
};
bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE, BT_ATT_LAST_ATTRIBUTE_HANDLE,
BT_UUID_CCID, NULL, 0, ccid_attr_cb, &search_param);
return search_param.attr;
}

View File

@ -23,4 +23,16 @@
*/
uint8_t bt_ccid_get_value(void);
/**
* @brief Get the GATT attribute of a CCID value
*
* Searches the current GATT database for a CCID characteristic that has the supplied CCID value.
*
* @param ccid The CCID the search for
*
* @retval NULL if none was found
* @retval A pointer to a GATT attribute if found
*/
const struct bt_gatt_attr *bt_ccid_find_attr(uint8_t ccid);
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_CCID_H_ */

View File

@ -406,11 +406,18 @@ static void test_broadcast_audio_update_inval(struct bt_cap_broadcast_source *br
static void test_broadcast_audio_update(struct bt_cap_broadcast_source *broadcast_source)
{
const uint16_t mock_ccid = 0xAB;
#if defined(CONFIG_BT_TBS)
/* TODO: We do not have a way to get the CCID value of GTBS, but for now set to 0x00 as we
* know that it is the first content control service initialized
*/
const uint16_t gtbs_ccid = 0x00;
#endif /* CONFIG_BT_TBS */
const uint8_t new_metadata[] = {
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_STREAM_CONTEXT,
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_MEDIA)),
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, mock_ccid),
BT_BYTES_LIST_LE16(BT_AUDIO_CONTEXT_TYPE_CONVERSATIONAL)),
#if defined(CONFIG_BT_TBS)
BT_AUDIO_CODEC_DATA(BT_AUDIO_METADATA_TYPE_CCID_LIST, gtbs_ccid),
#endif /* CONFIG_BT_TBS */
};
int err;