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