1 /*
2 * Copyright (c) 2022 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/bluetooth/bluetooth.h>
8 #include <zephyr/bluetooth/gatt.h>
9
10 #include "common.h"
11
12 CREATE_FLAG(flag_is_connected);
13 CREATE_FLAG(flag_discover_complete);
14 CREATE_FLAG(flag_security_changed);
15 CREATE_FLAG(flag_write_complete);
16 CREATE_FLAG(flag_read_complete);
17
18 static struct bt_conn *g_conn;
19 static uint16_t chrc_handle;
20 static uint16_t long_chrc_handle;
21 static uint16_t enc_chrc_handle;
22 static uint16_t lesc_chrc_handle;
23 static uint8_t att_err;
24 static const struct bt_uuid *test_svc_uuid = TEST_SERVICE_UUID;
25
26 #define ARRAY_ITEM(i, _) i
27 static uint8_t chrc_data[] = { LISTIFY(CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */
28 static uint8_t long_chrc_data[] = { LISTIFY(LONG_CHRC_SIZE, ARRAY_ITEM, (,)) }; /* 1, 2, 3 ... */
29 static uint8_t data_received[LONG_CHRC_SIZE];
30 static uint16_t data_received_size;
31
connected(struct bt_conn * conn,uint8_t err)32 static void connected(struct bt_conn *conn, uint8_t err)
33 {
34 char addr[BT_ADDR_LE_STR_LEN];
35
36 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
37
38 if (err != 0) {
39 FAIL("Failed to connect to %s (%u)\n", addr, err);
40 return;
41 }
42
43 printk("Connected to %s\n", addr);
44
45 __ASSERT_NO_MSG(g_conn == conn);
46
47 SET_FLAG(flag_is_connected);
48 }
49
disconnected(struct bt_conn * conn,uint8_t reason)50 static void disconnected(struct bt_conn *conn, uint8_t reason)
51 {
52 char addr[BT_ADDR_LE_STR_LEN];
53
54 if (conn != g_conn) {
55 return;
56 }
57
58 bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
59
60 printk("Disconnected: %s (reason 0x%02x)\n", addr, reason);
61
62 bt_conn_unref(g_conn);
63
64 g_conn = NULL;
65 UNSET_FLAG(flag_is_connected);
66 }
67
security_changed(struct bt_conn * conn,bt_security_t level,enum bt_security_err err)68 static void security_changed(struct bt_conn *conn, bt_security_t level, enum bt_security_err err)
69 {
70 if (err != BT_SECURITY_ERR_SUCCESS) {
71 FAIL("Security failed (err %d)\n", err);
72 } else {
73 SET_FLAG(flag_security_changed);
74 }
75 }
76
77 static struct bt_conn_cb conn_callbacks = {
78 .connected = connected,
79 .disconnected = disconnected,
80 .security_changed = security_changed,
81 };
82
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)83 void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
84 struct net_buf_simple *ad)
85 {
86 char addr_str[BT_ADDR_LE_STR_LEN];
87 int err;
88
89 if (g_conn != NULL) {
90 return;
91 }
92
93 /* We're only interested in connectable events */
94 if (type != BT_HCI_ADV_IND && type != BT_HCI_ADV_DIRECT_IND) {
95 return;
96 }
97
98 bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
99 printk("Device found: %s (RSSI %d)\n", addr_str, rssi);
100
101 printk("Stopping scan\n");
102 err = bt_le_scan_stop();
103 if (err != 0) {
104 FAIL("Could not stop scan: %d\n");
105 return;
106 }
107
108 err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
109 BT_LE_CONN_PARAM_DEFAULT, &g_conn);
110 if (err != 0) {
111 FAIL("Could not connect to peer: %d\n", err);
112 }
113 }
114
discover_func(struct bt_conn * conn,const struct bt_gatt_attr * attr,struct bt_gatt_discover_params * params)115 static uint8_t discover_func(struct bt_conn *conn,
116 const struct bt_gatt_attr *attr,
117 struct bt_gatt_discover_params *params)
118 {
119 int err;
120
121 if (attr == NULL) {
122 if (chrc_handle == 0 || long_chrc_handle == 0) {
123 FAIL("Did not discover chrc (%x) or long_chrc (%x)\n", chrc_handle,
124 long_chrc_handle);
125 }
126
127 (void)memset(params, 0, sizeof(*params));
128
129 SET_FLAG(flag_discover_complete);
130
131 return BT_GATT_ITER_STOP;
132 }
133
134 printk("[ATTRIBUTE] handle %u\n", attr->handle);
135
136 if (params->type == BT_GATT_DISCOVER_PRIMARY &&
137 bt_uuid_cmp(params->uuid, TEST_SERVICE_UUID) == 0) {
138 printk("Found test service\n");
139 params->uuid = NULL;
140 params->start_handle = attr->handle + 1;
141 params->type = BT_GATT_DISCOVER_CHARACTERISTIC;
142
143 err = bt_gatt_discover(conn, params);
144 if (err != 0) {
145 FAIL("Discover failed (err %d)\n", err);
146 }
147
148 return BT_GATT_ITER_STOP;
149 } else if (params->type == BT_GATT_DISCOVER_CHARACTERISTIC) {
150 struct bt_gatt_chrc *chrc = (struct bt_gatt_chrc *)attr->user_data;
151
152 if (bt_uuid_cmp(chrc->uuid, TEST_CHRC_UUID) == 0) {
153 printk("Found chrc\n");
154 chrc_handle = chrc->value_handle;
155 } else if (bt_uuid_cmp(chrc->uuid, TEST_LONG_CHRC_UUID) == 0) {
156 printk("Found long_chrc\n");
157 long_chrc_handle = chrc->value_handle;
158 } else if (bt_uuid_cmp(chrc->uuid, TEST_ENC_CHRC_UUID) == 0) {
159 printk("Found enc_chrc_handle\n");
160 enc_chrc_handle = chrc->value_handle;
161 } else if (bt_uuid_cmp(chrc->uuid, TEST_LESC_CHRC_UUID) == 0) {
162 printk("Found lesc_chrc_handle\n");
163 lesc_chrc_handle = chrc->value_handle;
164 }
165 }
166
167 return BT_GATT_ITER_CONTINUE;
168 }
169
gatt_discover(void)170 static void gatt_discover(void)
171 {
172 static struct bt_gatt_discover_params discover_params;
173 int err;
174
175 printk("Discovering services and characteristics\n");
176
177 discover_params.uuid = test_svc_uuid;
178 discover_params.func = discover_func;
179 discover_params.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
180 discover_params.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
181 discover_params.type = BT_GATT_DISCOVER_PRIMARY;
182
183 err = bt_gatt_discover(g_conn, &discover_params);
184 if (err != 0) {
185 FAIL("Discover failed(err %d)\n", err);
186 }
187
188 WAIT_FOR_FLAG(flag_discover_complete);
189 printk("Discover complete\n");
190 }
191
update_security(void)192 static void update_security(void)
193 {
194 int err;
195
196 printk("Updating security\n");
197 err = bt_conn_set_security(g_conn, BT_SECURITY_L2);
198 if (err != 0) {
199 FAIL("Set security failed (err %d)\n", err);
200 }
201
202 WAIT_FOR_FLAG(flag_security_changed);
203 printk("Security changed\n");
204 }
205
gatt_write_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_write_params * params)206 static void gatt_write_cb(struct bt_conn *conn, uint8_t err, struct bt_gatt_write_params *params)
207 {
208 (void)memset(params, 0, sizeof(*params));
209 att_err = err;
210
211 SET_FLAG(flag_write_complete);
212 }
213
gatt_write(uint16_t handle,uint8_t expect_att_err)214 static void gatt_write(uint16_t handle, uint8_t expect_att_err)
215 {
216 static struct bt_gatt_write_params write_params;
217 int err;
218
219 if (handle == chrc_handle) {
220 printk("Writing to chrc and expecting 0x%02X\n", expect_att_err);
221 write_params.data = chrc_data;
222 write_params.length = sizeof(chrc_data);
223 } else if (handle == long_chrc_handle) {
224 printk("Writing to long_chrc and expecting 0x%02X\n", expect_att_err);
225 write_params.data = long_chrc_data;
226 write_params.length = sizeof(long_chrc_data);
227 } else if (handle == enc_chrc_handle) {
228 printk("Writing to enc_chrc and expecting 0x%02X\n", expect_att_err);
229 write_params.data = chrc_data;
230 write_params.length = sizeof(chrc_data);
231 } else if (handle == lesc_chrc_handle) {
232 printk("Writing to lesc_chrc and expecting 0x%02X\n", expect_att_err);
233 write_params.data = chrc_data;
234 write_params.length = sizeof(chrc_data);
235 }
236
237 write_params.func = gatt_write_cb;
238 write_params.handle = handle;
239
240 UNSET_FLAG(flag_write_complete);
241
242 err = bt_gatt_write(g_conn, &write_params);
243 if (err != 0) {
244 FAIL("bt_gatt_write failed: %d\n", err);
245 }
246
247 WAIT_FOR_FLAG(flag_write_complete);
248
249 if (att_err != expect_att_err) {
250 FAIL("Write failed: 0x%02X\n", att_err);
251 }
252
253 printk("success\n");
254 }
255
gatt_read_cb(struct bt_conn * conn,uint8_t err,struct bt_gatt_read_params * params,const void * data,uint16_t length)256 static uint8_t gatt_read_cb(struct bt_conn *conn, uint8_t err,
257 struct bt_gatt_read_params *params,
258 const void *data, uint16_t length)
259 {
260 att_err = err;
261
262 if (err != BT_ATT_ERR_SUCCESS) {
263 printk("Read failed: 0x%02X\n", err);
264
265 (void)memset(params, 0, sizeof(*params));
266 SET_FLAG(flag_read_complete);
267
268 return BT_GATT_ITER_STOP;
269 }
270
271 if (data != NULL) {
272 if (data_received_size + length > sizeof(data_received)) {
273 FAIL("Invalid amount of data received: %u\n", data_received_size + length);
274 } else {
275 memcpy(&data_received[data_received_size], data, length);
276 data_received_size += length;
277 }
278
279 return BT_GATT_ITER_CONTINUE;
280 }
281
282 if (params->single.handle == chrc_handle) {
283 if (data_received_size != CHRC_SIZE ||
284 memcmp(data_received, chrc_data, data_received_size) != 0) {
285 FAIL("chrc data different than expected (%u %u)\n", length, CHRC_SIZE);
286 }
287 } else if (params->single.handle == long_chrc_handle) {
288 if (data_received_size != LONG_CHRC_SIZE ||
289 memcmp(data_received, long_chrc_data, data_received_size) != 0) {
290 FAIL("long_chrc data different than expected (%u %u)\n", length,
291 LONG_CHRC_SIZE);
292 }
293 } else if (params->single.handle == enc_chrc_handle) {
294 if (data_received_size != CHRC_SIZE ||
295 memcmp(data_received, chrc_data, data_received_size) != 0) {
296 FAIL("enc_chrc data different than expected (%u %u)\n", length, CHRC_SIZE);
297 }
298 } else if (params->single.handle == lesc_chrc_handle) {
299 if (data_received_size != CHRC_SIZE ||
300 memcmp(data_received, chrc_data, data_received_size) != 0) {
301 FAIL("lesc_chrc data different than expected (%u %u)\n", length, CHRC_SIZE);
302 }
303 }
304
305 (void)memset(params, 0, sizeof(*params));
306 SET_FLAG(flag_read_complete);
307
308 return BT_GATT_ITER_STOP;
309 }
310
gatt_read(uint16_t handle,uint8_t expect_att_err)311 static void gatt_read(uint16_t handle, uint8_t expect_att_err)
312 {
313 static struct bt_gatt_read_params read_params;
314 int err;
315
316 data_received_size = 0;
317 memset(data_received, 0, sizeof(data_received));
318
319 if (handle == chrc_handle) {
320 printk("Reading chrc and expecting 0x%02X\n", expect_att_err);
321 } else if (handle == long_chrc_handle) {
322 printk("Reading long_chrc and expecting 0x%02X\n", expect_att_err);
323 } else if (handle == enc_chrc_handle) {
324 printk("Reading enc_chrc and expecting 0x%02X\n", expect_att_err);
325 } else if (handle == lesc_chrc_handle) {
326 printk("Reading lesc_chrc and expecting 0x%02X\n", expect_att_err);
327 }
328
329 read_params.func = gatt_read_cb;
330 read_params.handle_count = 1;
331 read_params.single.handle = handle;
332 read_params.single.offset = 0;
333
334 UNSET_FLAG(flag_read_complete);
335
336 err = bt_gatt_read(g_conn, &read_params);
337 if (err != 0) {
338 FAIL("bt_gatt_read failed: %d\n", err);
339 }
340
341 WAIT_FOR_FLAG(flag_read_complete);
342
343 if (att_err != expect_att_err) {
344 FAIL("Read failed: 0x%02X\n", att_err);
345 }
346
347 printk("success\n");
348 }
349
test_main(void)350 static void test_main(void)
351 {
352 int err;
353
354 bt_conn_cb_register(&conn_callbacks);
355
356 err = bt_enable(NULL);
357 if (err != 0) {
358 FAIL("Bluetooth discover failed (err %d)\n", err);
359 }
360
361 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
362 if (err != 0) {
363 FAIL("Scanning failed to start (err %d)\n", err);
364 }
365
366 printk("Scanning successfully started\n");
367
368 WAIT_FOR_FLAG(flag_is_connected);
369
370 gatt_discover();
371
372 /* Write and read a few times to ensure stateless behavior */
373 for (size_t i = 0; i < 3; i++) {
374 gatt_write(chrc_handle, BT_ATT_ERR_SUCCESS);
375 gatt_read(chrc_handle, BT_ATT_ERR_SUCCESS);
376 gatt_write(long_chrc_handle, BT_ATT_ERR_SUCCESS);
377 gatt_read(long_chrc_handle, BT_ATT_ERR_SUCCESS);
378 }
379
380 gatt_write(enc_chrc_handle, BT_ATT_ERR_AUTHENTICATION);
381 gatt_read(enc_chrc_handle, BT_ATT_ERR_AUTHENTICATION);
382 gatt_write(lesc_chrc_handle, BT_ATT_ERR_AUTHENTICATION);
383 gatt_read(lesc_chrc_handle, BT_ATT_ERR_AUTHENTICATION);
384
385 update_security();
386
387 gatt_write(enc_chrc_handle, BT_ATT_ERR_SUCCESS);
388 gatt_read(enc_chrc_handle, BT_ATT_ERR_SUCCESS);
389 gatt_write(lesc_chrc_handle, BT_ATT_ERR_SUCCESS);
390 gatt_read(lesc_chrc_handle, BT_ATT_ERR_SUCCESS);
391
392 PASS("GATT client Passed\n");
393 }
394
395 static const struct bst_test_instance test_vcs[] = {
396 {
397 .test_id = "gatt_client",
398 .test_pre_init_f = test_init,
399 .test_tick_f = test_tick,
400 .test_main_f = test_main
401 },
402 BSTEST_END_MARKER
403 };
404
test_gatt_client_install(struct bst_test_list * tests)405 struct bst_test_list *test_gatt_client_install(struct bst_test_list *tests)
406 {
407 return bst_add_tests(tests, test_vcs);
408 }
409