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