device: Set disconnect timer to zero for fast disconnection
[platform/upstream/bluez.git] / monitor / main.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2011-2014  Intel Corporation
7  *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
8  *
9  *
10  */
11
12 #ifdef HAVE_CONFIG_H
13 #include <config.h>
14 #endif
15
16 #include <stdio.h>
17 #include <ctype.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <getopt.h>
21 #include <sys/un.h>
22
23 #include "src/shared/mainloop.h"
24 #include "src/shared/tty.h"
25
26 #include "packet.h"
27 #include "lmp.h"
28 #include "keys.h"
29 #include "analyze.h"
30 #include "ellisys.h"
31 #include "control.h"
32 #include "display.h"
33
34 static void signal_callback(int signum, void *user_data)
35 {
36         switch (signum) {
37         case SIGINT:
38         case SIGTERM:
39                 mainloop_quit();
40                 break;
41         }
42 }
43
44 static void usage(void)
45 {
46         printf("btmon - Bluetooth monitor\n"
47                 "Usage:\n");
48         printf("\tbtmon [options]\n");
49         printf("options:\n"
50                 "\t-r, --read <file>      Read traces in btsnoop format\n"
51                 "\t-w, --write <file>     Save traces in btsnoop format\n"
52                 "\t-a, --analyze <file>   Analyze traces in btsnoop format\n"
53                 "\t                       If gnuplot is installed on the\n"
54                 "\t                       system it will also attempt to plot\n"
55                 "\t                       packet latency graph.\n"
56                 "\t-s, --server <socket>  Start monitor server socket\n"
57                 "\t-p, --priority <level> Show only priority or lower\n"
58                 "\t-i, --index <num>      Show only specified controller\n"
59                 "\t-d, --tty <tty>        Read data from TTY\n"
60                 "\t-B, --tty-speed <rate> Set TTY speed (default 115200)\n"
61                 "\t-V, --vendor <compid>  Set default company identifier\n"
62                 "\t-M, --mgmt             Open channel for mgmt events\n"
63                 "\t-t, --time             Show time instead of time offset\n"
64                 "\t-T, --date             Show time and date information\n"
65                 "\t-S, --sco              Dump SCO traffic\n"
66                 "\t-A, --a2dp             Dump A2DP stream traffic\n"
67                 "\t-I, --iso              Dump ISO traffic\n"
68                 "\t-E, --ellisys [ip]     Send Ellisys HCI Injection\n"
69                 "\t-P, --no-pager         Disable pager usage\n"
70                 "\t-J  --jlink <device>,[<serialno>],[<interface>],[<speed>]\n"
71                 "\t                       Read data from RTT\n"
72                 "\t-R  --rtt [<address>],[<area>],[<name>]\n"
73                 "\t                       RTT control block parameters\n"
74 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
75                 "\t-C, --count <num>      Save traces by <num> rotation\n"
76                 "\t-W, --size <num>       Save traces at most <num> size\n"
77 #else
78                 "\t-C, --columns [width]  Output width if not a terminal\n"
79 #endif
80                 "\t-c, --color [mode]     Output color: auto/always/never\n"
81                 "\t-h, --help             Show help options\n");
82 }
83
84 static const struct option main_options[] = {
85         { "read",      required_argument, NULL, 'r' },
86         { "write",     required_argument, NULL, 'w' },
87         { "analyze",   required_argument, NULL, 'a' },
88         { "server",    required_argument, NULL, 's' },
89         { "priority",  required_argument, NULL, 'p' },
90         { "index",     required_argument, NULL, 'i' },
91         { "tty",       required_argument, NULL, 'd' },
92         { "tty-speed", required_argument, NULL, 'B' },
93         { "vendor",    required_argument, NULL, 'V' },
94         { "mgmt",      no_argument,       NULL, 'M' },
95         { "no-time",   no_argument,       NULL, 'N' },
96         { "time",      no_argument,       NULL, 't' },
97         { "date",      no_argument,       NULL, 'T' },
98         { "sco",       no_argument,       NULL, 'S' },
99         { "a2dp",      no_argument,       NULL, 'A' },
100         { "iso",       no_argument,       NULL, 'I' },
101         { "ellisys",   required_argument, NULL, 'E' },
102 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
103         { "count",   required_argument, NULL, 'C' },
104         { "size",    required_argument, NULL, 'W' },
105 #endif
106         { "no-pager",  no_argument,       NULL, 'P' },
107         { "jlink",     required_argument, NULL, 'J' },
108         { "rtt",       required_argument, NULL, 'R' },
109 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
110         { "columns",   required_argument, NULL, 'C' },
111 #endif
112         { "color",     required_argument, NULL, 'c' },
113         { "todo",      no_argument,       NULL, '#' },
114         { "version",   no_argument,       NULL, 'v' },
115         { "help",      no_argument,       NULL, 'h' },
116         { }
117 };
118
119 int main(int argc, char *argv[])
120 {
121         unsigned long filter_mask = 0;
122         bool use_pager = true;
123         const char *reader_path = NULL;
124         const char *writer_path = NULL;
125         const char *analyze_path = NULL;
126         const char *ellisys_server = NULL;
127         const char *tty = NULL;
128         unsigned int tty_speed = B115200;
129         unsigned short ellisys_port = 0;
130 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
131         int16_t rotate_count = -1;
132         ssize_t file_size = -1;
133 #endif
134         const char *str;
135         char *jlink = NULL;
136         char *rtt = NULL;
137         int exit_status;
138
139         mainloop_init();
140
141         filter_mask |= PACKET_FILTER_SHOW_TIME_OFFSET;
142
143         for (;;) {
144                 int opt;
145                 struct sockaddr_un addr;
146
147 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
148                 opt = getopt_long(argc, argv, "d:r:w:a:s:p:i:tTSE:C:W:vh",
149                                                 main_options, NULL);
150 #else
151                 opt = getopt_long(argc, argv,
152                                 "r:w:a:s:p:i:d:B:V:MNtTSAIE:PJ:R:C:c:vh",
153                                                 main_options, NULL);
154 #endif
155                 if (opt < 0)
156                         break;
157
158                 switch (opt) {
159                 case 'r':
160                         reader_path = optarg;
161                         break;
162                 case 'w':
163                         writer_path = optarg;
164                         break;
165                 case 'a':
166                         analyze_path = optarg;
167                         break;
168                 case 's':
169                         if (strlen(optarg) > sizeof(addr.sun_path) - 1) {
170                                 fprintf(stderr, "Socket name too long\n");
171                                 return EXIT_FAILURE;
172                         }
173                         control_server(optarg);
174                         break;
175                 case 'p':
176                         packet_set_priority(optarg);
177                         break;
178                 case 'i':
179                         if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
180                                 str = optarg + 3;
181                         else
182                                 str = optarg;
183                         if (!isdigit(*str)) {
184                                 usage();
185                                 return EXIT_FAILURE;
186                         }
187                         packet_select_index(atoi(str));
188                         break;
189                 case 'd':
190                         tty = optarg;
191                         break;
192                 case 'B':
193                         tty_speed = tty_get_speed(atoi(optarg));
194                         if (!tty_speed) {
195                                 fprintf(stderr, "Unknown speed: %s\n", optarg);
196                                 return EXIT_FAILURE;
197                         }
198                         break;
199                 case 'V':
200                         str = optarg;
201                         packet_set_fallback_manufacturer(atoi(str));
202                         break;
203                 case 'M':
204                         filter_mask |= PACKET_FILTER_SHOW_MGMT_SOCKET;
205                         break;
206                 case 'N':
207                         filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
208                         break;
209                 case 't':
210                         filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
211                         filter_mask |= PACKET_FILTER_SHOW_TIME;
212                         break;
213                 case 'T':
214                         filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
215                         filter_mask |= PACKET_FILTER_SHOW_TIME;
216                         filter_mask |= PACKET_FILTER_SHOW_DATE;
217                         break;
218                 case 'S':
219                         filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
220                         break;
221                 case 'A':
222                         filter_mask |= PACKET_FILTER_SHOW_A2DP_STREAM;
223                         break;
224                 case 'I':
225                         filter_mask |= PACKET_FILTER_SHOW_ISO_DATA;
226                         break;
227                 case 'E':
228                         ellisys_server = optarg;
229                         ellisys_port = 24352;
230                         break;
231                 case 'P':
232                         use_pager = false;
233                         break;
234 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
235                 case 'C':
236                         rotate_count = atoi(optarg);
237                         break;
238                 case 'W':
239                         file_size = atoll(optarg);
240                         break;
241 #endif
242                 case 'J':
243                         jlink = optarg;
244                         break;
245                 case 'R':
246                         rtt = optarg;
247                         break;
248 #ifndef TIZEN_FEATURE_BLUEZ_MODIFY
249                 case 'C':
250                         set_default_pager_num_columns(atoi(optarg));
251                         break;
252 #endif
253                 case 'c':
254                         if (strcmp("always", optarg) == 0)
255                                 set_monitor_color(COLOR_ALWAYS);
256                         else if (strcmp("never", optarg) == 0)
257                                 set_monitor_color(COLOR_NEVER);
258                         else if (strcmp("auto", optarg) == 0)
259                                 set_monitor_color(COLOR_AUTO);
260                         else {
261                                 fprintf(stderr, "Color option must be one of "
262                                                 "auto/always/never\n");
263                                 return EXIT_FAILURE;
264                         }
265                         break;
266                 case '#':
267                         packet_todo();
268                         lmp_todo();
269                         return EXIT_SUCCESS;
270                 case 'v':
271                         printf("%s\n", VERSION);
272                         return EXIT_SUCCESS;
273                 case 'h':
274                         usage();
275                         return EXIT_SUCCESS;
276                 default:
277                         return EXIT_FAILURE;
278                 }
279         }
280
281         if (argc - optind > 0) {
282                 fprintf(stderr, "Invalid command line parameters\n");
283                 return EXIT_FAILURE;
284         }
285
286         if (reader_path && analyze_path) {
287                 fprintf(stderr, "Display and analyze can't be combined\n");
288                 return EXIT_FAILURE;
289         }
290
291         printf("Bluetooth monitor ver %s\n", VERSION);
292
293         keys_setup();
294
295         packet_set_filter(filter_mask);
296
297         if (analyze_path) {
298                 analyze_trace(analyze_path);
299                 return EXIT_SUCCESS;
300         }
301
302         if (reader_path) {
303                 if (ellisys_server)
304                         ellisys_enable(ellisys_server, ellisys_port);
305
306                 control_reader(reader_path, use_pager);
307                 return EXIT_SUCCESS;
308         }
309
310 #ifdef TIZEN_FEATURE_BLUEZ_MODIFY
311         if (writer_path && !control_writer(writer_path,
312                                 rotate_count, file_size)) {
313                 printf("Failed to open '%s'\n", writer_path);
314                 return EXIT_FAILURE;
315         }
316 #else
317         if (writer_path && !control_writer(writer_path)) {
318                 printf("Failed to open '%s'\n", writer_path);
319                 return EXIT_FAILURE;
320         }
321 #endif
322
323         if (ellisys_server)
324                 ellisys_enable(ellisys_server, ellisys_port);
325
326         if (!tty && !jlink && control_tracing() < 0)
327                 return EXIT_FAILURE;
328
329         if (tty && control_tty(tty, tty_speed) < 0)
330                 return EXIT_FAILURE;
331
332         if (jlink && control_rtt(jlink, rtt) < 0)
333                 return EXIT_FAILURE;
334
335         exit_status = mainloop_run_with_signal(signal_callback, NULL);
336
337         keys_cleanup();
338
339         return exit_status;
340 }