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