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