2012-02-20 23:11:26 +08:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* BlueZ - Bluetooth protocol stack for Linux
|
|
|
|
*
|
2014-02-12 02:59:14 +08:00
|
|
|
* Copyright (C) 2011-2014 Intel Corporation
|
|
|
|
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
|
2012-02-20 23:11:26 +08:00
|
|
|
*
|
|
|
|
*
|
2014-02-12 02:59:14 +08:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
2012-02-20 23:11:26 +08:00
|
|
|
*
|
2014-02-12 02:59:14 +08:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
2012-02-20 23:11:26 +08:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2014-02-12 02:59:14 +08:00
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2012-02-20 23:11:26 +08:00
|
|
|
*
|
2014-02-12 02:59:14 +08:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2012-02-20 23:11:26 +08:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-12-07 18:46:04 +08:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2012-02-20 23:11:26 +08:00
|
|
|
#include <stdio.h>
|
2012-11-05 00:47:27 +08:00
|
|
|
#include <ctype.h>
|
2012-02-20 23:11:26 +08:00
|
|
|
#include <stdlib.h>
|
2012-11-05 00:47:27 +08:00
|
|
|
#include <string.h>
|
2012-03-02 08:56:59 +08:00
|
|
|
#include <getopt.h>
|
2017-10-04 14:23:03 +08:00
|
|
|
#include <sys/un.h>
|
2012-02-20 23:11:26 +08:00
|
|
|
|
2015-02-12 18:32:07 +08:00
|
|
|
#include "src/shared/mainloop.h"
|
2016-04-28 02:06:54 +08:00
|
|
|
#include "src/shared/tty.h"
|
2015-02-12 18:32:07 +08:00
|
|
|
|
2012-02-27 16:55:34 +08:00
|
|
|
#include "packet.h"
|
2014-01-08 16:53:22 +08:00
|
|
|
#include "lmp.h"
|
2014-02-17 16:21:59 +08:00
|
|
|
#include "keys.h"
|
2014-01-07 04:47:55 +08:00
|
|
|
#include "analyze.h"
|
2014-01-04 14:43:05 +08:00
|
|
|
#include "ellisys.h"
|
2012-02-27 16:55:34 +08:00
|
|
|
#include "control.h"
|
2012-02-20 23:11:26 +08:00
|
|
|
|
2012-02-28 02:35:31 +08:00
|
|
|
static void signal_callback(int signum, void *user_data)
|
|
|
|
{
|
|
|
|
switch (signum) {
|
|
|
|
case SIGINT:
|
|
|
|
case SIGTERM:
|
|
|
|
mainloop_quit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-27 10:00:36 +08:00
|
|
|
static void usage(void)
|
|
|
|
{
|
|
|
|
printf("btmon - Bluetooth monitor\n"
|
|
|
|
"Usage:\n");
|
|
|
|
printf("\tbtmon [options]\n");
|
|
|
|
printf("options:\n"
|
2012-11-01 09:28:41 +08:00
|
|
|
"\t-r, --read <file> Read traces in btsnoop format\n"
|
2012-10-31 11:03:06 +08:00
|
|
|
"\t-w, --write <file> Save traces in btsnoop format\n"
|
2014-01-07 04:47:55 +08:00
|
|
|
"\t-a, --analyze <file> Analyze traces in btsnoop format\n"
|
2012-10-31 11:03:06 +08:00
|
|
|
"\t-s, --server <socket> Start monitor server socket\n"
|
2015-11-08 10:48:21 +08:00
|
|
|
"\t-p, --priority <level> Show only priority or lower\n"
|
2012-11-05 00:47:27 +08:00
|
|
|
"\t-i, --index <num> Show only specified controller\n"
|
2016-04-22 20:36:14 +08:00
|
|
|
"\t-d, --tty <tty> Read data from TTY\n"
|
2016-04-22 20:56:09 +08:00
|
|
|
"\t-B, --tty-speed <rate> Set TTY speed (default 115200)\n"
|
2012-11-05 00:02:40 +08:00
|
|
|
"\t-t, --time Show time instead of time offset\n"
|
|
|
|
"\t-T, --date Show time and date information\n"
|
2013-04-17 23:03:42 +08:00
|
|
|
"\t-S, --sco Dump SCO traffic\n"
|
2017-04-25 19:56:34 +08:00
|
|
|
"\t-A, --a2dp Dump A2DP stream traffic\n"
|
2014-01-04 14:43:05 +08:00
|
|
|
"\t-E, --ellisys [ip] Send Ellisys HCI Injection\n"
|
2012-10-31 11:03:06 +08:00
|
|
|
"\t-h, --help Show help options\n");
|
2012-04-27 10:00:36 +08:00
|
|
|
}
|
|
|
|
|
2012-03-02 08:56:59 +08:00
|
|
|
static const struct option main_options[] = {
|
2016-04-21 22:09:48 +08:00
|
|
|
{ "tty", required_argument, NULL, 'd' },
|
2016-04-22 20:56:09 +08:00
|
|
|
{ "tty-speed", required_argument, NULL, 'B' },
|
2012-11-01 09:28:41 +08:00
|
|
|
{ "read", required_argument, NULL, 'r' },
|
2012-11-05 00:47:27 +08:00
|
|
|
{ "write", required_argument, NULL, 'w' },
|
2014-01-07 04:47:55 +08:00
|
|
|
{ "analyze", required_argument, NULL, 'a' },
|
2012-11-05 00:47:27 +08:00
|
|
|
{ "server", required_argument, NULL, 's' },
|
2015-11-08 14:48:00 +08:00
|
|
|
{ "priority",required_argument, NULL, 'p' },
|
2012-11-05 00:47:27 +08:00
|
|
|
{ "index", required_argument, NULL, 'i' },
|
2012-11-05 00:02:40 +08:00
|
|
|
{ "time", no_argument, NULL, 't' },
|
|
|
|
{ "date", no_argument, NULL, 'T' },
|
2013-04-17 23:03:42 +08:00
|
|
|
{ "sco", no_argument, NULL, 'S' },
|
2017-04-25 19:56:34 +08:00
|
|
|
{ "a2dp", no_argument, NULL, 'A' },
|
2014-01-04 14:43:05 +08:00
|
|
|
{ "ellisys", required_argument, NULL, 'E' },
|
2013-10-21 05:27:28 +08:00
|
|
|
{ "todo", no_argument, NULL, '#' },
|
2012-10-31 11:03:06 +08:00
|
|
|
{ "version", no_argument, NULL, 'v' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
2012-03-02 08:56:59 +08:00
|
|
|
{ }
|
|
|
|
};
|
|
|
|
|
2012-02-20 23:11:26 +08:00
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
2012-02-27 16:55:34 +08:00
|
|
|
unsigned long filter_mask = 0;
|
2014-01-07 04:47:55 +08:00
|
|
|
const char *reader_path = NULL;
|
|
|
|
const char *writer_path = NULL;
|
|
|
|
const char *analyze_path = NULL;
|
2014-01-04 14:43:05 +08:00
|
|
|
const char *ellisys_server = NULL;
|
2016-04-22 20:56:09 +08:00
|
|
|
const char *tty = NULL;
|
2016-04-28 02:06:54 +08:00
|
|
|
unsigned int tty_speed = B115200;
|
2014-01-04 14:43:05 +08:00
|
|
|
unsigned short ellisys_port = 0;
|
|
|
|
const char *str;
|
2014-02-17 16:21:59 +08:00
|
|
|
int exit_status;
|
2012-02-28 02:35:31 +08:00
|
|
|
sigset_t mask;
|
2012-02-21 01:17:34 +08:00
|
|
|
|
2012-02-27 16:55:34 +08:00
|
|
|
mainloop_init();
|
2012-02-20 23:11:26 +08:00
|
|
|
|
2012-11-05 00:02:40 +08:00
|
|
|
filter_mask |= PACKET_FILTER_SHOW_TIME_OFFSET;
|
|
|
|
|
2012-03-02 08:56:59 +08:00
|
|
|
for (;;) {
|
|
|
|
int opt;
|
2017-10-04 14:23:03 +08:00
|
|
|
struct sockaddr_un addr;
|
2012-03-02 08:56:59 +08:00
|
|
|
|
2017-04-25 19:56:34 +08:00
|
|
|
opt = getopt_long(argc, argv, "d:r:w:a:s:p:i:tTSAE:vh",
|
2012-11-05 00:02:40 +08:00
|
|
|
main_options, NULL);
|
2012-03-02 08:56:59 +08:00
|
|
|
if (opt < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
switch (opt) {
|
2016-04-21 22:09:48 +08:00
|
|
|
case 'd':
|
2016-04-22 20:56:09 +08:00
|
|
|
tty= optarg;
|
|
|
|
break;
|
|
|
|
case 'B':
|
2016-04-28 02:06:54 +08:00
|
|
|
tty_speed = tty_get_speed(atoi(optarg));
|
|
|
|
if (!tty_speed) {
|
|
|
|
fprintf(stderr, "Unknown speed: %s\n", optarg);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2016-04-21 22:09:48 +08:00
|
|
|
break;
|
2012-11-01 09:28:41 +08:00
|
|
|
case 'r':
|
|
|
|
reader_path = optarg;
|
|
|
|
break;
|
2012-10-31 11:03:06 +08:00
|
|
|
case 'w':
|
2013-08-24 01:58:52 +08:00
|
|
|
writer_path = optarg;
|
2012-03-02 08:56:59 +08:00
|
|
|
break;
|
2014-01-07 04:47:55 +08:00
|
|
|
case 'a':
|
|
|
|
analyze_path = optarg;
|
|
|
|
break;
|
2012-10-31 09:57:16 +08:00
|
|
|
case 's':
|
2017-10-04 14:23:03 +08:00
|
|
|
if (strlen(optarg) > sizeof(addr.sun_path) - 1) {
|
|
|
|
fprintf(stderr, "Socket name too long\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2012-10-31 09:57:16 +08:00
|
|
|
control_server(optarg);
|
|
|
|
break;
|
2015-11-08 10:48:21 +08:00
|
|
|
case 'p':
|
|
|
|
packet_set_priority(optarg);
|
|
|
|
break;
|
2012-11-05 00:47:27 +08:00
|
|
|
case 'i':
|
|
|
|
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
|
|
|
|
str = optarg + 3;
|
|
|
|
else
|
|
|
|
str = optarg;
|
|
|
|
if (!isdigit(*str)) {
|
|
|
|
usage();
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
packet_select_index(atoi(str));
|
|
|
|
break;
|
2012-11-05 00:02:40 +08:00
|
|
|
case 't':
|
|
|
|
filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
|
|
|
|
filter_mask |= PACKET_FILTER_SHOW_TIME;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
|
|
|
|
filter_mask |= PACKET_FILTER_SHOW_TIME;
|
|
|
|
filter_mask |= PACKET_FILTER_SHOW_DATE;
|
|
|
|
break;
|
2013-04-17 23:03:42 +08:00
|
|
|
case 'S':
|
|
|
|
filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
|
|
|
|
break;
|
2017-04-25 19:56:34 +08:00
|
|
|
case 'A':
|
|
|
|
filter_mask |= PACKET_FILTER_SHOW_A2DP_STREAM;
|
|
|
|
break;
|
2014-01-04 14:43:05 +08:00
|
|
|
case 'E':
|
|
|
|
ellisys_server = optarg;
|
|
|
|
ellisys_port = 24352;
|
|
|
|
break;
|
2013-10-21 05:27:28 +08:00
|
|
|
case '#':
|
|
|
|
packet_todo();
|
2014-01-08 16:53:22 +08:00
|
|
|
lmp_todo();
|
2013-10-21 05:27:28 +08:00
|
|
|
return EXIT_SUCCESS;
|
2012-04-27 10:00:37 +08:00
|
|
|
case 'v':
|
|
|
|
printf("%s\n", VERSION);
|
|
|
|
return EXIT_SUCCESS;
|
2012-04-27 10:00:36 +08:00
|
|
|
case 'h':
|
|
|
|
usage();
|
|
|
|
return EXIT_SUCCESS;
|
2012-03-02 08:56:59 +08:00
|
|
|
default:
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-03 11:46:06 +08:00
|
|
|
if (argc - optind > 0) {
|
|
|
|
fprintf(stderr, "Invalid command line parameters\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2014-01-07 04:47:55 +08:00
|
|
|
if (reader_path && analyze_path) {
|
|
|
|
fprintf(stderr, "Display and analyze can't be combined\n");
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
|
|
|
|
2012-02-28 02:35:31 +08:00
|
|
|
sigemptyset(&mask);
|
|
|
|
sigaddset(&mask, SIGINT);
|
|
|
|
sigaddset(&mask, SIGTERM);
|
|
|
|
|
|
|
|
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
|
|
|
|
|
2012-11-05 00:02:40 +08:00
|
|
|
printf("Bluetooth monitor ver %s\n", VERSION);
|
2012-02-22 20:42:47 +08:00
|
|
|
|
2014-02-17 16:21:59 +08:00
|
|
|
keys_setup();
|
|
|
|
|
2012-02-27 16:55:34 +08:00
|
|
|
packet_set_filter(filter_mask);
|
2012-02-20 23:11:26 +08:00
|
|
|
|
2014-01-07 04:47:55 +08:00
|
|
|
if (analyze_path) {
|
|
|
|
analyze_trace(analyze_path);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2012-11-01 09:28:41 +08:00
|
|
|
if (reader_path) {
|
2014-01-04 14:43:05 +08:00
|
|
|
if (ellisys_server)
|
|
|
|
ellisys_enable(ellisys_server, ellisys_port);
|
|
|
|
|
2012-11-01 09:28:41 +08:00
|
|
|
control_reader(reader_path);
|
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-07-15 18:30:36 +08:00
|
|
|
if (writer_path && !control_writer(writer_path)) {
|
|
|
|
printf("Failed to open '%s'\n", writer_path);
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
}
|
2013-08-24 01:58:52 +08:00
|
|
|
|
2014-01-04 14:43:05 +08:00
|
|
|
if (ellisys_server)
|
|
|
|
ellisys_enable(ellisys_server, ellisys_port);
|
|
|
|
|
2016-04-29 17:11:41 +08:00
|
|
|
if (!tty && control_tracing() < 0)
|
2016-04-23 21:41:52 +08:00
|
|
|
return EXIT_FAILURE;
|
2016-04-22 20:56:09 +08:00
|
|
|
|
2016-04-29 17:11:41 +08:00
|
|
|
if (tty && control_tty(tty, tty_speed) < 0)
|
2012-11-11 00:57:00 +08:00
|
|
|
return EXIT_FAILURE;
|
2012-02-20 23:11:26 +08:00
|
|
|
|
2014-02-17 16:21:59 +08:00
|
|
|
exit_status = mainloop_run();
|
|
|
|
|
|
|
|
keys_cleanup();
|
|
|
|
|
|
|
|
return exit_status;
|
2012-02-20 23:11:26 +08:00
|
|
|
}
|