hcidump.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * BlueZ - Bluetooth protocol stack for Linux
  5. *
  6. * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
  7. * Copyright (C) 2003-2011 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 <errno.h>
  17. #include <fcntl.h>
  18. #include <unistd.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <getopt.h>
  22. #include <poll.h>
  23. #include <sys/stat.h>
  24. #include <sys/types.h>
  25. #include <sys/ioctl.h>
  26. #include <sys/socket.h>
  27. #include "parser/parser.h"
  28. #include "parser/sdp.h"
  29. #include "lib/hci.h"
  30. #include "lib/hci_lib.h"
  31. #define SNAP_LEN HCI_MAX_FRAME_SIZE
  32. /* Modes */
  33. enum {
  34. PARSE,
  35. READ,
  36. WRITE,
  37. PPPDUMP,
  38. AUDIO
  39. };
  40. /* Default options */
  41. static int snap_len = SNAP_LEN;
  42. static int mode = PARSE;
  43. static char *dump_file = NULL;
  44. static char *pppdump_file = NULL;
  45. static char *audio_file = NULL;
  46. struct hcidump_hdr {
  47. uint16_t len;
  48. uint8_t in;
  49. uint8_t pad;
  50. uint32_t ts_sec;
  51. uint32_t ts_usec;
  52. } __attribute__ ((packed));
  53. #define HCIDUMP_HDR_SIZE (sizeof(struct hcidump_hdr))
  54. struct btsnoop_hdr {
  55. uint8_t id[8]; /* Identification Pattern */
  56. uint32_t version; /* Version Number = 1 */
  57. uint32_t type; /* Datalink Type */
  58. } __attribute__ ((packed));
  59. #define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
  60. struct btsnoop_pkt {
  61. uint32_t size; /* Original Length */
  62. uint32_t len; /* Included Length */
  63. uint32_t flags; /* Packet Flags */
  64. uint32_t drops; /* Cumulative Drops */
  65. uint64_t ts; /* Timestamp microseconds */
  66. uint8_t data[0]; /* Packet Data */
  67. } __attribute__ ((packed));
  68. #define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
  69. static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
  70. static uint32_t btsnoop_version = 0;
  71. static uint32_t btsnoop_type = 0;
  72. struct pktlog_hdr {
  73. uint32_t len;
  74. uint64_t ts;
  75. uint8_t type;
  76. } __attribute__ ((packed));
  77. #define PKTLOG_HDR_SIZE (sizeof(struct pktlog_hdr))
  78. static inline int read_n(int fd, char *buf, int len)
  79. {
  80. int t = 0, w;
  81. while (len > 0) {
  82. if ((w = read(fd, buf, len)) < 0) {
  83. if (errno == EINTR || errno == EAGAIN)
  84. continue;
  85. return -1;
  86. }
  87. if (!w)
  88. return 0;
  89. len -= w; buf += w; t += w;
  90. }
  91. return t;
  92. }
  93. static inline int write_n(int fd, char *buf, int len)
  94. {
  95. int t = 0, w;
  96. while (len > 0) {
  97. if ((w = write(fd, buf, len)) < 0) {
  98. if (errno == EINTR || errno == EAGAIN)
  99. continue;
  100. return -1;
  101. }
  102. if (!w)
  103. return 0;
  104. len -= w; buf += w; t += w;
  105. }
  106. return t;
  107. }
  108. static int process_frames(int dev, int sock, int fd, unsigned long flags)
  109. {
  110. struct cmsghdr *cmsg;
  111. struct msghdr msg;
  112. struct iovec iv;
  113. struct hcidump_hdr *dh;
  114. struct btsnoop_pkt *dp;
  115. struct frame frm;
  116. struct pollfd fds[2];
  117. int nfds = 0;
  118. char *buf;
  119. char ctrl[100];
  120. int len, hdr_size = HCIDUMP_HDR_SIZE;
  121. if (sock < 0)
  122. return -1;
  123. if (snap_len < SNAP_LEN)
  124. snap_len = SNAP_LEN;
  125. if (flags & DUMP_BTSNOOP)
  126. hdr_size = BTSNOOP_PKT_SIZE;
  127. buf = malloc(snap_len + hdr_size);
  128. if (!buf) {
  129. perror("Can't allocate data buffer");
  130. return -1;
  131. }
  132. dh = (void *) buf;
  133. dp = (void *) buf;
  134. frm.data = buf + hdr_size;
  135. if (dev == HCI_DEV_NONE)
  136. printf("system: ");
  137. else
  138. printf("device: hci%d ", dev);
  139. printf("snap_len: %d filter: 0x%lx\n", snap_len, parser.filter);
  140. memset(&msg, 0, sizeof(msg));
  141. fds[nfds].fd = sock;
  142. fds[nfds].events = POLLIN;
  143. fds[nfds].revents = 0;
  144. nfds++;
  145. while (1) {
  146. int i, n = poll(fds, nfds, -1);
  147. if (n <= 0)
  148. continue;
  149. for (i = 0; i < nfds; i++) {
  150. if (fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
  151. if (fds[i].fd == sock)
  152. printf("device: disconnected\n");
  153. else
  154. printf("client: disconnect\n");
  155. return 0;
  156. }
  157. }
  158. iv.iov_base = frm.data;
  159. iv.iov_len = snap_len;
  160. msg.msg_iov = &iv;
  161. msg.msg_iovlen = 1;
  162. msg.msg_control = ctrl;
  163. msg.msg_controllen = 100;
  164. len = recvmsg(sock, &msg, MSG_DONTWAIT);
  165. if (len < 0) {
  166. if (errno == EAGAIN || errno == EINTR)
  167. continue;
  168. perror("Receive failed");
  169. return -1;
  170. }
  171. /* Process control message */
  172. frm.data_len = len;
  173. frm.dev_id = dev;
  174. frm.in = 0;
  175. frm.pppdump_fd = parser.pppdump_fd;
  176. frm.audio_fd = parser.audio_fd;
  177. cmsg = CMSG_FIRSTHDR(&msg);
  178. while (cmsg) {
  179. int dir;
  180. switch (cmsg->cmsg_type) {
  181. case HCI_CMSG_DIR:
  182. memcpy(&dir, CMSG_DATA(cmsg), sizeof(int));
  183. frm.in = (uint8_t) dir;
  184. break;
  185. case HCI_CMSG_TSTAMP:
  186. memcpy(&frm.ts, CMSG_DATA(cmsg),
  187. sizeof(struct timeval));
  188. break;
  189. }
  190. cmsg = CMSG_NXTHDR(&msg, cmsg);
  191. }
  192. frm.ptr = frm.data;
  193. frm.len = frm.data_len;
  194. switch (mode) {
  195. case WRITE:
  196. /* Save or send dump */
  197. if (flags & DUMP_BTSNOOP) {
  198. uint64_t ts;
  199. uint8_t pkt_type = ((uint8_t *) frm.data)[0];
  200. dp->size = htobe32(frm.data_len);
  201. dp->len = dp->size;
  202. dp->flags = be32toh(frm.in & 0x01);
  203. dp->drops = 0;
  204. ts = (frm.ts.tv_sec - 946684800ll) * 1000000ll + frm.ts.tv_usec;
  205. dp->ts = htobe64(ts + 0x00E03AB44A676000ll);
  206. if (pkt_type == HCI_COMMAND_PKT ||
  207. pkt_type == HCI_EVENT_PKT)
  208. dp->flags |= be32toh(0x02);
  209. } else {
  210. dh->len = htobs(frm.data_len);
  211. dh->in = frm.in;
  212. dh->ts_sec = htobl(frm.ts.tv_sec);
  213. dh->ts_usec = htobl(frm.ts.tv_usec);
  214. }
  215. if (write_n(fd, buf, frm.data_len + hdr_size) < 0) {
  216. perror("Write error");
  217. return -1;
  218. }
  219. break;
  220. default:
  221. /* Parse and print */
  222. parse(&frm);
  223. break;
  224. }
  225. }
  226. return 0;
  227. }
  228. static void read_dump(int fd)
  229. {
  230. struct hcidump_hdr dh;
  231. struct btsnoop_pkt dp;
  232. struct pktlog_hdr ph;
  233. struct frame frm;
  234. int err;
  235. frm.data = malloc(HCI_MAX_FRAME_SIZE);
  236. if (!frm.data) {
  237. perror("Can't allocate data buffer");
  238. exit(1);
  239. }
  240. while (1) {
  241. if (parser.flags & DUMP_PKTLOG)
  242. err = read_n(fd, (void *) &ph, PKTLOG_HDR_SIZE);
  243. else if (parser.flags & DUMP_BTSNOOP)
  244. err = read_n(fd, (void *) &dp, BTSNOOP_PKT_SIZE);
  245. else
  246. err = read_n(fd, (void *) &dh, HCIDUMP_HDR_SIZE);
  247. if (err < 0)
  248. goto failed;
  249. if (!err)
  250. goto done;
  251. if (parser.flags & DUMP_PKTLOG) {
  252. switch (ph.type) {
  253. case 0x00:
  254. ((uint8_t *) frm.data)[0] = HCI_COMMAND_PKT;
  255. frm.in = 0;
  256. break;
  257. case 0x01:
  258. ((uint8_t *) frm.data)[0] = HCI_EVENT_PKT;
  259. frm.in = 1;
  260. break;
  261. case 0x02:
  262. ((uint8_t *) frm.data)[0] = HCI_ACLDATA_PKT;
  263. frm.in = 0;
  264. break;
  265. case 0x03:
  266. ((uint8_t *) frm.data)[0] = HCI_ACLDATA_PKT;
  267. frm.in = 1;
  268. break;
  269. default:
  270. lseek(fd, be32toh(ph.len) - 9, SEEK_CUR);
  271. continue;
  272. }
  273. frm.data_len = be32toh(ph.len) - 8;
  274. err = read_n(fd, frm.data + 1, frm.data_len - 1);
  275. } else if (parser.flags & DUMP_BTSNOOP) {
  276. uint32_t opcode;
  277. uint8_t pkt_type;
  278. switch (btsnoop_type) {
  279. case 1001:
  280. if (be32toh(dp.flags) & 0x02) {
  281. if (be32toh(dp.flags) & 0x01)
  282. pkt_type = HCI_EVENT_PKT;
  283. else
  284. pkt_type = HCI_COMMAND_PKT;
  285. } else
  286. pkt_type = HCI_ACLDATA_PKT;
  287. ((uint8_t *) frm.data)[0] = pkt_type;
  288. frm.data_len = be32toh(dp.len) + 1;
  289. err = read_n(fd, frm.data + 1, frm.data_len - 1);
  290. break;
  291. case 1002:
  292. frm.data_len = be32toh(dp.len);
  293. err = read_n(fd, frm.data, frm.data_len);
  294. break;
  295. case 2001:
  296. opcode = be32toh(dp.flags) & 0xffff;
  297. switch (opcode) {
  298. case 2:
  299. pkt_type = HCI_COMMAND_PKT;
  300. frm.in = 0;
  301. break;
  302. case 3:
  303. pkt_type = HCI_EVENT_PKT;
  304. frm.in = 1;
  305. break;
  306. case 4:
  307. pkt_type = HCI_ACLDATA_PKT;
  308. frm.in = 0;
  309. break;
  310. case 5:
  311. pkt_type = HCI_ACLDATA_PKT;
  312. frm.in = 1;
  313. break;
  314. case 6:
  315. pkt_type = HCI_SCODATA_PKT;
  316. frm.in = 0;
  317. break;
  318. case 7:
  319. pkt_type = HCI_SCODATA_PKT;
  320. frm.in = 1;
  321. break;
  322. default:
  323. pkt_type = 0xff;
  324. break;
  325. }
  326. ((uint8_t *) frm.data)[0] = pkt_type;
  327. frm.data_len = be32toh(dp.len) + 1;
  328. err = read_n(fd, frm.data + 1, frm.data_len - 1);
  329. }
  330. } else {
  331. frm.data_len = btohs(dh.len);
  332. err = read_n(fd, frm.data, frm.data_len);
  333. }
  334. if (err < 0)
  335. goto failed;
  336. if (!err)
  337. goto done;
  338. frm.ptr = frm.data;
  339. frm.len = frm.data_len;
  340. if (parser.flags & DUMP_PKTLOG) {
  341. uint64_t ts;
  342. ts = be64toh(ph.ts);
  343. frm.ts.tv_sec = ts >> 32;
  344. frm.ts.tv_usec = ts & 0xffffffff;
  345. } else if (parser.flags & DUMP_BTSNOOP) {
  346. uint64_t ts;
  347. frm.in = be32toh(dp.flags) & 0x01;
  348. ts = be64toh(dp.ts) - 0x00E03AB44A676000ll;
  349. frm.ts.tv_sec = (ts / 1000000ll) + 946684800ll;
  350. frm.ts.tv_usec = ts % 1000000ll;
  351. } else {
  352. frm.in = dh.in;
  353. frm.ts.tv_sec = btohl(dh.ts_sec);
  354. frm.ts.tv_usec = btohl(dh.ts_usec);
  355. }
  356. parse(&frm);
  357. }
  358. done:
  359. free(frm.data);
  360. return;
  361. failed:
  362. perror("Read failed");
  363. free(frm.data);
  364. exit(1);
  365. }
  366. static int open_file(char *file, int mode, unsigned long flags)
  367. {
  368. unsigned char buf[BTSNOOP_HDR_SIZE];
  369. struct btsnoop_hdr *hdr = (struct btsnoop_hdr *) buf;
  370. int fd, len, open_flags;
  371. if (mode == WRITE || mode == PPPDUMP || mode == AUDIO)
  372. open_flags = O_WRONLY | O_CREAT | O_TRUNC;
  373. else
  374. open_flags = O_RDONLY;
  375. fd = open(file, open_flags, 0644);
  376. if (fd < 0) {
  377. perror("Can't open dump file");
  378. exit(1);
  379. }
  380. if (mode == READ) {
  381. len = read(fd, buf, BTSNOOP_HDR_SIZE);
  382. if (len != BTSNOOP_HDR_SIZE) {
  383. lseek(fd, 0, SEEK_SET);
  384. return fd;
  385. }
  386. if (!memcmp(hdr->id, btsnoop_id, sizeof(btsnoop_id))) {
  387. parser.flags |= DUMP_BTSNOOP;
  388. btsnoop_version = be32toh(hdr->version);
  389. btsnoop_type = be32toh(hdr->type);
  390. printf("btsnoop version: %d datalink type: %d\n",
  391. btsnoop_version, btsnoop_type);
  392. if (btsnoop_version != 1) {
  393. fprintf(stderr, "Unsupported BTSnoop version\n");
  394. exit(1);
  395. }
  396. if (btsnoop_type != 1001 && btsnoop_type != 1002 &&
  397. btsnoop_type != 2001) {
  398. fprintf(stderr, "Unsupported BTSnoop datalink type\n");
  399. exit(1);
  400. }
  401. } else {
  402. if (buf[0] == 0x00 && buf[1] == 0x00) {
  403. parser.flags |= DUMP_PKTLOG;
  404. printf("packet logger data format\n");
  405. }
  406. parser.flags &= ~DUMP_BTSNOOP;
  407. lseek(fd, 0, SEEK_SET);
  408. return fd;
  409. }
  410. } else {
  411. if (flags & DUMP_BTSNOOP) {
  412. btsnoop_version = 1;
  413. btsnoop_type = 1002;
  414. memcpy(hdr->id, btsnoop_id, sizeof(btsnoop_id));
  415. hdr->version = htobe32(btsnoop_version);
  416. hdr->type = htobe32(btsnoop_type);
  417. printf("btsnoop version: %d datalink type: %d\n",
  418. btsnoop_version, btsnoop_type);
  419. len = write(fd, buf, BTSNOOP_HDR_SIZE);
  420. if (len < 0) {
  421. perror("Can't create dump header");
  422. exit(1);
  423. }
  424. if (len != BTSNOOP_HDR_SIZE) {
  425. fprintf(stderr, "Header size mismatch\n");
  426. exit(1);
  427. }
  428. }
  429. }
  430. return fd;
  431. }
  432. static int open_socket(int dev, unsigned long flags)
  433. {
  434. struct sockaddr_hci addr;
  435. struct hci_filter flt;
  436. int sk, opt;
  437. /* Create HCI socket */
  438. sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
  439. if (sk < 0) {
  440. perror("Can't create raw socket");
  441. return -1;
  442. }
  443. opt = 1;
  444. if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
  445. perror("Can't enable data direction info");
  446. goto fail;
  447. }
  448. opt = 1;
  449. if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
  450. perror("Can't enable time stamp");
  451. goto fail;
  452. }
  453. /* Setup filter */
  454. hci_filter_clear(&flt);
  455. hci_filter_all_ptypes(&flt);
  456. hci_filter_all_events(&flt);
  457. if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
  458. perror("Can't set filter");
  459. goto fail;
  460. }
  461. /* Bind socket to the HCI device */
  462. memset(&addr, 0, sizeof(addr));
  463. addr.hci_family = AF_BLUETOOTH;
  464. addr.hci_dev = dev;
  465. if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  466. printf("Can't attach to device hci%d. %s(%d)\n",
  467. dev, strerror(errno), errno);
  468. goto fail;
  469. }
  470. return sk;
  471. fail:
  472. close(sk);
  473. return -1;
  474. }
  475. static struct {
  476. char *name;
  477. int flag;
  478. } filters[] = {
  479. { "lmp", FILT_LMP },
  480. { "hci", FILT_HCI },
  481. { "sco", FILT_SCO },
  482. { "l2cap", FILT_L2CAP },
  483. { "a2mp", FILT_A2MP },
  484. { "rfcomm", FILT_RFCOMM },
  485. { "sdp", FILT_SDP },
  486. { "bnep", FILT_BNEP },
  487. { "cmtp", FILT_CMTP },
  488. { "hidp", FILT_HIDP },
  489. { "hcrp", FILT_HCRP },
  490. { "att", FILT_ATT },
  491. { "smp", FILT_SMP },
  492. { "avdtp", FILT_AVDTP },
  493. { "avctp", FILT_AVCTP },
  494. { "obex", FILT_OBEX },
  495. { "capi", FILT_CAPI },
  496. { "ppp", FILT_PPP },
  497. { "sap", FILT_SAP },
  498. { "csr", FILT_CSR },
  499. { "dga", FILT_DGA },
  500. { 0 }
  501. };
  502. static unsigned long parse_filter(int argc, char **argv)
  503. {
  504. unsigned long filter = 0;
  505. int i,n;
  506. for (i = 0; i < argc; i++) {
  507. for (n = 0; filters[n].name; n++) {
  508. if (!strcasecmp(filters[n].name, argv[i])) {
  509. filter |= filters[n].flag;
  510. break;
  511. }
  512. }
  513. }
  514. return filter;
  515. }
  516. static void usage(void)
  517. {
  518. printf(
  519. "Usage: hcidump [OPTION...] [filter]\n"
  520. " -i, --device=hci_dev HCI device\n"
  521. " -l, --snap-len=len Snap len (in bytes)\n"
  522. " -p, --psm=psm Default PSM\n"
  523. " -m, --manufacturer=compid Default manufacturer\n"
  524. " -w, --save-dump=file Save dump to a file\n"
  525. " -r, --read-dump=file Read dump from a file\n"
  526. " -t, --ts Display time stamps\n"
  527. " -a, --ascii Dump data in ascii\n"
  528. " -x, --hex Dump data in hex\n"
  529. " -X, --ext Dump data in hex and ascii\n"
  530. " -R, --raw Dump raw data\n"
  531. " -C, --cmtp=psm PSM for CMTP\n"
  532. " -H, --hcrp=psm PSM for HCRP\n"
  533. " -O, --obex=port Channel/PSM for OBEX\n"
  534. " -P, --ppp=channel Channel for PPP\n"
  535. " -S, --sap=channel Channel for SAP\n"
  536. " -D, --pppdump=file Extract PPP traffic\n"
  537. " -A, --audio=file Extract SCO audio data\n"
  538. " -Y, --novendor No vendor commands or events\n"
  539. " -h, --help Give this help list\n"
  540. " -v, --version Give version information\n"
  541. " --usage Give a short usage message\n"
  542. );
  543. }
  544. static struct option main_options[] = {
  545. { "device", 1, 0, 'i' },
  546. { "snap-len", 1, 0, 'l' },
  547. { "psm", 1, 0, 'p' },
  548. { "manufacturer", 1, 0, 'm' },
  549. { "save-dump", 1, 0, 'w' },
  550. { "read-dump", 1, 0, 'r' },
  551. { "timestamp", 0, 0, 't' },
  552. { "ascii", 0, 0, 'a' },
  553. { "hex", 0, 0, 'x' },
  554. { "ext", 0, 0, 'X' },
  555. { "raw", 0, 0, 'R' },
  556. { "cmtp", 1, 0, 'C' },
  557. { "hcrp", 1, 0, 'H' },
  558. { "obex", 1, 0, 'O' },
  559. { "ppp", 1, 0, 'P' },
  560. { "sap", 1, 0, 'S' },
  561. { "pppdump", 1, 0, 'D' },
  562. { "audio", 1, 0, 'A' },
  563. { "novendor", 0, 0, 'Y' },
  564. { "help", 0, 0, 'h' },
  565. { "version", 0, 0, 'v' },
  566. { 0 }
  567. };
  568. int main(int argc, char *argv[])
  569. {
  570. unsigned long flags = 0;
  571. unsigned long filter = 0;
  572. int device = 0;
  573. int defpsm = 0;
  574. int defcompid = DEFAULT_COMPID;
  575. int opt, pppdump_fd = -1, audio_fd = -1;
  576. uint16_t obex_port;
  577. while ((opt = getopt_long(argc, argv,
  578. "i:l:p:m:w:r:taxXRC:H:O:P:S:D:A:Yhv",
  579. main_options, NULL)) != -1) {
  580. switch(opt) {
  581. case 'i':
  582. if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system"))
  583. device = atoi(optarg + 3);
  584. else
  585. device = HCI_DEV_NONE;
  586. break;
  587. case 'l':
  588. snap_len = atoi(optarg);
  589. break;
  590. case 'p':
  591. defpsm = atoi(optarg);
  592. break;
  593. case 'm':
  594. defcompid = atoi(optarg);
  595. break;
  596. case 'w':
  597. mode = WRITE;
  598. dump_file = strdup(optarg);
  599. break;
  600. case 'r':
  601. mode = READ;
  602. dump_file = strdup(optarg);
  603. break;
  604. case 't':
  605. flags |= DUMP_TSTAMP;
  606. break;
  607. case 'a':
  608. flags |= DUMP_ASCII;
  609. break;
  610. case 'x':
  611. flags |= DUMP_HEX;
  612. break;
  613. case 'X':
  614. flags |= DUMP_EXT;
  615. break;
  616. case 'R':
  617. flags |= DUMP_RAW;
  618. break;
  619. case 'C':
  620. set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP);
  621. break;
  622. case 'H':
  623. set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL);
  624. break;
  625. case 'O':
  626. obex_port = atoi(optarg);
  627. if (obex_port > 31)
  628. set_proto(0, obex_port, 0, SDP_UUID_OBEX);
  629. else
  630. set_proto(0, 0, obex_port, SDP_UUID_OBEX);
  631. break;
  632. case 'P':
  633. set_proto(0, 0, atoi(optarg), SDP_UUID_LAN_ACCESS_PPP);
  634. break;
  635. case 'S':
  636. set_proto(0, 0, atoi(optarg), SDP_UUID_SIM_ACCESS);
  637. break;
  638. case 'D':
  639. pppdump_file = strdup(optarg);
  640. break;
  641. case 'A':
  642. audio_file = strdup(optarg);
  643. break;
  644. case 'Y':
  645. flags |= DUMP_NOVENDOR;
  646. break;
  647. case 'v':
  648. printf("%s\n", VERSION);
  649. exit(0);
  650. case 'h':
  651. default:
  652. usage();
  653. exit(0);
  654. }
  655. }
  656. argc -= optind;
  657. argv += optind;
  658. optind = 0;
  659. printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION);
  660. if (argc > 0)
  661. filter = parse_filter(argc, argv);
  662. /* Default settings */
  663. if (!filter)
  664. filter = ~0L;
  665. if (pppdump_file)
  666. pppdump_fd = open_file(pppdump_file, PPPDUMP, flags);
  667. if (audio_file)
  668. audio_fd = open_file(audio_file, AUDIO, flags);
  669. switch (mode) {
  670. case PARSE:
  671. flags |= DUMP_VERBOSE;
  672. init_parser(flags, filter, defpsm, defcompid,
  673. pppdump_fd, audio_fd);
  674. process_frames(device, open_socket(device, flags), -1, flags);
  675. break;
  676. case READ:
  677. flags |= DUMP_VERBOSE;
  678. init_parser(flags, filter, defpsm, defcompid,
  679. pppdump_fd, audio_fd);
  680. read_dump(open_file(dump_file, mode, flags));
  681. break;
  682. case WRITE:
  683. flags |= DUMP_BTSNOOP;
  684. process_frames(device, open_socket(device, flags),
  685. open_file(dump_file, mode, flags), flags);
  686. break;
  687. }
  688. return 0;
  689. }