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