1 /** @file
2  * @brief Bluetooth BR/EDR shell module
3  *
4  * Provide some Bluetooth shell commands that can be useful to applications.
5  */
6 
7 /*
8  * Copyright (c) 2018 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 
34 #if defined(CONFIG_BT_CONN)
35 /* Connection context for BR/EDR legacy pairing in sec mode 3 */
36 static struct bt_conn *pairing_conn;
37 #endif /* CONFIG_BT_CONN */
38 
39 #define DATA_BREDR_MTU		48
40 
41 NET_BUF_POOL_FIXED_DEFINE(data_pool, 1, DATA_BREDR_MTU, 8, NULL);
42 
43 #define SDP_CLIENT_USER_BUF_LEN		512
44 NET_BUF_POOL_FIXED_DEFINE(sdp_client_pool, CONFIG_BT_MAX_CONN,
45 			  SDP_CLIENT_USER_BUF_LEN, 8, NULL);
46 
cmd_auth_pincode(const struct shell * sh,size_t argc,char * argv[])47 static int cmd_auth_pincode(const struct shell *sh,
48 			    size_t argc, char *argv[])
49 {
50 	struct bt_conn *conn;
51 	uint8_t max = 16U;
52 
53 	if (default_conn) {
54 		conn = default_conn;
55 	} else if (pairing_conn) {
56 		conn = pairing_conn;
57 	} else {
58 		conn = NULL;
59 	}
60 
61 	if (!conn) {
62 		shell_print(sh, "Not connected");
63 		return -ENOEXEC;
64 	}
65 
66 	if (strlen(argv[1]) > max) {
67 		shell_print(sh, "PIN code value invalid - enter max %u "
68 			    "digits", max);
69 		return -ENOEXEC;
70 	}
71 
72 	shell_print(sh, "PIN code \"%s\" applied", argv[1]);
73 
74 	bt_conn_auth_pincode_entry(conn, argv[1]);
75 
76 	return 0;
77 }
78 
cmd_connect(const struct shell * sh,size_t argc,char * argv[])79 static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
80 {
81 	struct bt_conn *conn;
82 	bt_addr_t addr;
83 	int err;
84 
85 	err = bt_addr_from_str(argv[1], &addr);
86 	if (err) {
87 		shell_print(sh, "Invalid peer address (err %d)", err);
88 		return -ENOEXEC;
89 	}
90 
91 	conn = bt_conn_create_br(&addr, BT_BR_CONN_PARAM_DEFAULT);
92 	if (!conn) {
93 		shell_print(sh, "Connection failed");
94 		return -ENOEXEC;
95 	}
96 
97 	shell_print(sh, "Connection pending");
98 
99 	/* unref connection obj in advance as app user */
100 	bt_conn_unref(conn);
101 
102 	return 0;
103 }
104 
br_device_found(const bt_addr_t * addr,int8_t rssi,const uint8_t cod[3],const uint8_t eir[240])105 static void br_device_found(const bt_addr_t *addr, int8_t rssi,
106 				  const uint8_t cod[3], const uint8_t eir[240])
107 {
108 	char br_addr[BT_ADDR_STR_LEN];
109 	char name[239];
110 	int len = 240;
111 
112 	(void)memset(name, 0, sizeof(name));
113 
114 	while (len) {
115 		if (len < 2) {
116 			break;
117 		}
118 
119 		/* Look for early termination */
120 		if (!eir[0]) {
121 			break;
122 		}
123 
124 		/* Check if field length is correct */
125 		if (eir[0] > len - 1) {
126 			break;
127 		}
128 
129 		switch (eir[1]) {
130 		case BT_DATA_NAME_SHORTENED:
131 		case BT_DATA_NAME_COMPLETE:
132 			if (eir[0] > sizeof(name) - 1) {
133 				memcpy(name, &eir[2], sizeof(name) - 1);
134 			} else {
135 				memcpy(name, &eir[2], eir[0] - 1);
136 			}
137 			break;
138 		default:
139 			break;
140 		}
141 
142 		/* Parse next AD Structure */
143 		len -= eir[0] + 1;
144 		eir += eir[0] + 1;
145 	}
146 
147 	bt_addr_to_str(addr, br_addr, sizeof(br_addr));
148 
149 	shell_print(ctx_shell, "[DEVICE]: %s, RSSI %i %s", br_addr, rssi, name);
150 }
151 
152 static struct bt_br_discovery_result br_discovery_results[5];
153 
br_discovery_complete(const struct bt_br_discovery_result * results,size_t count)154 static void br_discovery_complete(const struct bt_br_discovery_result *results,
155 				  size_t count)
156 {
157 	size_t i;
158 
159 	shell_print(ctx_shell, "BR/EDR discovery complete");
160 
161 	for (i = 0; i < count; i++) {
162 		br_device_found(&results[i].addr, results[i].rssi,
163 				results[i].cod, results[i].eir);
164 	}
165 }
166 
167 static struct bt_br_discovery_cb discovery_cb = {
168 	.recv = NULL,
169 	.timeout = br_discovery_complete,
170 };
171 
cmd_discovery(const struct shell * sh,size_t argc,char * argv[])172 static int cmd_discovery(const struct shell *sh, size_t argc, char *argv[])
173 {
174 	const char *action;
175 
176 	action = argv[1];
177 	if (!strcmp(action, "on")) {
178 		static bool reg_cb = true;
179 		struct bt_br_discovery_param param;
180 
181 		param.limited = false;
182 		param.length = 8U;
183 
184 		if (argc > 2) {
185 			param.length = atoi(argv[2]);
186 		}
187 
188 		if (argc > 3 && !strcmp(argv[3], "limited")) {
189 			param.limited = true;
190 		}
191 
192 		if (reg_cb) {
193 			reg_cb = false;
194 			bt_br_discovery_cb_register(&discovery_cb);
195 		}
196 
197 		if (bt_br_discovery_start(&param, br_discovery_results,
198 					  ARRAY_SIZE(br_discovery_results)) < 0) {
199 			shell_print(sh, "Failed to start discovery");
200 			return -ENOEXEC;
201 		}
202 
203 		shell_print(sh, "Discovery started");
204 	} else if (!strcmp(action, "off")) {
205 		if (bt_br_discovery_stop()) {
206 			shell_print(sh, "Failed to stop discovery");
207 			return -ENOEXEC;
208 		}
209 
210 		shell_print(sh, "Discovery stopped");
211 	} else {
212 		shell_help(sh);
213 		return SHELL_CMD_HELP_PRINTED;
214 	}
215 
216 	return 0;
217 }
218 
l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)219 static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
220 {
221 	shell_print(ctx_shell, "Incoming data channel %p len %u", chan,
222 		    buf->len);
223 
224 	return 0;
225 }
226 
l2cap_connected(struct bt_l2cap_chan * chan)227 static void l2cap_connected(struct bt_l2cap_chan *chan)
228 {
229 	shell_print(ctx_shell, "Channel %p connected", chan);
230 }
231 
l2cap_disconnected(struct bt_l2cap_chan * chan)232 static void l2cap_disconnected(struct bt_l2cap_chan *chan)
233 {
234 	shell_print(ctx_shell, "Channel %p disconnected", chan);
235 }
236 
l2cap_alloc_buf(struct bt_l2cap_chan * chan)237 static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan)
238 {
239 	shell_print(ctx_shell, "Channel %p requires buffer", chan);
240 
241 	return net_buf_alloc(&data_pool, K_FOREVER);
242 }
243 
244 static const struct bt_l2cap_chan_ops l2cap_ops = {
245 	.alloc_buf	= l2cap_alloc_buf,
246 	.recv		= l2cap_recv,
247 	.connected	= l2cap_connected,
248 	.disconnected	= l2cap_disconnected,
249 };
250 
251 static struct bt_l2cap_br_chan l2cap_chan = {
252 	.chan.ops	= &l2cap_ops,
253 	 /* Set for now min. MTU */
254 	.rx.mtu		= 48,
255 };
256 
l2cap_accept(struct bt_conn * conn,struct bt_l2cap_server * server,struct bt_l2cap_chan ** chan)257 static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_server *server,
258 			struct bt_l2cap_chan **chan)
259 {
260 	shell_print(ctx_shell, "Incoming BR/EDR conn %p", conn);
261 
262 	if (l2cap_chan.chan.conn) {
263 		shell_error(ctx_shell, "No channels available");
264 		return -ENOMEM;
265 	}
266 
267 	*chan = &l2cap_chan.chan;
268 
269 	return 0;
270 }
271 
272 static struct bt_l2cap_server br_server = {
273 	.accept = l2cap_accept,
274 };
275 
cmd_l2cap_register(const struct shell * sh,size_t argc,char * argv[])276 static int cmd_l2cap_register(const struct shell *sh,
277 			      size_t argc, char *argv[])
278 {
279 	if (br_server.psm) {
280 		shell_print(sh, "Already registered");
281 		return -ENOEXEC;
282 	}
283 
284 	br_server.psm = strtoul(argv[1], NULL, 16);
285 
286 	if (bt_l2cap_br_server_register(&br_server) < 0) {
287 		shell_error(sh, "Unable to register psm");
288 		br_server.psm = 0U;
289 		return -ENOEXEC;
290 	}
291 
292 	shell_print(sh, "L2CAP psm %u registered", br_server.psm);
293 
294 	return 0;
295 }
296 
cmd_discoverable(const struct shell * sh,size_t argc,char * argv[])297 static int cmd_discoverable(const struct shell *sh,
298 			    size_t argc, char *argv[])
299 {
300 	int err;
301 	const char *action;
302 
303 	action = argv[1];
304 
305 	if (!strcmp(action, "on")) {
306 		err = bt_br_set_discoverable(true);
307 	} else if (!strcmp(action, "off")) {
308 		err = bt_br_set_discoverable(false);
309 	} else {
310 		shell_help(sh);
311 		return SHELL_CMD_HELP_PRINTED;
312 	}
313 
314 	if (err) {
315 		shell_print(sh, "BR/EDR set/reset discoverable failed "
316 			    "(err %d)", err);
317 		return -ENOEXEC;
318 	}
319 
320 	shell_print(sh, "BR/EDR set/reset discoverable done");
321 
322 	return 0;
323 }
324 
cmd_connectable(const struct shell * sh,size_t argc,char * argv[])325 static int cmd_connectable(const struct shell *sh,
326 			   size_t argc, char *argv[])
327 {
328 	int err;
329 	const char *action;
330 
331 	action = argv[1];
332 
333 	if (!strcmp(action, "on")) {
334 		err = bt_br_set_connectable(true);
335 	} else if (!strcmp(action, "off")) {
336 		err = bt_br_set_connectable(false);
337 	} else {
338 		shell_help(sh);
339 		return SHELL_CMD_HELP_PRINTED;
340 	}
341 
342 	if (err) {
343 		shell_print(sh, "BR/EDR set/rest connectable failed "
344 			    "(err %d)", err);
345 		return -ENOEXEC;
346 	}
347 
348 	shell_print(sh, "BR/EDR set/reset connectable done");
349 
350 	return 0;
351 }
352 
cmd_oob(const struct shell * sh,size_t argc,char * argv[])353 static int cmd_oob(const struct shell *sh, size_t argc, char *argv[])
354 {
355 	char addr[BT_ADDR_STR_LEN];
356 	struct bt_br_oob oob;
357 	int err;
358 
359 	err = bt_br_oob_get_local(&oob);
360 	if (err) {
361 		shell_print(sh, "BR/EDR OOB data failed");
362 		return -ENOEXEC;
363 	}
364 
365 	bt_addr_to_str(&oob.addr, addr, sizeof(addr));
366 
367 	shell_print(sh, "BR/EDR OOB data:");
368 	shell_print(sh, "  addr %s", addr);
369 	return 0;
370 }
371 
sdp_hfp_ag_user(struct bt_conn * conn,struct bt_sdp_client_result * result,const struct bt_sdp_discover_params * params)372 static uint8_t sdp_hfp_ag_user(struct bt_conn *conn,
373 			       struct bt_sdp_client_result *result,
374 			       const struct bt_sdp_discover_params *params)
375 {
376 	char addr[BT_ADDR_STR_LEN];
377 	uint16_t param, version;
378 	uint16_t features;
379 	int err;
380 
381 	conn_addr_str(conn, addr, sizeof(addr));
382 
383 	if (result && result->resp_buf) {
384 		shell_print(ctx_shell, "SDP HFPAG data@%p (len %u) hint %u from"
385 			    " remote %s", result->resp_buf,
386 			    result->resp_buf->len, result->next_record_hint,
387 			    addr);
388 
389 		/*
390 		 * Focus to get BT_SDP_ATTR_PROTO_DESC_LIST attribute item to
391 		 * get HFPAG Server Channel Number operating on RFCOMM protocol.
392 		 */
393 		err = bt_sdp_get_proto_param(result->resp_buf,
394 					     BT_SDP_PROTO_RFCOMM, &param);
395 		if (err < 0) {
396 			shell_error(ctx_shell, "Error getting Server CN, "
397 				    "err %d", err);
398 			goto done;
399 		}
400 		shell_print(ctx_shell, "HFPAG Server CN param 0x%04x", param);
401 
402 		err = bt_sdp_get_profile_version(result->resp_buf,
403 						 BT_SDP_HANDSFREE_SVCLASS,
404 						 &version);
405 		if (err < 0) {
406 			shell_error(ctx_shell, "Error getting profile version, "
407 				    "err %d", err);
408 			goto done;
409 		}
410 		shell_print(ctx_shell, "HFP version param 0x%04x", version);
411 
412 		/*
413 		 * Focus to get BT_SDP_ATTR_SUPPORTED_FEATURES attribute item to
414 		 * get profile Supported Features mask.
415 		 */
416 		err = bt_sdp_get_features(result->resp_buf, &features);
417 		if (err < 0) {
418 			shell_error(ctx_shell, "Error getting HFPAG Features, "
419 				    "err %d", err);
420 			goto done;
421 		}
422 		shell_print(ctx_shell, "HFPAG Supported Features param 0x%04x",
423 		      features);
424 	} else {
425 		shell_print(ctx_shell, "No SDP HFPAG data from remote %s",
426 			    addr);
427 	}
428 done:
429 	return BT_SDP_DISCOVER_UUID_CONTINUE;
430 }
431 
sdp_a2src_user(struct bt_conn * conn,struct bt_sdp_client_result * result,const struct bt_sdp_discover_params * params)432 static uint8_t sdp_a2src_user(struct bt_conn *conn,
433 			      struct bt_sdp_client_result *result,
434 			      const struct bt_sdp_discover_params *params)
435 {
436 	char addr[BT_ADDR_STR_LEN];
437 	uint16_t param, version;
438 	uint16_t features;
439 	int err;
440 
441 	conn_addr_str(conn, addr, sizeof(addr));
442 
443 	if (result && result->resp_buf) {
444 		shell_print(ctx_shell, "SDP A2SRC data@%p (len %u) hint %u from"
445 			    " remote %s", result->resp_buf,
446 			    result->resp_buf->len, result->next_record_hint,
447 			    addr);
448 
449 		/*
450 		 * Focus to get BT_SDP_ATTR_PROTO_DESC_LIST attribute item to
451 		 * get A2SRC Server PSM Number.
452 		 */
453 		err = bt_sdp_get_proto_param(result->resp_buf,
454 					     BT_SDP_PROTO_L2CAP, &param);
455 		if (err < 0) {
456 			shell_error(ctx_shell, "A2SRC PSM Number not found, "
457 				    "err %d", err);
458 			goto done;
459 		}
460 
461 		shell_print(ctx_shell, "A2SRC Server PSM Number param 0x%04x",
462 			    param);
463 
464 		/*
465 		 * Focus to get BT_SDP_ATTR_PROFILE_DESC_LIST attribute item to
466 		 * get profile version number.
467 		 */
468 		err = bt_sdp_get_profile_version(result->resp_buf,
469 						 BT_SDP_ADVANCED_AUDIO_SVCLASS,
470 						 &version);
471 		if (err < 0) {
472 			shell_error(ctx_shell, "A2SRC version not found, "
473 				    "err %d", err);
474 			goto done;
475 		}
476 		shell_print(ctx_shell, "A2SRC version param 0x%04x", version);
477 
478 		/*
479 		 * Focus to get BT_SDP_ATTR_SUPPORTED_FEATURES attribute item to
480 		 * get profile supported features mask.
481 		 */
482 		err = bt_sdp_get_features(result->resp_buf, &features);
483 		if (err < 0) {
484 			shell_error(ctx_shell, "A2SRC Features not found, "
485 				    "err %d", err);
486 			goto done;
487 		}
488 		shell_print(ctx_shell, "A2SRC Supported Features param 0x%04x",
489 		      features);
490 	} else {
491 		shell_print(ctx_shell, "No SDP A2SRC data from remote %s",
492 			    addr);
493 	}
494 done:
495 	return BT_SDP_DISCOVER_UUID_CONTINUE;
496 }
497 
498 static struct bt_sdp_discover_params discov_hfpag = {
499 	.type = BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
500 	.uuid = BT_UUID_DECLARE_16(BT_SDP_HANDSFREE_AGW_SVCLASS),
501 	.func = sdp_hfp_ag_user,
502 	.pool = &sdp_client_pool,
503 };
504 
505 static struct bt_sdp_discover_params discov_a2src = {
506 	.type = BT_SDP_DISCOVER_SERVICE_SEARCH_ATTR,
507 	.uuid = BT_UUID_DECLARE_16(BT_SDP_AUDIO_SOURCE_SVCLASS),
508 	.func = sdp_a2src_user,
509 	.pool = &sdp_client_pool,
510 };
511 
512 static struct bt_sdp_discover_params discov;
513 
cmd_sdp_find_record(const struct shell * sh,size_t argc,char * argv[])514 static int cmd_sdp_find_record(const struct shell *sh,
515 			       size_t argc, char *argv[])
516 {
517 	int err;
518 	const char *action;
519 
520 	if (!default_conn) {
521 		shell_print(sh, "Not connected");
522 		return -ENOEXEC;
523 	}
524 
525 	action = argv[1];
526 
527 	if (!strcmp(action, "HFPAG")) {
528 		discov = discov_hfpag;
529 	} else if (!strcmp(action, "A2SRC")) {
530 		discov = discov_a2src;
531 	} else {
532 		shell_help(sh);
533 		return SHELL_CMD_HELP_PRINTED;
534 	}
535 
536 	shell_print(sh, "SDP UUID \'%s\' gets applied", action);
537 
538 	err = bt_sdp_discover(default_conn, &discov);
539 	if (err) {
540 		shell_error(sh, "SDP discovery failed: err %d", err);
541 		return -ENOEXEC;
542 	}
543 
544 	shell_print(sh, "SDP discovery started");
545 
546 	return 0;
547 }
548 
549 #define HELP_NONE "[none]"
550 #define HELP_ADDR_LE "<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>"
551 
552 SHELL_STATIC_SUBCMD_SET_CREATE(br_cmds,
553 	SHELL_CMD_ARG(auth-pincode, NULL, "<pincode>", cmd_auth_pincode, 2, 0),
554 	SHELL_CMD_ARG(connect, NULL, "<address>", cmd_connect, 2, 0),
555 	SHELL_CMD_ARG(discovery, NULL,
556 		      "<value: on, off> [length: 1-48] [mode: limited]",
557 		      cmd_discovery, 2, 2),
558 	SHELL_CMD_ARG(iscan, NULL, "<value: on, off>", cmd_discoverable, 2, 0),
559 	SHELL_CMD_ARG(l2cap-register, NULL, "<psm>", cmd_l2cap_register, 2, 0),
560 	SHELL_CMD_ARG(oob, NULL, NULL, cmd_oob, 1, 0),
561 	SHELL_CMD_ARG(pscan, NULL, "<value: on, off>", cmd_connectable, 2, 0),
562 	SHELL_CMD_ARG(sdp-find, NULL, "<HFPAG>", cmd_sdp_find_record, 2, 0),
563 	SHELL_SUBCMD_SET_END
564 );
565 
cmd_br(const struct shell * sh,size_t argc,char ** argv)566 static int cmd_br(const struct shell *sh, size_t argc, char **argv)
567 {
568 	if (argc == 1) {
569 		shell_help(sh);
570 		return SHELL_CMD_HELP_PRINTED;
571 	}
572 
573 	shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
574 
575 	return -ENOEXEC;
576 }
577 
578 SHELL_CMD_ARG_REGISTER(br, &br_cmds, "Bluetooth BR/EDR shell commands", cmd_br,
579 		       1, 1);
580