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