Bluetooth: Audio: Broadcast Assistant: Check add_source duplication

Added a check for checking duplication when adding a source in the
broadcast assistant, as per requirement in BAP 6.5.4. It is not
permitted to add a source such that a combination of broadcast_id,
adv_sid and address type would result in same triple of values.
Added a recv_state struct to cache these values when read, and moved
past_avail and srd_ids into this as well.

Signed-off-by: Fredrik Danebjer <frdn@demant.com>
This commit is contained in:
Fredrik Danebjer 2024-03-18 11:44:02 +01:00 committed by Fabio Baltieri
commit bbb87ae0ae

View file

@ -3,6 +3,7 @@
/* /*
* Copyright (c) 2019 Bose Corporation * Copyright (c) 2019 Bose Corporation
* Copyright (c) 2022-2023 Nordic Semiconductor ASA * Copyright (c) 2022-2023 Nordic Semiconductor ASA
* Copyright (c) 2024 Demant A/S
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -34,17 +35,21 @@ LOG_MODULE_REGISTER(bt_bap_broadcast_assistant, CONFIG_BT_BAP_BROADCAST_ASSISTAN
#define MINIMUM_RECV_STATE_LEN 15 #define MINIMUM_RECV_STATE_LEN 15
struct bap_broadcast_assistant_recv_state_info {
uint8_t src_id;
bt_addr_le_t addr;
uint8_t adv_sid;
uint32_t broadcast_id;
/** Cached PAST available */
bool past_avail;
};
struct bap_broadcast_assistant_instance { struct bap_broadcast_assistant_instance {
struct bt_conn *conn; struct bt_conn *conn;
bool scanning; bool scanning;
uint8_t pa_sync; uint8_t pa_sync;
uint8_t recv_state_cnt; uint8_t recv_state_cnt;
/* Source ID cache so that we can notify application about
* which source ID was removed
*/
uint8_t src_ids[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
/** Cached PAST available */
bool past_avail[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
uint16_t start_handle; uint16_t start_handle;
uint16_t end_handle; uint16_t end_handle;
@ -62,6 +67,9 @@ struct bap_broadcast_assistant_instance {
struct k_work_delayable bap_read_work; struct k_work_delayable bap_read_work;
uint16_t long_read_handle; uint16_t long_read_handle;
struct bap_broadcast_assistant_recv_state_info recv_states
[CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT];
}; };
static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs); static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs);
@ -273,10 +281,10 @@ static uint8_t parse_and_send_recv_state(struct bt_conn *conn, uint16_t handle,
return BT_GATT_ITER_STOP; return BT_GATT_ITER_STOP;
} }
broadcast_assistant.src_ids[index] = recv_state->src_id; broadcast_assistant.recv_states[index].src_id = recv_state->src_id;
broadcast_assistant.past_avail[index] = past_available(conn, broadcast_assistant.recv_states[index].past_avail = past_available(conn,
&recv_state->addr, &recv_state->addr,
recv_state->adv_sid); recv_state->adv_sid);
bap_broadcast_assistant_recv_state_changed(conn, 0, recv_state); bap_broadcast_assistant_recv_state_changed(conn, 0, recv_state);
@ -434,9 +442,9 @@ static uint8_t notify_handler(struct bt_conn *conn,
return parse_and_send_recv_state(conn, handle, data, length, &recv_state); return parse_and_send_recv_state(conn, handle, data, length, &recv_state);
} }
} else { } else {
broadcast_assistant.past_avail[index] = false; broadcast_assistant.recv_states[index].past_avail = false;
bap_broadcast_assistant_recv_state_removed(conn, 0, bap_broadcast_assistant_recv_state_removed(conn, 0,
broadcast_assistant.src_ids[index]); broadcast_assistant.recv_states[index].src_id);
} }
return BT_GATT_ITER_CONTINUE; return BT_GATT_ITER_CONTINUE;
@ -471,8 +479,14 @@ static uint8_t read_recv_state_cb(struct bt_conn *conn, uint8_t err,
if (cb_err != 0) { if (cb_err != 0) {
LOG_DBG("Invalid receive state"); LOG_DBG("Invalid receive state");
} else { } else {
broadcast_assistant.src_ids[index] = recv_state.src_id; struct bap_broadcast_assistant_recv_state_info *stored_state =
broadcast_assistant.past_avail[index] = &broadcast_assistant.recv_states[index];
stored_state->src_id = recv_state.src_id;
stored_state->adv_sid = recv_state.adv_sid;
stored_state->broadcast_id = recv_state.broadcast_id;
bt_addr_le_copy(&stored_state->addr, &recv_state.addr);
broadcast_assistant.recv_states[index].past_avail =
past_available(conn, &recv_state.addr, past_available(conn, &recv_state.addr,
recv_state.adv_sid); recv_state.adv_sid);
} }
@ -782,8 +796,9 @@ static int broadcast_assistant_reset(struct bap_broadcast_assistant_instance *in
(void)k_work_cancel_delayable(&inst->bap_read_work); (void)k_work_cancel_delayable(&inst->bap_read_work);
for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT; i++) { for (int i = 0U; i < CONFIG_BT_BAP_BROADCAST_ASSISTANT_RECV_STATE_COUNT; i++) {
inst->src_ids[i] = 0U; memset(&inst->recv_states[i], 0,
inst->past_avail[i] = false; sizeof(struct bap_broadcast_assistant_recv_state_info));
inst->recv_states[i].past_avail = false;
inst->recv_state_handles[i] = 0U; inst->recv_state_handles[i] = 0U;
} }
@ -998,6 +1013,7 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
const struct bt_bap_broadcast_assistant_add_src_param *param) const struct bt_bap_broadcast_assistant_add_src_param *param)
{ {
struct bt_bap_bass_cp_add_src *cp; struct bt_bap_bass_cp_add_src *cp;
struct bap_broadcast_assistant_recv_state_info *state;
if (conn == NULL) { if (conn == NULL) {
LOG_DBG("conn is NULL"); LOG_DBG("conn is NULL");
@ -1013,6 +1029,21 @@ int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
return -EBUSY; return -EBUSY;
} }
/* Check if this operation would result in a duplicate before proceeding */
for (size_t i = 0; i < ARRAY_SIZE(broadcast_assistant.recv_states); i++) {
state = &broadcast_assistant.recv_states[i];
if (param->addr.type == state->addr.type && param->adv_sid == state->adv_sid &&
param->broadcast_id == state->broadcast_id) {
LOG_DBG("recv_state using broadcast_id=0x%06X, adv_sid=0x%02X, and "
"addr.type=0x%02X already exists with src_id=0x%02X",
param->broadcast_id, param->adv_sid, param->addr.type,
state->src_id);
return -EINVAL;
}
}
/* Reset buffer before using */ /* Reset buffer before using */
net_buf_simple_reset(&att_buf); net_buf_simple_reset(&att_buf);
cp = net_buf_simple_add(&att_buf, sizeof(*cp)); cp = net_buf_simple_add(&att_buf, sizeof(*cp));
@ -1108,10 +1139,10 @@ int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
*/ */
known_recv_state = false; known_recv_state = false;
past_avail = false; past_avail = false;
for (size_t i = 0; i < ARRAY_SIZE(broadcast_assistant.src_ids); i++) { for (size_t i = 0; i < ARRAY_SIZE(broadcast_assistant.recv_states); i++) {
if (broadcast_assistant.src_ids[i] == param->src_id) { if (broadcast_assistant.recv_states[i].src_id == param->src_id) {
known_recv_state = true; known_recv_state = true;
past_avail = broadcast_assistant.past_avail[i]; past_avail = broadcast_assistant.recv_states[i].past_avail;
break; break;
} }
} }