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