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(&params, 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(&params, &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(&params, 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, &params);
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