1 /** @file
2 * @brief Bluetooth shell module
3 *
4 * Provide some Bluetooth shell commands that can be useful to applications.
5 */
6
7 /*
8 * Copyright (c) 2017 Intel Corporation
9 *
10 * SPDX-License-Identifier: Apache-2.0
11 */
12
13 #include <errno.h>
14 #include <zephyr/types.h>
15 #include <stddef.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <zephyr/sys/byteorder.h>
19 #include <zephyr/kernel.h>
20
21 #include <zephyr/settings/settings.h>
22
23 #include <zephyr/bluetooth/hci.h>
24 #include <zephyr/bluetooth/bluetooth.h>
25 #include <zephyr/bluetooth/conn.h>
26 #include <zephyr/bluetooth/l2cap.h>
27 #include <zephyr/bluetooth/classic/rfcomm.h>
28 #include <zephyr/bluetooth/classic/sdp.h>
29
30 #include <zephyr/shell/shell.h>
31
32 #include "host/shell/bt.h"
33 #include "host/shell/bt_shell_private.h"
34
35 #define CREDITS 10
36 #define DATA_MTU (23 * CREDITS)
37
38 #define L2CAP_POLICY_NONE 0x00
39 #define L2CAP_POLICY_ALLOWLIST 0x01
40 #define L2CAP_POLICY_16BYTE_KEY 0x02
41
42 NET_BUF_POOL_FIXED_DEFINE(data_tx_pool, 1, BT_L2CAP_SDU_BUF_SIZE(DATA_MTU),
43 CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
44 NET_BUF_POOL_FIXED_DEFINE(data_rx_pool, 1, DATA_MTU, 8, NULL);
45
46 static uint8_t l2cap_policy;
47 static struct bt_conn *l2cap_allowlist[CONFIG_BT_MAX_CONN];
48
49 static uint32_t l2cap_rate;
50 static uint32_t l2cap_recv_delay_ms;
51 static K_FIFO_DEFINE(l2cap_recv_fifo);
52 struct l2ch {
53 struct k_work_delayable recv_work;
54 struct bt_l2cap_le_chan ch;
55 };
56 #define L2CH_CHAN(_chan) CONTAINER_OF(_chan, struct l2ch, ch.chan)
57 #define L2CH_WORK(_work) CONTAINER_OF(k_work_delayable_from_work(_work), \
58 struct l2ch, recv_work)
59 #define L2CAP_CHAN(_chan) _chan->ch.chan
60
61 static bool metrics;
62
l2cap_recv_metrics(struct bt_l2cap_chan * chan,struct net_buf * buf)63 static int l2cap_recv_metrics(struct bt_l2cap_chan *chan, struct net_buf *buf)
64 {
65 static uint32_t len;
66 static uint32_t cycle_stamp;
67 uint32_t delta;
68
69 delta = k_cycle_get_32() - cycle_stamp;
70 delta = (uint32_t)k_cyc_to_ns_floor64(delta);
71
72 /* if last data rx-ed was greater than 1 second in the past,
73 * reset the metrics.
74 */
75 if (delta > 1000000000) {
76 len = 0U;
77 l2cap_rate = 0U;
78 cycle_stamp = k_cycle_get_32();
79 } else {
80 len += buf->len;
81 l2cap_rate = ((uint64_t)len << 3) * 1000000000U / delta;
82 }
83
84 return 0;
85 }
86
l2cap_recv_cb(struct k_work * work)87 static void l2cap_recv_cb(struct k_work *work)
88 {
89 struct l2ch *c = L2CH_WORK(work);
90 struct net_buf *buf;
91
92 while ((buf = k_fifo_get(&l2cap_recv_fifo, K_NO_WAIT))) {
93 bt_shell_print("Confirming reception");
94 bt_l2cap_chan_recv_complete(&c->ch.chan, buf);
95 }
96 }
97
l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)98 static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
99 {
100 struct l2ch *l2ch = L2CH_CHAN(chan);
101
102 if (metrics) {
103 return l2cap_recv_metrics(chan, buf);
104 }
105
106 bt_shell_print("Incoming data channel %p len %u",
107 chan, buf->len);
108
109 if (buf->len) {
110 bt_shell_hexdump(buf->data, buf->len);
111 }
112
113 if (l2cap_recv_delay_ms > 0) {
114 /* Submit work only if queue is empty */
115 if (k_fifo_is_empty(&l2cap_recv_fifo)) {
116 bt_shell_print("Delaying response in %u ms...",
117 l2cap_recv_delay_ms);
118 }
119
120 k_fifo_put(&l2cap_recv_fifo, buf);
121 k_work_schedule(&l2ch->recv_work, K_MSEC(l2cap_recv_delay_ms));
122
123 return -EINPROGRESS;
124 }
125
126 return 0;
127 }
128
l2cap_sent(struct bt_l2cap_chan * chan)129 static void l2cap_sent(struct bt_l2cap_chan *chan)
130 {
131 bt_shell_print("Outgoing data channel %p transmitted", chan);
132 }
133
l2cap_status(struct bt_l2cap_chan * chan,atomic_t * status)134 static void l2cap_status(struct bt_l2cap_chan *chan, atomic_t *status)
135 {
136 bt_shell_print("Channel %p status %u", chan, (uint32_t)*status);
137 }
138
l2cap_connected(struct bt_l2cap_chan * chan)139 static void l2cap_connected(struct bt_l2cap_chan *chan)
140 {
141 struct l2ch *c = L2CH_CHAN(chan);
142
143 k_work_init_delayable(&c->recv_work, l2cap_recv_cb);
144
145 bt_shell_print("Channel %p connected", chan);
146 }
147
l2cap_disconnected(struct bt_l2cap_chan * chan)148 static void l2cap_disconnected(struct bt_l2cap_chan *chan)
149 {
150 bt_shell_print("Channel %p disconnected", chan);
151 }
152
l2cap_alloc_buf(struct bt_l2cap_chan * chan)153 static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan)
154 {
155 /* print if metrics is disabled */
156 if (!metrics) {
157 bt_shell_print("Channel %p requires buffer", chan);
158 }
159
160 return net_buf_alloc(&data_rx_pool, K_FOREVER);
161 }
162
163 static const struct bt_l2cap_chan_ops l2cap_ops = {
164 .alloc_buf = l2cap_alloc_buf,
165 .recv = l2cap_recv,
166 .sent = l2cap_sent,
167 .status = l2cap_status,
168 .connected = l2cap_connected,
169 .disconnected = l2cap_disconnected,
170 };
171
172 static struct l2ch l2ch_chan = {
173 .ch.chan.ops = &l2cap_ops,
174 .ch.rx.mtu = DATA_MTU,
175 };
176
l2cap_allowlist_remove(struct bt_conn * conn,uint8_t reason)177 static void l2cap_allowlist_remove(struct bt_conn *conn, uint8_t reason)
178 {
179 int i;
180
181 for (i = 0; i < ARRAY_SIZE(l2cap_allowlist); i++) {
182 if (l2cap_allowlist[i] == conn) {
183 bt_conn_unref(l2cap_allowlist[i]);
184 l2cap_allowlist[i] = NULL;
185 }
186 }
187 }
188
189 BT_CONN_CB_DEFINE(l2cap_conn_callbacks) = {
190 .disconnected = l2cap_allowlist_remove,
191 };
192
l2cap_accept_policy(struct bt_conn * conn)193 static int l2cap_accept_policy(struct bt_conn *conn)
194 {
195 int i;
196
197 if (l2cap_policy == L2CAP_POLICY_16BYTE_KEY) {
198 uint8_t enc_key_size = bt_conn_enc_key_size(conn);
199
200 if (enc_key_size && enc_key_size < BT_ENC_KEY_SIZE_MAX) {
201 return -EPERM;
202 }
203 } else if (l2cap_policy == L2CAP_POLICY_ALLOWLIST) {
204 for (i = 0; i < ARRAY_SIZE(l2cap_allowlist); i++) {
205 if (l2cap_allowlist[i] == conn) {
206 return 0;
207 }
208 }
209
210 return -EACCES;
211 }
212
213 return 0;
214 }
215
l2cap_accept(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)216 static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
217 struct bt_l2cap_chan **chan)
218 {
219 int err;
220
221 bt_shell_print("Incoming conn %p", conn);
222
223 err = l2cap_accept_policy(conn);
224 if (err < 0) {
225 return err;
226 }
227
228 if (l2ch_chan.ch.chan.conn) {
229 bt_shell_print("No channels available");
230 return -ENOMEM;
231 }
232
233 *chan = &l2ch_chan.ch.chan;
234
235 return 0;
236 }
237
238 static struct bt_l2cap_server server = {
239 .accept = l2cap_accept,
240 };
241
cmd_register(const struct shell * sh,size_t argc,char * argv[])242 static int cmd_register(const struct shell *sh, size_t argc, char *argv[])
243 {
244 const char *policy;
245
246 if (server.psm) {
247 shell_error(sh, "Already registered");
248 return -ENOEXEC;
249 }
250
251 server.psm = strtoul(argv[1], NULL, 16);
252
253 if (argc > 2) {
254 server.sec_level = strtoul(argv[2], NULL, 10);
255 }
256
257 if (argc > 3) {
258 policy = argv[3];
259
260 if (!strcmp(policy, "allowlist")) {
261 l2cap_policy = L2CAP_POLICY_ALLOWLIST;
262 } else if (!strcmp(policy, "16byte_key")) {
263 l2cap_policy = L2CAP_POLICY_16BYTE_KEY;
264 } else {
265 return -EINVAL;
266 }
267 }
268
269 if (bt_l2cap_server_register(&server) < 0) {
270 shell_error(sh, "Unable to register psm");
271 server.psm = 0U;
272 return -ENOEXEC;
273 } else {
274 shell_print(sh, "L2CAP psm %u sec_level %u registered",
275 server.psm, server.sec_level);
276 }
277
278 return 0;
279 }
280
281 #if defined(CONFIG_BT_L2CAP_ECRED)
cmd_ecred_reconfigure(const struct shell * sh,size_t argc,char * argv[])282 static int cmd_ecred_reconfigure(const struct shell *sh, size_t argc, char *argv[])
283 {
284 struct bt_l2cap_chan *l2cap_ecred_chans[] = { &l2ch_chan.ch.chan, NULL };
285 uint16_t mtu;
286 int err = 0;
287
288 if (!default_conn) {
289 shell_error(sh, "Not connected");
290 return -ENOEXEC;
291 }
292
293 if (!l2ch_chan.ch.chan.conn) {
294 shell_error(sh, "Channel not connected");
295 return -ENOEXEC;
296 }
297
298 mtu = shell_strtoul(argv[1], 10, &err);
299 if (err) {
300 shell_error(sh, "Unable to parse MTU (err %d)", err);
301
302 return -ENOEXEC;
303 }
304
305 err = bt_l2cap_ecred_chan_reconfigure(l2cap_ecred_chans, mtu);
306 if (err < 0) {
307 shell_error(sh, "Unable to reconfigure channel (err %d)", err);
308 } else {
309 shell_print(sh, "L2CAP reconfiguration pending");
310 }
311
312 return err;
313 }
314
cmd_ecred_connect(const struct shell * sh,size_t argc,char * argv[])315 static int cmd_ecred_connect(const struct shell *sh, size_t argc, char *argv[])
316 {
317 struct bt_l2cap_chan *l2cap_ecred_chans[] = { &l2ch_chan.ch.chan, NULL };
318 uint16_t psm;
319 int err = 0;
320
321 if (!default_conn) {
322 shell_error(sh, "Not connected");
323
324 return -ENOEXEC;
325 }
326
327 if (l2ch_chan.ch.chan.conn) {
328 shell_error(sh, "Channel already in use");
329
330 return -ENOEXEC;
331 }
332
333 psm = shell_strtoul(argv[1], 16, &err);
334 if (err) {
335 shell_error(sh, "Unable to parse PSM (err %d)", err);
336
337 return err;
338 }
339
340 if (argc > 2) {
341 int sec;
342
343 sec = shell_strtoul(argv[2], 10, &err);
344 if (err) {
345 shell_error(sh, "Unable to parse security level (err %d)", err);
346
347 return err;
348 }
349
350 l2ch_chan.ch.required_sec_level = sec;
351 }
352
353 err = bt_l2cap_ecred_chan_connect(default_conn, l2cap_ecred_chans, psm);
354 if (err < 0) {
355 shell_error(sh, "Unable to connect to psm %u (err %d)", psm, err);
356 } else {
357 shell_print(sh, "L2CAP connection pending");
358 }
359
360 return err;
361 }
362 #endif /* CONFIG_BT_L2CAP_ECRED */
363
cmd_connect(const struct shell * sh,size_t argc,char * argv[])364 static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
365 {
366 uint16_t psm;
367 int err;
368
369 if (!default_conn) {
370 shell_error(sh, "Not connected");
371 return -ENOEXEC;
372 }
373
374 if (l2ch_chan.ch.chan.conn) {
375 shell_error(sh, "Channel already in use");
376 return -ENOEXEC;
377 }
378
379 psm = strtoul(argv[1], NULL, 16);
380
381 if (argc > 2) {
382 int sec;
383
384 sec = *argv[2] - '0';
385
386 l2ch_chan.ch.required_sec_level = sec;
387 }
388
389 err = bt_l2cap_chan_connect(default_conn, &l2ch_chan.ch.chan, psm);
390 if (err < 0) {
391 shell_error(sh, "Unable to connect to psm %u (err %d)", psm, err);
392 } else {
393 shell_print(sh, "L2CAP connection pending");
394 }
395
396 return err;
397 }
398
cmd_disconnect(const struct shell * sh,size_t argc,char * argv[])399 static int cmd_disconnect(const struct shell *sh, size_t argc, char *argv[])
400 {
401 int err;
402
403 err = bt_l2cap_chan_disconnect(&l2ch_chan.ch.chan);
404 if (err) {
405 shell_print(sh, "Unable to disconnect: %u", -err);
406 }
407
408 return err;
409 }
410
cmd_send(const struct shell * sh,size_t argc,char * argv[])411 static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
412 {
413 static uint8_t buf_data[DATA_MTU] = { [0 ... (DATA_MTU - 1)] = 0xff };
414 int ret, len = DATA_MTU, count = 1;
415 struct net_buf *buf;
416
417 if (argc > 1) {
418 count = strtoul(argv[1], NULL, 10);
419 }
420
421 if (argc > 2) {
422 len = strtoul(argv[2], NULL, 10);
423 if (len > DATA_MTU) {
424 shell_print(sh, "Length exceeds TX MTU for the channel");
425 return -ENOEXEC;
426 }
427 }
428
429 len = MIN(l2ch_chan.ch.tx.mtu, len);
430
431 while (count--) {
432 shell_print(sh, "Rem %d", count);
433 buf = net_buf_alloc(&data_tx_pool, K_SECONDS(2));
434 if (!buf) {
435 if (l2ch_chan.ch.state != BT_L2CAP_CONNECTED) {
436 shell_print(sh, "Channel disconnected, stopping TX");
437
438 return -EAGAIN;
439 }
440 shell_print(sh, "Allocation timeout, stopping TX");
441
442 return -EAGAIN;
443 }
444 net_buf_reserve(buf, BT_L2CAP_SDU_CHAN_SEND_RESERVE);
445
446 net_buf_add_mem(buf, buf_data, len);
447 ret = bt_l2cap_chan_send(&l2ch_chan.ch.chan, buf);
448 if (ret < 0) {
449 shell_print(sh, "Unable to send: %d", -ret);
450 net_buf_unref(buf);
451 return -ENOEXEC;
452 }
453 }
454
455 return 0;
456 }
457
cmd_recv(const struct shell * sh,size_t argc,char * argv[])458 static int cmd_recv(const struct shell *sh, size_t argc, char *argv[])
459 {
460 if (argc > 1) {
461 l2cap_recv_delay_ms = strtoul(argv[1], NULL, 10);
462 } else {
463 shell_print(sh, "l2cap receive delay: %u ms",
464 l2cap_recv_delay_ms);
465 }
466
467 return 0;
468 }
469
cmd_metrics(const struct shell * sh,size_t argc,char * argv[])470 static int cmd_metrics(const struct shell *sh, size_t argc, char *argv[])
471 {
472 const char *action;
473
474 if (argc < 2) {
475 shell_print(sh, "l2cap rate: %u bps.", l2cap_rate);
476
477 return 0;
478 }
479
480 action = argv[1];
481
482 if (!strcmp(action, "on")) {
483 metrics = true;
484 } else if (!strcmp(action, "off")) {
485 metrics = false;
486 } else {
487 shell_help(sh);
488 return 0;
489 }
490
491 shell_print(sh, "l2cap metrics %s.", action);
492 return 0;
493 }
494
cmd_allowlist_add(const struct shell * sh,size_t argc,char * argv[])495 static int cmd_allowlist_add(const struct shell *sh, size_t argc, char *argv[])
496 {
497 int i;
498
499 if (!default_conn) {
500 shell_error(sh, "Not connected");
501 return 0;
502 }
503
504 for (i = 0; i < ARRAY_SIZE(l2cap_allowlist); i++) {
505 if (l2cap_allowlist[i] == NULL) {
506 l2cap_allowlist[i] = bt_conn_ref(default_conn);
507 return 0;
508 }
509 }
510
511 return -ENOMEM;
512 }
513
cmd_allowlist_remove(const struct shell * sh,size_t argc,char * argv[])514 static int cmd_allowlist_remove(const struct shell *sh, size_t argc, char *argv[])
515 {
516 if (!default_conn) {
517 shell_error(sh, "Not connected");
518 return 0;
519 }
520
521 l2cap_allowlist_remove(default_conn, 0);
522
523 return 0;
524 }
525
526 #define HELP_NONE "[none]"
527
528 SHELL_STATIC_SUBCMD_SET_CREATE(allowlist_cmds,
529 SHELL_CMD_ARG(add, NULL, HELP_NONE, cmd_allowlist_add, 1, 0),
530 SHELL_CMD_ARG(remove, NULL, HELP_NONE, cmd_allowlist_remove, 1, 0),
531 SHELL_SUBCMD_SET_END
532 );
533
534 SHELL_STATIC_SUBCMD_SET_CREATE(l2cap_cmds,
535 SHELL_CMD_ARG(connect, NULL, "<psm> [sec_level]", cmd_connect, 2, 1),
536 SHELL_CMD_ARG(disconnect, NULL, HELP_NONE, cmd_disconnect, 1, 0),
537 SHELL_CMD_ARG(metrics, NULL, "<value on, off>", cmd_metrics, 2, 0),
538 SHELL_CMD_ARG(recv, NULL, "[delay (in milliseconds)", cmd_recv, 1, 1),
539 SHELL_CMD_ARG(register, NULL, "<psm> [sec_level] "
540 "[policy: allowlist, 16byte_key]", cmd_register, 2, 2),
541 SHELL_CMD_ARG(send, NULL, "[number of packets] [length of packet(s)]",
542 cmd_send, 1, 2),
543 SHELL_CMD_ARG(allowlist, &allowlist_cmds, HELP_NONE, NULL, 1, 0),
544 #if defined(CONFIG_BT_L2CAP_ECRED)
545 SHELL_CMD_ARG(ecred-connect, NULL, "<psm (hex)> [sec_level (dec)]",
546 cmd_ecred_connect, 2, 1),
547 SHELL_CMD_ARG(ecred-reconfigure, NULL, "<mtu (dec)>",
548 cmd_ecred_reconfigure, 1, 1),
549 #endif /* CONFIG_BT_L2CAP_ECRED */
550 SHELL_SUBCMD_SET_END
551 );
552
cmd_l2cap(const struct shell * sh,size_t argc,char ** argv)553 static int cmd_l2cap(const struct shell *sh, size_t argc, char **argv)
554 {
555 if (argc == 1) {
556 shell_help(sh);
557 /* shell returns 1 when help is printed */
558 return 1;
559 }
560
561 shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
562
563 return -ENOEXEC;
564 }
565
566 SHELL_CMD_ARG_REGISTER(l2cap, &l2cap_cmds, "Bluetooth L2CAP shell commands",
567 cmd_l2cap, 1, 1);
568