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