1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdio.h>
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/byteorder.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/hci.h>
13 #include <zephyr/bluetooth/l2cap.h>
14 #include <zephyr/bluetooth/att.h>
15 #include <zephyr/bluetooth/gatt.h>
16 #include <zephyr/bluetooth/uuid.h>
17 #include <zephyr/bluetooth/conn.h>
18 
19 #include "testlib/att_read.h"
20 
21 #include <argparse.h>		/* For get_device_nbr() */
22 #include "utils.h"
23 #include "bstests.h"
24 
25 #define strucc struct
26 
27 #include <zephyr/logging/log.h>
28 LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);
29 
30 DEFINE_FLAG(is_connected);
31 DEFINE_FLAG(is_subscribed);
32 DEFINE_FLAG(one_indication);
33 DEFINE_FLAG(two_notifications);
34 DEFINE_FLAG(flag_data_length_updated);
35 
36 static struct bt_conn *dconn;
37 
38 /* Defined in hci_core.c */
39 extern k_tid_t bt_testing_tx_tid_get(void);
40 
connected(struct bt_conn * conn,uint8_t conn_err)41 static void connected(struct bt_conn *conn, uint8_t conn_err)
42 {
43 	char addr[BT_ADDR_LE_STR_LEN];
44 
45 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
46 
47 	if (conn_err) {
48 		FAIL("Failed to connect to %s (%u)", addr, conn_err);
49 		return;
50 	}
51 
52 	LOG_DBG("%s", addr);
53 
54 	dconn = bt_conn_ref(conn);
55 	SET_FLAG(is_connected);
56 }
57 
disconnected(struct bt_conn * conn,uint8_t reason)58 static void disconnected(struct bt_conn *conn, uint8_t reason)
59 {
60 	char addr[BT_ADDR_LE_STR_LEN];
61 
62 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
63 
64 	LOG_DBG("%p %s (reason 0x%02x)", conn, addr, reason);
65 
66 	UNSET_FLAG(is_connected);
67 }
68 
data_len_updated(struct bt_conn * conn,struct bt_conn_le_data_len_info * info)69 static void data_len_updated(struct bt_conn *conn,
70 			     struct bt_conn_le_data_len_info *info)
71 {
72 	LOG_DBG("Data length updated: TX %d RX %d",
73 		info->tx_max_len,
74 		info->rx_max_len);
75 	SET_FLAG(flag_data_length_updated);
76 }
77 
do_dlu(struct bt_conn * conn)78 static void do_dlu(struct bt_conn *conn)
79 {
80 	int err;
81 	struct bt_conn_le_data_len_param param;
82 
83 	param.tx_max_len = CONFIG_BT_CTLR_DATA_LENGTH_MAX;
84 	param.tx_max_time = 2500;
85 
86 	LOG_INF("update DL");
87 	err = bt_conn_le_data_len_update(conn, &param);
88 	ASSERT(err == 0, "Can't update data length (err %d)\n", err);
89 
90 	WAIT_FOR_FLAG(flag_data_length_updated);
91 }
92 
93 BT_CONN_CB_DEFINE(conn_callbacks) = {
94 	.connected = connected,
95 	.disconnected = disconnected,
96 	.le_data_len_updated = data_len_updated,
97 };
98 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)99 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
100 			 struct net_buf_simple *ad)
101 {
102 	char str[BT_ADDR_LE_STR_LEN];
103 	struct bt_le_conn_param *param;
104 	struct bt_conn *conn;
105 	int err;
106 
107 	err = bt_le_scan_stop();
108 	if (err) {
109 		FAIL("Stop LE scan failed (err %d)", err);
110 		return;
111 	}
112 
113 	bt_addr_le_to_str(addr, str, sizeof(str));
114 	LOG_DBG("Connecting to %s", str);
115 
116 	param = BT_LE_CONN_PARAM_DEFAULT;
117 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &conn);
118 	if (err) {
119 		FAIL("Create conn failed (err %d)", err);
120 		return;
121 	}
122 }
123 
124 /* In your area */
125 #define ADV_PARAM_SINGLE BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_ONE_TIME, \
126 					 BT_GAP_ADV_FAST_INT_MIN_2,	\
127 					 BT_GAP_ADV_FAST_INT_MAX_2, NULL)
128 
connecc(void)129 static strucc bt_conn *connecc(void)
130 {
131 	int err;
132 	struct bt_conn *conn;
133 
134 	UNSET_FLAG(is_connected);
135 
136 	err = bt_le_adv_start(ADV_PARAM_SINGLE, NULL, 0, NULL, 0);
137 	ASSERT(!err, "Adving failed to start (err %d)\n", err);
138 
139 	LOG_DBG(" wait connecc...");
140 
141 	WAIT_FOR_FLAG(is_connected);
142 	LOG_INF("conecd");
143 
144 	conn = dconn;
145 	dconn = NULL;
146 
147 	return conn;
148 }
149 
connect(void)150 static struct bt_conn *connect(void)
151 {
152 	int err;
153 	struct bt_conn *conn;
154 
155 	UNSET_FLAG(is_connected);
156 
157 	err = bt_le_scan_start(BT_LE_SCAN_ACTIVE_CONTINUOUS, device_found);
158 	ASSERT(!err, "Scanning failed to start (err %d)\n", err);
159 
160 	LOG_DBG("Central initiating connection...");
161 	WAIT_FOR_FLAG(is_connected);
162 	LOG_INF("Connected as central");
163 
164 	conn = dconn;
165 	dconn = NULL;
166 
167 	return conn;
168 }
169 
read_from(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t buf_len,uint16_t offset)170 static ssize_t read_from(struct bt_conn *conn, const struct bt_gatt_attr *attr,
171 			 void *buf, uint16_t buf_len, uint16_t offset)
172 {
173 	static uint16_t counter;
174 
175 	LOG_INF("read from: len %d", buf_len);
176 
177 	memset(buf, 0, buf_len);
178 	sys_put_le16(counter, buf);
179 	counter++;
180 
181 	LOG_HEXDUMP_DBG(buf, buf_len, "Response data");
182 
183 	return sizeof(uint16_t);
184 }
185 
written_to(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)186 static ssize_t written_to(struct bt_conn *conn,
187 			  const struct bt_gatt_attr *attr,
188 			  const void *buf,
189 			  uint16_t len,
190 			  uint16_t offset,
191 			  uint8_t flags)
192 {
193 	LOG_INF("written to: handle 0x%x len %d flags 0x%x",
194 		attr->handle,
195 		len,
196 		flags);
197 
198 	LOG_HEXDUMP_DBG(buf, len, "Write data");
199 
200 	return len;
201 }
202 
203 #define test_service_uuid                                                                          \
204 	BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf0debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412))
205 #define test_characteristic_uuid                                                                   \
206 	BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf2debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412))
207 
208 BT_GATT_SERVICE_DEFINE(test_gatt_service, BT_GATT_PRIMARY_SERVICE(test_service_uuid),
209 		       BT_GATT_CHARACTERISTIC(test_characteristic_uuid,
210 					      (BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE |
211 					       BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE),
212 					      BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
213 					      read_from, written_to, NULL),
214 		       BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),);
215 
send_write_handle(struct bt_conn * conn)216 static void send_write_handle(struct bt_conn *conn)
217 {
218 	int err;
219 	uint16_t handle;
220 	uint8_t data[sizeof(handle)];
221 	const struct bt_gatt_attr *attr = &test_gatt_service.attrs[2];
222 
223 	/* Inform tester which handle it should write to */
224 	handle = bt_gatt_attr_get_handle(attr);
225 	sys_put_le16(handle, data);
226 
227 	err = bt_gatt_notify(conn, attr, data, sizeof(data));
228 	ASSERT(!err, "Failed to transmit handle for write (err %d)\n", err);
229 }
230 
gatt_read(struct bt_conn * conn,uint16_t handle)231 static void gatt_read(struct bt_conn *conn, uint16_t handle)
232 {
233 	static uint16_t prev_val;
234 	uint16_t value;
235 	int err;
236 
237 	NET_BUF_SIMPLE_DEFINE(buf, BT_ATT_MAX_ATTRIBUTE_LEN);
238 
239 	err = bt_testlib_att_read_by_handle_sync(&buf, NULL, NULL, conn, 0, handle, 0);
240 	ASSERT(!err, "Failed read: err %d", err);
241 
242 	value = net_buf_simple_pull_le16(&buf);
243 
244 	ASSERT(prev_val == value, "Something's up: expected %d got %d", prev_val, value);
245 	prev_val++;
246 
247 	LOG_INF("Read by handle: handle %x val %d err %d", handle, value, err);
248 }
249 
find_the_chrc(struct bt_conn * conn,const struct bt_uuid * svc,const struct bt_uuid * chrc,uint16_t * chrc_value_handle)250 static void find_the_chrc(struct bt_conn *conn, const struct bt_uuid *svc,
251 			  const struct bt_uuid *chrc, uint16_t *chrc_value_handle)
252 {
253 	uint16_t svc_handle;
254 	uint16_t svc_end_handle;
255 	uint16_t chrc_end_handle;
256 	int err;
257 
258 	err = bt_testlib_gatt_discover_primary(&svc_handle, &svc_end_handle, conn, svc, 1, 0xffff);
259 	ASSERT(!err, "Failed to discover service %d");
260 
261 	LOG_DBG("svc_handle: %u, svc_end_handle: %u", svc_handle, svc_end_handle);
262 
263 	err = bt_testlib_gatt_discover_characteristic(chrc_value_handle, &chrc_end_handle,
264 						      NULL, conn, chrc, (svc_handle + 1),
265 						      svc_end_handle);
266 	ASSERT(!err, "Failed to get value handle %d");
267 
268 	LOG_DBG("chrc_value_handle: %u, chrc_end_handle: %u", *chrc_value_handle, chrc_end_handle);
269 }
270 
good_peer_procedure(void)271 void good_peer_procedure(void)
272 {
273 	LOG_DBG("Test 0 start: good peer");
274 	int err;
275 	uint16_t handle;
276 	struct bt_conn *conn;
277 
278 	err = bt_enable(NULL);
279 	ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
280 	LOG_DBG("Central: Bluetooth initialized.");
281 
282 	conn = connecc();
283 
284 	find_the_chrc(conn, test_service_uuid, test_characteristic_uuid, &handle);
285 
286 	uint32_t timeout_ms = PROCEDURE_1_TIMEOUT_MS;
287 	uint32_t start_time = k_uptime_get_32();
288 
289 	while (k_uptime_get_32() - start_time < timeout_ms) {
290 		gatt_read(conn, handle);
291 	}
292 
293 	PASS("Good peer done\n");
294 }
295 
dut_procedure(void)296 void dut_procedure(void)
297 {
298 	LOG_DBG("Test 0 start: DUT");
299 	int err;
300 
301 	struct bt_conn *good, *bad;
302 
303 	err = bt_enable(NULL);
304 	ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
305 	LOG_DBG("Central: Bluetooth initialized.");
306 
307 	LOG_DBG("Central: Connect to good peer");
308 	good = connect();
309 
310 	LOG_DBG("Central: Connect to bad peer");
311 	bad = connect();
312 
313 	LOG_DBG("Central: Connected to both peers");
314 
315 	do_dlu(bad);
316 	send_write_handle(bad);
317 
318 	/* Pass unless some assert in callbacks fails. */
319 	PASS("DUT done\n");
320 }
321 
test_procedure_0(void)322 void test_procedure_0(void)
323 {
324 	/* Test purpose:
325 	 *
326 	 * Verify that a Zephyr host server/client combo can tolerate a spec
327 	 * violating peer that batches ATT requests without waiting for
328 	 * responses.
329 	 *
330 	 * To do this, the application on the DUT will be connected to two
331 	 * peers:
332 	 *
333 	 * - a "nice" peer, running a legal stress test, that is, running a
334 	 * discovery procedure over and over again.
335 	 * - a "bad" peer, spamming ATT requests as fast as possible.
336 	 *
337 	 * The good peer uses the Zephyr host to send requests.
338 	 * The bad peer uses the tinyhost (raw hci) to send requests.
339 	 *
340 	 * The DUT is allowed to disconnect the ACL of the bad peer.
341 	 * If that happens, the bad peer will reconnect and continue.
342 	 * The connection with the good peer must remain stable.
343 	 *
344 	 * Test procedure:
345 	 * At the same time, and for T > ATT_TIMEOUT:
346 	 * - Good peer sends valid ATT write requests to DUT
347 	 * - Good peer validates ATT responses from DUT
348 	 * - Bad peer sends ATT requests as fast as it can
349 	 *
350 	 * [verdict]
351 	 * - no buffer allocation failures for responding to the good peer,
352 	 * timeouts or stalls.
353 	 */
354 	bool dut = (get_device_nbr() == DUT_DEVICE_NBR);
355 
356 	/* We use the same image for both to lighten build load. */
357 	if (dut) {
358 		dut_procedure();
359 	} else {
360 		good_peer_procedure();
361 	}
362 }
363 
write_done(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)364 static void write_done(struct bt_conn *conn, uint8_t err,
365 		       struct bt_gatt_write_params *params)
366 {
367 	LOG_INF("Write done: err %d", err);
368 }
369 
gatt_write(struct bt_conn * conn,struct bt_gatt_write_params * params)370 static void gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
371 {
372 	static uint8_t data[10] = {1};
373 	int err;
374 
375 	memset(params, 0, sizeof(*params));
376 	params->handle = 0x1337;
377 	params->func = write_done;
378 	params->length = sizeof(data);
379 	params->data = data;
380 
381 	LOG_INF("Queue GATT write");
382 
383 	err = bt_gatt_write(conn, params);
384 	ASSERT(!err, "Failed write: err %d", err);
385 }
386 
test_procedure_1(void)387 void test_procedure_1(void)
388 {
389 	/* Test purpose:
390 	 *
391 	 * Verify that the Zephyr host does not pipeline ATT requests.
392 	 * I.e. always waits for a response before enqueuing the next request.
393 	 *
394 	 * Test procedure:
395 	 *
396 	 * - DUT sends a bunch of ATT reads in a loop
397 	 * - Tester delays responses to allow for the LL to transport any other requests.
398 	 * - Tester fails if it detects another request before it has sent the response
399 	 *
400 	 */
401 
402 	LOG_DBG("Test start: ATT pipeline protocol");
403 	int err;
404 
405 	err = bt_enable(NULL);
406 	ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
407 	LOG_DBG("Central: Bluetooth initialized.");
408 
409 	struct bt_conn *tester = connect();
410 
411 	do_dlu(tester);
412 
413 	static struct bt_gatt_write_params parmesans[100];
414 
415 	for (int i = 0; i < ARRAY_SIZE(parmesans); i++) {
416 		gatt_write(tester, &parmesans[i]);
417 	}
418 
419 	bt_conn_disconnect(tester, BT_HCI_ERR_REMOTE_POWER_OFF);
420 	bt_conn_unref(tester);
421 
422 	/* Pass unless some assert in callbacks fails. */
423 	PASS("DUT done\n");
424 }
425 
test_tick(bs_time_t HW_device_time)426 void test_tick(bs_time_t HW_device_time)
427 {
428 	bs_trace_debug_time(0, "Simulation ends now.\n");
429 	if (bst_result != Passed) {
430 		bst_result = Failed;
431 		bs_trace_error("Test did not pass before simulation ended.\n");
432 	}
433 }
434 
test_init(void)435 void test_init(void)
436 {
437 	bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED);
438 	bst_result = In_progress;
439 }
440 
441 static const struct bst_test_instance test_to_add[] = {
442 	{
443 		.test_id = "dut",
444 		.test_pre_init_f = test_init,
445 		.test_tick_f = test_tick,
446 		.test_main_f = test_procedure_0,
447 	},
448 	{
449 		.test_id = "dut_1",
450 		.test_pre_init_f = test_init,
451 		.test_tick_f = test_tick,
452 		.test_main_f = test_procedure_1,
453 	},
454 	BSTEST_END_MARKER,
455 };
456 
install(struct bst_test_list * tests)457 static struct bst_test_list *install(struct bst_test_list *tests)
458 {
459 	return bst_add_tests(tests, test_to_add);
460 };
461 
462 bst_test_install_t test_installers[] = {install, NULL};
463 
main(void)464 int main(void)
465 {
466 	bst_main();
467 
468 	return 0;
469 }
470