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