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