1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/bluetooth.h>
8 #include <zephyr/bluetooth/gatt.h>
9 
10 #include "common.h"
11 
12 CREATE_FLAG(flag_is_connected);
13 CREATE_FLAG(flag_discover_complete);
14 CREATE_FLAG(flag_write_complete);
15 CREATE_FLAG(flag_chan_1_read);
16 CREATE_FLAG(flag_chan_2_read);
17 CREATE_FLAG(flag_db_hash_read);
18 CREATE_FLAG(flag_encrypted);
19 
20 static struct bt_conn *g_conn;
21 static uint16_t chrc_handle;
22 static uint16_t csf_handle;
23 static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID;
24 
connected(struct bt_conn * conn,uint8_t err)25 static void connected(struct bt_conn *conn, uint8_t err)
26 {
27 	char addr[BT_ADDR_LE_STR_LEN];
28 
29 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
30 
31 	if (err != 0) {
32 		FAIL("Failed to connect to %s (%u)\n", addr, err);
33 
34 		return;
35 	}
36 
37 	printk("Connected to %s\n", addr);
38 
39 	SET_FLAG(flag_is_connected);
40 }
41 
disconnected(struct bt_conn * conn,uint8_t reason)42 static void disconnected(struct bt_conn *conn, uint8_t reason)
43 {
44 	char addr[BT_ADDR_LE_STR_LEN];
45 
46 	if (conn != g_conn) {
47 		return;
48 	}
49 
50 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
51 
52 	printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
53 
54 	bt_conn_unref(g_conn);
55 
56 	g_conn = NULL;
57 	UNSET_FLAG(flag_is_connected);
58 }
59 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)60 void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
61 {
62 	if (err != BT_SECURITY_ERR_SUCCESS) {
63 		FAIL("Encryption failed\n");
64 	} else if (level < BT_SECURITY_L2) {
65 		FAIL("Insufficient security\n");
66 	} else {
67 		SET_FLAG(flag_encrypted);
68 	}
69 }
70 
71 BT_CONN_CB_DEFINE(conn_callbacks) = {
72 	.connected = connected,
73 	.disconnected = disconnected,
74 	.security_changed = security_changed,
75 };
76 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)77 void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad)
78 {
79 	char addr_str[BT_ADDR_LE_STR_LEN];
80 	int err;
81 
82 	if (g_conn != NULL) {
83 		return;
84 	}
85 
86 	/* We're only interested in connectable events */
87 	if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
88 		return;
89 	}
90 
91 	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
92 	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
93 
94 	printk("Stopping scan\n");
95 	err = bt_le_scan_stop();
96 	if (err != 0) {
97 		FAIL("Could not stop scan (err %d)\n");
98 
99 		return;
100 	}
101 
102 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &g_conn);
103 	if (err != 0) {
104 		FAIL("Could not connect to peer (err %d)", err);
105 	}
106 }
107 
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)108 static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr,
109 			     struct bt_gatt_discover_params *params)
110 {
111 	int err;
112 
113 	if (attr == NULL) {
114 		if (chrc_handle == 0) {
115 			FAIL("Did not discover chrc (%x)\n", chrc_handle);
116 		}
117 
118 		(void)memset(params, 0, sizeof(*params));
119 
120 		SET_FLAG(flag_discover_complete);
121 
122 		return BT_GATT_ITER_STOP;
123 	}
124 
125 	printk("[ATTRIBUTE] handle %u\n", attr->handle);
126 
127 	if (params->type == BT_GATT_DISCOVER_PRIMARY &&
128 	    bt_uuid_cmp(params->uuid, TEST_SERVICE_UUID) == 0) {
129 		printk("Found test service\n");
130 		params->uuid = NULL;
131 		params->start_handle = attr->handle + 1;
132 		params->type = BT_GATT_DISCOVER_CHARACTERISTIC;
133 
134 		err = bt_gatt_discover(conn, params);
135 		if (err != 0) {
136 			FAIL("Discover failed (err %d)\n", err);
137 		}
138 
139 		return BT_GATT_ITER_STOP;
140 	} else if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
141 		const struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data;
142 
143 		if (bt_uuid_cmp(chrc->uuid, TEST_CHRC_UUID) == 0) {
144 			printk("Found chrc\n");
145 			chrc_handle = chrc->value_handle;
146 
147 		} else if (bt_uuid_cmp(chrc->uuid, BT_UUID_GATT_CLIENT_FEATURES) == 0) {
148 			printk("Found csf\n");
149 			csf_handle = chrc->value_handle;
150 		}
151 	}
152 
153 	return BT_GATT_ITER_CONTINUE;
154 }
155 
gatt_discover(const struct bt_uuid * uuid,uint8_t type)156 static void gatt_discover(const struct bt_uuid *uuid, uint8_t type)
157 {
158 	static struct bt_gatt_discover_params discover_params;
159 	int err;
160 
161 	printk("Discovering services and characteristics\n");
162 
163 	discover_params.uuid = uuid;
164 	discover_params.func = discover_func;
165 	discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
166 	discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
167 	discover_params.type = type;
168 	discover_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
169 
170 	UNSET_FLAG(flag_discover_complete);
171 
172 	err = bt_gatt_discover(g_conn, &discover_params);
173 	if (err != 0) {
174 		FAIL("Discover failed(err %d)\n", err);
175 	}
176 
177 	WAIT_FOR_FLAG(flag_discover_complete);
178 	printk("Discover complete\n");
179 }
180 static struct bt_gatt_read_params chan_1_read = {
181 	.handle_count = 1,
182 	.single = {
183 		.handle = 0, /* Will be set later */
184 		.offset = 0,
185 	},
186 	.chan_opt = BT_ATT_CHAN_OPT_NONE,
187 };
188 static struct bt_gatt_read_params chan_2_read = {
189 	.handle_count = 1,
190 	.single = {
191 		.handle = 0, /* Will be set later */
192 		.offset = 0,
193 	},
194 	.chan_opt = BT_ATT_CHAN_OPT_NONE,
195 };
196 static struct bt_gatt_read_params db_hash_read = {
197 	.handle_count = 0,
198 	.by_uuid = {
199 		.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE,
200 		.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE,
201 		.uuid = BT_UUID_GATT_DB_HASH,
202 	},
203 	.chan_opt = BT_ATT_CHAN_OPT_NONE,
204 };
205 
expect_status(uint8_t err,uint8_t status)206 void expect_status(uint8_t err, uint8_t status)
207 {
208 	if (err != status) {
209 		FAIL("Unexpected status from read: 0x%02X, expected 0x%02X\n", err, status);
210 	}
211 }
212 
gatt_read_expect_success_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)213 static uint8_t gatt_read_expect_success_cb(struct bt_conn *conn, uint8_t err,
214 					   struct bt_gatt_read_params *params, const void *data,
215 					   uint16_t length)
216 {
217 	printk("GATT read cb: err 0x%02X\n", err);
218 	expect_status(err, BT_ATT_ERR_SUCCESS);
219 
220 	if (params == &db_hash_read) {
221 		SET_FLAG(flag_db_hash_read);
222 	} else if (params == &chan_1_read) {
223 		SET_FLAG(flag_chan_1_read);
224 	} else if (params == &chan_2_read) {
225 		SET_FLAG(flag_chan_2_read);
226 	} else {
227 		FAIL("Unexpected params\n");
228 	}
229 
230 	return 0;
231 }
232 
gatt_read_expect_err_unlikely_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)233 static uint8_t gatt_read_expect_err_unlikely_cb(struct bt_conn *conn, uint8_t err,
234 						struct bt_gatt_read_params *params,
235 						const void *data, uint16_t length)
236 {
237 	printk("GATT read cb: err 0x%02X\n", err);
238 	expect_status(err, BT_ATT_ERR_UNLIKELY);
239 
240 	if (params == &chan_1_read) {
241 		SET_FLAG(flag_chan_1_read);
242 	} else if (params == &chan_2_read) {
243 		SET_FLAG(flag_chan_2_read);
244 	} else {
245 		FAIL("Unexpected params\n");
246 	}
247 
248 	return 0;
249 }
250 
gatt_read_expect_err_out_of_sync_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)251 static uint8_t gatt_read_expect_err_out_of_sync_cb(struct bt_conn *conn, uint8_t err,
252 						   struct bt_gatt_read_params *params,
253 						   const void *data, uint16_t length)
254 {
255 	printk("GATT read cb: err 0x%02X\n", err);
256 	expect_status(err, BT_ATT_ERR_DB_OUT_OF_SYNC);
257 
258 	if (params == &chan_1_read) {
259 		SET_FLAG(flag_chan_1_read);
260 	} else if (params == &chan_2_read) {
261 		SET_FLAG(flag_chan_2_read);
262 	} else {
263 		FAIL("Unexpected params\n");
264 	}
265 
266 	return 0;
267 }
268 
gatt_read(struct bt_gatt_read_params * read_params)269 static void gatt_read(struct bt_gatt_read_params *read_params)
270 {
271 	int err;
272 
273 	printk("Reading\n");
274 
275 	err = bt_gatt_read(g_conn, read_params);
276 	if (err != 0) {
277 		FAIL("bt_gatt_read failed: %d\n", err);
278 	}
279 }
280 
write_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)281 static void write_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params)
282 {
283 	if (err != BT_ATT_ERR_SUCCESS) {
284 		FAIL("Write failed: 0x%02X\n", err);
285 	}
286 
287 	SET_FLAG(flag_write_complete);
288 }
289 
enable_robust_caching(void)290 static void enable_robust_caching(void)
291 {
292 	/* Client Supported Features Characteristic Value
293 	 * Bit 0: Robust Caching
294 	 * Bit 1: EATT
295 	 */
296 	static const uint8_t csf[] = { BIT(0) | BIT(1) };
297 	static struct bt_gatt_write_params write_params = {
298 		.func = write_cb,
299 		.offset = 0,
300 		.data = csf,
301 		.length = sizeof(csf),
302 		.chan_opt = BT_ATT_CHAN_OPT_NONE,
303 	};
304 	int err;
305 
306 	printk("Writing to Client Supported Features Characteristic\n");
307 
308 	write_params.handle = csf_handle;
309 	UNSET_FLAG(flag_write_complete);
310 
311 	err = bt_gatt_write(g_conn, &write_params);
312 	if (err) {
313 		FAIL("bt_gatt_write failed (err %d)\n", err);
314 	}
315 
316 	WAIT_FOR_FLAG(flag_write_complete);
317 	printk("Success\n");
318 }
319 
test_main_common(bool connect_eatt)320 static void test_main_common(bool connect_eatt)
321 {
322 	int err;
323 
324 	backchannel_init();
325 
326 	err = bt_enable(NULL);
327 	if (err != 0) {
328 		FAIL("Bluetooth discover failed (err %d)\n", err);
329 	}
330 
331 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
332 	if (err != 0) {
333 		FAIL("Scanning failed to start (err %d)\n", err);
334 	}
335 
336 	printk("Scanning successfully started\n");
337 
338 	WAIT_FOR_FLAG(flag_is_connected);
339 
340 	err = bt_conn_set_security(g_conn, BT_SECURITY_L2);
341 	if (err) {
342 		FAIL("Failed to start encryption procedure\n");
343 	}
344 
345 	WAIT_FOR_FLAG(flag_encrypted);
346 
347 	gatt_discover(test_svc_uuid, BT_GATT_DISCOVER_PRIMARY);
348 	gatt_discover(BT_UUID_GATT_CLIENT_FEATURES, BT_GATT_DISCOVER_CHARACTERISTIC);
349 
350 	enable_robust_caching();
351 
352 	if (connect_eatt) {
353 		while (bt_eatt_count(g_conn) < 1) {
354 			/* Wait for EATT channel to connect, in case it hasn't already */
355 			k_sleep(K_MSEC(10));
356 		}
357 	}
358 
359 	/* Tell the server to register additional service */
360 	backchannel_sync_send();
361 
362 	/* Wait for new service to be added by server */
363 	backchannel_sync_wait();
364 
365 	chan_1_read.single.handle = chrc_handle;
366 	chan_2_read.single.handle = chrc_handle;
367 }
368 
test_main_db_hash_read_eatt(void)369 static void test_main_db_hash_read_eatt(void)
370 {
371 	test_main_common(true);
372 
373 	/* Read the DB hash to become change-aware */
374 	db_hash_read.func = gatt_read_expect_success_cb;
375 	gatt_read(&db_hash_read);
376 	WAIT_FOR_FLAG(flag_db_hash_read);
377 
378 	/* These shall now succeed */
379 	chan_1_read.func = gatt_read_expect_success_cb;
380 	chan_2_read.func = gatt_read_expect_success_cb;
381 	UNSET_FLAG(flag_chan_1_read);
382 	UNSET_FLAG(flag_chan_2_read);
383 	gatt_read(&chan_1_read);
384 	gatt_read(&chan_2_read);
385 	WAIT_FOR_FLAG(flag_chan_1_read);
386 	WAIT_FOR_FLAG(flag_chan_2_read);
387 
388 	/* Signal to server that reads are done */
389 	backchannel_sync_send();
390 
391 	PASS("GATT client Passed\n");
392 }
393 
test_main_out_of_sync_eatt(void)394 static void test_main_out_of_sync_eatt(void)
395 {
396 	test_main_common(true);
397 
398 	chan_1_read.func = gatt_read_expect_err_out_of_sync_cb;
399 	chan_2_read.func = gatt_read_expect_err_out_of_sync_cb;
400 	gatt_read(&chan_1_read);
401 	gatt_read(&chan_2_read);
402 
403 	/* Wait until received response on both reads. When robust caching is implemented
404 	 * on the client side, the waiting shall be done automatically by the host when
405 	 * reading the DB hash.
406 	 */
407 	WAIT_FOR_FLAG(flag_chan_1_read);
408 	WAIT_FOR_FLAG(flag_chan_2_read);
409 
410 	/* Read the DB hash to become change-aware */
411 	db_hash_read.func = gatt_read_expect_success_cb;
412 	gatt_read(&db_hash_read);
413 	WAIT_FOR_FLAG(flag_db_hash_read);
414 
415 	/* These shall now succeed */
416 	chan_1_read.func = gatt_read_expect_success_cb;
417 	chan_2_read.func = gatt_read_expect_success_cb;
418 	UNSET_FLAG(flag_chan_1_read);
419 	UNSET_FLAG(flag_chan_2_read);
420 	gatt_read(&chan_1_read);
421 	gatt_read(&chan_2_read);
422 	WAIT_FOR_FLAG(flag_chan_1_read);
423 	WAIT_FOR_FLAG(flag_chan_2_read);
424 
425 	/* Signal to server that reads are done */
426 	backchannel_sync_send();
427 
428 	PASS("GATT client Passed\n");
429 }
430 
test_main_retry_reads_eatt(void)431 static void test_main_retry_reads_eatt(void)
432 {
433 	test_main_common(true);
434 
435 	chan_1_read.func = gatt_read_expect_err_out_of_sync_cb;
436 	chan_2_read.func = gatt_read_expect_err_out_of_sync_cb;
437 	gatt_read(&chan_1_read);
438 	gatt_read(&chan_2_read);
439 
440 	/* Wait until received response on both reads. When robust caching is implemented
441 	 * on the client side, the waiting shall be done automatically by the host when
442 	 * reading the DB hash.
443 	 */
444 	WAIT_FOR_FLAG(flag_chan_1_read);
445 	WAIT_FOR_FLAG(flag_chan_2_read);
446 
447 	/* Retry the reads, these shall time out */
448 	chan_1_read.func = gatt_read_expect_err_unlikely_cb;
449 	chan_2_read.func = gatt_read_expect_err_unlikely_cb;
450 	UNSET_FLAG(flag_chan_1_read);
451 	UNSET_FLAG(flag_chan_2_read);
452 	gatt_read(&chan_1_read);
453 	gatt_read(&chan_2_read);
454 	WAIT_FOR_FLAG(flag_chan_1_read);
455 	WAIT_FOR_FLAG(flag_chan_2_read);
456 
457 	/* Signal to server that reads are done */
458 	backchannel_sync_send();
459 
460 	PASS("GATT client Passed\n");
461 }
462 
test_main_db_hash_read_no_eatt(void)463 static void test_main_db_hash_read_no_eatt(void)
464 {
465 	test_main_common(false);
466 
467 	/* Read the DB hash to become change-aware */
468 	db_hash_read.func = gatt_read_expect_success_cb;
469 	gatt_read(&db_hash_read);
470 	WAIT_FOR_FLAG(flag_db_hash_read);
471 
472 	/* Read shall now succeed */
473 	chan_1_read.func = gatt_read_expect_success_cb;
474 	UNSET_FLAG(flag_chan_1_read);
475 	gatt_read(&chan_1_read);
476 	WAIT_FOR_FLAG(flag_chan_1_read);
477 
478 	/* Signal to server that reads are done */
479 	backchannel_sync_send();
480 
481 	PASS("GATT client Passed\n");
482 }
483 
test_main_out_of_sync_no_eatt(void)484 static void test_main_out_of_sync_no_eatt(void)
485 {
486 	test_main_common(false);
487 
488 	chan_1_read.func = gatt_read_expect_err_out_of_sync_cb;
489 	gatt_read(&chan_1_read);
490 	WAIT_FOR_FLAG(flag_chan_1_read);
491 
492 	/* Read the DB hash to become change-aware */
493 	db_hash_read.func = gatt_read_expect_success_cb;
494 	gatt_read(&db_hash_read);
495 	WAIT_FOR_FLAG(flag_db_hash_read);
496 
497 	/* Read shall now succeed */
498 	chan_1_read.func = gatt_read_expect_success_cb;
499 	UNSET_FLAG(flag_chan_1_read);
500 	gatt_read(&chan_1_read);
501 	WAIT_FOR_FLAG(flag_chan_1_read);
502 
503 	/* Signal to server that reads are done */
504 	backchannel_sync_send();
505 
506 	PASS("GATT client Passed\n");
507 }
508 
test_main_retry_reads_no_eatt(void)509 static void test_main_retry_reads_no_eatt(void)
510 {
511 	test_main_common(false);
512 
513 	chan_1_read.func = gatt_read_expect_err_out_of_sync_cb;
514 	gatt_read(&chan_1_read);
515 	WAIT_FOR_FLAG(flag_chan_1_read);
516 
517 	/* Read again to become change-aware */
518 	chan_1_read.func = gatt_read_expect_success_cb;
519 	UNSET_FLAG(flag_chan_1_read);
520 	gatt_read(&chan_1_read);
521 	WAIT_FOR_FLAG(flag_chan_1_read);
522 
523 	/* Signal to server that reads are done */
524 	backchannel_sync_send();
525 
526 	PASS("GATT client Passed\n");
527 }
528 
529 static const struct bst_test_instance test_vcs[] = {
530 	{
531 		.test_id = "gatt_client_db_hash_read_eatt",
532 		.test_pre_init_f = test_init,
533 		.test_tick_f = test_tick,
534 		.test_main_f = test_main_db_hash_read_eatt,
535 	},
536 	{
537 		.test_id = "gatt_client_out_of_sync_eatt",
538 		.test_pre_init_f = test_init,
539 		.test_tick_f = test_tick,
540 		.test_main_f = test_main_out_of_sync_eatt,
541 	},
542 	{
543 		.test_id = "gatt_client_retry_reads_eatt",
544 		.test_pre_init_f = test_init,
545 		.test_tick_f = test_tick,
546 		.test_main_f = test_main_retry_reads_eatt,
547 	},
548 	{
549 		.test_id = "gatt_client_db_hash_read_no_eatt",
550 		.test_pre_init_f = test_init,
551 		.test_tick_f = test_tick,
552 		.test_main_f = test_main_db_hash_read_no_eatt,
553 	},
554 	{
555 		.test_id = "gatt_client_out_of_sync_no_eatt",
556 		.test_pre_init_f = test_init,
557 		.test_tick_f = test_tick,
558 		.test_main_f = test_main_out_of_sync_no_eatt,
559 	},
560 	{
561 		.test_id = "gatt_client_retry_reads_no_eatt",
562 		.test_pre_init_f = test_init,
563 		.test_tick_f = test_tick,
564 		.test_main_f = test_main_retry_reads_no_eatt,
565 	},
566 	BSTEST_END_MARKER,
567 };
568 
test_gatt_client_install(struct bst_test_list * tests)569 struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests)
570 {
571 	return bst_add_tests(tests, test_vcs);
572 }
573