1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 
9 #include <zephyr/bluetooth/bluetooth.h>
10 #include <zephyr/bluetooth/conn.h>
11 #include <zephyr/bluetooth/gatt.h>
12 #include <zephyr/bluetooth/uuid.h>
13 
14 #include <zephyr/settings/settings.h>
15 
16 #include <zephyr/logging/log.h>
17 
18 #include "testlib/conn.h"
19 #include "testlib/scan.h"
20 
21 #include "babblekit/flags.h"
22 #include "babblekit/sync.h"
23 #include "babblekit/testcase.h"
24 
25 #include "common.h"
26 #include "bt_settings_hook.h"
27 
28 LOG_MODULE_REGISTER(server, LOG_LEVEL_DBG);
29 
30 static DEFINE_FLAG(ccc_cfg_changed_flag);
31 static DEFINE_FLAG(disconnected_flag);
32 static DEFINE_FLAG(security_changed_flag);
33 
34 static struct bt_conn_cb server_conn_cb;
35 
ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)36 static void ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
37 {
38 	ARG_UNUSED(attr);
39 
40 	bool notif_enabled = (value == BT_GATT_CCC_NOTIFY);
41 
42 	LOG_INF("CCC Update: notification %s", notif_enabled ? "enabled" : "disabled");
43 
44 	SET_FLAG(ccc_cfg_changed_flag);
45 }
46 
47 BT_GATT_SERVICE_DEFINE(test_gatt_service, BT_GATT_PRIMARY_SERVICE(test_service_uuid),
48 		       BT_GATT_CHARACTERISTIC(test_characteristic_uuid, BT_GATT_CHRC_NOTIFY,
49 					      BT_GATT_PERM_NONE, NULL, NULL, NULL),
50 		       BT_GATT_CCC(ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
51 
disconnected(struct bt_conn * conn,uint8_t reason)52 static void disconnected(struct bt_conn *conn, uint8_t reason)
53 {
54 	char addr_str[BT_ADDR_LE_STR_LEN];
55 
56 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
57 
58 	LOG_DBG("Disconnected: %s (reason 0x%02x)", addr_str, reason);
59 
60 	SET_FLAG(disconnected_flag);
61 }
62 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)63 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
64 {
65 	char addr_str[BT_ADDR_LE_STR_LEN];
66 
67 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
68 
69 	TEST_ASSERT(err == 0, "Security update failed: %s level %u err %d", addr_str, level, err);
70 
71 	LOG_DBG("Security changed: %s level %u", addr_str, level);
72 	SET_FLAG(security_changed_flag);
73 }
74 
init_server_conn_callbacks(void)75 static void init_server_conn_callbacks(void)
76 {
77 	int err;
78 
79 	server_conn_cb.connected = NULL;
80 	server_conn_cb.disconnected = disconnected;
81 	server_conn_cb.security_changed = security_changed;
82 	server_conn_cb.identity_resolved = NULL;
83 
84 	err = bt_conn_cb_register(&server_conn_cb);
85 	TEST_ASSERT(err == 0, "Failed to set server conn callbacks (err %d)", err);
86 }
87 
connect_and_set_security(struct bt_conn ** conn)88 static void connect_and_set_security(struct bt_conn **conn)
89 {
90 	int err;
91 	bt_addr_le_t client = {};
92 
93 	err = bt_testlib_scan_find_name(&client, ADVERTISER_NAME);
94 	TEST_ASSERT(err == 0, "Failed to start scan (err %d)", err);
95 
96 	err = bt_testlib_connect(&client, conn);
97 	TEST_ASSERT(err == 0, "Failed to initiate connection (err %d)", err);
98 
99 	err = bt_conn_set_security(*conn, BT_SECURITY_L2);
100 	TEST_ASSERT(err == 0, "Failed to set security (err %d)", err);
101 
102 	WAIT_FOR_FLAG(security_changed_flag);
103 }
104 
server_procedure(void)105 void server_procedure(void)
106 {
107 	/* Test purpose:
108 	 *
109 	 * Verifies that we are deleting GATT settings linked to a peer that we
110 	 * bonded with.
111 	 *
112 	 * Two devices:
113 	 * - `server`: GATT server, connect and elevate security
114 	 * - `client`: GATT client, when connected, will subscribe to CCC
115 	 *
116 	 * [verdict]
117 	 * - the server doesn't have settings leftover
118 	 */
119 
120 	int err;
121 	struct bt_conn *conn = NULL;
122 
123 	int number_of_settings_left = 0;
124 
125 	TEST_START("server");
126 
127 	err = bt_enable(NULL);
128 	TEST_ASSERT(err == 0, "Cannot enable Bluetooth (err %d)", err);
129 
130 	LOG_DBG("Bluetooth initialized");
131 
132 	err = settings_load();
133 	TEST_ASSERT(err == 0, "Failed to load settings (err %d)", err);
134 
135 	err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY);
136 	TEST_ASSERT(err == 0, "(1) Failed to unpair (err %d)", err);
137 
138 	start_settings_record();
139 
140 	init_server_conn_callbacks();
141 
142 	connect_and_set_security(&conn);
143 
144 	WAIT_FOR_FLAG(ccc_cfg_changed_flag);
145 
146 	/* Settings may be written to flash on disconnection. */
147 	err = bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
148 	TEST_ASSERT(err == 0, "Failed to disconnect (err %d)", err);
149 
150 	WAIT_FOR_FLAG(disconnected_flag);
151 
152 	err = bt_unpair(BT_ID_DEFAULT, BT_ADDR_LE_ANY);
153 	TEST_ASSERT(err == 0, "(2) Failed to unpair (err %d)", err);
154 
155 	number_of_settings_left = get_settings_list_size();
156 
157 	stop_settings_record();
158 	settings_list_cleanup();
159 
160 	if (number_of_settings_left > 0) {
161 		TEST_FAIL("'bt_unpair' did not clear the settings properly.");
162 	}
163 
164 	TEST_PASS("server");
165 }
166