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(¢ral_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