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