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