1 /* Copyright (c) 2023 Nordic Semiconductor ASA
2 * SPDX-License-Identifier: Apache-2.0
3 */
4
5 #include <string.h>
6
7 #include <zephyr/kernel.h>
8
9 #include <zephyr/bluetooth/att.h>
10 #include <zephyr/bluetooth/addr.h>
11 #include <zephyr/bluetooth/conn.h>
12 #include <zephyr/bluetooth/gatt.h>
13 #include <zephyr/bluetooth/uuid.h>
14 #include <zephyr/bluetooth/hci_types.h>
15 #include <zephyr/bluetooth/bluetooth.h>
16
17 #include <zephyr/logging/log.h>
18
19 #include <zephyr/settings/settings.h>
20
21 #include "common.h"
22 #include "settings.h"
23
24 #include "argparse.h"
25 #include "bs_pc_backchannel.h"
26
27 #define CLIENT_CLIENT_CHAN 0
28 #define SERVER_CLIENT_CHAN 1
29
30 CREATE_FLAG(connected_flag);
31 CREATE_FLAG(disconnected_flag);
32 CREATE_FLAG(security_updated_flag);
33
34 #define BT_UUID_DUMMY_SERVICE BT_UUID_DECLARE_128(DUMMY_SERVICE_TYPE)
35 #define BT_UUID_DUMMY_SERVICE_NOTIFY BT_UUID_DECLARE_128(DUMMY_SERVICE_NOTIFY_TYPE)
36
37 static struct bt_conn *default_conn;
38
39 static struct bt_conn_cb central_cb;
40
41 CREATE_FLAG(gatt_write_flag);
42 static uint8_t gatt_write_att_err;
43
gatt_write_cb(struct bt_conn * conn,uint8_t att_err,struct bt_gatt_write_params * params)44 static void gatt_write_cb(struct bt_conn *conn, uint8_t att_err,
45 struct bt_gatt_write_params *params)
46 {
47 gatt_write_att_err = att_err;
48
49 if (att_err) {
50 FAIL("GATT write ATT error (err %d)\n", att_err);
51 }
52
53 SET_FLAG(gatt_write_flag);
54 }
55
gatt_write(struct bt_conn * conn,uint16_t handle,const uint8_t * write_buf,size_t write_size)56 static int gatt_write(struct bt_conn *conn, uint16_t handle, const uint8_t *write_buf,
57 size_t write_size)
58 {
59 int err;
60 struct bt_gatt_write_params params;
61
62 params.func = gatt_write_cb;
63 params.handle = handle;
64 params.offset = 0;
65 params.data = write_buf;
66 params.length = write_size;
67
68 UNSET_FLAG(gatt_write_flag);
69
70 /* `bt_gatt_write` is used instead of `bt_gatt_subscribe` and
71 * `bt_gatt_unsubscribe` to bypass subscribtion checks of GATT client
72 */
73 err = bt_gatt_write(conn, ¶ms);
74 if (err) {
75 FAIL("GATT write failed (err %d)", err);
76 }
77
78 WAIT_FOR_FLAG(gatt_write_flag);
79
80 return gatt_write_att_err;
81 }
82
ccc_subscribe(void)83 static void ccc_subscribe(void)
84 {
85 int err;
86 uint8_t buf = 1;
87
88 err = gatt_write(default_conn, CCC_HANDLE, &buf, sizeof(buf));
89 if (err) {
90 FAIL("Failed to subscribe (att err %d)", err);
91 }
92 }
93
ccc_unsubscribe(void)94 static void ccc_unsubscribe(void)
95 {
96 int err;
97 uint8_t buf = 0;
98
99 err = gatt_write(default_conn, CCC_HANDLE, &buf, sizeof(buf));
100 if (err) {
101 FAIL("Failed to unsubscribe (att err %d)", err);
102 }
103 }
104
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)105 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
106 struct net_buf_simple *ad)
107 {
108 int err;
109 char addr_str[BT_ADDR_LE_STR_LEN];
110
111 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
112
113 LOG_DBG("Device found: %s (RSSI %d)", addr_str, rssi);
114
115 err = bt_le_scan_stop();
116 if (err) {
117 FAIL("Failed to stop scanner (err %d)\n", err);
118 }
119
120 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT,
121 &default_conn);
122 if (err) {
123 FAIL("Could not connect to peer: %s (err %d)\n", addr_str, err);
124 }
125 }
126
connected(struct bt_conn * conn,uint8_t err)127 static void connected(struct bt_conn *conn, uint8_t err)
128 {
129 const bt_addr_le_t *addr;
130 char addr_str[BT_ADDR_LE_STR_LEN];
131
132 addr = bt_conn_get_dst(conn);
133 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
134
135 if (err) {
136 FAIL("Failed to connect to %s (err %d)\n", addr_str, err);
137 }
138
139 LOG_DBG("Connected: %s", addr_str);
140
141 if (conn == default_conn) {
142 SET_FLAG(connected_flag);
143 }
144 }
145
disconnected(struct bt_conn * conn,uint8_t reason)146 static void disconnected(struct bt_conn *conn, uint8_t reason)
147 {
148 char addr_str[BT_ADDR_LE_STR_LEN];
149
150 bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
151
152 LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason);
153
154 SET_FLAG(disconnected_flag);
155
156 if (default_conn != conn) {
157 return;
158 }
159
160 bt_conn_unref(default_conn);
161 default_conn = NULL;
162 }
163
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)164 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
165 {
166 char addr_str[BT_ADDR_LE_STR_LEN];
167
168 bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
169
170 if (!err) {
171 LOG_DBG("Security changed: %s level %u", addr_str, level);
172 SET_FLAG(security_updated_flag);
173 } else {
174 LOG_DBG("Security failed: %s level %u err %d", addr_str, level, err);
175 }
176 }
177
start_scan(void)178 static void start_scan(void)
179 {
180 int err;
181
182 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
183 if (err) {
184 FAIL("Scanning failed to start (err %d)\n", err);
185 }
186
187 LOG_DBG("Scanning successfully started");
188 }
189
disconnect(void)190 static void disconnect(void)
191 {
192 int err;
193
194 err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
195 if (err) {
196 FAIL("Disconnection failed (err %d)\n", err);
197 }
198
199 WAIT_FOR_FLAG(disconnected_flag);
200 UNSET_FLAG(disconnected_flag);
201 }
202
203 /* Test steps */
204
connect_pair_subscribe(void)205 static void connect_pair_subscribe(void)
206 {
207 int err;
208
209 start_scan();
210
211 WAIT_FOR_FLAG(connected_flag);
212 UNSET_FLAG(connected_flag);
213
214 err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
215 if (err != 0) {
216 FAIL("Failed to set security (err %d)\n", err);
217 }
218
219 WAIT_FOR_FLAG(security_updated_flag);
220 UNSET_FLAG(security_updated_flag);
221
222 /* subscribe while being paired */
223 ccc_subscribe();
224
225 /* confirm to server that we subscribed */
226 backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID);
227 /* wait for server to check that the subscribtion is well registered */
228 backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID);
229 }
230
connect_unsubscribe(void)231 static void connect_unsubscribe(void)
232 {
233 start_scan();
234
235 WAIT_FOR_FLAG(connected_flag);
236 UNSET_FLAG(connected_flag);
237
238 /* wait for server to check that the subscribtion has not been restored */
239 backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID);
240
241 LOG_DBG("Trying to unsubscribe without being paired...");
242 /* try to unsubscribe */
243 ccc_unsubscribe();
244
245 /* confirm to server that we send unsubscribtion request */
246 backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID);
247 /* wait for server to check that the unsubscribtion is ignored */
248 backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID);
249 }
250
connect_restore_sec(void)251 static void connect_restore_sec(void)
252 {
253 int err;
254
255 start_scan();
256
257 WAIT_FOR_FLAG(connected_flag);
258 UNSET_FLAG(connected_flag);
259
260 err = bt_conn_set_security(default_conn, BT_SECURITY_L2);
261 if (err != 0) {
262 FAIL("Failed to set security (err %d)\n", err);
263 }
264
265 WAIT_FOR_FLAG(security_updated_flag);
266 UNSET_FLAG(security_updated_flag);
267
268 /* notify the end of security update to server */
269 backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID);
270 /* wait for server to check that the subscribtion has been restored */
271 backchannel_sync_wait(SERVER_CLIENT_CHAN, SERVER_ID);
272
273 /* wait for server to check that the subscription no longer exist */
274 backchannel_sync_send(SERVER_CLIENT_CHAN, SERVER_ID);
275 }
276
277 /* Util functions */
278
central_backchannel_init(void)279 void central_backchannel_init(void)
280 {
281 uint device_number = get_device_nbr();
282 uint channel_numbers[2] = {
283 0,
284 0,
285 };
286 uint device_numbers[2];
287 uint num_ch = 2;
288 uint *ch;
289
290 device_numbers[0] = (device_number == GOOD_CLIENT_ID) ? BAD_CLIENT_ID : GOOD_CLIENT_ID;
291 device_numbers[1] = SERVER_ID;
292
293 LOG_DBG("Opening back channels for device %d", device_number);
294 ch = bs_open_back_channel(device_number, device_numbers, channel_numbers, num_ch);
295 if (!ch) {
296 FAIL("Unable to open backchannel\n");
297 }
298 LOG_DBG("Back channels for device %d opened", device_number);
299 }
300
set_public_addr(void)301 static void set_public_addr(void)
302 {
303 bt_addr_le_t addr = {BT_ADDR_LE_RANDOM, {{0x0A, 0x89, 0x67, 0x45, 0x23, 0xC1}}};
304
305 bt_id_create(&addr, NULL);
306 }
307
308 /* Main functions */
309
run_central(void)310 void run_central(void)
311 {
312 int err;
313
314 central_cb.connected = connected;
315 central_cb.disconnected = disconnected;
316 central_cb.security_changed = security_changed;
317
318 central_backchannel_init();
319 set_public_addr();
320
321 err = bt_enable(NULL);
322 if (err) {
323 FAIL("Bluetooth init failed (err %d)\n", err);
324 }
325
326 LOG_DBG("Bluetooth initialized");
327
328 bt_conn_cb_register(¢ral_cb);
329
330 err = settings_load();
331 if (err) {
332 FAIL("Settings load failed (err %d)\n", err);
333 }
334
335 err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY);
336 if (err) {
337 FAIL("Unpairing failed (err %d)\n", err);
338 }
339
340 connect_pair_subscribe();
341 disconnect();
342
343 /* tell the bad client that we disconnected and wait for him to disconnect */
344 backchannel_sync_send(CLIENT_CLIENT_CHAN, BAD_CLIENT_ID);
345 backchannel_sync_wait(CLIENT_CLIENT_CHAN, BAD_CLIENT_ID);
346
347 connect_restore_sec();
348 disconnect();
349
350 PASS("Central test passed\n");
351 }
352
run_bad_central(void)353 void run_bad_central(void)
354 {
355 int err;
356
357 central_cb.connected = connected;
358 central_cb.disconnected = disconnected;
359 central_cb.security_changed = security_changed;
360
361 central_backchannel_init();
362 set_public_addr();
363
364 /* wait for good central to disconnect from server */
365 backchannel_sync_wait(CLIENT_CLIENT_CHAN, GOOD_CLIENT_ID);
366
367 err = bt_enable(NULL);
368 if (err) {
369 FAIL("Bluetooth init failed (err %d)\n");
370 }
371
372 LOG_DBG("Bluetooth initialized");
373
374 bt_conn_cb_register(¢ral_cb);
375
376 err = settings_load();
377 if (err) {
378 FAIL("Settings load failed (err %d)\n");
379 }
380
381 connect_unsubscribe();
382 disconnect();
383
384 PASS("Bad Central test passed\n");
385
386 /* tell the good client that we disconnected from the server */
387 backchannel_sync_send(CLIENT_CLIENT_CHAN, GOOD_CLIENT_ID);
388 }
389