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 }
72 
test_ase_control_point_get(void)73 const struct bt_gatt_attr *test_ase_control_point_get(void)
74 {
75 	static const struct bt_gatt_attr *attr;
76 
77 	if (attr == NULL) {
78 		bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE,
79 					  BT_ATT_LAST_ATTRIBUTE_HANDLE,
80 					  BT_UUID_ASCS_ASE_CP, NULL, 1, attr_found, &attr);
81 	}
82 
83 	zassert_not_null(attr, "ASE Control Point not found");
84 
85 	return attr;
86 
87 }
88 
test_ase_get(const struct bt_uuid * uuid,int num_ase,...)89 uint8_t test_ase_get(const struct bt_uuid *uuid, int num_ase, ...)
90 {
91 	const struct bt_gatt_attr *attr = NULL;
92 	va_list attrs;
93 	uint8_t i;
94 
95 	va_start(attrs, num_ase);
96 
97 	for (i = 0; i < num_ase; i++) {
98 		const struct bt_gatt_attr *prev = attr;
99 
100 		bt_gatt_foreach_attr_type(BT_ATT_FIRST_ATTRIBUTE_HANDLE,
101 					  BT_ATT_LAST_ATTRIBUTE_HANDLE,
102 					  uuid, NULL, i + 1, attr_found, &attr);
103 
104 		/* Another attribute was not found */
105 		if (attr == prev) {
106 			break;
107 		}
108 
109 		*(va_arg(attrs, const struct bt_gatt_attr **)) = attr;
110 	}
111 
112 	va_end(attrs);
113 
114 	return i;
115 }
116 
test_ase_id_get(const struct bt_gatt_attr * ase)117 uint8_t test_ase_id_get(const struct bt_gatt_attr *ase)
118 {
119 	struct test_ase_chrc_value_hdr hdr = { 0 };
120 	ssize_t ret;
121 
122 	ret = ase->read(NULL, ase, &hdr, sizeof(hdr), 0);
123 	zassert_false(ret < 0, "ase->read returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
124 
125 	return hdr.ase_id;
126 }
127 
128 static struct bt_bap_stream *stream_allocated;
129 static const struct bt_audio_codec_qos_pref qos_pref =
130 	BT_AUDIO_CODEC_QOS_PREF(true, BT_GAP_LE_PHY_2M, 0x02, 10, 40000, 40000, 40000, 40000);
131 
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_audio_codec_qos_pref * const pref,struct bt_bap_ascs_rsp * rsp)132 static int unicast_server_cb_config_custom_fake(struct bt_conn *conn, const struct bt_bap_ep *ep,
133 						enum bt_audio_dir dir,
134 						const struct bt_audio_codec_cfg *codec_cfg,
135 						struct bt_bap_stream **stream,
136 						struct bt_audio_codec_qos_pref *const pref,
137 						struct bt_bap_ascs_rsp *rsp)
138 {
139 	*stream = stream_allocated;
140 	*pref = qos_pref;
141 	*rsp = BT_BAP_ASCS_RSP(BT_BAP_ASCS_RSP_CODE_SUCCESS, BT_BAP_ASCS_REASON_NONE);
142 
143 	bt_bap_stream_cb_register(*stream, &mock_bap_stream_ops);
144 
145 	return 0;
146 }
147 
test_ase_control_client_config_codec(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)148 void test_ase_control_client_config_codec(struct bt_conn *conn, uint8_t ase_id,
149 					  struct bt_bap_stream *stream)
150 {
151 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
152 	const uint8_t buf[] = {
153 		0x01,           /* Opcode = Config Codec */
154 		0x01,           /* Number_of_ASEs */
155 		ase_id,         /* ASE_ID[0] */
156 		0x01,           /* Target_Latency[0] = Target low latency */
157 		0x02,           /* Target_PHY[0] = LE 2M PHY */
158 		0x06,           /* Codec_ID[0].Coding_Format = LC3 */
159 		0x00, 0x00,     /* Codec_ID[0].Company_ID */
160 		0x00, 0x00,     /* Codec_ID[0].Vendor_Specific_Codec_ID */
161 		0x00,           /* Codec_Specific_Configuration_Length[0] */
162 	};
163 
164 	ssize_t ret;
165 
166 	stream_allocated = stream;
167 	mock_bap_unicast_server_cb_config_fake.custom_fake = unicast_server_cb_config_custom_fake;
168 
169 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
170 	zassert_false(ret < 0, "cp_attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
171 
172 	stream_allocated = NULL;
173 }
174 
test_ase_control_client_config_qos(struct bt_conn * conn,uint8_t ase_id)175 void test_ase_control_client_config_qos(struct bt_conn *conn, uint8_t ase_id)
176 {
177 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
178 	const uint8_t buf[] = {
179 		0x02,                   /* Opcode = Config QoS */
180 		0x01,                   /* Number_of_ASEs */
181 		ase_id,                 /* ASE_ID[0] */
182 		0x01,                   /* CIG_ID[0] */
183 		0x01,                   /* CIS_ID[0] */
184 		0xFF, 0x00, 0x00,       /* SDU_Interval[0] */
185 		0x00,                   /* Framing[0] */
186 		0x02,                   /* PHY[0] */
187 		0x64, 0x00,             /* Max_SDU[0] */
188 		0x02,                   /* Retransmission_Number[0] */
189 		0x0A, 0x00,             /* Max_Transport_Latency[0] */
190 		0x40, 0x9C, 0x00,       /* Presentation_Delay[0] */
191 	};
192 	ssize_t ret;
193 
194 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
195 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
196 }
197 
test_ase_control_client_enable(struct bt_conn * conn,uint8_t ase_id)198 void test_ase_control_client_enable(struct bt_conn *conn, uint8_t ase_id)
199 {
200 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
201 	const uint8_t buf[] = {
202 		0x03,                   /* Opcode = Enable */
203 		0x01,                   /* Number_of_ASEs */
204 		ase_id,                 /* ASE_ID[0] */
205 		0x00,                   /* Metadata_Length[0] */
206 	};
207 	ssize_t ret;
208 
209 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
210 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
211 }
212 
test_ase_control_client_disable(struct bt_conn * conn,uint8_t ase_id)213 void test_ase_control_client_disable(struct bt_conn *conn, uint8_t ase_id)
214 {
215 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
216 	const uint8_t buf[] = {
217 		0x05,                   /* Opcode = Disable */
218 		0x01,                   /* Number_of_ASEs */
219 		ase_id,                 /* ASE_ID[0] */
220 	};
221 	ssize_t ret;
222 
223 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
224 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
225 }
226 
test_ase_control_client_release(struct bt_conn * conn,uint8_t ase_id)227 void test_ase_control_client_release(struct bt_conn *conn, uint8_t ase_id)
228 {
229 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
230 	const uint8_t buf[] = {
231 		0x08,                   /* Opcode = Disable */
232 		0x01,                   /* Number_of_ASEs */
233 		ase_id,                 /* ASE_ID[0] */
234 	};
235 	ssize_t ret;
236 
237 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
238 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
239 }
240 
test_ase_control_client_update_metadata(struct bt_conn * conn,uint8_t ase_id)241 void test_ase_control_client_update_metadata(struct bt_conn *conn, uint8_t ase_id)
242 {
243 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
244 	const uint8_t buf[] = {
245 		0x07,                   /* Opcode = Update Metadata */
246 		0x01,                   /* Number_of_ASEs */
247 		ase_id,                 /* ASE_ID[0] */
248 		0x04,                   /* Metadata_Length[0] */
249 		0x03, 0x02, 0x04, 0x00, /* Metadata[0] = Streaming Context (Media) */
250 	};
251 	ssize_t ret;
252 
253 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
254 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
255 }
256 
test_ase_control_client_receiver_start_ready(struct bt_conn * conn,uint8_t ase_id)257 void test_ase_control_client_receiver_start_ready(struct bt_conn *conn, uint8_t ase_id)
258 {
259 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
260 	const uint8_t buf[] = {
261 		0x04,                   /* Opcode = Receiver Start Ready */
262 		0x01,                   /* Number_of_ASEs */
263 		ase_id,                 /* ASE_ID[0] */
264 	};
265 	ssize_t ret;
266 
267 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
268 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
269 }
270 
test_ase_control_client_receiver_stop_ready(struct bt_conn * conn,uint8_t ase_id)271 void test_ase_control_client_receiver_stop_ready(struct bt_conn *conn, uint8_t ase_id)
272 {
273 	const struct bt_gatt_attr *attr = test_ase_control_point_get();
274 	const uint8_t buf[] = {
275 		0x06,                   /* Opcode = Receiver Stop Ready */
276 		0x01,                   /* Number_of_ASEs */
277 		ase_id,                 /* ASE_ID[0] */
278 	};
279 	ssize_t ret;
280 
281 	ret = attr->write(conn, attr, (void *)buf, sizeof(buf), 0, 0);
282 	zassert_false(ret < 0, "attr->write returned unexpected (err 0x%02x)", BT_GATT_ERR(ret));
283 }
284 
test_preamble_state_codec_configured(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)285 void test_preamble_state_codec_configured(struct bt_conn *conn, uint8_t ase_id,
286 					  struct bt_bap_stream *stream)
287 {
288 	test_ase_control_client_config_codec(conn, ase_id, stream);
289 	test_mocks_reset();
290 }
291 
test_preamble_state_qos_configured(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)292 void test_preamble_state_qos_configured(struct bt_conn *conn, uint8_t ase_id,
293 					struct bt_bap_stream *stream)
294 {
295 	test_ase_control_client_config_codec(conn, ase_id, stream);
296 	test_ase_control_client_config_qos(conn, ase_id);
297 	test_mocks_reset();
298 }
299 
test_preamble_state_enabling(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream)300 void test_preamble_state_enabling(struct bt_conn *conn, uint8_t ase_id,
301 				  struct bt_bap_stream *stream)
302 {
303 	test_ase_control_client_config_codec(conn, ase_id, stream);
304 	test_ase_control_client_config_qos(conn, ase_id);
305 	test_ase_control_client_enable(conn, ase_id);
306 	test_mocks_reset();
307 }
308 
test_preamble_state_streaming(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream,struct bt_iso_chan ** chan,bool source)309 void test_preamble_state_streaming(struct bt_conn *conn, uint8_t ase_id,
310 				   struct bt_bap_stream *stream, struct bt_iso_chan **chan,
311 				   bool source)
312 {
313 	int err;
314 
315 	test_ase_control_client_config_codec(conn, ase_id, stream);
316 	test_ase_control_client_config_qos(conn, ase_id);
317 	test_ase_control_client_enable(conn, ase_id);
318 
319 	err = mock_bt_iso_accept(conn, 0x01, 0x01, chan);
320 	zassert_equal(0, err, "Failed to connect iso: err %d", err);
321 
322 	if (source) {
323 		test_ase_control_client_receiver_start_ready(conn, ase_id);
324 	} else {
325 		err = bt_bap_stream_start(stream);
326 		zassert_equal(0, err, "bt_bap_stream_start err %d", err);
327 	}
328 
329 	test_mocks_reset();
330 }
331 
test_preamble_state_disabling(struct bt_conn * conn,uint8_t ase_id,struct bt_bap_stream * stream,struct bt_iso_chan ** chan)332 void test_preamble_state_disabling(struct bt_conn *conn, uint8_t ase_id,
333 				   struct bt_bap_stream *stream, struct bt_iso_chan **chan)
334 {
335 	int err;
336 
337 	test_ase_control_client_config_codec(conn, ase_id, stream);
338 	test_ase_control_client_config_qos(conn, ase_id);
339 	test_ase_control_client_enable(conn, ase_id);
340 
341 	err = mock_bt_iso_accept(conn, 0x01, 0x01, chan);
342 	zassert_equal(0, err, "Failed to connect iso: err %d", err);
343 
344 	test_ase_control_client_receiver_start_ready(conn, ase_id);
345 	test_ase_control_client_disable(conn, ase_id);
346 
347 	test_mocks_reset();
348 }
349