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