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(&central_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