1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/types.h>
9 #include <stddef.h>
10 #include <errno.h>
11 
12 #include <zephyr/bluetooth/bluetooth.h>
13 #include <zephyr/bluetooth/hci.h>
14 #include <zephyr/bluetooth/conn.h>
15 #include <zephyr/bluetooth/uuid.h>
16 #include <zephyr/bluetooth/gatt.h>
17 
18 #include "babblekit/testcase.h"
19 #include "babblekit/flags.h"
20 #include "common.h"
21 
22 extern enum bst_result_t bst_result;
23 
24 DEFINE_FLAG_STATIC(flag_is_chrc_ctx_validated);
25 
26 static struct bt_conn *g_conn;
27 
connected(struct bt_conn * conn,uint8_t err)28 static void connected(struct bt_conn *conn, uint8_t err)
29 {
30 	char addr[BT_ADDR_LE_STR_LEN];
31 
32 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
33 
34 	if (err != 0) {
35 		TEST_FAIL("Failed to connect to %s (%u)", addr, err);
36 		return;
37 	}
38 
39 	printk("Connected to %s\n", addr);
40 
41 	g_conn = bt_conn_ref(conn);
42 }
43 
disconnected(struct bt_conn * conn,uint8_t reason)44 static void disconnected(struct bt_conn *conn, uint8_t reason)
45 {
46 	char addr[BT_ADDR_LE_STR_LEN];
47 
48 	if (conn != g_conn) {
49 		return;
50 	}
51 
52 	bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
53 
54 	printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
55 
56 	bt_conn_unref(g_conn);
57 
58 	g_conn = NULL;
59 }
60 
61 static struct bt_conn_cb conn_callbacks = {
62 	.connected = connected,
63 	.disconnected = disconnected,
64 };
65 
66 struct test_chrc_ctx {
67 	uint16_t auth_read_cnt;
68 	uint16_t read_cnt;
69 	uint16_t auth_write_cnt;
70 	uint16_t write_cnt;
71 	uint8_t data[CHRC_SIZE];
72 };
73 
read_test_chrc(struct test_chrc_ctx * chrc_ctx,struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)74 static ssize_t read_test_chrc(struct test_chrc_ctx *chrc_ctx,
75 			      struct bt_conn *conn,
76 			      const struct bt_gatt_attr *attr,
77 			      void *buf, uint16_t len, uint16_t offset)
78 {
79 	chrc_ctx->read_cnt++;
80 
81 	return bt_gatt_attr_read(conn, attr, buf, len, offset,
82 				 (void *)chrc_ctx->data,
83 				 sizeof(chrc_ctx->data));
84 }
85 
write_test_chrc(struct test_chrc_ctx * chrc_ctx,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)86 static ssize_t write_test_chrc(struct test_chrc_ctx *chrc_ctx,
87 			       const void *buf, uint16_t len,
88 			       uint16_t offset, uint8_t flags)
89 {
90 	chrc_ctx->write_cnt++;
91 
92 	if (len != sizeof(chrc_ctx->data)) {
93 		printk("Invalid chrc length\n");
94 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
95 	}
96 
97 	if (offset != 0) {
98 		printk("Invalid chrc offset and length\n");
99 		return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
100 	}
101 
102 	if (flags != 0) {
103 		TEST_FAIL("Invalid flags %u", flags);
104 		return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
105 	}
106 
107 	(void)memcpy(chrc_ctx->data, buf, len);
108 
109 	return len;
110 }
111 
112 static struct test_chrc_ctx unhandled_chrc_ctx;
113 
read_test_unhandled_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)114 static ssize_t read_test_unhandled_chrc(struct bt_conn *conn,
115 					 const struct bt_gatt_attr *attr,
116 					 void *buf, uint16_t len, uint16_t offset)
117 {
118 	return read_test_chrc(&unhandled_chrc_ctx, conn, attr, buf, len, offset);
119 }
120 
write_test_unhandled_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)121 static ssize_t write_test_unhandled_chrc(struct bt_conn *conn,
122 					  const struct bt_gatt_attr *attr,
123 					  const void *buf, uint16_t len,
124 					  uint16_t offset, uint8_t flags)
125 {
126 	printk("unhandled chrc len %u offset %u\n", len, offset);
127 
128 	return write_test_chrc(&unhandled_chrc_ctx, buf, len, offset, flags);
129 }
130 
131 static struct test_chrc_ctx unauthorized_chrc_ctx;
132 
read_test_unauthorized_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)133 static ssize_t read_test_unauthorized_chrc(struct bt_conn *conn,
134 					   const struct bt_gatt_attr *attr,
135 					   void *buf, uint16_t len, uint16_t offset)
136 {
137 	return read_test_chrc(&unauthorized_chrc_ctx, conn, attr, buf, len, offset);
138 }
139 
write_test_unauthorized_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)140 static ssize_t write_test_unauthorized_chrc(struct bt_conn *conn,
141 					    const struct bt_gatt_attr *attr,
142 					    const void *buf, uint16_t len,
143 					    uint16_t offset, uint8_t flags)
144 {
145 	printk("unauthorized chrc len %u offset %u\n", len, offset);
146 
147 	return write_test_chrc(&unauthorized_chrc_ctx, buf, len, offset, flags);
148 }
149 
150 static struct test_chrc_ctx authorized_chrc_ctx;
151 
read_test_authorized_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)152 static ssize_t read_test_authorized_chrc(struct bt_conn *conn,
153 					 const struct bt_gatt_attr *attr,
154 					 void *buf, uint16_t len, uint16_t offset)
155 {
156 	return read_test_chrc(&authorized_chrc_ctx, conn, attr, buf, len, offset);
157 }
158 
write_test_authorized_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)159 static ssize_t write_test_authorized_chrc(struct bt_conn *conn,
160 					  const struct bt_gatt_attr *attr,
161 					  const void *buf, uint16_t len,
162 					  uint16_t offset, uint8_t flags)
163 {
164 	printk("authorized chrc len %u offset %u\n", len, offset);
165 
166 	return write_test_chrc(&authorized_chrc_ctx, buf, len, offset, flags);
167 }
168 
169 static const struct test_chrc_ctx zeroed_chrc_ctx;
170 
unhandled_chrc_operation_validate(void)171 static bool unhandled_chrc_operation_validate(void)
172 {
173 	if (memcmp(&unauthorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) {
174 		return false;
175 	}
176 
177 	if (memcmp(&authorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) {
178 		return false;
179 	}
180 
181 	if ((unhandled_chrc_ctx.read_cnt != 1) && (unhandled_chrc_ctx.write_cnt != 1)) {
182 		return false;
183 	}
184 
185 	if ((unhandled_chrc_ctx.auth_read_cnt != 0) &&
186 	    (unhandled_chrc_ctx.auth_write_cnt != 0)) {
187 		return false;
188 	}
189 
190 	return true;
191 }
192 
unauthorized_chrc_operation_validate(void)193 static bool unauthorized_chrc_operation_validate(void)
194 {
195 	if (memcmp(&unhandled_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) {
196 		return false;
197 	}
198 
199 	if (memcmp(&authorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) {
200 		return false;
201 	}
202 
203 	if ((unauthorized_chrc_ctx.read_cnt != 0) && (unauthorized_chrc_ctx.write_cnt != 0)) {
204 		return false;
205 	}
206 
207 	if ((unauthorized_chrc_ctx.auth_read_cnt != 1) &&
208 	    (unauthorized_chrc_ctx.auth_write_cnt != 1)) {
209 		return false;
210 	}
211 
212 	return true;
213 }
214 
authorized_chrc_operation_validate(void)215 static bool authorized_chrc_operation_validate(void)
216 {
217 	if (memcmp(&unhandled_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) {
218 		return false;
219 	}
220 
221 	if (memcmp(&unauthorized_chrc_ctx, &zeroed_chrc_ctx, sizeof(zeroed_chrc_ctx)) != 0) {
222 		return false;
223 	}
224 
225 	if ((authorized_chrc_ctx.read_cnt != 1) && (authorized_chrc_ctx.write_cnt != 1)) {
226 		return false;
227 	}
228 
229 	if ((authorized_chrc_ctx.auth_read_cnt != 1) &&
230 	    (authorized_chrc_ctx.auth_write_cnt != 1)) {
231 		return false;
232 	}
233 
234 	return true;
235 }
236 
write_cp_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)237 static ssize_t write_cp_chrc(struct bt_conn *conn,
238 			     const struct bt_gatt_attr *attr,
239 			     const void *buf, uint16_t len,
240 			     uint16_t offset, uint8_t flags)
241 {
242 	static uint16_t cp_write_cnt;
243 	bool pass;
244 	char *log_str;
245 
246 	if (cp_write_cnt == 0) {
247 		pass = unhandled_chrc_operation_validate();
248 		log_str = "unhandled";
249 	} else if (cp_write_cnt == 1) {
250 		pass = unauthorized_chrc_operation_validate();
251 		log_str = "unauthorized";
252 	} else if (cp_write_cnt == 2) {
253 		pass = authorized_chrc_operation_validate();
254 		log_str = "authorized";
255 	} else {
256 		TEST_FAIL("Invalid value of CP write counter %u", cp_write_cnt);
257 		return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
258 	}
259 
260 	if (pass) {
261 		printk("Correct context for %s chrc\n", log_str);
262 	} else {
263 		TEST_FAIL("Invalid context for %s chrc", log_str);
264 		return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
265 	}
266 
267 	memset(&unhandled_chrc_ctx, 0, sizeof(unhandled_chrc_ctx));
268 	memset(&unauthorized_chrc_ctx, 0, sizeof(unauthorized_chrc_ctx));
269 	memset(&authorized_chrc_ctx, 0, sizeof(authorized_chrc_ctx));
270 
271 	cp_write_cnt++;
272 
273 	if (cp_write_cnt == 3) {
274 		SET_FLAG(flag_is_chrc_ctx_validated);
275 	}
276 
277 	return len;
278 }
279 
280 BT_GATT_SERVICE_DEFINE(test_svc,
281 	BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID),
282 	BT_GATT_CHARACTERISTIC(TEST_UNHANDLED_CHRC_UUID,
283 			       BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ,
284 			       BT_GATT_PERM_WRITE | BT_GATT_PERM_READ,
285 			       read_test_unhandled_chrc,
286 			       write_test_unhandled_chrc, NULL),
287 	BT_GATT_CHARACTERISTIC(TEST_UNAUTHORIZED_CHRC_UUID,
288 			       BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ,
289 			       BT_GATT_PERM_WRITE | BT_GATT_PERM_READ,
290 			       read_test_unauthorized_chrc,
291 			       write_test_unauthorized_chrc, NULL),
292 	BT_GATT_CHARACTERISTIC(TEST_AUTHORIZED_CHRC_UUID,
293 			       BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ,
294 			       BT_GATT_PERM_WRITE | BT_GATT_PERM_READ,
295 			       read_test_authorized_chrc,
296 			       write_test_authorized_chrc, NULL),
297 	BT_GATT_CHARACTERISTIC(TEST_CP_CHRC_UUID,
298 			       BT_GATT_CHRC_WRITE,
299 			       BT_GATT_PERM_WRITE,
300 			       NULL, write_cp_chrc, NULL),
301 );
302 
gatt_read_authorize(struct bt_conn * conn,const struct bt_gatt_attr * attr)303 static bool gatt_read_authorize(struct bt_conn *conn, const struct bt_gatt_attr *attr)
304 {
305 	if (bt_uuid_cmp(attr->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) {
306 		unauthorized_chrc_ctx.auth_read_cnt++;
307 		return false;
308 	} else if (bt_uuid_cmp(attr->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) {
309 		authorized_chrc_ctx.auth_read_cnt++;
310 		return true;
311 	} else {
312 		return true;
313 	}
314 }
315 
gatt_write_authorize(struct bt_conn * conn,const struct bt_gatt_attr * attr)316 static bool gatt_write_authorize(struct bt_conn *conn, const struct bt_gatt_attr *attr)
317 {
318 	if (bt_uuid_cmp(attr->uuid, TEST_UNAUTHORIZED_CHRC_UUID) == 0) {
319 		unauthorized_chrc_ctx.auth_write_cnt++;
320 		return false;
321 	} else if (bt_uuid_cmp(attr->uuid, TEST_AUTHORIZED_CHRC_UUID) == 0) {
322 		authorized_chrc_ctx.auth_write_cnt++;
323 		return true;
324 	} else {
325 		return true;
326 	}
327 }
328 
329 static const struct bt_gatt_authorization_cb gatt_authorization_callbacks = {
330 	.read_authorize = gatt_read_authorize,
331 	.write_authorize = gatt_write_authorize,
332 };
333 
test_main(void)334 static void test_main(void)
335 {
336 	int err;
337 	const struct bt_data ad[] = {
338 		BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))
339 	};
340 
341 	err = bt_gatt_authorization_cb_register(&gatt_authorization_callbacks);
342 	if (err) {
343 		TEST_FAIL("Registering GATT authorization callbacks failed (err %d)", err);
344 		return;
345 	}
346 
347 	bt_conn_cb_register(&conn_callbacks);
348 
349 	err = bt_enable(NULL);
350 	if (err != 0) {
351 		TEST_FAIL("Bluetooth init failed (err %d)", err);
352 		return;
353 	}
354 
355 	printk("Bluetooth initialized\n");
356 
357 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
358 	if (err != 0) {
359 		TEST_FAIL("Advertising failed to start (err %d)", err);
360 		return;
361 	}
362 
363 	printk("Advertising successfully started\n");
364 
365 	WAIT_FOR_FLAG(flag_is_chrc_ctx_validated);
366 
367 	TEST_PASS("GATT server passed");
368 }
369 
370 static const struct bst_test_instance test_gatt_server[] = {
371 	{
372 		.test_id = "gatt_server",
373 		.test_main_f = test_main
374 	},
375 	BSTEST_END_MARKER
376 };
377 
test_gatt_server_install(struct bst_test_list * tests)378 struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests)
379 {
380 	return bst_add_tests(tests, test_gatt_server);
381 }
382