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/rfcomm.h>
28 #include <zephyr/bluetooth/sdp.h>
29 
30 #include <zephyr/shell/shell.h>
31 
32 #include "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 0;
64 	}
65 
66 	if (strlen(argv[1]) > max) {
67 		shell_print(sh, "PIN code value invalid - enter max %u "
68 			    "digits", max);
69 		return 0;
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 	} else {
95 
96 		shell_print(sh, "Connection pending");
97 
98 		/* unref connection obj in advance as app user */
99 		bt_conn_unref(conn);
100 	}
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(struct bt_br_discovery_result * results,size_t count)154 static void br_discovery_complete(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 
cmd_discovery(const struct shell * sh,size_t argc,char * argv[])167 static int cmd_discovery(const struct shell *sh, size_t argc, char *argv[])
168 {
169 	const char *action;
170 
171 	action = argv[1];
172 	if (!strcmp(action, "on")) {
173 		struct bt_br_discovery_param param;
174 
175 		param.limited = false;
176 		param.length = 8U;
177 
178 		if (argc > 2) {
179 			param.length = atoi(argv[2]);
180 		}
181 
182 		if (argc > 3 && !strcmp(argv[3], "limited")) {
183 			param.limited = true;
184 		}
185 
186 		if (bt_br_discovery_start(&param, br_discovery_results,
187 					  ARRAY_SIZE(br_discovery_results),
188 					  br_discovery_complete) < 0) {
189 			shell_print(sh, "Failed to start discovery");
190 			return 0;
191 		}
192 
193 		shell_print(sh, "Discovery started");
194 	} else if (!strcmp(action, "off")) {
195 		if (bt_br_discovery_stop()) {
196 			shell_print(sh, "Failed to stop discovery");
197 			return 0;
198 		}
199 
200 		shell_print(sh, "Discovery stopped");
201 	} else {
202 		shell_help(sh);
203 	}
204 
205 	return 0;
206 }
207 
l2cap_recv(struct bt_l2cap_chan * chan,struct net_buf * buf)208 static int l2cap_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
209 {
210 	shell_print(ctx_shell, "Incoming data channel %p len %u", chan,
211 		    buf->len);
212 
213 	return 0;
214 }
215 
l2cap_connected(struct bt_l2cap_chan * chan)216 static void l2cap_connected(struct bt_l2cap_chan *chan)
217 {
218 	shell_print(ctx_shell, "Channel %p connected", chan);
219 }
220 
l2cap_disconnected(struct bt_l2cap_chan * chan)221 static void l2cap_disconnected(struct bt_l2cap_chan *chan)
222 {
223 	shell_print(ctx_shell, "Channel %p disconnected", chan);
224 }
225 
l2cap_alloc_buf(struct bt_l2cap_chan * chan)226 static struct net_buf *l2cap_alloc_buf(struct bt_l2cap_chan *chan)
227 {
228 	shell_print(ctx_shell, "Channel %p requires buffer", chan);
229 
230 	return net_buf_alloc(&data_pool, K_FOREVER);
231 }
232 
233 static const struct bt_l2cap_chan_ops l2cap_ops = {
234 	.alloc_buf	= l2cap_alloc_buf,
235 	.recv		= l2cap_recv,
236 	.connected	= l2cap_connected,
237 	.disconnected	= l2cap_disconnected,
238 };
239 
240 static struct bt_l2cap_br_chan l2cap_chan = {
241 	.chan.ops	= &l2cap_ops,
242 	 /* Set for now min. MTU */
243 	.rx.mtu		= 48,
244 };
245 
l2cap_accept(struct bt_conn * conn,struct bt_l2cap_chan ** chan)246 static int l2cap_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
247 {
248 	shell_print(ctx_shell, "Incoming BR/EDR conn %p", conn);
249 
250 	if (l2cap_chan.chan.conn) {
251 		shell_error(ctx_shell, "No channels available");
252 		return -ENOMEM;
253 	}
254 
255 	*chan = &l2cap_chan.chan;
256 
257 	return 0;
258 }
259 
260 static struct bt_l2cap_server br_server = {
261 	.accept = l2cap_accept,
262 };
263 
cmd_l2cap_register(const struct shell * sh,size_t argc,char * argv[])264 static int cmd_l2cap_register(const struct shell *sh,
265 			      size_t argc, char *argv[])
266 {
267 	if (br_server.psm) {
268 		shell_print(sh, "Already registered");
269 		return 0;
270 	}
271 
272 	br_server.psm = strtoul(argv[1], NULL, 16);
273 
274 	if (bt_l2cap_br_server_register(&br_server) < 0) {
275 		shell_error(sh, "Unable to register psm");
276 		br_server.psm = 0U;
277 		return -ENOEXEC;
278 	} else {
279 		shell_print(sh, "L2CAP psm %u registered", br_server.psm);
280 	}
281 
282 	return 0;
283 }
284 
cmd_discoverable(const struct shell * sh,size_t argc,char * argv[])285 static int cmd_discoverable(const struct shell *sh,
286 			    size_t argc, char *argv[])
287 {
288 	int err;
289 	const char *action;
290 
291 	action = argv[1];
292 
293 	if (!strcmp(action, "on")) {
294 		err = bt_br_set_discoverable(true);
295 	} else if (!strcmp(action, "off")) {
296 		err = bt_br_set_discoverable(false);
297 	} else {
298 		shell_help(sh);
299 		return 0;
300 	}
301 
302 	if (err) {
303 		shell_print(sh, "BR/EDR set/reset discoverable failed "
304 			    "(err %d)", err);
305 		return -ENOEXEC;
306 	} else {
307 		shell_print(sh, "BR/EDR set/reset discoverable done");
308 	}
309 
310 	return 0;
311 }
312 
cmd_connectable(const struct shell * sh,size_t argc,char * argv[])313 static int cmd_connectable(const struct shell *sh,
314 			   size_t argc, char *argv[])
315 {
316 	int err;
317 	const char *action;
318 
319 	action = argv[1];
320 
321 	if (!strcmp(action, "on")) {
322 		err = bt_br_set_connectable(true);
323 	} else if (!strcmp(action, "off")) {
324 		err = bt_br_set_connectable(false);
325 	} else {
326 		shell_help(sh);
327 		return 0;
328 	}
329 
330 	if (err) {
331 		shell_print(sh, "BR/EDR set/rest connectable failed "
332 			    "(err %d)", err);
333 		return -ENOEXEC;
334 	} else {
335 		shell_print(sh, "BR/EDR set/reset connectable done");
336 	}
337 
338 	return 0;
339 }
340 
cmd_oob(const struct shell * sh,size_t argc,char * argv[])341 static int cmd_oob(const struct shell *sh, size_t argc, char *argv[])
342 {
343 	char addr[BT_ADDR_STR_LEN];
344 	struct bt_br_oob oob;
345 	int err;
346 
347 	err = bt_br_oob_get_local(&oob);
348 	if (err) {
349 		shell_print(sh, "BR/EDR OOB data failed");
350 		return -ENOEXEC;
351 	}
352 
353 	bt_addr_to_str(&oob.addr, addr, sizeof(addr));
354 
355 	shell_print(sh, "BR/EDR OOB data:");
356 	shell_print(sh, "  addr %s", addr);
357 	return 0;
358 }
359 
sdp_hfp_ag_user(struct bt_conn * conn,struct bt_sdp_client_result * result)360 static uint8_t sdp_hfp_ag_user(struct bt_conn *conn,
361 			       struct bt_sdp_client_result *result)
362 {
363 	char addr[BT_ADDR_STR_LEN];
364 	uint16_t param, version;
365 	uint16_t features;
366 	int res;
367 
368 	conn_addr_str(conn, addr, sizeof(addr));
369 
370 	if (result) {
371 		shell_print(ctx_shell, "SDP HFPAG data@%p (len %u) hint %u from"
372 			    " remote %s", result->resp_buf,
373 			    result->resp_buf->len, result->next_record_hint,
374 			    addr);
375 
376 		/*
377 		 * Focus to get BT_SDP_ATTR_PROTO_DESC_LIST attribute item to
378 		 * get HFPAG Server Channel Number operating on RFCOMM protocol.
379 		 */
380 		res = bt_sdp_get_proto_param(result->resp_buf,
381 					     BT_SDP_PROTO_RFCOMM, &param);
382 		if (res < 0) {
383 			shell_error(ctx_shell, "Error getting Server CN, "
384 				    "err %d", res);
385 			goto done;
386 		}
387 		shell_print(ctx_shell, "HFPAG Server CN param 0x%04x", param);
388 
389 		res = bt_sdp_get_profile_version(result->resp_buf,
390 						 BT_SDP_HANDSFREE_SVCLASS,
391 						 &version);
392 		if (res < 0) {
393 			shell_error(ctx_shell, "Error getting profile version, "
394 				    "err %d", res);
395 			goto done;
396 		}
397 		shell_print(ctx_shell, "HFP version param 0x%04x", version);
398 
399 		/*
400 		 * Focus to get BT_SDP_ATTR_SUPPORTED_FEATURES attribute item to
401 		 * get profile Supported Features mask.
402 		 */
403 		res = bt_sdp_get_features(result->resp_buf, &features);
404 		if (res < 0) {
405 			shell_error(ctx_shell, "Error getting HFPAG Features, "
406 				    "err %d", res);
407 			goto done;
408 		}
409 		shell_print(ctx_shell, "HFPAG Supported Features param 0x%04x",
410 		      features);
411 	} else {
412 		shell_print(ctx_shell, "No SDP HFPAG data from remote %s",
413 			    addr);
414 	}
415 done:
416 	return BT_SDP_DISCOVER_UUID_CONTINUE;
417 }
418 
sdp_a2src_user(struct bt_conn * conn,struct bt_sdp_client_result * result)419 static uint8_t sdp_a2src_user(struct bt_conn *conn,
420 			   struct bt_sdp_client_result *result)
421 {
422 	char addr[BT_ADDR_STR_LEN];
423 	uint16_t param, version;
424 	uint16_t features;
425 	int res;
426 
427 	conn_addr_str(conn, addr, sizeof(addr));
428 
429 	if (result) {
430 		shell_print(ctx_shell, "SDP A2SRC data@%p (len %u) hint %u from"
431 			    " remote %s", result->resp_buf,
432 			    result->resp_buf->len, result->next_record_hint,
433 			    addr);
434 
435 		/*
436 		 * Focus to get BT_SDP_ATTR_PROTO_DESC_LIST attribute item to
437 		 * get A2SRC Server PSM Number.
438 		 */
439 		res = bt_sdp_get_proto_param(result->resp_buf,
440 					     BT_SDP_PROTO_L2CAP, &param);
441 		if (res < 0) {
442 			shell_error(ctx_shell, "A2SRC PSM Number not found, "
443 				    "err %d", res);
444 			goto done;
445 		}
446 
447 		shell_print(ctx_shell, "A2SRC Server PSM Number param 0x%04x",
448 			    param);
449 
450 		/*
451 		 * Focus to get BT_SDP_ATTR_PROFILE_DESC_LIST attribute item to
452 		 * get profile version number.
453 		 */
454 		res = bt_sdp_get_profile_version(result->resp_buf,
455 						 BT_SDP_ADVANCED_AUDIO_SVCLASS,
456 						 &version);
457 		if (res < 0) {
458 			shell_error(ctx_shell, "A2SRC version not found, "
459 				    "err %d", res);
460 			goto done;
461 		}
462 		shell_print(ctx_shell, "A2SRC version param 0x%04x", version);
463 
464 		/*
465 		 * Focus to get BT_SDP_ATTR_SUPPORTED_FEATURES attribute item to
466 		 * get profile supported features mask.
467 		 */
468 		res = bt_sdp_get_features(result->resp_buf, &features);
469 		if (res < 0) {
470 			shell_error(ctx_shell, "A2SRC Features not found, "
471 				    "err %d", res);
472 			goto done;
473 		}
474 		shell_print(ctx_shell, "A2SRC Supported Features param 0x%04x",
475 		      features);
476 	} else {
477 		shell_print(ctx_shell, "No SDP A2SRC data from remote %s",
478 			    addr);
479 	}
480 done:
481 	return BT_SDP_DISCOVER_UUID_CONTINUE;
482 }
483 
484 static struct bt_sdp_discover_params discov_hfpag = {
485 	.uuid = BT_UUID_DECLARE_16(BT_SDP_HANDSFREE_AGW_SVCLASS),
486 	.func = sdp_hfp_ag_user,
487 	.pool = &sdp_client_pool,
488 };
489 
490 static struct bt_sdp_discover_params discov_a2src = {
491 	.uuid = BT_UUID_DECLARE_16(BT_SDP_AUDIO_SOURCE_SVCLASS),
492 	.func = sdp_a2src_user,
493 	.pool = &sdp_client_pool,
494 };
495 
496 static struct bt_sdp_discover_params discov;
497 
cmd_sdp_find_record(const struct shell * sh,size_t argc,char * argv[])498 static int cmd_sdp_find_record(const struct shell *sh,
499 			       size_t argc, char *argv[])
500 {
501 	int res;
502 	const char *action;
503 
504 	if (!default_conn) {
505 		shell_print(sh, "Not connected");
506 		return 0;
507 	}
508 
509 	action = argv[1];
510 
511 	if (!strcmp(action, "HFPAG")) {
512 		discov = discov_hfpag;
513 	} else if (!strcmp(action, "A2SRC")) {
514 		discov = discov_a2src;
515 	} else {
516 		shell_help(sh);
517 		return 0;
518 	}
519 
520 	shell_print(sh, "SDP UUID \'%s\' gets applied", action);
521 
522 	res = bt_sdp_discover(default_conn, &discov);
523 	if (res) {
524 		shell_error(sh, "SDP discovery failed: result %d", res);
525 		return -ENOEXEC;
526 	} else {
527 		shell_print(sh, "SDP discovery started");
528 	}
529 
530 	return 0;
531 }
532 
533 #define HELP_NONE "[none]"
534 #define HELP_ADDR_LE "<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>"
535 
536 SHELL_STATIC_SUBCMD_SET_CREATE(br_cmds,
537 	SHELL_CMD_ARG(auth-pincode, NULL, "<pincode>", cmd_auth_pincode, 2, 0),
538 	SHELL_CMD_ARG(connect, NULL, "<address>", cmd_connect, 2, 0),
539 	SHELL_CMD_ARG(discovery, NULL,
540 		      "<value: on, off> [length: 1-48] [mode: limited]",
541 		      cmd_discovery, 2, 2),
542 	SHELL_CMD_ARG(iscan, NULL, "<value: on, off>", cmd_discoverable, 2, 0),
543 	SHELL_CMD_ARG(l2cap-register, NULL, "<psm>", cmd_l2cap_register, 2, 0),
544 	SHELL_CMD_ARG(oob, NULL, NULL, cmd_oob, 1, 0),
545 	SHELL_CMD_ARG(pscan, NULL, "<value: on, off>", cmd_connectable, 2, 0),
546 	SHELL_CMD_ARG(sdp-find, NULL, "<HFPAG>", cmd_sdp_find_record, 2, 0),
547 	SHELL_SUBCMD_SET_END
548 );
549 
cmd_br(const struct shell * sh,size_t argc,char ** argv)550 static int cmd_br(const struct shell *sh, size_t argc, char **argv)
551 {
552 	if (argc == 1) {
553 		shell_help(sh);
554 		/* shell returns 1 when help is printed */
555 		return 1;
556 	}
557 
558 	shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
559 
560 	return -ENOEXEC;
561 }
562 
563 SHELL_CMD_ARG_REGISTER(br, &br_cmds, "Bluetooth BR/EDR shell commands", cmd_br,
564 		       1, 1);
565