1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * EATT notification reliability test:
7  * A central acting as a GATT client scans and connects
8  * to a peripheral acting as a GATT server.
9  * The GATT client will then attempt to connect a number of CONFIG_BT_EATT_MAX bearers
10  * over EATT, send notifications, disconnect all bearers and reconnect EATT_BEARERS_TEST
11  * and send start a transaction with a request, then send a lot of notifications
12  * before the response is received.
13  * The test might be expanded by checking that all the notifications all transmitted
14  * on EATT channels.
15  */
16 
17 #include <zephyr/bluetooth/bluetooth.h>
18 #include <zephyr/bluetooth/gatt.h>
19 #include <zephyr/bluetooth/conn.h>
20 #include <zephyr/bluetooth/att.h>
21 
22 #include "common.h"
23 
24 CREATE_FLAG(flag_is_connected);
25 CREATE_FLAG(flag_discover_complete);
26 CREATE_FLAG(flag_is_encrypted);
27 
28 static struct bt_conn *g_conn;
29 static const struct bt_gatt_attr *local_attr;
30 static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID;
31 
32 #define NUM_NOTIF 100
33 #define SAMPLE_DATA 1
34 #define EATT_BEARERS_TEST 1
35 
36 volatile int num_eatt_channels;
37 
connected(struct bt_conn * conn,uint8_t err)38 static void connected(struct bt_conn *conn, uint8_t err)
39 {
40 	char addr[BT_ADDR_LE_STR_LEN];
41 
42 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
43 
44 	if (err != 0) {
45 		FAIL("Failed to connect to %s (%u)\n", addr, err);
46 		return;
47 	}
48 
49 	printk("Connected to %s\n", addr);
50 	SET_FLAG(flag_is_connected);
51 }
52 
disconnected(struct bt_conn * conn,uint8_t reason)53 static void disconnected(struct bt_conn *conn, uint8_t reason)
54 {
55 	char addr[BT_ADDR_LE_STR_LEN];
56 
57 	if (conn != g_conn) {
58 		return;
59 	}
60 
61 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
62 
63 	printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
64 
65 	bt_conn_unref(g_conn);
66 
67 	g_conn = NULL;
68 	UNSET_FLAG(flag_is_connected);
69 }
70 
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err security_err)71 static void security_changed(struct bt_conn *conn, bt_security_t level,
72 			     enum bt_security_err security_err)
73 {
74 	if (security_err == BT_SECURITY_ERR_SUCCESS && level > BT_SECURITY_L1) {
75 		SET_FLAG(flag_is_encrypted);
76 	}
77 }
78 
79 BT_CONN_CB_DEFINE(conn_callbacks) = {
80 	.connected = connected,
81 	.disconnected = disconnected,
82 	.security_changed = security_changed,
83 };
84 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)85 void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
86 		  struct net_buf_simple *ad)
87 {
88 	char addr_str[BT_ADDR_LE_STR_LEN];
89 	int err;
90 
91 	if (g_conn != NULL) {
92 		return;
93 	}
94 
95 	/* We're only interested in connectable events */
96 	if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
97 		return;
98 	}
99 
100 	bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
101 	printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
102 
103 	printk("Stopping scan\n");
104 	err = bt_le_scan_stop();
105 	if (err != 0) {
106 		FAIL("Could not stop scan: %d");
107 		return;
108 	}
109 
110 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
111 				BT_LE_CONN_PARAM_DEFAULT, &g_conn);
112 	if (err != 0) {
113 		FAIL("Could not connect to peer: %d", err);
114 	}
115 }
116 
send_notification(void)117 void send_notification(void)
118 {
119 	const uint8_t sample_dat = SAMPLE_DATA;
120 	int err;
121 
122 	do {
123 		err = bt_gatt_notify(g_conn, local_attr, &sample_dat, sizeof(sample_dat));
124 		if (!err) {
125 			return;
126 		} else if (err != -ENOMEM) {
127 			printk("GATT notify failed (err %d)\n", err);
128 			return;
129 		}
130 		k_sleep(K_TICKS(1));
131 	} while (err == -ENOMEM);
132 }
133 
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)134 static uint8_t discover_func(struct bt_conn *conn,
135 		const struct bt_gatt_attr *attr,
136 		struct bt_gatt_discover_params *params)
137 {
138 	SET_FLAG(flag_discover_complete);
139 	printk("Discover complete\n");
140 
141 	return BT_GATT_ITER_STOP;
142 }
143 
gatt_discover(void)144 static void gatt_discover(void)
145 {
146 	static struct bt_gatt_discover_params discover_params;
147 	int err;
148 
149 	printk("Discovering services and characteristics\n");
150 
151 	discover_params.uuid = test_svc_uuid;
152 	discover_params.func = discover_func;
153 	discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
154 	discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
155 	discover_params.type = BT_GATT_DISCOVER_PRIMARY;
156 	discover_params.chan_opt = BT_ATT_CHAN_OPT_NONE;
157 
158 	err = bt_gatt_discover(g_conn, &discover_params);
159 	if (err != 0) {
160 		FAIL("Discover failed(err %d)\n", err);
161 	}
162 }
163 
164 BT_GATT_SERVICE_DEFINE(g_svc,
165 	BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID),
166 	BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID, BT_GATT_CHRC_NOTIFY,
167 			       BT_GATT_PERM_READ, NULL, NULL, NULL),
168 	BT_GATT_CCC(NULL,
169 		    BT_GATT_PERM_READ | BT_GATT_PERM_WRITE));
170 
test_main(void)171 static void test_main(void)
172 {
173 	int err;
174 
175 	device_sync_init(PERIPHERAL_ID);
176 
177 	err = bt_enable(NULL);
178 	if (err != 0) {
179 		FAIL("Bluetooth enable failed (err %d)\n", err);
180 	}
181 
182 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
183 	if (err != 0) {
184 		FAIL("Scanning failed to start (err %d)\n", err);
185 	}
186 
187 	printk("Scanning successfully started\n");
188 
189 	WAIT_FOR_FLAG(flag_is_connected);
190 
191 	err = bt_conn_set_security(g_conn, BT_SECURITY_L2);
192 	if (err) {
193 		FAIL("Failed to start encryption procedure\n");
194 	}
195 
196 	WAIT_FOR_FLAG(flag_is_encrypted);
197 
198 	err = bt_eatt_connect(g_conn, CONFIG_BT_EATT_MAX);
199 	if (err) {
200 		FAIL("Sending credit based connection request failed (err %d)\n", err);
201 	}
202 
203 	/* Wait for the channels to be connected */
204 	while (bt_eatt_count(g_conn) < CONFIG_BT_EATT_MAX) {
205 		k_sleep(K_TICKS(1));
206 	}
207 
208 	printk("Waiting for sync\n");
209 	device_sync_wait();
210 
211 	local_attr = &g_svc.attrs[1];
212 
213 	printk("############# Notification test\n");
214 	for (int idx = 0; idx < NUM_NOTIF; idx++) {
215 		printk("Notification %d\n", idx);
216 		send_notification();
217 	}
218 
219 	printk("############# Disconnect and reconnect\n");
220 	for (int idx = 0; idx < CONFIG_BT_EATT_MAX; idx++) {
221 		bt_eatt_disconnect_one(g_conn);
222 		while (bt_eatt_count(g_conn) != (CONFIG_BT_EATT_MAX - idx)) {
223 			k_sleep(K_TICKS(1));
224 		}
225 	}
226 
227 	printk("Connecting %d bearers\n", EATT_BEARERS_TEST);
228 	err = bt_eatt_connect(g_conn, EATT_BEARERS_TEST);
229 	if (err) {
230 		FAIL("Sending credit based connection request failed (err %d)\n", err);
231 	}
232 
233 	/* Wait for the channels to be connected */
234 	while (bt_eatt_count(g_conn) < EATT_BEARERS_TEST) {
235 		k_sleep(K_TICKS(1));
236 	}
237 
238 	printk("############# Send notifications during discovery request\n");
239 	gatt_discover();
240 	while (!TEST_FLAG(flag_discover_complete)) {
241 		printk("Notifying...\n");
242 		send_notification();
243 	}
244 
245 	printk("Sending final sync\n");
246 	device_sync_send();
247 
248 	PASS("Client Passed\n");
249 }
250 
251 static const struct bst_test_instance test_vcs[] = {
252 	{
253 		.test_id = "client",
254 		.test_pre_init_f = test_init,
255 		.test_tick_f = test_tick,
256 		.test_main_f = test_main
257 	},
258 	BSTEST_END_MARKER
259 };
260 
test_client_install(struct bst_test_list * tests)261 struct bst_test_list *test_client_install(struct bst_test_list *tests)
262 {
263 	return bst_add_tests(tests, test_vcs);
264 }
265