1 /*
2  * Copyright (c) 2022 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/bluetooth/bluetooth.h>
8 #include <zephyr/bluetooth/l2cap.h>
9 
10 #include "babblekit/testcase.h"
11 #include "babblekit/flags.h"
12 
13 extern enum bst_result_t bst_result;
14 
15 static struct bt_conn *default_conn;
16 
17 #define PSM 0x80
18 #define DATA_SIZE 500
19 #define USER_DATA_SIZE 10
20 
21 /* Pool to allocate a buffer that is too large to send */
22 NET_BUF_POOL_DEFINE(buf_pool, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_SIZE), USER_DATA_SIZE, NULL);
23 
24 DEFINE_FLAG_STATIC(is_connected);
25 DEFINE_FLAG_STATIC(is_sent);
26 DEFINE_FLAG_STATIC(has_received);
27 DEFINE_FLAG_STATIC(chan_connected);
28 
chan_connected_cb(struct bt_l2cap_chan * l2cap_chan)29 static void chan_connected_cb(struct bt_l2cap_chan *l2cap_chan)
30 {
31 	(void)l2cap_chan;
32 
33 	SET_FLAG(chan_connected);
34 }
35 
chan_disconnected_cb(struct bt_l2cap_chan * l2cap_chan)36 static void chan_disconnected_cb(struct bt_l2cap_chan *l2cap_chan)
37 {
38 	(void)l2cap_chan;
39 
40 	UNSET_FLAG(chan_connected);
41 }
42 
alloc_buf_cb(struct bt_l2cap_chan * chan)43 struct net_buf *alloc_buf_cb(struct bt_l2cap_chan *chan)
44 {
45 	return net_buf_alloc(&buf_pool, K_NO_WAIT);
46 }
47 
chan_recv_cb(struct bt_l2cap_chan * chan,struct net_buf * buf)48 static int chan_recv_cb(struct bt_l2cap_chan *chan, struct net_buf *buf)
49 {
50 	ARG_UNUSED(chan);
51 	ARG_UNUSED(buf);
52 
53 	SET_FLAG(has_received);
54 
55 	return 0;
56 }
57 
sent_cb(struct bt_l2cap_chan * chan)58 void sent_cb(struct bt_l2cap_chan *chan)
59 {
60 	SET_FLAG(is_sent);
61 }
62 
63 static const struct bt_l2cap_chan_ops l2cap_ops = {
64 	.connected = chan_connected_cb,
65 	.disconnected = chan_disconnected_cb,
66 	.recv = chan_recv_cb,
67 	.sent = sent_cb,
68 	.alloc_buf = alloc_buf_cb,
69 };
70 
71 static struct bt_l2cap_le_chan channel;
72 
accept(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** l2cap_chan)73 static int accept(struct bt_conn *conn, struct bt_l2cap_server *server,
74 		  struct bt_l2cap_chan **l2cap_chan)
75 {
76 	channel.chan.ops = &l2cap_ops;
77 	*l2cap_chan = &channel.chan;
78 	channel.rx.mtu = DATA_SIZE;
79 
80 	return 0;
81 }
82 
83 static struct bt_l2cap_server server = {
84 	.accept = accept,
85 	.sec_level = BT_SECURITY_L1,
86 	.psm = PSM,
87 };
88 
connect_l2cap_channel(void)89 static void connect_l2cap_channel(void)
90 {
91 	struct bt_l2cap_chan *chans[] = {&channel.chan, NULL};
92 	int err;
93 
94 	channel.chan.ops = &l2cap_ops;
95 
96 	channel.rx.mtu = DATA_SIZE;
97 
98 	err = bt_l2cap_ecred_chan_connect(default_conn, chans, server.psm);
99 	if (err) {
100 		TEST_FAIL("Failed to send ecred connection request (err %d)", err);
101 	}
102 }
103 
register_l2cap_server(void)104 static void register_l2cap_server(void)
105 {
106 	int err;
107 
108 	err = bt_l2cap_server_register(&server);
109 	if (err < 0) {
110 		TEST_FAIL("Failed to get free server (err %d)");
111 		return;
112 	}
113 }
114 
connected(struct bt_conn * conn,uint8_t err)115 static void connected(struct bt_conn *conn, uint8_t err)
116 {
117 	if (err) {
118 		TEST_FAIL("Failed to connect (err %d)", err);
119 		bt_conn_unref(default_conn);
120 		default_conn = NULL;
121 		return;
122 	}
123 
124 	default_conn = bt_conn_ref(conn);
125 
126 	SET_FLAG(is_connected);
127 }
128 
disconnected(struct bt_conn * conn,uint8_t reason)129 static void disconnected(struct bt_conn *conn, uint8_t reason)
130 {
131 	if (default_conn != conn) {
132 		TEST_FAIL("Connection mismatch %p %p)", default_conn, conn);
133 		return;
134 	}
135 
136 	bt_conn_unref(default_conn);
137 	default_conn = NULL;
138 	UNSET_FLAG(is_connected);
139 }
140 
141 BT_CONN_CB_DEFINE(conn_callbacks) = {
142 	.connected = connected,
143 	.disconnected = disconnected,
144 };
145 
device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)146 static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
147 			 struct net_buf_simple *ad)
148 {
149 	struct bt_le_conn_param *param;
150 	int err;
151 
152 	err = bt_le_scan_stop();
153 	if (err) {
154 		TEST_FAIL("Failed to stop scanning (err %d)", err);
155 		return;
156 	}
157 
158 	param = BT_LE_CONN_PARAM_DEFAULT;
159 	err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, param, &default_conn);
160 	if (err) {
161 		TEST_FAIL("Failed to create connection (err %d)", err);
162 		return;
163 	}
164 }
165 
test_peripheral_main(void)166 static void test_peripheral_main(void)
167 {
168 	int err;
169 	const struct bt_data ad[] = {
170 		BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
171 	};
172 
173 	err = bt_enable(NULL);
174 	if (err != 0) {
175 		TEST_FAIL("Bluetooth init failed (err %d)", err);
176 		return;
177 	}
178 
179 	err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
180 	if (err != 0) {
181 		TEST_FAIL("Advertising failed to start (err %d)", err);
182 		return;
183 	}
184 
185 	WAIT_FOR_FLAG(is_connected);
186 
187 	register_l2cap_server();
188 
189 	if (!IS_ENABLED(CONFIG_NO_RUNTIME_CHECKS)) {
190 		TEST_PASS("Peripheral done");
191 		return;
192 	}
193 
194 	WAIT_FOR_FLAG(has_received);
195 
196 	/* /\* Wait until we get the credits *\/ */
197 	/* k_sleep(K_MSEC(100)); */
198 
199 	err = bt_conn_disconnect(default_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
200 	if (err) {
201 		TEST_FAIL("Failed to disconnect (err %d)", err);
202 		return;
203 	}
204 
205 	TEST_PASS("Test passed");
206 }
207 
208 #define FILL	       0xAA
209 
print_user_data(struct net_buf * buf)210 static void print_user_data(struct net_buf *buf)
211 {
212 	for (int i = 0; i < buf->user_data_size; i++) {
213 		printk("%02X", buf->user_data[i]);
214 	}
215 	printk("\n");
216 }
217 
test_central_main(void)218 static void test_central_main(void)
219 {
220 	struct net_buf *buf;
221 	int err;
222 	bool has_checks = !IS_ENABLED(CONFIG_NO_RUNTIME_CHECKS);
223 
224 	printk("##################\n");
225 	printk("(%s-checks) Starting test\n",
226 	       has_checks ? "Enabled" : "Disabled");
227 
228 	err = bt_enable(NULL);
229 	if (err != 0) {
230 		TEST_FAIL("Bluetooth discover failed (err %d)", err);
231 	}
232 
233 	err = bt_le_scan_start(BT_LE_SCAN_PASSIVE, device_found);
234 	if (err != 0) {
235 		TEST_FAIL("Scanning failed to start (err %d)", err);
236 	}
237 
238 	WAIT_FOR_FLAG(is_connected);
239 
240 	connect_l2cap_channel();
241 	WAIT_FOR_FLAG(chan_connected);
242 
243 	buf = net_buf_alloc(&buf_pool, K_NO_WAIT);
244 	if (!buf) {
245 		TEST_FAIL("Buffer allcation failed");
246 	}
247 
248 	net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
249 
250 	(void)net_buf_add(buf, DATA_SIZE);
251 	/* Fill the user data with a non-zero pattern */
252 	(void)memset(buf->user_data, FILL, buf->user_data_size);
253 
254 	printk("Buffer user_data before\n");
255 	print_user_data(buf);
256 
257 	/* Send the buffer. We don't care that the other side receives it.
258 	 * Only about when we will get called.
259 	 */
260 	err = bt_l2cap_chan_send(&channel.chan, buf);
261 
262 	/* L2CAP will take our `buf` with non-null user_data. We verify that:
263 	 * - it is cleared
264 	 * - we don't segfault later (e.g. in `tx_notify`)
265 	 */
266 
267 	if (err != 0) {
268 		TEST_FAIL("Got error %d", err);
269 	}
270 
271 	WAIT_FOR_FLAG(is_sent);
272 
273 	printk("Buffer user_data after (should've been cleared)\n");
274 	print_user_data(buf);
275 
276 	printk("\n");
277 
278 	/* Validate that the user data has changed */
279 	for (int i = 0; i < USER_DATA_SIZE; i++) {
280 		if (buf->user_data[i] == FILL) {
281 			TEST_FAIL("Buffer user data should be reset by stack.");
282 		}
283 	}
284 
285 	TEST_PASS("(Disabled-checks) Test passed");
286 }
287 
288 static const struct bst_test_instance test_def[] = {
289 	{
290 		.test_id = "peripheral",
291 		.test_descr = "Peripheral",
292 		.test_main_f = test_peripheral_main,
293 	},
294 	{
295 		.test_id = "central",
296 		.test_descr = "Central",
297 		.test_main_f = test_central_main,
298 	},
299 	BSTEST_END_MARKER,
300 };
301 
test_main_l2cap_ecred_install(struct bst_test_list * tests)302 struct bst_test_list *test_main_l2cap_ecred_install(struct bst_test_list *tests)
303 {
304 	return bst_add_tests(tests, test_def);
305 }
306