1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <string.h>
11
12 #include <zephyr/kernel.h>
13
14 #include <zephyr/sys/printk.h>
15
16 #include <zephyr/bluetooth/conn.h>
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/hci.h>
19
20 #include <zephyr/logging/log.h>
21 LOG_MODULE_DECLARE(bt_bsim_privacy, LOG_LEVEL_INF);
22
23 #include "bs_types.h"
24 #include "bs_tracing.h"
25 #include "bstests.h"
26 #include "bs_cmd_line.h"
27
28 #define FAIL(...) \
29 do { \
30 bst_result = Failed; \
31 bs_trace_error_time_line(__VA_ARGS__); \
32 } while (0)
33
34 #define PASS(...) \
35 do { \
36 bst_result = Passed; \
37 bs_trace_info_time(1, __VA_ARGS__); \
38 } while (0)
39
40 extern enum bst_result_t bst_result;
41
42 #define CREATE_FLAG(flag) static atomic_t flag = (atomic_t) false
43 #define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
44 #define GET_FLAG(flag) (bool)atomic_get(&flag)
45 #define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false)
46 #define WAIT_FOR_FLAG(flag) \
47 while (!(bool)atomic_get(&flag)) { \
48 (void)k_sleep(K_MSEC(1)); \
49 }
50
51 CREATE_FLAG(paired_flag);
52 CREATE_FLAG(connected_flag);
53 CREATE_FLAG(wait_disconnection);
54 CREATE_FLAG(wait_scanned);
55
56 static struct bt_conn *default_conn;
57
58 enum adv_param_t {
59 CONN_SCAN,
60 CONN_NSCAN,
61 NCONN_SCAN,
62 NCONN_NSCAN,
63 };
64
65 enum addr_type_t {
66 RPA,
67 IDENTITY_ADDR,
68 };
69
70 static enum addr_type_t test_addr_type;
71
72 static bool use_ext_adv;
73
74 static bool scannable_test;
75 static bool connectable_test;
76 static enum adv_param_t adv_param;
77
78 static int sim_id;
79
peripheral_test_args_parse(int argc,char * argv[])80 void peripheral_test_args_parse(int argc, char *argv[])
81 {
82 char *addr_type_arg = NULL;
83
84 bs_args_struct_t args_struct[] = {
85 {
86 .dest = &sim_id,
87 .type = 'i',
88 .name = "{positive integer}",
89 .option = "sim-id",
90 .descript = "Simulation ID counter",
91 },
92 {
93 .dest = &addr_type_arg,
94 .type = 's',
95 .name = "{identity, rsa}",
96 .option = "addr-type",
97 .descript = "Address type to test",
98 },
99 {
100 .dest = &use_ext_adv,
101 .type = 'b',
102 .name = "{0, 1}",
103 .option = "use-ext-adv",
104 .descript = "Use Extended Advertising",
105 },
106 {
107 .dest = &scannable_test,
108 .type = 'b',
109 .name = "{0, 1}",
110 .option = "scannable",
111 .descript = "Use a scannable advertiser for the test",
112 },
113 {
114 .dest = &connectable_test,
115 .type = 'b',
116 .name = "{0, 1}",
117 .option = "connectable",
118 .descript = "Use a connectable advertiser for the test",
119 },
120 };
121
122 bs_args_parse_all_cmd_line(argc, argv, args_struct);
123
124 if (addr_type_arg != NULL) {
125 if (!strcmp(addr_type_arg, "identity")) {
126 test_addr_type = IDENTITY_ADDR;
127 } else if (!strcmp(addr_type_arg, "rpa")) {
128 test_addr_type = RPA;
129 }
130 }
131
132 if (connectable_test && scannable_test) {
133 if (!use_ext_adv) {
134 adv_param = CONN_SCAN;
135 }
136 } else if (connectable_test) {
137 adv_param = CONN_NSCAN;
138 } else if (scannable_test) {
139 adv_param = NCONN_SCAN;
140 } else {
141 adv_param = NCONN_NSCAN;
142 }
143 }
144
wait_for_scanned(void)145 static void wait_for_scanned(void)
146 {
147 LOG_DBG("Waiting for scan request");
148 WAIT_FOR_FLAG(wait_scanned);
149 UNSET_FLAG(wait_scanned);
150 }
151
adv_scanned_cb(struct bt_le_ext_adv * adv,struct bt_le_ext_adv_scanned_info * info)152 static void adv_scanned_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_scanned_info *info)
153 {
154 LOG_DBG("Scan request received");
155 SET_FLAG(wait_scanned);
156 }
157
158 static struct bt_le_ext_adv_cb adv_cb = {
159 .scanned = adv_scanned_cb,
160 };
161
create_adv(struct bt_le_ext_adv ** adv)162 static void create_adv(struct bt_le_ext_adv **adv)
163 {
164 int err;
165 struct bt_le_adv_param params;
166
167 memset(¶ms, 0, sizeof(struct bt_le_adv_param));
168
169 params.options |= BT_LE_ADV_OPT_CONN;
170
171 params.id = BT_ID_DEFAULT;
172 params.sid = 0;
173 params.interval_min = BT_GAP_ADV_SLOW_INT_MIN;
174 params.interval_max = BT_GAP_ADV_SLOW_INT_MAX;
175
176 err = bt_le_ext_adv_create(¶ms, &adv_cb, adv);
177 if (err) {
178 LOG_ERR("Failed to create advertiser (%d)", err);
179 return;
180 }
181
182 LOG_DBG("Advertiser created");
183 }
184
update_adv_params(struct bt_le_ext_adv * adv,enum adv_param_t adv_params,enum addr_type_t addr_type)185 static void update_adv_params(struct bt_le_ext_adv *adv, enum adv_param_t adv_params,
186 enum addr_type_t addr_type)
187 {
188 int err;
189 struct bt_le_adv_param params;
190
191 memset(¶ms, 0, sizeof(struct bt_le_adv_param));
192
193 if (adv_params == CONN_SCAN) {
194 params.options |= BT_LE_ADV_OPT_CONN;
195 params.options |= BT_LE_ADV_OPT_SCANNABLE;
196 LOG_DBG("Advertiser params: CONN_SCAN");
197 } else if (adv_params == CONN_NSCAN) {
198 params.options |= BT_LE_ADV_OPT_CONN;
199 LOG_DBG("Advertiser params: CONN_NSCAN");
200 } else if (adv_params == NCONN_SCAN) {
201 params.options |= BT_LE_ADV_OPT_SCANNABLE;
202 LOG_DBG("Advertiser params: NCONN_SCAN");
203 } else if (adv_params == NCONN_NSCAN) {
204 LOG_DBG("Advertiser params: NCONN_NSCAN");
205 }
206
207 if (use_ext_adv) {
208 params.options |= BT_LE_ADV_OPT_EXT_ADV;
209 LOG_DBG("Advertiser params: EXT_ADV");
210 params.options |= BT_LE_ADV_OPT_NOTIFY_SCAN_REQ;
211 LOG_DBG("Advertiser params: NOTIFY_SCAN_REQ");
212 } else {
213 LOG_DBG("Advertiser params: LEGACY_ADV");
214 }
215
216 if (addr_type == IDENTITY_ADDR) {
217 LOG_DBG("Advertiser params: USE_IDENTITY");
218 params.options |= BT_LE_ADV_OPT_USE_IDENTITY;
219 } else if (addr_type == RPA) {
220 LOG_DBG("Advertiser params: USE_RPA");
221 }
222
223 params.id = BT_ID_DEFAULT;
224 params.sid = 0;
225 params.interval_min = BT_GAP_ADV_SLOW_INT_MIN;
226 params.interval_max = BT_GAP_ADV_SLOW_INT_MAX;
227
228 err = bt_le_ext_adv_update_param(adv, ¶ms);
229 if (err) {
230 LOG_ERR("Failed to update advertiser set (%d)", err);
231 return;
232 }
233
234 if (use_ext_adv && adv_params == NCONN_SCAN) {
235 struct bt_data sd =
236 BT_DATA_BYTES(BT_DATA_NAME_COMPLETE, 'z', 'e', 'p', 'h', 'y', 'r');
237 size_t sd_len = 1;
238
239 err = bt_le_ext_adv_set_data(adv, NULL, 0, &sd, sd_len);
240 if (err) {
241 LOG_ERR("Failed to set advertising data (%d)", err);
242 }
243
244 LOG_DBG("Advertiser data set");
245 }
246
247 LOG_DBG("Advertiser params updated");
248 }
249
start_adv(struct bt_le_ext_adv * adv)250 static void start_adv(struct bt_le_ext_adv *adv)
251 {
252 int err;
253 int32_t timeout = 0;
254 uint8_t num_events = 0;
255
256 struct bt_le_ext_adv_start_param start_params;
257
258 start_params.timeout = timeout;
259 start_params.num_events = num_events;
260
261 err = bt_le_ext_adv_start(adv, &start_params);
262
263 if (err) {
264 LOG_ERR("Failed to start advertiser (%d)", err);
265 return;
266 }
267
268 LOG_DBG("Advertiser started");
269 }
270
stop_adv(struct bt_le_ext_adv * adv)271 static void stop_adv(struct bt_le_ext_adv *adv)
272 {
273 int err;
274
275 err = bt_le_ext_adv_stop(adv);
276 if (err) {
277 LOG_WRN("Failed to stop advertiser (%d)", err);
278 return;
279 }
280
281 LOG_DBG("Advertiser stopped");
282 }
283
disconnect(void)284 static void disconnect(void)
285 {
286 LOG_DBG("Starting disconnection");
287 int err;
288
289 err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
290 if (err) {
291 FAIL("Disconnection failed (err %d)\n", err);
292 }
293
294 WAIT_FOR_FLAG(wait_disconnection);
295 UNSET_FLAG(wait_disconnection);
296 }
297
wait_for_connection(void)298 static void wait_for_connection(void)
299 {
300 WAIT_FOR_FLAG(connected_flag);
301 UNSET_FLAG(connected_flag);
302 }
303
connected(struct bt_conn * conn,uint8_t err)304 static void connected(struct bt_conn *conn, uint8_t err)
305 {
306 LOG_DBG("Peripheral Connected function");
307
308 char addr[BT_ADDR_LE_STR_LEN];
309
310 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
311
312 if (err) {
313 LOG_WRN("Failed to connect to %s (%u)", addr, err);
314 return;
315 }
316
317 LOG_DBG("Connected: %s", addr);
318
319 default_conn = bt_conn_ref(conn);
320
321 if (!GET_FLAG(paired_flag)) {
322 if (bt_conn_set_security(conn, BT_SECURITY_L2)) {
323 FAIL("Failed to set security\n");
324 }
325 } else {
326 SET_FLAG(connected_flag);
327 }
328 }
329
disconnected(struct bt_conn * conn,uint8_t reason)330 static void disconnected(struct bt_conn *conn, uint8_t reason)
331 {
332 char addr[BT_ADDR_LE_STR_LEN];
333
334 if (conn != default_conn) {
335 return;
336 }
337
338 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
339
340 LOG_DBG("Disconnected: %s (reason 0x%02x)", addr, reason);
341
342 bt_conn_unref(default_conn);
343 default_conn = NULL;
344
345 LOG_DBG("Disconnected");
346 SET_FLAG(wait_disconnection);
347 }
348
identity_resolved(struct bt_conn * conn,const bt_addr_le_t * rpa,const bt_addr_le_t * identity)349 static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
350 const bt_addr_le_t *identity)
351 {
352 char addr_identity[BT_ADDR_LE_STR_LEN];
353 char addr_rpa[BT_ADDR_LE_STR_LEN];
354
355 bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity));
356 bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa));
357
358 LOG_DBG("Identity resolved %s -> %s", addr_rpa, addr_identity);
359 }
360
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)361 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
362 {
363 char addr[BT_ADDR_LE_STR_LEN];
364
365 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
366
367 if (!err) {
368 LOG_DBG("Security changed: %s level %u", addr, level);
369 } else {
370 LOG_ERR("Security failed: %s level %u err %d", addr, level);
371 }
372 }
373
pairing_complete(struct bt_conn * conn,bool bonded)374 static void pairing_complete(struct bt_conn *conn, bool bonded)
375 {
376 LOG_DBG("Pairing complete");
377 SET_FLAG(paired_flag);
378 }
379
pairing_failed(struct bt_conn * conn,enum bt_security_err reason)380 static void pairing_failed(struct bt_conn *conn, enum bt_security_err reason)
381 {
382 LOG_WRN("Pairing failed (%d). Disconnecting.", reason);
383 bt_conn_disconnect(conn, BT_HCI_ERR_AUTH_FAIL);
384 }
385
386 static struct bt_conn_cb peri_cb;
387
388 static struct bt_conn_auth_info_cb auth_cb_info = {
389 .pairing_complete = pairing_complete,
390 .pairing_failed = pairing_failed,
391 };
392
test_peripheral_main(void)393 static void test_peripheral_main(void)
394 {
395 LOG_DBG("Peripheral device");
396
397 int err;
398 struct bt_le_ext_adv *adv = NULL;
399
400 peri_cb.connected = connected;
401 peri_cb.disconnected = disconnected;
402 peri_cb.security_changed = security_changed;
403 peri_cb.identity_resolved = identity_resolved;
404
405 bt_conn_cb_register(&peri_cb);
406
407 err = bt_enable(NULL);
408 if (err) {
409 FAIL("Bluetooth init failed (err %d)\n", err);
410 }
411
412 LOG_DBG("Bluetooth initialized");
413
414 bt_conn_auth_info_cb_register(&auth_cb_info);
415
416 create_adv(&adv);
417
418 update_adv_params(adv, CONN_NSCAN, RPA);
419 start_adv(adv);
420
421 WAIT_FOR_FLAG(paired_flag);
422
423 disconnect();
424 stop_adv(adv);
425
426 update_adv_params(adv, adv_param, test_addr_type);
427 start_adv(adv);
428
429 /* (the connection with identity should fail with privacy network mode) */
430 if (connectable_test) {
431 wait_for_connection();
432 disconnect();
433 } else if (scannable_test && use_ext_adv) {
434 wait_for_scanned();
435 }
436
437 /* It is up to the controller to decide if it should send an
438 * AUX_SCAN_RSP or not when it gets ordered to stop advertising right
439 * after receiving the AUX_SCAN_REQ.
440 *
441 * Some test cases depend on receiving AUX_SCAN_RSP, so don't stop the
442 * advertiser. This ensures we will always get it.
443 */
444 }
445
test_peripheral(void)446 void test_peripheral(void)
447 {
448 char *addr_tested = "";
449
450 if (test_addr_type == RPA) {
451 addr_tested = "RPA";
452 } else if (test_addr_type == IDENTITY_ADDR) {
453 addr_tested = "identity address";
454 }
455
456 LOG_INF("Peripheral test START (id: %d: %s advertiser, "
457 "%sconnectable %sscannable, testing %s)\n",
458 sim_id, use_ext_adv ? "extended" : "legacy", connectable_test ? "" : "non-",
459 scannable_test ? "" : "non-", addr_tested);
460
461 test_peripheral_main();
462
463 PASS("passed\n");
464 }
465