1 /* main.c - Application main entry point */
2
3 /*
4 * Copyright (c) 2019 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #include <zephyr/kernel.h>
10 #include <stddef.h>
11 #include <zephyr/ztest.h>
12
13 #include <zephyr/bluetooth/buf.h>
14 #include <zephyr/bluetooth/bluetooth.h>
15 #include <zephyr/bluetooth/gatt.h>
16
17 /* Custom Service Variables */
18 static const struct bt_uuid_128 test_uuid = BT_UUID_INIT_128(
19 0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
20 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
21 static const struct bt_uuid_128 test_chrc_uuid = BT_UUID_INIT_128(
22 0xf2, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
23 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
24
25 static uint8_t test_value[] = { 'T', 'e', 's', 't', '\0' };
26
27 static const struct bt_uuid_128 test1_uuid = BT_UUID_INIT_128(
28 0xf4, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
29 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
30
31 static const struct bt_uuid_128 test1_nfy_uuid = BT_UUID_INIT_128(
32 0xf5, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12,
33 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12);
34
35 static uint8_t nfy_enabled;
36
test1_ccc_cfg_changed(const struct bt_gatt_attr * attr,uint16_t value)37 static void test1_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
38 {
39 nfy_enabled = (value == BT_GATT_CCC_NOTIFY) ? 1 : 0;
40 }
41
read_test(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)42 static ssize_t read_test(struct bt_conn *conn, const struct bt_gatt_attr *attr,
43 void *buf, uint16_t len, uint16_t offset)
44 {
45 const char *value = attr->user_data;
46
47 return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
48 strlen(value));
49 }
50
write_test(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)51 static ssize_t write_test(struct bt_conn *conn, const struct bt_gatt_attr *attr,
52 const void *buf, uint16_t len, uint16_t offset,
53 uint8_t flags)
54 {
55 uint8_t *value = attr->user_data;
56
57 if (offset + len > sizeof(test_value)) {
58 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
59 }
60
61 memcpy(value + offset, buf, len);
62
63 return len;
64 }
65
66 static struct bt_gatt_attr test_attrs[] = {
67 /* Vendor Primary Service Declaration */
68 BT_GATT_PRIMARY_SERVICE(&test_uuid),
69
70 BT_GATT_CHARACTERISTIC(&test_chrc_uuid.uuid,
71 BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
72 BT_GATT_PERM_READ_AUTHEN |
73 BT_GATT_PERM_WRITE_AUTHEN,
74 read_test, write_test, test_value),
75 };
76
77 static struct bt_gatt_service test_svc = BT_GATT_SERVICE(test_attrs);
78
79 static struct bt_gatt_attr test1_attrs[] = {
80 /* Vendor Primary Service Declaration */
81 BT_GATT_PRIMARY_SERVICE(&test1_uuid),
82
83 BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid,
84 BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE,
85 NULL, NULL, &nfy_enabled),
86 BT_GATT_CCC(test1_ccc_cfg_changed,
87 BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
88 };
89
90 static struct bt_gatt_service test1_svc = BT_GATT_SERVICE(test1_attrs);
91
92 ZTEST_SUITE(test_gatt, NULL, NULL, NULL, NULL, NULL);
93
ZTEST(test_gatt,test_gatt_register)94 ZTEST(test_gatt, test_gatt_register)
95 {
96 /* Ensure our test services are not already registered */
97 bt_gatt_service_unregister(&test_svc);
98 bt_gatt_service_unregister(&test1_svc);
99
100 /* Attempt to register services */
101 zassert_false(bt_gatt_service_register(&test_svc),
102 "Test service registration failed");
103 zassert_false(bt_gatt_service_register(&test1_svc),
104 "Test service1 registration failed");
105
106 /* Attempt to register already registered services */
107 zassert_true(bt_gatt_service_register(&test_svc),
108 "Test service duplicate succeeded");
109 zassert_true(bt_gatt_service_register(&test1_svc),
110 "Test service1 duplicate succeeded");
111 }
112
ZTEST(test_gatt,test_gatt_unregister)113 ZTEST(test_gatt, test_gatt_unregister)
114 {
115 /* Attempt to unregister last */
116 zassert_false(bt_gatt_service_unregister(&test1_svc),
117 "Test service1 unregister failed");
118 zassert_false(bt_gatt_service_register(&test1_svc),
119 "Test service1 re-registration failed");
120
121 /* Attempt to unregister first/middle */
122 zassert_false(bt_gatt_service_unregister(&test_svc),
123 "Test service unregister failed");
124 zassert_false(bt_gatt_service_register(&test_svc),
125 "Test service re-registration failed");
126
127 /* Attempt to unregister all reverse order */
128 zassert_false(bt_gatt_service_unregister(&test1_svc),
129 "Test service1 unregister failed");
130 zassert_false(bt_gatt_service_unregister(&test_svc),
131 "Test service unregister failed");
132
133 zassert_false(bt_gatt_service_register(&test_svc),
134 "Test service registration failed");
135 zassert_false(bt_gatt_service_register(&test1_svc),
136 "Test service1 registration failed");
137
138 /* Attempt to unregister all same order */
139 zassert_false(bt_gatt_service_unregister(&test_svc),
140 "Test service1 unregister failed");
141 zassert_false(bt_gatt_service_unregister(&test1_svc),
142 "Test service unregister failed");
143 }
144
145 /* Test that a service A can be re-registered after registering it once, unregistering it, and then
146 * registering another service B.
147 * No pre-allocated handles. Repeat the process multiple times.
148 */
ZTEST(test_gatt,test_gatt_reregister)149 ZTEST(test_gatt, test_gatt_reregister)
150 {
151 struct bt_gatt_attr local_test_attrs[] = {
152 /* Vendor Primary Service Declaration */
153 BT_GATT_PRIMARY_SERVICE(&test_uuid),
154
155 BT_GATT_CHARACTERISTIC(&test_chrc_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
156 BT_GATT_PERM_READ_AUTHEN | BT_GATT_PERM_WRITE_AUTHEN,
157 read_test, write_test, test_value),
158 };
159
160 struct bt_gatt_attr local_test1_attrs[] = {
161 /* Vendor Primary Service Declaration */
162 BT_GATT_PRIMARY_SERVICE(&test1_uuid),
163
164 BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid, BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE,
165 NULL, NULL, &nfy_enabled),
166 BT_GATT_CCC(test1_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
167 };
168 struct bt_gatt_service local_test_svc = BT_GATT_SERVICE(local_test_attrs);
169 struct bt_gatt_service local_test1_svc = BT_GATT_SERVICE(local_test1_attrs);
170
171 /* Check that the procedure is successful for a few iterations to verify stability and
172 * detect residual state or memory issues.
173 */
174 for (int i = 0; i < 10; i++) {
175
176 /* Check that the handles are initially 0x0000 before registering the service */
177 for (int j = 0; j < local_test_svc.attr_count; j++) {
178 zassert_equal(local_test_svc.attrs[j].handle, 0x0000,
179 "Test service A handle not initially reset");
180 }
181
182 zassert_false(bt_gatt_service_register(&local_test_svc),
183 "Test service A registration failed");
184
185 zassert_false(bt_gatt_service_unregister(&local_test_svc),
186 "Test service A unregister failed");
187
188 /* Check that the handles are the same as before registering the service */
189 for (int j = 0; j < local_test_svc.attr_count; j++) {
190 zassert_equal(local_test_svc.attrs[j].handle, 0x0000,
191 "Test service A handle not reset");
192 }
193
194 zassert_false(bt_gatt_service_register(&local_test1_svc),
195 "Test service B registration failed");
196
197 zassert_false(bt_gatt_service_register(&local_test_svc),
198 "Test service A re-registering failed...");
199
200 /* Clean up */
201 zassert_false(bt_gatt_service_unregister(&local_test_svc),
202 "Test service A unregister failed");
203 zassert_false(bt_gatt_service_unregister(&local_test1_svc),
204 "Test service B unregister failed");
205 }
206 }
207
208 /* Test that a service A can be re-registered after registering it once, unregistering it, and then
209 * registering another service B.
210 * Service A and B both have pre-allocated handles for their attributes.
211 * Check that pre-allocated handles are the same after unregistering as they were before
212 * registering the service.
213 */
ZTEST(test_gatt,test_gatt_reregister_pre_allocated_handles)214 ZTEST(test_gatt, test_gatt_reregister_pre_allocated_handles)
215 {
216 struct bt_gatt_attr local_test_attrs[] = {
217 /* Vendor Primary Service Declaration */
218 BT_GATT_PRIMARY_SERVICE(&test_uuid),
219
220 BT_GATT_CHARACTERISTIC(&test_chrc_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
221 BT_GATT_PERM_READ_AUTHEN | BT_GATT_PERM_WRITE_AUTHEN,
222 read_test, write_test, test_value),
223 };
224
225 struct bt_gatt_attr local_test1_attrs[] = {
226 /* Vendor Primary Service Declaration */
227 BT_GATT_PRIMARY_SERVICE(&test1_uuid),
228
229 BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid, BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE,
230 NULL, NULL, &nfy_enabled),
231 BT_GATT_CCC(test1_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
232 };
233
234 struct bt_gatt_service prealloc_test_svc = BT_GATT_SERVICE(local_test_attrs);
235 struct bt_gatt_service prealloc_test1_svc = BT_GATT_SERVICE(local_test1_attrs);
236
237 /* Pre-allocate handles for both services */
238 for (int i = 0; i < prealloc_test_svc.attr_count; i++) {
239 prealloc_test_svc.attrs[i].handle = 0x0100 + i;
240 }
241 for (int i = 0; i < prealloc_test1_svc.attr_count; i++) {
242 prealloc_test1_svc.attrs[i].handle = 0x0200 + i;
243 }
244
245 zassert_false(bt_gatt_service_register(&prealloc_test_svc),
246 "Test service A registration failed");
247
248 zassert_false(bt_gatt_service_unregister(&prealloc_test_svc),
249 "Test service A unregister failed");
250
251 /* Check that the handles are the same as before registering the service */
252 for (int i = 0; i < prealloc_test_svc.attr_count; i++) {
253 zassert_equal(prealloc_test_svc.attrs[i].handle, 0x0100 + i,
254 "Test service A handle not reset");
255 }
256
257 zassert_false(bt_gatt_service_register(&prealloc_test1_svc),
258 "Test service B registration failed");
259
260 zassert_false(bt_gatt_service_register(&prealloc_test_svc),
261 "Test service A re-registering failed...");
262
263 /* Clean up */
264 zassert_false(bt_gatt_service_unregister(&prealloc_test_svc),
265 "Test service A unregister failed");
266 zassert_false(bt_gatt_service_unregister(&prealloc_test1_svc),
267 "Test service B unregister failed");
268 }
269
270 /* Test that a service A can be re-registered after registering it once, unregistering it, and then
271 * registering another service B.
272 * Service A has pre-allocated handles for its attributes, while Service B has handles assigned by
273 * the stack when registered.
274 * Check that pre-allocated handles are the same after unregistering as they were before
275 * registering the service.
276 */
ZTEST(test_gatt,test_gatt_reregister_pre_allocated_handle_single)277 ZTEST(test_gatt, test_gatt_reregister_pre_allocated_handle_single)
278 {
279 struct bt_gatt_attr local_test_attrs[] = {
280 /* Vendor Primary Service Declaration */
281 BT_GATT_PRIMARY_SERVICE(&test_uuid),
282
283 BT_GATT_CHARACTERISTIC(&test_chrc_uuid.uuid, BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
284 BT_GATT_PERM_READ_AUTHEN | BT_GATT_PERM_WRITE_AUTHEN,
285 read_test, write_test, test_value),
286 };
287
288 struct bt_gatt_attr local_test1_attrs[] = {
289 /* Vendor Primary Service Declaration */
290 BT_GATT_PRIMARY_SERVICE(&test1_uuid),
291
292 BT_GATT_CHARACTERISTIC(&test1_nfy_uuid.uuid, BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE,
293 NULL, NULL, &nfy_enabled),
294 BT_GATT_CCC(test1_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
295 };
296
297 struct bt_gatt_service prealloc_test_svc = BT_GATT_SERVICE(local_test_attrs);
298 struct bt_gatt_service auto_test_svc = BT_GATT_SERVICE(local_test1_attrs);
299
300 /* Pre-allocate handles for one service only */
301 for (int j = 0; j < prealloc_test_svc.attr_count; j++) {
302 prealloc_test_svc.attrs[j].handle = 0x0100 + j;
303 }
304
305 zassert_false(bt_gatt_service_register(&prealloc_test_svc),
306 "Test service A registration failed");
307
308 zassert_false(bt_gatt_service_unregister(&prealloc_test_svc),
309 "Test service A unregister failed");
310
311 /* Check that the handles are the same as before registering the service */
312 for (int i = 0; i < prealloc_test_svc.attr_count; i++) {
313 zassert_equal(prealloc_test_svc.attrs[i].handle, 0x0100 + i,
314 "Test service A handle not reset");
315 }
316
317 zassert_false(bt_gatt_service_register(&auto_test_svc),
318 "Test service B registration failed");
319
320 zassert_false(bt_gatt_service_register(&prealloc_test_svc),
321 "Test service A re-registering failed...");
322
323 /* Clean up */
324 zassert_false(bt_gatt_service_unregister(&prealloc_test_svc),
325 "Test service A unregister failed");
326 zassert_false(bt_gatt_service_unregister(&auto_test_svc),
327 "Test service B unregister failed");
328 }
329
count_attr(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)330 static uint8_t count_attr(const struct bt_gatt_attr *attr, uint16_t handle,
331 void *user_data)
332 {
333 uint16_t *count = user_data;
334
335 (*count)++;
336
337 return BT_GATT_ITER_CONTINUE;
338 }
339
find_attr(const struct bt_gatt_attr * attr,uint16_t handle,void * user_data)340 static uint8_t find_attr(const struct bt_gatt_attr *attr, uint16_t handle,
341 void *user_data)
342 {
343 const struct bt_gatt_attr **tmp = user_data;
344
345 *tmp = attr;
346
347 return BT_GATT_ITER_CONTINUE;
348 }
349
ZTEST(test_gatt,test_gatt_foreach)350 ZTEST(test_gatt, test_gatt_foreach)
351 {
352 const struct bt_gatt_attr *attr;
353 uint16_t num = 0;
354
355 /* Attempt to register services */
356 zassert_false(bt_gatt_service_register(&test_svc),
357 "Test service registration failed");
358 zassert_false(bt_gatt_service_register(&test1_svc),
359 "Test service1 registration failed");
360
361 /* Iterate attributes */
362 bt_gatt_foreach_attr(test_attrs[0].handle, 0xffff, count_attr, &num);
363 zassert_equal(num, 7, "Number of attributes don't match");
364
365 /* Iterate 1 attribute */
366 num = 0;
367 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, NULL, NULL, 1,
368 count_attr, &num);
369 zassert_equal(num, 1, "Number of attributes don't match");
370
371 /* Find attribute by UUID */
372 attr = NULL;
373 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
374 &test_chrc_uuid.uuid, NULL, 0, find_attr,
375 &attr);
376 zassert_not_null(attr, "Attribute don't match");
377 if (attr) {
378 zassert_equal(attr->uuid, &test_chrc_uuid.uuid,
379 "Attribute UUID don't match");
380 }
381
382 /* Find attribute by DATA */
383 attr = NULL;
384 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff, NULL,
385 test_value, 0, find_attr, &attr);
386 zassert_not_null(attr, "Attribute don't match");
387 if (attr) {
388 zassert_equal(attr->user_data, test_value,
389 "Attribute value don't match");
390 }
391
392 /* Find all characteristics */
393 num = 0;
394 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
395 BT_UUID_GATT_CHRC, NULL, 0, count_attr, &num);
396 zassert_equal(num, 2, "Number of attributes don't match");
397
398 /* Find 1 characteristic */
399 attr = NULL;
400 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
401 BT_UUID_GATT_CHRC, NULL, 1, find_attr, &attr);
402 zassert_not_null(attr, "Attribute don't match");
403
404 /* Find attribute by UUID and DATA */
405 attr = NULL;
406 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
407 &test1_nfy_uuid.uuid, &nfy_enabled, 1,
408 find_attr, &attr);
409 zassert_not_null(attr, "Attribute don't match");
410 if (attr) {
411 zassert_equal(attr->uuid, &test1_nfy_uuid.uuid,
412 "Attribute UUID don't match");
413 zassert_equal(attr->user_data, &nfy_enabled,
414 "Attribute value don't match");
415 }
416 }
417
ZTEST(test_gatt,test_gatt_read)418 ZTEST(test_gatt, test_gatt_read)
419 {
420 const struct bt_gatt_attr *attr;
421 uint8_t buf[256];
422 ssize_t ret;
423
424 /* Find attribute by UUID */
425 attr = NULL;
426 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
427 &test_chrc_uuid.uuid, NULL, 0, find_attr,
428 &attr);
429 zassert_not_null(attr, "Attribute don't match");
430 zassert_equal(attr->uuid, &test_chrc_uuid.uuid,
431 "Attribute UUID don't match");
432
433 ret = attr->read(NULL, attr, (void *)buf, sizeof(buf), 0);
434 zassert_equal(ret, strlen(test_value),
435 "Attribute read unexpected return");
436 zassert_mem_equal(buf, test_value, ret,
437 "Attribute read value don't match");
438 }
439
ZTEST(test_gatt,test_gatt_write)440 ZTEST(test_gatt, test_gatt_write)
441 {
442 const struct bt_gatt_attr *attr;
443 char *value = " ";
444 ssize_t ret;
445
446 /* Need our service to be registered */
447 zassert_false(bt_gatt_service_register(&test_svc),
448 "Test service registration failed");
449
450 /* Find attribute by UUID */
451 attr = NULL;
452 bt_gatt_foreach_attr_type(test_attrs[0].handle, 0xffff,
453 &test_chrc_uuid.uuid, NULL, 0, find_attr,
454 &attr);
455 zassert_not_null(attr, "Attribute don't match");
456
457 ret = attr->write(NULL, attr, (void *)value, strlen(value), 0, 0);
458 zassert_equal(ret, strlen(value), "Attribute write unexpected return");
459 zassert_mem_equal(value, test_value, ret,
460 "Attribute write value don't match");
461 }
462
ZTEST(test_gatt,test_bt_att_err_to_str)463 ZTEST(test_gatt, test_bt_att_err_to_str)
464 {
465 /* Test a couple of entries */
466 zassert_str_equal(bt_att_err_to_str(BT_ATT_ERR_SUCCESS),
467 "BT_ATT_ERR_SUCCESS");
468 zassert_str_equal(bt_att_err_to_str(BT_ATT_ERR_INSUFFICIENT_ENCRYPTION),
469 "BT_ATT_ERR_INSUFFICIENT_ENCRYPTION");
470 zassert_str_equal(bt_att_err_to_str(BT_ATT_ERR_OUT_OF_RANGE),
471 "BT_ATT_ERR_OUT_OF_RANGE");
472
473 /* Test a entries that is not used */
474 zassert_mem_equal(bt_att_err_to_str(0x14),
475 "(unknown)", strlen("(unknown)"));
476 zassert_mem_equal(bt_att_err_to_str(0xFB),
477 "(unknown)", strlen("(unknown)"));
478
479 for (uint16_t i = 0; i <= UINT8_MAX; i++) {
480 zassert_not_null(bt_att_err_to_str(i), ": %d", i);
481 }
482 }
483
ZTEST(test_gatt,test_bt_gatt_err_to_str)484 ZTEST(test_gatt, test_bt_gatt_err_to_str)
485 {
486 /* Test a couple of entries */
487 zassert_str_equal(bt_gatt_err_to_str(BT_GATT_ERR(BT_ATT_ERR_SUCCESS)),
488 "BT_ATT_ERR_SUCCESS");
489 zassert_str_equal(bt_gatt_err_to_str(BT_GATT_ERR(BT_ATT_ERR_INSUFFICIENT_ENCRYPTION)),
490 "BT_ATT_ERR_INSUFFICIENT_ENCRYPTION");
491 zassert_str_equal(bt_gatt_err_to_str(BT_GATT_ERR(BT_ATT_ERR_OUT_OF_RANGE)),
492 "BT_ATT_ERR_OUT_OF_RANGE");
493
494 /* Test entries that are not used */
495 zassert_mem_equal(bt_gatt_err_to_str(BT_GATT_ERR(0x14)),
496 "(unknown)", strlen("(unknown)"));
497 zassert_mem_equal(bt_gatt_err_to_str(BT_GATT_ERR(0xFB)),
498 "(unknown)", strlen("(unknown)"));
499
500 /* Test positive values */
501 for (uint16_t i = 0; i <= UINT8_MAX; i++) {
502 zassert_not_null(bt_gatt_err_to_str(i), ": %d", i);
503 }
504
505 /* Test negative values */
506 for (uint16_t i = 0; i <= UINT8_MAX; i++) {
507 zassert_not_null(bt_gatt_err_to_str(-i), ": %d", i);
508 }
509 }
510