1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stddef.h>
8 #include <errno.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/types.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/bluetooth/hci.h>
13 #include <zephyr/bluetooth/conn.h>
14 #include <zephyr/bluetooth/uuid.h>
15 #include <zephyr/bluetooth/gatt.h>
16
17 #include "babblekit/testcase.h"
18 #include "babblekit/flags.h"
19 #include "common.h"
20
21 extern enum bst_result_t bst_result;
22
23 DEFINE_FLAG_STATIC(flag_is_connected);
24
25 #define NUM_ITERATIONS 10
26
connected(struct bt_conn * conn,uint8_t err)27 static void connected(struct bt_conn *conn, uint8_t err)
28 {
29 char addr[BT_ADDR_LE_STR_LEN];
30
31 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
32
33 if (err != 0) {
34 TEST_FAIL("Failed to connect to %s (%u)", addr, err);
35 return;
36 }
37
38 printk("Connected to %s\n", addr);
39
40 SET_FLAG(flag_is_connected);
41 }
42
disconnected(struct bt_conn * conn,uint8_t reason)43 static void disconnected(struct bt_conn *conn, uint8_t reason)
44 {
45 char addr[BT_ADDR_LE_STR_LEN];
46
47 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
48
49 printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
50
51 UNSET_FLAG(flag_is_connected);
52 }
53
54 BT_CONN_CB_DEFINE(conn_callbacks) = {
55 .connected = connected,
56 .disconnected = disconnected,
57 };
58
59 static uint8_t chrc_data[CHRC_SIZE];
60 static uint8_t long_chrc_data[LONG_CHRC_SIZE];
61
read_test_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)62 static ssize_t read_test_chrc(struct bt_conn *conn,
63 const struct bt_gatt_attr *attr,
64 void *buf, uint16_t len, uint16_t offset)
65 {
66 return bt_gatt_attr_read(conn, attr, buf, len, offset,
67 (void *)chrc_data, sizeof(chrc_data));
68 }
69
write_test_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)70 static ssize_t write_test_chrc(struct bt_conn *conn,
71 const struct bt_gatt_attr *attr,
72 const void *buf, uint16_t len,
73 uint16_t offset, uint8_t flags)
74 {
75 printk("chrc len %u offset %u\n", len, offset);
76
77 if (len > sizeof(chrc_data)) {
78 printk("Invalid chrc length\n");
79 return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
80 } else if (offset + len > sizeof(chrc_data)) {
81 printk("Invalid chrc offset and length\n");
82 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
83 }
84
85 if (flags != 0) {
86 TEST_FAIL("Invalid flags %u", flags);
87 return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
88 }
89
90 (void)memcpy(chrc_data + offset, buf, len);
91
92 return len;
93 }
94
read_long_test_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)95 static ssize_t read_long_test_chrc(struct bt_conn *conn,
96 const struct bt_gatt_attr *attr,
97 void *buf, uint16_t len, uint16_t offset)
98 {
99 return bt_gatt_attr_read(conn, attr, buf, len, offset,
100 (void *)long_chrc_data, sizeof(long_chrc_data));
101 }
102
write_long_test_chrc(struct bt_conn * conn,const struct bt_gatt_attr * attr,const void * buf,uint16_t len,uint16_t offset,uint8_t flags)103 static ssize_t write_long_test_chrc(struct bt_conn *conn,
104 const struct bt_gatt_attr *attr,
105 const void *buf, uint16_t len,
106 uint16_t offset, uint8_t flags)
107 {
108 static uint8_t prepare_count;
109
110 printk("long_chrc len %u offset %u\n", len, offset);
111
112 if (len > sizeof(long_chrc_data)) {
113 printk("Invalid long_chrc length\n");
114 return BT_GATT_ERR(BT_ATT_ERR_INVALID_ATTRIBUTE_LEN);
115 } else if (offset + len > sizeof(long_chrc_data)) {
116 printk("Invalid long_chrc offset and length\n");
117 return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
118 }
119
120 if (flags & BT_GATT_WRITE_FLAG_PREPARE) {
121 printk("prepare_count %u\n", prepare_count++);
122 return BT_GATT_ERR(BT_ATT_ERR_SUCCESS);
123 }
124
125 (void)memcpy(long_chrc_data + offset, buf, len);
126 prepare_count = 0;
127
128 return len;
129 }
130
131 BT_GATT_SERVICE_DEFINE(test_svc,
132 BT_GATT_PRIMARY_SERVICE(TEST_SERVICE_UUID),
133 BT_GATT_CHARACTERISTIC(TEST_CHRC_UUID,
134 BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ,
135 BT_GATT_PERM_WRITE | BT_GATT_PERM_READ,
136 read_test_chrc, write_test_chrc, NULL),
137 BT_GATT_CHARACTERISTIC(TEST_LONG_CHRC_UUID,
138 BT_GATT_CHRC_WRITE | BT_GATT_CHRC_READ,
139 BT_GATT_PERM_WRITE | BT_GATT_PERM_READ | BT_GATT_PERM_PREPARE_WRITE,
140 read_long_test_chrc, write_long_test_chrc, NULL),
141 );
142
test_main(void)143 static void test_main(void)
144 {
145 int err;
146 const struct bt_data ad[] = {
147 BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR))
148 };
149
150 for (int i = 0; i < NUM_ITERATIONS; i++) {
151 err = bt_enable(NULL);
152 if (err != 0) {
153 TEST_FAIL("Bluetooth init failed (err %d)", err);
154 return;
155 }
156
157 printk("Bluetooth initialized\n");
158
159 err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
160 if (err != 0) {
161 TEST_FAIL("Advertising failed to start (err %d)", err);
162 return;
163 }
164
165 printk("Advertising successfully started\n");
166
167 WAIT_FOR_FLAG(flag_is_connected);
168
169 WAIT_FOR_FLAG_UNSET(flag_is_connected);
170
171 err = bt_disable();
172 if (err != 0) {
173 TEST_FAIL("Bluetooth disable failed (err %d)", err);
174 return;
175 }
176
177 printk("Bluetooth disabled\n");
178 }
179
180 TEST_PASS("GATT server passed");
181 }
182
183 static const struct bst_test_instance test_gatt_server[] = {
184 {
185 .test_id = "gatt_server",
186 .test_main_f = test_main
187 },
188 BSTEST_END_MARKER
189 };
190
test_gatt_server_install(struct bst_test_list * tests)191 struct bst_test_list *test_gatt_server_install(struct bst_test_list *tests)
192 {
193 return bst_add_tests(tests, test_gatt_server);
194 }
195