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 <string.h>
10
11 #include <zephyr/kernel.h>
12
13 #include <zephyr/sys/printk.h>
14
15 #include <zephyr/bluetooth/conn.h>
16 #include <zephyr/bluetooth/bluetooth.h>
17
18 #include <zephyr/logging/log.h>
19 LOG_MODULE_DECLARE(bt_bsim_privacy, LOG_LEVEL_INF);
20
21 #include "bs_types.h"
22 #include "bs_tracing.h"
23 #include "bstests.h"
24 #include "bs_cmd_line.h"
25
26 #define CREATE_FLAG(flag) static atomic_t flag = (atomic_t) false
27 #define SET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) true)
28 #define GET_FLAG(flag) (bool)atomic_get(&flag)
29 #define UNSET_FLAG(flag) (void)atomic_set(&flag, (atomic_t) false)
30 #define WAIT_FOR_FLAG(flag) \
31 while (!(bool)atomic_get(&flag)) { \
32 (void)k_sleep(K_MSEC(1)); \
33 }
34
35 #define FAIL(...) \
36 do { \
37 bst_result = Failed; \
38 bs_trace_error_time_line(__VA_ARGS__); \
39 } while (0)
40
41 #define PASS(...) \
42 do { \
43 bst_result = Passed; \
44 bs_trace_info_time(1, __VA_ARGS__); \
45 } while (0)
46
47 extern enum bst_result_t bst_result;
48
49 CREATE_FLAG(paired);
50 CREATE_FLAG(rpa_tested);
51 CREATE_FLAG(identity_tested);
52
53 static void start_scan(void);
54
55 static struct bt_conn *default_conn;
56
57 static bt_addr_le_t peer_rpa;
58 static bt_addr_le_t peer_identity;
59
60 enum addr_type_t {
61 RPA,
62 IDENTITY_ADDR,
63 };
64 static enum addr_type_t test_addr_type;
65
66 static bool use_active_scan;
67 static bool connection_test;
68
69 static int sim_id;
70
central_test_args_parse(int argc,char * argv[])71 void central_test_args_parse(int argc, char *argv[])
72 {
73 char *addr_type_arg = NULL;
74
75 bs_args_struct_t args_struct[] = {
76 {
77 .dest = &sim_id,
78 .type = 'i',
79 .name = "{positive integer}",
80 .option = "sim-id",
81 .descript = "Simulation ID counter",
82 },
83 {
84 .dest = &addr_type_arg,
85 .type = 's',
86 .name = "{identity, rpa}",
87 .option = "addr-type",
88 .descript = "Address type to test",
89 },
90 {
91 .dest = &use_active_scan,
92 .type = 'b',
93 .name = "{0, 1}",
94 .option = "active-scan",
95 .descript = "",
96 },
97 {
98 .dest = &connection_test,
99 .type = 'b',
100 .name = "{0, 1}",
101 .option = "connection-test",
102 .descript = "",
103 },
104 };
105
106 bs_args_parse_all_cmd_line(argc, argv, args_struct);
107
108 if (addr_type_arg != NULL) {
109 if (!strcmp(addr_type_arg, "identity")) {
110 test_addr_type = IDENTITY_ADDR;
111 } else if (!strcmp(addr_type_arg, "rpa")) {
112 test_addr_type = RPA;
113 }
114 }
115 }
116
wait_check_result(void)117 static void wait_check_result(void)
118 {
119 if (test_addr_type == IDENTITY_ADDR) {
120 WAIT_FOR_FLAG(identity_tested);
121 LOG_INF("Identity address tested");
122 } else if (test_addr_type == RPA) {
123 WAIT_FOR_FLAG(rpa_tested);
124 LOG_INF("Resolvable Private Address tested");
125 }
126 }
127
check_addresses(const bt_addr_le_t * peer_addr)128 static void check_addresses(const bt_addr_le_t *peer_addr)
129 {
130 LOG_DBG("Check addresses");
131
132 bool addr_equal;
133
134 if (test_addr_type == IDENTITY_ADDR) {
135 SET_FLAG(identity_tested);
136 addr_equal = bt_addr_le_eq(&peer_identity, peer_addr);
137 if (!addr_equal) {
138 FAIL("The peer address is not the same as the peer previously paired.\n");
139 }
140 } else if (test_addr_type == RPA) {
141 SET_FLAG(rpa_tested);
142 addr_equal = bt_addr_le_eq(&peer_identity, peer_addr);
143 if (!addr_equal) {
144 FAIL("The resolved address is not the same as the peer previously "
145 "paired.\n");
146 }
147 }
148 }
149
150
151
scan_recv(const struct bt_le_scan_recv_info * info,struct net_buf_simple * ad)152 static void scan_recv(const struct bt_le_scan_recv_info *info,
153 struct net_buf_simple *ad)
154 {
155 char addr_str[BT_ADDR_LE_STR_LEN];
156 int err;
157
158 if (default_conn) {
159 return;
160 }
161
162 bt_addr_le_to_str(info->addr, addr_str, sizeof(addr_str));
163 LOG_INF("Device found: %s (RSSI %d)", addr_str, info->rssi);
164
165 /* In the case of extended advertising and active scanning, this
166 * callback will be called twice: once for the AUX_ADV_IND and
167 * another time for the AUX_SCAN_RSP.
168 *
169 * We have to be careful not to stop the scanner before we have gotten
170 * the second one, as the peripheral side waits until it gets an
171 * AUX_SCAN_REQ to end the test.
172 *
173 * There is a catch though, since we have to bond, in order to exchange
174 * the address resolving keys, then this check should only apply after
175 * the pairing is done.
176 */
177 if (GET_FLAG(paired) &&
178 info->adv_props == (BT_GAP_ADV_PROP_EXT_ADV | BT_GAP_ADV_PROP_SCANNABLE)) {
179 LOG_DBG("skipping AUX_ADV_IND report, waiting for AUX_SCAN_REQ "
180 "(props: 0x%x)", info->adv_props);
181 return;
182 }
183
184 if (GET_FLAG(paired)) {
185 check_addresses(info->addr);
186 }
187
188 if (connection_test || !GET_FLAG(paired)) {
189 if (bt_le_scan_stop()) {
190 LOG_DBG("Failed to stop scanner");
191 return;
192 }
193 LOG_DBG("Scanner stopped: conn %d paired %d", connection_test, GET_FLAG(paired));
194
195 err = bt_conn_le_create(info->addr,
196 BT_CONN_LE_CREATE_CONN,
197 BT_LE_CONN_PARAM_DEFAULT,
198 &default_conn);
199 if (err) {
200 LOG_DBG("Create conn to %s failed (%u)", addr_str, err);
201 start_scan();
202 }
203 }
204 }
205
206 static struct bt_le_scan_cb scan_cb = {
207 .recv = scan_recv,
208 };
209
start_scan(void)210 static void start_scan(void)
211 {
212 int err;
213
214 LOG_DBG("Using %s scan", use_active_scan ? "active" : "passive");
215
216 err = bt_le_scan_start(use_active_scan ? BT_LE_SCAN_ACTIVE : BT_LE_SCAN_PASSIVE,
217 NULL);
218
219 if (err) {
220 FAIL("Scanning failed to start (err %d)\n", err);
221 }
222
223 LOG_DBG("Scanning successfully started");
224 }
225
connected(struct bt_conn * conn,uint8_t err)226 static void connected(struct bt_conn *conn, uint8_t err)
227 {
228 char addr[BT_ADDR_LE_STR_LEN];
229
230 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
231
232 LOG_DBG("Connected: %s", addr);
233 }
234
disconnected(struct bt_conn * conn,uint8_t reason)235 static void disconnected(struct bt_conn *conn, uint8_t reason)
236 {
237 char addr[BT_ADDR_LE_STR_LEN];
238
239 if (conn != default_conn) {
240 return;
241 }
242
243 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
244
245 LOG_DBG("Disconnected: %s (reason 0x%02x)", addr, reason);
246
247 bt_conn_unref(default_conn);
248 default_conn = NULL;
249
250 start_scan();
251 }
252
identity_resolved(struct bt_conn * conn,const bt_addr_le_t * rpa,const bt_addr_le_t * identity)253 static void identity_resolved(struct bt_conn *conn, const bt_addr_le_t *rpa,
254 const bt_addr_le_t *identity)
255 {
256 char addr_identity[BT_ADDR_LE_STR_LEN];
257 char addr_rpa[BT_ADDR_LE_STR_LEN];
258
259 bt_addr_le_to_str(identity, addr_identity, sizeof(addr_identity));
260 bt_addr_le_to_str(rpa, addr_rpa, sizeof(addr_rpa));
261
262 LOG_DBG("Identity resolved %s -> %s", addr_rpa, addr_identity);
263
264 bt_addr_le_copy(&peer_rpa, rpa);
265 bt_addr_le_copy(&peer_identity, identity);
266
267 SET_FLAG(paired);
268 }
269
270 static struct bt_conn_cb central_cb;
271
test_central(void)272 void test_central(void)
273 {
274 int err;
275
276 LOG_DBG("Central device");
277
278 central_cb.connected = connected;
279 central_cb.disconnected = disconnected;
280 central_cb.identity_resolved = identity_resolved;
281
282 bt_conn_cb_register(¢ral_cb);
283 bt_le_scan_cb_register(&scan_cb);
284
285 err = bt_enable(NULL);
286 if (err) {
287 FAIL("Bluetooth init failed (err %d)\n", err);
288 }
289
290 UNSET_FLAG(identity_tested);
291 UNSET_FLAG(rpa_tested);
292
293 start_scan();
294
295 wait_check_result();
296 }
297
test_central_main(void)298 void test_central_main(void)
299 {
300 char *addr_tested = "";
301
302 if (test_addr_type == RPA) {
303 addr_tested = "RPA";
304 } else if (test_addr_type == IDENTITY_ADDR) {
305 addr_tested = "identity address";
306 }
307
308 LOG_INF("Central test START (id: %d: params: %s scan, %sconnectable test, testing %s)\n",
309 sim_id, use_active_scan ? "active" : "passive", connection_test ? "" : "non-",
310 addr_tested);
311
312 test_central();
313
314 PASS("passed\n");
315 }
316