1 /*
2 * Copyright (c) 2023 Codecoup
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdarg.h>
7 #include <stdbool.h>
8 #include <stddef.h>
9 #include <stdint.h>
10
11 #include <zephyr/bluetooth/att.h>
12 #include <zephyr/bluetooth/gap.h>
13 #include <zephyr/bluetooth/hci_types.h>
14 #include <zephyr/bluetooth/iso.h>
15 #include <zephyr/fff.h>
16 #include <zephyr/types.h>
17 #include <zephyr/bluetooth/audio/audio.h>
18 #include <zephyr/bluetooth/audio/bap.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/gatt.h>
21 #include <zephyr/bluetooth/uuid.h>
22 #include <zephyr/sys/util_macro.h>
23 #include <zephyr/ztest_assert.h>
24 #include <sys/types.h>
25
26 #include "bap_unicast_server.h"
27 #include "bap_stream.h"
28 #include "conn.h"
29 #include "gatt.h"
30 #include "iso.h"
31 #include "mock_kernel.h"
32 #include "pacs.h"
33
34 #include "test_common.h"
35
test_mocks_init(void)36 void test_mocks_init(void)
37 {
38 mock_bap_unicast_server_init();
39 mock_bt_iso_init();
40 mock_kernel_init();
41 mock_bt_pacs_init();
42 mock_bap_stream_init();
43 mock_bt_gatt_init();
44 }
45
test_mocks_cleanup(void)46 void test_mocks_cleanup(void)
47 {
48 mock_bap_unicast_server_cleanup();
49 mock_bt_iso_cleanup();
50 mock_kernel_cleanup();
51 mock_bt_pacs_cleanup();
52 mock_bap_stream_cleanup();
53 mock_bt_gatt_cleanup();
54 }
55
test_mocks_reset(void)56 void test_mocks_reset(void)
57 {
58 test_mocks_cleanup();
59 test_mocks_init();
60 }
61
attr_found(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)62 static uint8_t attr_found(const struct bt_gatt_attr *attr, uint16_t handle, void *user_data)
63 {
64 const struct bt_gatt_attr **result = user_data;
65
66 *result = attr;
67
68 return BT_GATT_ITER_STOP;
69 }
70
test_conn_init(struct bt_conn * conn)71 void test_conn_init(struct bt_conn *conn)
72 {
73 conn->index = 0;
74 conn->info.type = BT_CONN_TYPE_LE;
75 conn->info.role = BT_CONN_ROLE_PERIPHERAL;
76 conn->info.state = BT_CONN_STATE_CONNECTED;
77 conn->info.security.level = BT_SECURITY_L2;
78 conn->info.security.enc_key_size = BT_ENC_KEY_SIZE_MAX;
79 conn->info.security.flags = BT_SECURITY_FLAG_OOB | BT_SECURITY_FLAG_SC;
80 conn->info.le.interval = BT_GAP_INIT_CONN_INT_MIN;
81 }
82
test_ase_control_point_get(void)83 const struct bt_gatt_attr *test_ase_control_point_get(void)
84 {
85 static const struct bt_gatt_attr *attr;
86
87 if (attr == NULL) {
88 bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE,
89 BT_ATT_LAST_ATTRIBUTE_HANDLE,
90 BT_UUID_ASCS_ASE_CP, NULL, 1, attr_found, &attr);
91 }
92
93 zassert_not_null(attr, "ASE Control Point not found");
94
95 return attr;
96
97 }
98
test_ase_get(const struct bt_uuid * uuid,int num_ase,...)99 uint8_t test_ase_get(const struct bt_uuid *uuid, int num_ase, ...)
100 {
101 const struct bt_gatt_attr *attr = NULL;
102 va_list attrs;
103 uint8_t i;
104
105 va_start(attrs, num_ase);
106
107 for (i = 0; i < num_ase; i++) {
108 const struct bt_gatt_attr *prev = attr;
109
110 bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE,
111 BT_ATT_LAST_ATTRIBUTE_HANDLE,
112 uuid, NULL, i + 1, attr_found, &attr);
113
114 /* Another attribute was not found */
115 if (attr == prev) {
116 break;
117 }
118
119 *(va_arg(attrs, const struct bt_gatt_attr **)) = attr;
120 }
121
122 va_end(attrs);
123
124 return i;
125 }
126
test_ase_id_get(const struct bt_gatt_attr * ase)127 uint8_t test_ase_id_get(const struct bt_gatt_attr *ase)
128 {
129 struct test_ase_chrc_value_hdr hdr = { 0 };
130 ssize_t ret;
131
132 ret = ase->read(NULL, ase, &hdr, sizeof(hdr), 0);
133 zassert_false(ret < 0, "ase->read returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
134
135 return hdr.ase_id;
136 }
137
138 static struct bt_bap_stream *stream_allocated;
139 static const struct bt_bap_qos_cfg_pref qos_pref =
140 BT_BAP_QOS_CFG_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000);
141
unicast_server_cb_config_custom_fake(struct bt_conn * conn,const struct bt_bap_ep * ep,enum bt_audio_dir dir,const struct bt_audio_codec_cfg * codec_cfg,struct bt_bap_stream ** stream,struct bt_bap_qos_cfg_pref * const pref,struct bt_bap_ascs_rsp * rsp)142 static int unicast_server_cb_config_custom_fake(struct bt_conn *conn, const struct bt_bap_ep *ep,
143 enum bt_audio_dir dir,
144 const struct bt_audio_codec_cfg *codec_cfg,
145 struct bt_bap_stream **stream,
146 struct bt_bap_qos_cfg_pref *const pref,
147 struct bt_bap_ascs_rsp *rsp)
148 {
149 *stream = stream_allocated;
150 *pref = qos_pref;
151 *rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
152
153 bt_bap_stream_cb_register(*stream, &mock_bap_stream_ops);
154
155 return 0;
156 }
157
test_ase_control_client_config_codec(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)158 void test_ase_control_client_config_codec(struct bt_conn *conn, uint8_t ase_id,
159 struct bt_bap_stream *stream)
160 {
161 const struct bt_gatt_attr *attr = test_ase_control_point_get();
162 const uint8_t buf[] = {
163 0x01, /* Opcode = Config Codec */
164 0x01, /* Number_of_ASEs */
165 ase_id, /* ASE_ID[0] */
166 0x01, /* Target_Latency[0] = Target low latency */
167 0x02, /* Target_PHY[0] = LE 2M PHY */
168 0x06, /* Codec_ID[0].Coding_Format = LC3 */
169 0x00, 0x00, /* Codec_ID[0].Company_ID */
170 0x00, 0x00, /* Codec_ID[0].Vendor_Specific_Codec_ID */
171 0x00, /* Codec_Specific_Configuration_Length[0] */
172 };
173
174 ssize_t ret;
175
176 stream_allocated = stream;
177 mock_bap_unicast_server_cb_config_fake.custom_fake = unicast_server_cb_config_custom_fake;
178
179 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
180 zassert_false(ret < 0, "cp_attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
181
182 stream_allocated = NULL;
183 }
184
test_ase_control_client_config_qos(struct bt_conn * conn,uint8_t ase_id)185 void test_ase_control_client_config_qos(struct bt_conn *conn, uint8_t ase_id)
186 {
187 const struct bt_gatt_attr *attr = test_ase_control_point_get();
188 const uint8_t buf[] = {
189 0x02, /* Opcode = Config QoS */
190 0x01, /* Number_of_ASEs */
191 ase_id, /* ASE_ID[0] */
192 0x01, /* CIG_ID[0] */
193 0x01, /* CIS_ID[0] */
194 0xFF, 0x00, 0x00, /* SDU_Interval[0] */
195 0x00, /* Framing[0] */
196 0x02, /* PHY[0] */
197 0x64, 0x00, /* Max_SDU[0] */
198 0x02, /* Retransmission_Number[0] */
199 0x0A, 0x00, /* Max_Transport_Latency[0] */
200 0x40, 0x9C, 0x00, /* Presentation_Delay[0] */
201 };
202 ssize_t ret;
203
204 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
205 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
206 }
207
test_ase_control_client_enable(struct bt_conn * conn,uint8_t ase_id)208 void test_ase_control_client_enable(struct bt_conn *conn, uint8_t ase_id)
209 {
210 const struct bt_gatt_attr *attr = test_ase_control_point_get();
211 const uint8_t buf[] = {
212 0x03, /* Opcode = Enable */
213 0x01, /* Number_of_ASEs */
214 ase_id, /* ASE_ID[0] */
215 0x00, /* Metadata_Length[0] */
216 };
217 ssize_t ret;
218
219 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
220 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
221 }
222
test_ase_control_client_disable(struct bt_conn * conn,uint8_t ase_id)223 void test_ase_control_client_disable(struct bt_conn *conn, uint8_t ase_id)
224 {
225 const struct bt_gatt_attr *attr = test_ase_control_point_get();
226 const uint8_t buf[] = {
227 0x05, /* Opcode = Disable */
228 0x01, /* Number_of_ASEs */
229 ase_id, /* ASE_ID[0] */
230 };
231 ssize_t ret;
232
233 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
234 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
235 }
236
test_ase_control_client_release(struct bt_conn * conn,uint8_t ase_id)237 void test_ase_control_client_release(struct bt_conn *conn, uint8_t ase_id)
238 {
239 const struct bt_gatt_attr *attr = test_ase_control_point_get();
240 const uint8_t buf[] = {
241 0x08, /* Opcode = Release */
242 0x01, /* Number_of_ASEs */
243 ase_id, /* ASE_ID[0] */
244 };
245 ssize_t ret;
246
247 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
248 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
249 }
250
test_ase_control_client_update_metadata(struct bt_conn * conn,uint8_t ase_id)251 void test_ase_control_client_update_metadata(struct bt_conn *conn, uint8_t ase_id)
252 {
253 const struct bt_gatt_attr *attr = test_ase_control_point_get();
254 const uint8_t buf[] = {
255 0x07, /* Opcode = Update Metadata */
256 0x01, /* Number_of_ASEs */
257 ase_id, /* ASE_ID[0] */
258 0x04, /* Metadata_Length[0] */
259 0x03, 0x02, 0x04, 0x00, /* Metadata[0] = Streaming Context (Media) */
260 };
261 ssize_t ret;
262
263 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
264 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
265 }
266
test_ase_control_client_receiver_start_ready(struct bt_conn * conn,uint8_t ase_id)267 void test_ase_control_client_receiver_start_ready(struct bt_conn *conn, uint8_t ase_id)
268 {
269 const struct bt_gatt_attr *attr = test_ase_control_point_get();
270 const uint8_t buf[] = {
271 0x04, /* Opcode = Receiver Start Ready */
272 0x01, /* Number_of_ASEs */
273 ase_id, /* ASE_ID[0] */
274 };
275 ssize_t ret;
276
277 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
278 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
279 }
280
test_ase_control_client_receiver_stop_ready(struct bt_conn * conn,uint8_t ase_id)281 void test_ase_control_client_receiver_stop_ready(struct bt_conn *conn, uint8_t ase_id)
282 {
283 const struct bt_gatt_attr *attr = test_ase_control_point_get();
284 const uint8_t buf[] = {
285 0x06, /* Opcode = Receiver Stop Ready */
286 0x01, /* Number_of_ASEs */
287 ase_id, /* ASE_ID[0] */
288 };
289 ssize_t ret;
290
291 ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
292 zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
293 }
294
test_preamble_state_codec_configured(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)295 void test_preamble_state_codec_configured(struct bt_conn *conn, uint8_t ase_id,
296 struct bt_bap_stream *stream)
297 {
298 test_ase_control_client_config_codec(conn, ase_id, stream);
299 test_mocks_reset();
300 }
301
test_preamble_state_qos_configured(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)302 void test_preamble_state_qos_configured(struct bt_conn *conn, uint8_t ase_id,
303 struct bt_bap_stream *stream)
304 {
305 test_ase_control_client_config_codec(conn, ase_id, stream);
306 test_ase_control_client_config_qos(conn, ase_id);
307 test_mocks_reset();
308 }
309
test_preamble_state_enabling(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)310 void test_preamble_state_enabling(struct bt_conn *conn, uint8_t ase_id,
311 struct bt_bap_stream *stream)
312 {
313 test_ase_control_client_config_codec(conn, ase_id, stream);
314 test_ase_control_client_config_qos(conn, ase_id);
315 test_ase_control_client_enable(conn, ase_id);
316 test_mocks_reset();
317 }
318
test_preamble_state_streaming(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream,struct bt_iso_chan ** chan,bool source)319 void test_preamble_state_streaming(struct bt_conn *conn, uint8_t ase_id,
320 struct bt_bap_stream *stream, struct bt_iso_chan **chan,
321 bool source)
322 {
323 int err;
324
325 test_ase_control_client_config_codec(conn, ase_id, stream);
326 test_ase_control_client_config_qos(conn, ase_id);
327 test_ase_control_client_enable(conn, ase_id);
328
329 err = mock_bt_iso_accept(conn, 0x01, 0x01, chan);
330 zassert_equal(0, err, "Failed to connect iso: err %d", err);
331
332 if (source) {
333 test_ase_control_client_receiver_start_ready(conn, ase_id);
334 } else {
335 err = bt_bap_stream_start(stream);
336 zassert_equal(0, err, "bt_bap_stream_start err %d", err);
337 }
338
339 test_mocks_reset();
340 }
341
test_preamble_state_disabling(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream,struct bt_iso_chan ** chan)342 void test_preamble_state_disabling(struct bt_conn *conn, uint8_t ase_id,
343 struct bt_bap_stream *stream, struct bt_iso_chan **chan)
344 {
345 int err;
346
347 test_ase_control_client_config_codec(conn, ase_id, stream);
348 test_ase_control_client_config_qos(conn, ase_id);
349 test_ase_control_client_enable(conn, ase_id);
350
351 err = mock_bt_iso_accept(conn, 0x01, 0x01, chan);
352 zassert_equal(0, err, "Failed to connect iso: err %d", err);
353
354 test_ase_control_client_receiver_start_ready(conn, ase_id);
355 test_ase_control_client_disable(conn, ase_id);
356
357 test_mocks_reset();
358 }
359
test_preamble_state_releasing(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream,struct bt_iso_chan ** chan,bool source)360 void test_preamble_state_releasing(struct bt_conn *conn, uint8_t ase_id,
361 struct bt_bap_stream *stream, struct bt_iso_chan **chan,
362 bool source)
363 {
364 test_preamble_state_streaming(conn, ase_id, stream, chan, source);
365 test_ase_control_client_release(conn, ase_id);
366
367 /* Reset the mocks especially the function call count */
368 mock_bap_unicast_server_cleanup();
369 mock_bt_iso_cleanup();
370 mock_bap_stream_cleanup();
371 mock_bt_gatt_cleanup();
372 mock_bap_unicast_server_init();
373 mock_bt_iso_init();
374 mock_bap_stream_init();
375 mock_bt_gatt_init();
376
377 /* At this point, ISO is still connected, thus ASE is in releasing state */
378 }
379