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