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, ¶m);
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
connecc(void)124 static strucc bt_conn *connecc(void)
125 {
126 int err;
127 struct bt_conn *conn;
128
129 UNSET_FLAG(is_connected);
130
131 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, NULL, 0, NULL, 0);
132 ASSERT(!err, "Adving failed to start (err %d)\n", err);
133
134 LOG_DBG(" wait connecc...");
135
136 WAIT_FOR_FLAG(is_connected);
137 LOG_INF("conecd");
138
139 conn = dconn;
140 dconn = NULL;
141
142 return conn;
143 }
144
connect(void)145 static struct bt_conn *connect(void)
146 {
147 int err;
148 struct bt_conn *conn;
149
150 UNSET_FLAG(is_connected);
151
152 err = bt_le_scan_start(BT_LE_SCAN_ACTIVE_CONTINUOUS, device_found);
153 ASSERT(!err, "Scanning failed to start (err %d)\n", err);
154
155 LOG_DBG("Central initiating connection...");
156 WAIT_FOR_FLAG(is_connected);
157 LOG_INF("Connected as central");
158
159 conn = dconn;
160 dconn = NULL;
161
162 return conn;
163 }
164
read_from(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t buf_len,uint16_t offset)165 static ssize_t read_from(struct bt_conn *conn, const struct bt_gatt_attr *attr,
166 void *buf, uint16_t buf_len, uint16_t offset)
167 {
168 static uint16_t counter;
169
170 LOG_INF("read from: len %d", buf_len);
171
172 memset(buf, 0, buf_len);
173 sys_put_le16(counter, buf);
174 counter++;
175
176 LOG_HEXDUMP_DBG(buf, buf_len, "Response data");
177
178 return sizeof(uint16_t);
179 }
180
written_to(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)181 static ssize_t written_to(struct bt_conn *conn,
182 const struct bt_gatt_attr *attr,
183 const void *buf,
184 uint16_t len,
185 uint16_t offset,
186 uint8_t flags)
187 {
188 LOG_INF("written to: handle 0x%x len %d flags 0x%x",
189 attr->handle,
190 len,
191 flags);
192
193 LOG_HEXDUMP_DBG(buf, len, "Write data");
194
195 return len;
196 }
197
198 #define test_service_uuid \
199 BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf0debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412))
200 #define test_characteristic_uuid \
201 BT_UUID_DECLARE_128(BT_UUID_128_ENCODE(0xf2debc9a, 0x7856, 0x3412, 0x7856, 0x341278563412))
202
203 BT_GATT_SERVICE_DEFINE(test_gatt_service, BT_GATT_PRIMARY_SERVICE(test_service_uuid),
204 BT_GATT_CHARACTERISTIC(test_characteristic_uuid,
205 (BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE |
206 BT_GATT_CHRC_NOTIFY | BT_GATT_CHRC_INDICATE),
207 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE,
208 read_from, written_to, NULL),
209 BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),);
210
send_write_handle(struct bt_conn * conn)211 static void send_write_handle(struct bt_conn *conn)
212 {
213 int err;
214 uint16_t handle;
215 uint8_t data[sizeof(handle)];
216 const struct bt_gatt_attr *attr = &test_gatt_service.attrs[2];
217
218 /* Inform tester which handle it should write to */
219 handle = bt_gatt_attr_get_handle(attr);
220 sys_put_le16(handle, data);
221
222 err = bt_gatt_notify(conn, attr, data, sizeof(data));
223 ASSERT(!err, "Failed to transmit handle for write (err %d)\n", err);
224 }
225
gatt_read(struct bt_conn * conn,uint16_t handle)226 static void gatt_read(struct bt_conn *conn, uint16_t handle)
227 {
228 static uint16_t prev_val;
229 uint16_t value;
230 int err;
231
232 NET_BUF_SIMPLE_DEFINE(buf, BT_ATT_MAX_ATTRIBUTE_LEN);
233
234 err = bt_testlib_att_read_by_handle_sync(&buf, NULL, NULL, conn, 0, handle, 0);
235 ASSERT(!err, "Failed read: err %d", err);
236
237 value = net_buf_simple_pull_le16(&buf);
238
239 ASSERT(prev_val == value, "Something's up: expected %d got %d", prev_val, value);
240 prev_val++;
241
242 LOG_INF("Read by handle: handle %x val %d err %d", handle, value, err);
243 }
244
find_the_chrc(struct bt_conn * conn,const struct bt_uuid * svc,const struct bt_uuid * chrc,uint16_t * chrc_value_handle)245 static void find_the_chrc(struct bt_conn *conn, const struct bt_uuid *svc,
246 const struct bt_uuid *chrc, uint16_t *chrc_value_handle)
247 {
248 uint16_t svc_handle;
249 uint16_t svc_end_handle;
250 uint16_t chrc_end_handle;
251 int err;
252
253 err = bt_testlib_gatt_discover_primary(&svc_handle, &svc_end_handle, conn, svc, 1, 0xffff);
254 ASSERT(!err, "Failed to discover service %d");
255
256 LOG_DBG("svc_handle: %u, svc_end_handle: %u", svc_handle, svc_end_handle);
257
258 err = bt_testlib_gatt_discover_characteristic(chrc_value_handle, &chrc_end_handle,
259 NULL, conn, chrc, (svc_handle + 1),
260 svc_end_handle);
261 ASSERT(!err, "Failed to get value handle %d");
262
263 LOG_DBG("chrc_value_handle: %u, chrc_end_handle: %u", *chrc_value_handle, chrc_end_handle);
264 }
265
good_peer_procedure(void)266 void good_peer_procedure(void)
267 {
268 LOG_DBG("Test 0 start: good peer");
269 int err;
270 uint16_t handle;
271 struct bt_conn *conn;
272
273 err = bt_enable(NULL);
274 ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
275 LOG_DBG("Central: Bluetooth initialized.");
276
277 conn = connecc();
278
279 find_the_chrc(conn, test_service_uuid, test_characteristic_uuid, &handle);
280
281 uint32_t timeout_ms = PROCEDURE_1_TIMEOUT_MS;
282 uint32_t start_time = k_uptime_get_32();
283
284 while (k_uptime_get_32() - start_time < timeout_ms) {
285 gatt_read(conn, handle);
286 }
287
288 PASS("Good peer done\n");
289 }
290
dut_procedure(void)291 void dut_procedure(void)
292 {
293 LOG_DBG("Test 0 start: DUT");
294 int err;
295
296 struct bt_conn *good, *bad;
297
298 err = bt_enable(NULL);
299 ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
300 LOG_DBG("Central: Bluetooth initialized.");
301
302 LOG_DBG("Central: Connect to good peer");
303 good = connect();
304
305 LOG_DBG("Central: Connect to bad peer");
306 bad = connect();
307
308 LOG_DBG("Central: Connected to both peers");
309
310 do_dlu(bad);
311 send_write_handle(bad);
312
313 /* Pass unless some assert in callbacks fails. */
314 PASS("DUT done\n");
315 }
316
test_procedure_0(void)317 void test_procedure_0(void)
318 {
319 /* Test purpose:
320 *
321 * Verify that a Zephyr host server/client combo can tolerate a spec
322 * violating peer that batches ATT requests without waiting for
323 * responses.
324 *
325 * To do this, the application on the DUT will be connected to two
326 * peers:
327 *
328 * - a "nice" peer, running a legal stress test, that is, running a
329 * discovery procedure over and over again.
330 * - a "bad" peer, spamming ATT requests as fast as possible.
331 *
332 * The good peer uses the Zephyr host to send requests.
333 * The bad peer uses the tinyhost (raw hci) to send requests.
334 *
335 * The DUT is allowed to disconnect the ACL of the bad peer.
336 * If that happens, the bad peer will reconnect and continue.
337 * The connection with the good peer must remain stable.
338 *
339 * Test procedure:
340 * At the same time, and for T > ATT_TIMEOUT:
341 * - Good peer sends valid ATT write requests to DUT
342 * - Good peer validates ATT responses from DUT
343 * - Bad peer sends ATT requests as fast as it can
344 *
345 * [verdict]
346 * - no buffer allocation failures for responding to the good peer,
347 * timeouts or stalls.
348 */
349 bool dut = (get_device_nbr() == DUT_DEVICE_NBR);
350
351 /* We use the same image for both to lighten build load. */
352 if (dut) {
353 dut_procedure();
354 } else {
355 good_peer_procedure();
356 }
357 }
358
write_done(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)359 static void write_done(struct bt_conn *conn, uint8_t err,
360 struct bt_gatt_write_params *params)
361 {
362 LOG_INF("Write done: err %d", err);
363 }
364
gatt_write(struct bt_conn * conn,struct bt_gatt_write_params * params)365 static void gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)
366 {
367 static uint8_t data[10] = {1};
368 int err;
369
370 memset(params, 0, sizeof(*params));
371 params->handle = 0x1337;
372 params->func = write_done;
373 params->length = sizeof(data);
374 params->data = data;
375
376 LOG_INF("Queue GATT write");
377
378 err = bt_gatt_write(conn, params);
379 ASSERT(!err, "Failed write: err %d", err);
380 }
381
test_procedure_1(void)382 void test_procedure_1(void)
383 {
384 /* Test purpose:
385 *
386 * Verify that the Zephyr host does not pipeline ATT requests.
387 * I.e. always waits for a response before enqueuing the next request.
388 *
389 * Test procedure:
390 *
391 * - DUT sends a bunch of ATT reads in a loop
392 * - Tester delays responses to allow for the LL to transport any other requests.
393 * - Tester fails if it detects another request before it has sent the response
394 *
395 */
396
397 LOG_DBG("Test start: ATT pipeline protocol");
398 int err;
399
400 err = bt_enable(NULL);
401 ASSERT(err == 0, "Can't enable Bluetooth (err %d)\n", err);
402 LOG_DBG("Central: Bluetooth initialized.");
403
404 struct bt_conn *tester = connect();
405
406 do_dlu(tester);
407
408 static struct bt_gatt_write_params parmesans[100];
409
410 for (int i = 0; i < ARRAY_SIZE(parmesans); i++) {
411 gatt_write(tester, &parmesans[i]);
412 }
413
414 bt_conn_disconnect(tester, BT_HCI_ERR_REMOTE_POWER_OFF);
415 bt_conn_unref(tester);
416
417 /* Pass unless some assert in callbacks fails. */
418 PASS("DUT done\n");
419 }
420
test_tick(bs_time_t HW_device_time)421 void test_tick(bs_time_t HW_device_time)
422 {
423 bs_trace_debug_time(0, "Simulation ends now.\n");
424 if (bst_result != Passed) {
425 bst_result = Failed;
426 bs_trace_error("Test did not pass before simulation ended.\n");
427 }
428 }
429
test_init(void)430 void test_init(void)
431 {
432 bst_ticker_set_next_tick_absolute(TEST_TIMEOUT_SIMULATED);
433 bst_result = In_progress;
434 }
435
436 static const struct bst_test_instance test_to_add[] = {
437 {
438 .test_id = "dut",
439 .test_pre_init_f = test_init,
440 .test_tick_f = test_tick,
441 .test_main_f = test_procedure_0,
442 },
443 {
444 .test_id = "dut_1",
445 .test_pre_init_f = test_init,
446 .test_tick_f = test_tick,
447 .test_main_f = test_procedure_1,
448 },
449 BSTEST_END_MARKER,
450 };
451
install(struct bst_test_list * tests)452 static struct bst_test_list *install(struct bst_test_list *tests)
453 {
454 return bst_add_tests(tests, test_to_add);
455 };
456
457 bst_test_install_t test_installers[] = {install, NULL};
458
main(void)459 int main(void)
460 {
461 bst_main();
462
463 return 0;
464 }
465