1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <zephyr/autoconf.h>
12 #include <zephyr/bluetooth/addr.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/audio/bap.h>
15 #include <zephyr/bluetooth/iso.h>
16 #include <zephyr/sys/slist.h>
17 #include <zephyr/ztest_assert.h>
18 
19 #include "bap_broadcast_assistant.h"
20 #include "test_common.h"
21 
22 static sys_slist_t broadcast_assistant_cbs = SYS_SLIST_STATIC_INIT(&broadcast_assistant_cbs);
23 
24 /* when > 0 immediately return from the add_src callback the specified number of times
25  * This allows us to test the CAP cancel command by not successfully sending all the
26  * requests, so that we can cancel before the CAP commander implementation is done
27  * with the procedure.
28  * This is based on the fact that we are not actually sending any requests on air, and
29  * that we are using this function as a synchronous function, rather than an asynchronous
30  * function.
31  */
32 static unsigned int add_src_skip;
33 
set_skip_add_src(unsigned int setting)34 void set_skip_add_src(unsigned int setting)
35 {
36 	add_src_skip = setting;
37 }
38 
39 struct bap_broadcast_assistant_recv_state_info {
40 	uint8_t src_id;
41 	/** Cached PAST available */
42 	bool past_avail;
43 	uint8_t adv_sid;
44 	uint32_t broadcast_id;
45 	bt_addr_le_t addr;
46 };
47 
48 struct bap_broadcast_assistant_instance {
49 	struct bt_conn *conn;
50 	struct bap_broadcast_assistant_recv_state_info recv_states;
51 	/*
52 	 * the following are not part of the broadcast_assistant instance, but adding them allow us
53 	 * to easily check pa_sync and bis_sync states
54 	 */
55 	enum bt_bap_pa_state pa_sync_state;
56 	uint8_t num_subgroups;
57 	struct bt_bap_bass_subgroup subgroups[CONFIG_BT_BAP_BASS_MAX_SUBGROUPS];
58 };
59 
60 static struct bap_broadcast_assistant_instance broadcast_assistants[CONFIG_BT_MAX_CONN];
61 static uint8_t max_src_id;
62 
inst_by_conn(struct bt_conn * conn)63 static struct bap_broadcast_assistant_instance *inst_by_conn(struct bt_conn *conn)
64 {
65 	struct bap_broadcast_assistant_instance *inst;
66 
67 	zassert_not_null(conn, "conn is NULL");
68 
69 	inst = &broadcast_assistants[bt_conn_index(conn)];
70 
71 	return inst;
72 }
73 
bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb * cb)74 int bt_bap_broadcast_assistant_register_cb(struct bt_bap_broadcast_assistant_cb *cb)
75 {
76 	struct bt_bap_broadcast_assistant_cb *tmp;
77 
78 	if (cb == NULL) {
79 		return -EINVAL;
80 	}
81 
82 	SYS_SLIST_FOR_EACH_CONTAINER(&broadcast_assistant_cbs, tmp, _node) {
83 		if (tmp == cb) {
84 			return -EALREADY;
85 		}
86 	}
87 
88 	sys_slist_append(&broadcast_assistant_cbs, &cb->_node);
89 
90 	return 0;
91 }
92 
bt_bap_broadcast_assistant_unregister_cb(struct bt_bap_broadcast_assistant_cb * cb)93 int bt_bap_broadcast_assistant_unregister_cb(struct bt_bap_broadcast_assistant_cb *cb)
94 {
95 	if (cb == NULL) {
96 		return -EINVAL;
97 	}
98 
99 	if (!sys_slist_find_and_remove(&broadcast_assistant_cbs, &cb->_node)) {
100 		return -EALREADY;
101 	}
102 
103 	return 0;
104 }
105 
bt_bap_broadcast_assistant_add_src(struct bt_conn * conn,const struct bt_bap_broadcast_assistant_add_src_param * param)106 int bt_bap_broadcast_assistant_add_src(struct bt_conn *conn,
107 				       const struct bt_bap_broadcast_assistant_add_src_param *param)
108 {
109 	struct bap_broadcast_assistant_instance *inst;
110 	struct bt_bap_scan_delegator_recv_state state;
111 	struct bt_bap_broadcast_assistant_cb *listener, *next;
112 
113 	if (add_src_skip != 0) {
114 		add_src_skip--;
115 
116 		return 0;
117 	}
118 
119 	/* Note that proper parameter checking is done in the caller */
120 	zassert_not_null(conn, "conn is NULL");
121 	zassert_not_null(param, "param is NULL");
122 
123 	inst = inst_by_conn(conn);
124 	zassert_not_null(inst, "inst is NULL");
125 
126 	max_src_id++;
127 	inst->recv_states.src_id = max_src_id;
128 	inst->recv_states.past_avail = false;
129 	inst->recv_states.adv_sid = param->adv_sid;
130 	inst->recv_states.broadcast_id = param->broadcast_id;
131 	inst->pa_sync_state = param->pa_sync;
132 	inst->num_subgroups = param->num_subgroups;
133 	state.pa_sync_state = param->pa_sync;
134 	state.src_id = max_src_id;
135 	state.num_subgroups = param->num_subgroups;
136 	for (size_t i = 0; i < param->num_subgroups; i++) {
137 		state.subgroups[i].bis_sync = param->subgroups[i].bis_sync;
138 		inst->subgroups[i].bis_sync = param->subgroups[i].bis_sync;
139 	}
140 
141 	bt_addr_le_copy(&inst->recv_states.addr, &param->addr);
142 
143 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
144 		if (listener->add_src != NULL) {
145 			listener->add_src(conn, 0);
146 		}
147 		if (listener->recv_state != NULL) {
148 			listener->recv_state(conn, 0, &state);
149 		}
150 	}
151 
152 	return 0;
153 }
154 
bt_bap_broadcast_assistant_mod_src(struct bt_conn * conn,const struct bt_bap_broadcast_assistant_mod_src_param * param)155 int bt_bap_broadcast_assistant_mod_src(struct bt_conn *conn,
156 				       const struct bt_bap_broadcast_assistant_mod_src_param *param)
157 {
158 	struct bap_broadcast_assistant_instance *inst;
159 	struct bt_bap_scan_delegator_recv_state state;
160 	struct bt_bap_broadcast_assistant_cb *listener, *next;
161 
162 	zassert_not_null(conn, "conn is NULL");
163 	zassert_not_null(param, "param is NULL");
164 
165 	inst = inst_by_conn(conn);
166 	zassert_not_null(inst, "inst is NULL");
167 
168 	state.pa_sync_state = param->pa_sync ? BT_BAP_PA_STATE_SYNCED : BT_BAP_PA_STATE_NOT_SYNCED;
169 	state.src_id = param->src_id;
170 	inst->recv_states.src_id = param->src_id;
171 	inst->pa_sync_state = param->pa_sync;
172 
173 	state.num_subgroups = param->num_subgroups;
174 	inst->num_subgroups = param->num_subgroups;
175 	for (size_t i = 0; i < param->num_subgroups; i++) {
176 		state.subgroups[i].bis_sync = param->subgroups[i].bis_sync;
177 		inst->subgroups[i].bis_sync = param->subgroups[i].bis_sync;
178 	}
179 		SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
180 			if (listener->mod_src != NULL) {
181 				listener->mod_src(conn, 0);
182 			}
183 			if (listener->recv_state != NULL) {
184 				listener->recv_state(conn, 0, &state);
185 			}
186 		}
187 
188 	return 0;
189 }
190 
bt_bap_broadcast_assistant_rem_src(struct bt_conn * conn,uint8_t src_id)191 int bt_bap_broadcast_assistant_rem_src(struct bt_conn *conn, uint8_t src_id)
192 {
193 	struct bap_broadcast_assistant_instance *inst;
194 	struct bt_bap_broadcast_assistant_cb *listener, *next;
195 
196 	zassert_not_null(conn, "conn is NULL");
197 
198 	inst = inst_by_conn(conn);
199 	zassert_equal(src_id, inst->recv_states.src_id, "Invalid src_id");
200 	zassert_equal(BT_BAP_PA_STATE_NOT_SYNCED, inst->pa_sync_state, "Invalid sync state");
201 	for (int i = 0; i < inst->num_subgroups; i++) {
202 		zassert_equal(0, inst->subgroups[i].bis_sync);
203 	}
204 
205 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
206 		if (listener->rem_src != NULL) {
207 			listener->rem_src(conn, 0);
208 		}
209 	}
210 
211 	return 0;
212 }
213 
bt_bap_broadcast_assistant_set_broadcast_code(struct bt_conn * conn,uint8_t src_id,const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])214 int bt_bap_broadcast_assistant_set_broadcast_code(
215 	struct bt_conn *conn, uint8_t src_id,
216 	const uint8_t broadcast_code[BT_ISO_BROADCAST_CODE_SIZE])
217 {
218 	struct bt_bap_broadcast_assistant_cb *listener, *next;
219 	int err;
220 
221 	zassert_not_null(conn, "conn is NULL");
222 
223 	zassert_equal(src_id, RANDOM_SRC_ID, "Invalid src_id");
224 
225 	err = strncmp((const char *)broadcast_code, BROADCAST_CODE, sizeof(BROADCAST_CODE));
226 	zassert_equal(0, err, "Unexpected broadcast code");
227 
228 	SYS_SLIST_FOR_EACH_CONTAINER_SAFE(&broadcast_assistant_cbs, listener, next, _node) {
229 		if (listener->broadcast_code != NULL) {
230 			listener->broadcast_code(conn, 0);
231 		}
232 	}
233 
234 	return 0;
235 }
236