1 /** @file
2  * @brief Bluetooth RFCOMM 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 #define DATA_MTU 48
36 
37 NET_BUF_POOL_FIXED_DEFINE(pool, 1, DATA_MTU, CONFIG_BT_CONN_TX_USER_DATA_SIZE, NULL);
38 
39 static struct bt_sdp_attribute spp_attrs[] = {
40 	BT_SDP_NEW_SERVICE,
41 	BT_SDP_LIST(
42 		BT_SDP_ATTR_SVCLASS_ID_LIST,
43 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
44 		BT_SDP_DATA_ELEM_LIST(
45 		{
46 			BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
47 			BT_SDP_ARRAY_16(BT_SDP_SERIAL_PORT_SVCLASS)
48 		},
49 		)
50 	),
51 	BT_SDP_LIST(
52 		BT_SDP_ATTR_PROTO_DESC_LIST,
53 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 12),
54 		BT_SDP_DATA_ELEM_LIST(
55 		{
56 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 3),
57 			BT_SDP_DATA_ELEM_LIST(
58 			{
59 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
60 				BT_SDP_ARRAY_16(BT_SDP_PROTO_L2CAP)
61 			},
62 			)
63 		},
64 		{
65 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 5),
66 			BT_SDP_DATA_ELEM_LIST(
67 			{
68 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
69 				BT_SDP_ARRAY_16(BT_SDP_PROTO_RFCOMM)
70 			},
71 			{
72 				BT_SDP_TYPE_SIZE(BT_SDP_UINT8),
73 				BT_SDP_ARRAY_8(BT_RFCOMM_CHAN_SPP)
74 			},
75 			)
76 		},
77 		)
78 	),
79 	BT_SDP_LIST(
80 		BT_SDP_ATTR_PROFILE_DESC_LIST,
81 		BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 8),
82 		BT_SDP_DATA_ELEM_LIST(
83 		{
84 			BT_SDP_TYPE_SIZE_VAR(BT_SDP_SEQ8, 6),
85 			BT_SDP_DATA_ELEM_LIST(
86 			{
87 				BT_SDP_TYPE_SIZE(BT_SDP_UUID16),
88 				BT_SDP_ARRAY_16(BT_SDP_SERIAL_PORT_SVCLASS)
89 			},
90 			{
91 				BT_SDP_TYPE_SIZE(BT_SDP_UINT16),
92 				BT_SDP_ARRAY_16(0x0102)
93 			},
94 			)
95 		},
96 		)
97 	),
98 	BT_SDP_SERVICE_NAME("Serial Port"),
99 };
100 
101 static struct bt_sdp_record spp_rec = BT_SDP_RECORD(spp_attrs);
102 
rfcomm_recv(struct bt_rfcomm_dlc * dlci,struct net_buf * buf)103 static void rfcomm_recv(struct bt_rfcomm_dlc *dlci, struct net_buf *buf)
104 {
105 	bt_shell_print("Incoming data dlc %p len %u", dlci, buf->len);
106 }
107 
rfcomm_connected(struct bt_rfcomm_dlc * dlci)108 static void rfcomm_connected(struct bt_rfcomm_dlc *dlci)
109 {
110 	bt_shell_print("Dlc %p connected", dlci);
111 }
112 
rfcomm_disconnected(struct bt_rfcomm_dlc * dlci)113 static void rfcomm_disconnected(struct bt_rfcomm_dlc *dlci)
114 {
115 	bt_shell_print("Dlc %p disconnected", dlci);
116 }
117 
118 static struct bt_rfcomm_dlc_ops rfcomm_ops = {
119 	.recv		= rfcomm_recv,
120 	.connected	= rfcomm_connected,
121 	.disconnected	= rfcomm_disconnected,
122 };
123 
124 static struct bt_rfcomm_dlc rfcomm_dlc = {
125 	.ops = &rfcomm_ops,
126 	.mtu = 30,
127 };
128 
rfcomm_accept(struct bt_conn * conn,struct bt_rfcomm_server * server,struct bt_rfcomm_dlc ** dlc)129 static int rfcomm_accept(struct bt_conn *conn, struct bt_rfcomm_server *server,
130 			 struct bt_rfcomm_dlc **dlc)
131 {
132 	bt_shell_print("Incoming RFCOMM conn %p", conn);
133 
134 	if (rfcomm_dlc.session) {
135 		bt_shell_error("No channels available");
136 		return -ENOMEM;
137 	}
138 
139 	*dlc = &rfcomm_dlc;
140 
141 	return 0;
142 }
143 
144 struct bt_rfcomm_server rfcomm_server = {
145 	.accept = &rfcomm_accept,
146 };
147 
cmd_register(const struct shell * sh,size_t argc,char * argv[])148 static int cmd_register(const struct shell *sh, size_t argc, char *argv[])
149 {
150 	int ret;
151 
152 	if (rfcomm_server.channel) {
153 		shell_error(sh, "Already registered");
154 		return -ENOEXEC;
155 	}
156 
157 	rfcomm_server.channel = BT_RFCOMM_CHAN_SPP;
158 
159 	ret = bt_rfcomm_server_register(&rfcomm_server);
160 	if (ret < 0) {
161 		shell_error(sh, "Unable to register channel %x", ret);
162 		rfcomm_server.channel = 0U;
163 		return -ENOEXEC;
164 	} else {
165 		shell_print(sh, "RFCOMM channel %u registered",
166 			    rfcomm_server.channel);
167 		bt_sdp_register_service(&spp_rec);
168 	}
169 
170 	return 0;
171 }
172 
cmd_connect(const struct shell * sh,size_t argc,char * argv[])173 static int cmd_connect(const struct shell *sh, size_t argc, char *argv[])
174 {
175 	uint8_t channel;
176 	int err;
177 
178 	if (!default_conn) {
179 		shell_error(sh, "Not connected");
180 		return -ENOEXEC;
181 	}
182 
183 	channel = strtoul(argv[1], NULL, 16);
184 
185 	err = bt_rfcomm_dlc_connect(default_conn, &rfcomm_dlc, channel);
186 	if (err < 0) {
187 		shell_error(sh, "Unable to connect to channel %d (err %u)",
188 			    channel, err);
189 	} else {
190 		shell_print(sh, "RFCOMM connection pending");
191 	}
192 
193 	return err;
194 }
195 
cmd_send(const struct shell * sh,size_t argc,char * argv[])196 static int cmd_send(const struct shell *sh, size_t argc, char *argv[])
197 {
198 	uint8_t buf_data[DATA_MTU] = { [0 ... (DATA_MTU - 1)] = 0xff };
199 	int ret, len, count = 1;
200 	struct net_buf *buf;
201 
202 	if (argc > 1) {
203 		count = strtoul(argv[1], NULL, 10);
204 	}
205 
206 	while (count--) {
207 		buf = bt_rfcomm_create_pdu(&pool);
208 		/* Should reserve one byte in tail for FCS */
209 		len = MIN(rfcomm_dlc.mtu, net_buf_tailroom(buf) - 1);
210 
211 		net_buf_add_mem(buf, buf_data, len);
212 		ret = bt_rfcomm_dlc_send(&rfcomm_dlc, buf);
213 		if (ret < 0) {
214 			shell_error(sh, "Unable to send: %d", -ret);
215 			net_buf_unref(buf);
216 			return -ENOEXEC;
217 		}
218 	}
219 
220 	return 0;
221 }
222 
cmd_disconnect(const struct shell * sh,size_t argc,char * argv[])223 static int cmd_disconnect(const struct shell *sh, size_t argc, char *argv[])
224 {
225 	int err;
226 
227 	err = bt_rfcomm_dlc_disconnect(&rfcomm_dlc);
228 	if (err) {
229 		shell_error(sh, "Unable to disconnect: %u", -err);
230 	}
231 
232 	return err;
233 }
234 
cmd_send_rpn(const struct shell * sh,size_t argc,char * argv[])235 static int cmd_send_rpn(const struct shell *sh, size_t argc, char *argv[])
236 {
237 	int err;
238 	struct bt_rfcomm_rpn rpn;
239 
240 	if (!rfcomm_dlc.session) {
241 		shell_error(sh, "Not connected");
242 		return -ENOEXEC;
243 	}
244 
245 	/* Initialize RPN with default values */
246 	memset(&rpn, 0, sizeof(rpn));
247 
248 	/* Set default values for RPN parameters */
249 	rpn.baud_rate = BT_RFCOMM_RPN_BAUD_RATE_9600;
250 	rpn.line_settings = BT_RFCOMM_SET_LINE_SETTINGS(
251 		BT_RFCOMM_RPN_DATA_BITS_8,
252 		BT_RFCOMM_RPN_STOP_BITS_1,
253 		BT_RFCOMM_RPN_PARITY_NONE);
254 	rpn.flow_control = BT_RFCOMM_RPN_FLOW_NONE;
255 	rpn.xon_char = BT_RFCOMM_RPN_XON_CHAR;
256 	rpn.xoff_char = BT_RFCOMM_RPN_XOFF_CHAR;
257 	rpn.param_mask = BT_RFCOMM_RPN_PARAM_MASK_ALL;
258 
259 	shell_print(sh, "Sending RFCOMM RPN command with default settings");
260 
261 	err = bt_rfcomm_send_rpn_cmd(&rfcomm_dlc, &rpn);
262 	if (err < 0) {
263 		shell_error(sh, "Unable to send RPN command: %d", err);
264 		return -ENOEXEC;
265 	}
266 
267 	shell_print(sh, "RFCOMM RPN command sent successfully");
268 	return 0;
269 }
270 
271 #define HELP_NONE "[none]"
272 #define HELP_ADDR_LE "<address: XX:XX:XX:XX:XX:XX> <type: (public|random)>"
273 
274 SHELL_STATIC_SUBCMD_SET_CREATE(rfcomm_cmds,
275 	SHELL_CMD_ARG(register, NULL, HELP_NONE, cmd_register, 1, 0),
276 	SHELL_CMD_ARG(connect, NULL, "<channel>", cmd_connect, 2, 0),
277 	SHELL_CMD_ARG(disconnect, NULL, HELP_NONE, cmd_disconnect, 1, 0),
278 	SHELL_CMD_ARG(send, NULL, "<number of packets>", cmd_send, 2, 0),
279 	SHELL_CMD_ARG(rpn, NULL, "Send RPN command with default settings", cmd_send_rpn, 1, 0),
280 	SHELL_SUBCMD_SET_END
281 );
282 
cmd_rfcomm(const struct shell * sh,size_t argc,char ** argv)283 static int cmd_rfcomm(const struct shell *sh, size_t argc, char **argv)
284 {
285 	if (argc == 1) {
286 		shell_help(sh);
287 		/* shell returns 1 when help is printed */
288 		return 1;
289 	}
290 
291 	shell_error(sh, "%s unknown parameter: %s", argv[0], argv[1]);
292 
293 	return -ENOEXEC;
294 }
295 
296 SHELL_CMD_ARG_REGISTER(rfcomm, &rfcomm_cmds, "Bluetooth RFCOMM shell commands",
297 		       cmd_rfcomm, 1, 1);
298