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