main.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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. #ifdef HAVE_CONFIG_H
  12. #include <config.h>
  13. #endif
  14. #define _GNU_SOURCE
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <getopt.h>
  20. #include <sys/un.h>
  21. #include "src/shared/mainloop.h"
  22. #include "src/shared/tty.h"
  23. #include "packet.h"
  24. #include "lmp.h"
  25. #include "keys.h"
  26. #include "analyze.h"
  27. #include "ellisys.h"
  28. #include "control.h"
  29. #include "display.h"
  30. static void signal_callback(int signum, void *user_data)
  31. {
  32. switch (signum) {
  33. case SIGINT:
  34. case SIGTERM:
  35. mainloop_quit();
  36. break;
  37. }
  38. }
  39. static void usage(void)
  40. {
  41. printf("btmon - Bluetooth monitor\n"
  42. "Usage:\n");
  43. printf("\tbtmon [options]\n");
  44. printf("options:\n"
  45. "\t-r, --read <file> Read traces in btsnoop format\n"
  46. "\t-w, --write <file> Save traces in btsnoop format\n"
  47. "\t-a, --analyze <file> Analyze traces in btsnoop format\n"
  48. "\t-s, --server <socket> Start monitor server socket\n"
  49. "\t-p, --priority <level> Show only priority or lower\n"
  50. "\t-i, --index <num> Show only specified controller\n"
  51. "\t-d, --tty <tty> Read data from TTY\n"
  52. "\t-B, --tty-speed <rate> Set TTY speed (default 115200)\n"
  53. "\t-V, --vendor <compid> Set default company identifier\n"
  54. "\t-M, --mgmt Open channel for mgmt events\n"
  55. "\t-t, --time Show time instead of time offset\n"
  56. "\t-T, --date Show time and date information\n"
  57. "\t-S, --sco Dump SCO traffic\n"
  58. "\t-A, --a2dp Dump A2DP stream traffic\n"
  59. "\t-E, --ellisys [ip] Send Ellisys HCI Injection\n"
  60. "\t-P, --no-pager Disable pager usage\n"
  61. "\t-J --jlink <device>,[<serialno>],[<interface>],[<speed>]\n"
  62. "\t Read data from RTT\n"
  63. "\t-R --rtt [<address>],[<area>],[<name>]\n"
  64. "\t RTT control block parameters\n"
  65. "\t-C, --columns [width] Output width if not a terminal\n"
  66. "\t-c, --color [mode] Output color: auto/always/never\n"
  67. "\t-h, --help Show help options\n");
  68. }
  69. static const struct option main_options[] = {
  70. { "read", required_argument, NULL, 'r' },
  71. { "write", required_argument, NULL, 'w' },
  72. { "analyze", required_argument, NULL, 'a' },
  73. { "server", required_argument, NULL, 's' },
  74. { "priority", required_argument, NULL, 'p' },
  75. { "index", required_argument, NULL, 'i' },
  76. { "tty", required_argument, NULL, 'd' },
  77. { "tty-speed", required_argument, NULL, 'B' },
  78. { "vendor", required_argument, NULL, 'V' },
  79. { "mgmt", no_argument, NULL, 'M' },
  80. { "no-time", no_argument, NULL, 'N' },
  81. { "time", no_argument, NULL, 't' },
  82. { "date", no_argument, NULL, 'T' },
  83. { "sco", no_argument, NULL, 'S' },
  84. { "a2dp", no_argument, NULL, 'A' },
  85. { "ellisys", required_argument, NULL, 'E' },
  86. { "no-pager", no_argument, NULL, 'P' },
  87. { "jlink", required_argument, NULL, 'J' },
  88. { "rtt", required_argument, NULL, 'R' },
  89. { "columns", required_argument, NULL, 'C' },
  90. { "color", required_argument, NULL, 'c' },
  91. { "todo", no_argument, NULL, '#' },
  92. { "version", no_argument, NULL, 'v' },
  93. { "help", no_argument, NULL, 'h' },
  94. { }
  95. };
  96. int main(int argc, char *argv[])
  97. {
  98. unsigned long filter_mask = 0;
  99. bool use_pager = true;
  100. const char *reader_path = NULL;
  101. const char *writer_path = NULL;
  102. const char *analyze_path = NULL;
  103. const char *ellisys_server = NULL;
  104. const char *tty = NULL;
  105. unsigned int tty_speed = B115200;
  106. unsigned short ellisys_port = 0;
  107. const char *str;
  108. char *jlink = NULL;
  109. char *rtt = NULL;
  110. int exit_status;
  111. mainloop_init();
  112. filter_mask |= PACKET_FILTER_SHOW_TIME_OFFSET;
  113. for (;;) {
  114. int opt;
  115. struct sockaddr_un addr;
  116. opt = getopt_long(argc, argv,
  117. "r:w:a:s:p:i:d:B:V:MNtTSAE:PJ:R:C:c:vh",
  118. main_options, NULL);
  119. if (opt < 0)
  120. break;
  121. switch (opt) {
  122. case 'r':
  123. reader_path = optarg;
  124. break;
  125. case 'w':
  126. writer_path = optarg;
  127. break;
  128. case 'a':
  129. analyze_path = optarg;
  130. break;
  131. case 's':
  132. if (strlen(optarg) > sizeof(addr.sun_path) - 1) {
  133. fprintf(stderr, "Socket name too long\n");
  134. return EXIT_FAILURE;
  135. }
  136. control_server(optarg);
  137. break;
  138. case 'p':
  139. packet_set_priority(optarg);
  140. break;
  141. case 'i':
  142. if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
  143. str = optarg + 3;
  144. else
  145. str = optarg;
  146. if (!isdigit(*str)) {
  147. usage();
  148. return EXIT_FAILURE;
  149. }
  150. packet_select_index(atoi(str));
  151. break;
  152. case 'd':
  153. tty = optarg;
  154. break;
  155. case 'B':
  156. tty_speed = tty_get_speed(atoi(optarg));
  157. if (!tty_speed) {
  158. fprintf(stderr, "Unknown speed: %s\n", optarg);
  159. return EXIT_FAILURE;
  160. }
  161. break;
  162. case 'V':
  163. str = optarg;
  164. packet_set_fallback_manufacturer(atoi(str));
  165. break;
  166. case 'M':
  167. filter_mask |= PACKET_FILTER_SHOW_MGMT_SOCKET;
  168. break;
  169. case 'N':
  170. filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
  171. break;
  172. case 't':
  173. filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
  174. filter_mask |= PACKET_FILTER_SHOW_TIME;
  175. break;
  176. case 'T':
  177. filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
  178. filter_mask |= PACKET_FILTER_SHOW_TIME;
  179. filter_mask |= PACKET_FILTER_SHOW_DATE;
  180. break;
  181. case 'S':
  182. filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
  183. break;
  184. case 'A':
  185. filter_mask |= PACKET_FILTER_SHOW_A2DP_STREAM;
  186. break;
  187. case 'E':
  188. ellisys_server = optarg;
  189. ellisys_port = 24352;
  190. break;
  191. case 'P':
  192. use_pager = false;
  193. break;
  194. case 'J':
  195. jlink = optarg;
  196. break;
  197. case 'R':
  198. rtt = optarg;
  199. break;
  200. case 'C':
  201. set_default_pager_num_columns(atoi(optarg));
  202. break;
  203. case 'c':
  204. if (strcmp("always", optarg) == 0)
  205. set_monitor_color(COLOR_ALWAYS);
  206. else if (strcmp("never", optarg) == 0)
  207. set_monitor_color(COLOR_NEVER);
  208. else if (strcmp("auto", optarg) == 0)
  209. set_monitor_color(COLOR_AUTO);
  210. else {
  211. fprintf(stderr, "Color option must be one of "
  212. "auto/always/never\n");
  213. return EXIT_FAILURE;
  214. }
  215. break;
  216. case '#':
  217. packet_todo();
  218. lmp_todo();
  219. return EXIT_SUCCESS;
  220. case 'v':
  221. printf("%s\n", VERSION);
  222. return EXIT_SUCCESS;
  223. case 'h':
  224. usage();
  225. return EXIT_SUCCESS;
  226. default:
  227. return EXIT_FAILURE;
  228. }
  229. }
  230. if (argc - optind > 0) {
  231. fprintf(stderr, "Invalid command line parameters\n");
  232. return EXIT_FAILURE;
  233. }
  234. if (reader_path && analyze_path) {
  235. fprintf(stderr, "Display and analyze can't be combined\n");
  236. return EXIT_FAILURE;
  237. }
  238. printf("Bluetooth monitor ver %s\n", VERSION);
  239. keys_setup();
  240. packet_set_filter(filter_mask);
  241. if (analyze_path) {
  242. analyze_trace(analyze_path);
  243. return EXIT_SUCCESS;
  244. }
  245. if (reader_path) {
  246. if (ellisys_server)
  247. ellisys_enable(ellisys_server, ellisys_port);
  248. control_reader(reader_path, use_pager);
  249. return EXIT_SUCCESS;
  250. }
  251. if (writer_path && !control_writer(writer_path)) {
  252. printf("Failed to open '%s'\n", writer_path);
  253. return EXIT_FAILURE;
  254. }
  255. if (ellisys_server)
  256. ellisys_enable(ellisys_server, ellisys_port);
  257. if (!tty && !jlink && control_tracing() < 0)
  258. return EXIT_FAILURE;
  259. if (tty && control_tty(tty, tty_speed) < 0)
  260. return EXIT_FAILURE;
  261. if (jlink && control_rtt(jlink, rtt) < 0)
  262. return EXIT_FAILURE;
  263. exit_status = mainloop_run_with_signal(signal_callback, NULL);
  264. keys_cleanup();
  265. return exit_status;
  266. }