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