hcidump.c revision 0033462dddb3b4adf56ea28680c1f135f25a4387
1/* 2 * 3 * Bluetooth packet analyzer - HCI sniffer 4 * 5 * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com> 6 * Copyright (C) 2003-2005 Marcel Holtmann <marcel@holtmann.org> 7 * 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License as published by 11 * the Free Software Foundation; either version 2 of the License, or 12 * (at your option) any later version. 13 * 14 * This program is distributed in the hope that it will be useful, 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 * GNU General Public License for more details. 18 * 19 * You should have received a copy of the GNU General Public License 20 * along with this program; if not, write to the Free Software 21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 22 * 23 * 24 * $Id$ 25 */ 26 27#ifdef HAVE_CONFIG_H 28#include <config.h> 29#endif 30 31#include <stdio.h> 32#include <errno.h> 33#include <fcntl.h> 34#include <unistd.h> 35#include <stdlib.h> 36#include <string.h> 37#include <getopt.h> 38#include <sys/stat.h> 39#include <sys/types.h> 40#include <sys/ioctl.h> 41#include <sys/socket.h> 42 43#include <bluetooth/bluetooth.h> 44#include <bluetooth/hci.h> 45#include <bluetooth/hci_lib.h> 46 47#include <arpa/inet.h> 48#include <netinet/in.h> 49#include <netdb.h> 50 51#include "parser/parser.h" 52#include "parser/sdp.h" 53 54#if __BYTE_ORDER == __LITTLE_ENDIAN 55static inline uint64_t ntoh64(uint64_t n) 56{ 57 uint64_t h; 58 uint64_t tmp = ntohl(n & 0x00000000ffffffff); 59 h = ntohl(n >> 32); 60 h |= tmp << 32; 61 return h; 62} 63#elif __BYTE_ORDER == __BIG_ENDIAN 64#define ntoh64(x) (x) 65#else 66#error "Unknown byte order" 67#endif 68#define hton64(x) ntoh64(x) 69 70#define SNAP_LEN HCI_MAX_FRAME_SIZE 71#define DEFAULT_PORT 10839; 72 73/* Modes */ 74enum { 75 PARSE, 76 READ, 77 WRITE, 78 RECEIVE, 79 SEND, 80 AUDIO 81}; 82 83/* Default options */ 84static int device; 85static int snap_len = SNAP_LEN; 86static int defpsm = 0; 87static int defcompid = DEFAULT_COMPID; 88static int mode = PARSE; 89static int permcheck = 1; 90static long flags; 91static long filter; 92static char *dump_file = NULL; 93static char *audio_file = NULL; 94static in_addr_t dump_addr = INADDR_LOOPBACK; 95static in_port_t dump_port = DEFAULT_PORT; 96 97struct hcidump_hdr { 98 uint16_t len; 99 uint8_t in; 100 uint8_t pad; 101 uint32_t ts_sec; 102 uint32_t ts_usec; 103} __attribute__ ((packed)); 104#define HCIDUMP_HDR_SIZE (sizeof(struct hcidump_hdr)) 105 106struct btsnoop_hdr { 107 uint8_t id[8]; /* Identification Pattern */ 108 uint32_t version; /* Version Number = 1 */ 109 uint32_t type; /* Datalink Type */ 110} __attribute__ ((packed)); 111#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr)) 112 113struct btsnoop_pkt { 114 uint32_t size; /* Original Length */ 115 uint32_t len; /* Included Length */ 116 uint32_t flags; /* Packet Flags */ 117 uint32_t drops; /* Cumulative Drops */ 118 uint64_t ts; /* Timestamp microseconds */ 119 uint8_t data[0]; /* Packet Data */ 120} __attribute__ ((packed)); 121#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt)) 122 123static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 }; 124 125static uint32_t btsnoop_version = 0; 126static uint32_t btsnoop_type = 0; 127 128static inline int read_n(int fd, char *buf, int len) 129{ 130 register int t = 0, w; 131 132 while (len > 0) { 133 if ((w = read(fd, buf, len)) < 0) { 134 if (errno == EINTR || errno == EAGAIN) 135 continue; 136 return -1; 137 } 138 if (!w) 139 return 0; 140 len -= w; buf += w; t += w; 141 } 142 return t; 143} 144 145static inline int write_n(int fd, char *buf, int len) 146{ 147 register int t = 0, w; 148 149 while (len > 0) { 150 if ((w = write(fd, buf, len)) < 0) { 151 if (errno == EINTR || errno == EAGAIN) 152 continue; 153 return -1; 154 } 155 if (!w) 156 return 0; 157 len -= w; buf += w; t += w; 158 } 159 return t; 160} 161 162static void process_frames(int dev, int sock, int fd, unsigned long flags) 163{ 164 struct cmsghdr *cmsg; 165 struct msghdr msg; 166 struct iovec iv; 167 struct hcidump_hdr *dh; 168 struct btsnoop_pkt *dp; 169 struct frame frm; 170 char *buf, *ctrl; 171 int len, hdr_size = HCIDUMP_HDR_SIZE; 172 173 if (snap_len < SNAP_LEN) 174 snap_len = SNAP_LEN; 175 176 if (flags & DUMP_BTSNOOP) 177 hdr_size = BTSNOOP_PKT_SIZE; 178 179 buf = malloc(snap_len + hdr_size); 180 if (!buf) { 181 perror("Can't allocate data buffer"); 182 exit(1); 183 } 184 185 dh = (void *) buf; 186 dp = (void *) buf; 187 frm.data = buf + hdr_size; 188 189 ctrl = malloc(100); 190 if (!ctrl) { 191 perror("Can't allocate control buffer"); 192 exit(1); 193 } 194 195 if (dev == HCI_DEV_NONE) 196 printf("system: "); 197 else 198 printf("device: hci%d ", dev); 199 200 printf("snap_len: %d filter: 0x%lx\n", snap_len, filter); 201 202 memset(&msg, 0, sizeof(msg)); 203 204 while (1) { 205 iv.iov_base = frm.data; 206 iv.iov_len = snap_len; 207 208 msg.msg_iov = &iv; 209 msg.msg_iovlen = 1; 210 msg.msg_control = ctrl; 211 msg.msg_controllen = 100; 212 213 len = recvmsg(sock, &msg, 0); 214 if (len < 0) { 215 perror("Receive failed"); 216 exit(1); 217 } 218 219 /* Process control message */ 220 frm.data_len = len; 221 frm.dev_id = dev; 222 frm.in = 0; 223 frm.audio_fd = parser.audio_fd; 224 225 cmsg = CMSG_FIRSTHDR(&msg); 226 while (cmsg) { 227 switch (cmsg->cmsg_type) { 228 case HCI_CMSG_DIR: 229 frm.in = *((int *) CMSG_DATA(cmsg)); 230 break; 231 case HCI_CMSG_TSTAMP: 232 frm.ts = *((struct timeval *) CMSG_DATA(cmsg)); 233 break; 234 } 235 cmsg = CMSG_NXTHDR(&msg, cmsg); 236 } 237 238 frm.ptr = frm.data; 239 frm.len = frm.data_len; 240 241 switch (mode) { 242 case WRITE: 243 case SEND: 244 /* Save or send dump */ 245 if (flags & DUMP_BTSNOOP) { 246 uint64_t ts; 247 uint8_t pkt_type = ((uint8_t *) frm.data)[0]; 248 dp->size = htonl(frm.data_len); 249 dp->len = dp->size; 250 dp->flags = ntohl(frm.in & 0x01); 251 dp->drops = 0; 252 ts = (frm.ts.tv_sec - 946684800ll) * 1000000ll + frm.ts.tv_usec; 253 dp->ts = hton64(ts + 0x00E03AB44A676000ll); 254 if (pkt_type == HCI_COMMAND_PKT || 255 pkt_type == HCI_EVENT_PKT) 256 dp->flags |= ntohl(0x02); 257 } else { 258 dh->len = htobs(frm.data_len); 259 dh->in = frm.in; 260 dh->ts_sec = htobl(frm.ts.tv_sec); 261 dh->ts_usec = htobl(frm.ts.tv_usec); 262 } 263 264 if (write_n(fd, buf, frm.data_len + hdr_size) < 0) { 265 perror("Write error"); 266 exit(1); 267 } 268 break; 269 270 default: 271 /* Parse and print */ 272 parse(&frm); 273 break; 274 } 275 } 276} 277 278static void read_dump(int fd) 279{ 280 struct hcidump_hdr dh; 281 struct btsnoop_pkt dp; 282 struct frame frm; 283 uint8_t pkt_type; 284 int err; 285 286 frm.data = malloc(HCI_MAX_FRAME_SIZE); 287 if (!frm.data) { 288 perror("Can't allocate data buffer"); 289 exit(1); 290 } 291 292 while (1) { 293 if (parser.flags & DUMP_BTSNOOP) 294 err = read_n(fd, (void *) &dp, BTSNOOP_PKT_SIZE); 295 else 296 err = read_n(fd, (void *) &dh, HCIDUMP_HDR_SIZE); 297 298 if (err < 0) 299 goto failed; 300 if (!err) 301 return; 302 303 if (parser.flags & DUMP_BTSNOOP) { 304 switch (btsnoop_type) { 305 case 1001: 306 if (ntohl(dp.flags) & 0x02) { 307 if (ntohl(dp.flags) & 0x01) 308 pkt_type = HCI_EVENT_PKT; 309 else 310 pkt_type = HCI_COMMAND_PKT; 311 } else 312 pkt_type = HCI_ACLDATA_PKT; 313 314 ((uint8_t *) frm.data)[0] = pkt_type; 315 316 frm.data_len = ntohl(dp.len) + 1; 317 err = read_n(fd, frm.data + 1, frm.data_len - 1); 318 break; 319 320 case 1002: 321 frm.data_len = ntohl(dp.len); 322 err = read_n(fd, frm.data, frm.data_len); 323 break; 324 } 325 } else { 326 frm.data_len = btohs(dh.len); 327 err = read_n(fd, frm.data, frm.data_len); 328 } 329 330 if (err < 0) 331 goto failed; 332 if (!err) 333 return; 334 335 frm.ptr = frm.data; 336 frm.len = frm.data_len; 337 338 if (parser.flags & DUMP_BTSNOOP) { 339 uint64_t ts; 340 frm.in = ntohl(dp.flags) & 0x01; 341 ts = ntoh64(dp.ts) - 0x00E03AB44A676000ll; 342 frm.ts.tv_sec = (ts / 1000000ll) + 946684800ll; 343 frm.ts.tv_usec = ts % 1000000ll; 344 } else { 345 frm.in = dh.in; 346 frm.ts.tv_sec = btohl(dh.ts_sec); 347 frm.ts.tv_usec = btohl(dh.ts_usec); 348 } 349 350 parse(&frm); 351 } 352 353failed: 354 perror("Read failed"); 355 exit(1); 356} 357 358static int open_file(char *file, int mode, unsigned long flags) 359{ 360 struct btsnoop_hdr hdr; 361 int fd, len, open_flags; 362 363 if (mode == WRITE || mode == AUDIO) { 364 if (flags & DUMP_BTSNOOP) 365 open_flags = O_WRONLY | O_CREAT; 366 else 367 open_flags = O_WRONLY | O_CREAT | O_APPEND; 368 } else 369 open_flags = O_RDONLY; 370 371 fd = open(file, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); 372 if (fd < 0) { 373 perror("Can't open dump file"); 374 exit(1); 375 } 376 377 if (mode == READ) { 378 len = read(fd, &hdr, BTSNOOP_HDR_SIZE); 379 if (len != BTSNOOP_HDR_SIZE) { 380 lseek(fd, 0, SEEK_SET); 381 return fd; 382 } 383 384 if (!memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) { 385 parser.flags |= DUMP_BTSNOOP; 386 387 btsnoop_version = ntohl(hdr.version); 388 btsnoop_type = ntohl(hdr.type); 389 390 printf("btsnoop version: %d datalink type: %d\n", 391 btsnoop_version, btsnoop_type); 392 393 if (btsnoop_version != 1) { 394 fprintf(stderr, "Unsupported BTSnoop version\n"); 395 exit(1); 396 } 397 398 if (btsnoop_type != 1001 && btsnoop_type != 1002) { 399 fprintf(stderr, "Unsupported BTSnoop datalink type\n"); 400 exit(1); 401 } 402 } else { 403 parser.flags &= ~DUMP_BTSNOOP; 404 lseek(fd, 0, SEEK_SET); 405 return fd; 406 } 407 } else { 408 if (flags & DUMP_BTSNOOP) { 409 btsnoop_version = 1; 410 btsnoop_type = 1002; 411 412 memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id)); 413 hdr.version = htonl(btsnoop_version); 414 hdr.type = htonl(btsnoop_type); 415 416 printf("btsnoop version: %d datalink type: %d\n", 417 btsnoop_version, btsnoop_type); 418 419 len = write(fd, &hdr, BTSNOOP_HDR_SIZE); 420 if (len < 0) { 421 perror("Can't create dump header"); 422 exit(1); 423 } 424 425 if (len != BTSNOOP_HDR_SIZE) { 426 fprintf(stderr, "Header size mismatch\n"); 427 exit(1); 428 } 429 } 430 } 431 432 return fd; 433} 434 435static int open_socket(int dev, unsigned long flags) 436{ 437 struct sockaddr_hci addr; 438 struct hci_filter flt; 439 struct hci_dev_info di; 440 int sk, dd, opt; 441 442 if (permcheck && dev != HCI_DEV_NONE) { 443 dd = hci_open_dev(dev); 444 if (dd < 0) { 445 perror("Can't open device"); 446 exit(1); 447 } 448 449 if (hci_devinfo(dev, &di) < 0) { 450 perror("Can't get device info"); 451 exit(1); 452 } 453 454 opt = hci_test_bit(HCI_RAW, &di.flags); 455 if (ioctl(dd, HCISETRAW, opt) < 0) { 456 if (errno == EACCES) { 457 perror("Can't access device"); 458 exit(1); 459 } 460 } 461 462 hci_close_dev(dd); 463 } 464 465 /* Create HCI socket */ 466 sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); 467 if (sk < 0) { 468 perror("Can't create raw socket"); 469 exit(1); 470 } 471 472 opt = 1; 473 if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 474 perror("Can't enable data direction info"); 475 exit(1); 476 } 477 478 opt = 1; 479 if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { 480 perror("Can't enable time stamp"); 481 exit(1); 482 } 483 484 /* Setup filter */ 485 hci_filter_clear(&flt); 486 hci_filter_all_ptypes(&flt); 487 hci_filter_all_events(&flt); 488 if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { 489 perror("Can't set filter"); 490 exit(1); 491 } 492 493 /* Bind socket to the HCI device */ 494 addr.hci_family = AF_BLUETOOTH; 495 addr.hci_dev = dev; 496 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 497 printf("Can't attach to device hci%d. %s(%d)\n", 498 dev, strerror(errno), errno); 499 exit(1); 500 } 501 502 return sk; 503} 504 505static int open_connection(in_addr_t addr, in_port_t port) 506{ 507 struct sockaddr_in sa; 508 int sk, opt; 509 510 sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 511 if (sk < 0) { 512 perror("Can't create inet socket"); 513 exit(1); 514 } 515 516 opt = 1; 517 setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 518 519 sa.sin_family = AF_INET; 520 sa.sin_addr.s_addr = htonl(INADDR_ANY); 521 sa.sin_port = htons(0); 522 if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 523 perror("Can't bind inet socket"); 524 close(sk); 525 exit(1); 526 } 527 528 sa.sin_family = AF_INET; 529 sa.sin_addr.s_addr = htonl(addr); 530 sa.sin_port = htons(port); 531 if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 532 perror("Can't connect inet socket"); 533 close(sk); 534 exit(1); 535 } 536 537 return sk; 538} 539 540static int wait_connection(in_addr_t addr, in_port_t port) 541{ 542 struct sockaddr_in sa; 543 struct hostent *host; 544 socklen_t len; 545 int sk, nsk, opt; 546 547 sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 548 if (sk < 0) { 549 perror("Can't create inet socket"); 550 exit(1); 551 } 552 553 opt = 1; 554 setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 555 556 sa.sin_family = AF_INET; 557 sa.sin_addr.s_addr = htonl(addr); 558 sa.sin_port = htons(port); 559 if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 560 perror("Can't bind inet socket"); 561 close(sk); 562 exit(1); 563 } 564 565 host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET); 566 printf("device: %s:%d snap_len: %d filter: 0x%lx\n", 567 host ? host->h_name : inet_ntoa(sa.sin_addr), 568 ntohs(sa.sin_port), snap_len, filter); 569 570 if (listen(sk, 1)) { 571 perror("Can't listen on inet socket"); 572 close(sk); 573 exit(1); 574 } 575 576 len = sizeof(sa); 577 nsk = accept(sk, (struct sockaddr *) &sa, &len); 578 if (nsk < 0) { 579 perror("Can't accept new inet socket"); 580 close(sk); 581 exit(1); 582 } 583 584 host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET); 585 printf("device: %s snap_len: %d filter: 0x%lx\n", 586 host ? host->h_name : inet_ntoa(sa.sin_addr), snap_len, filter); 587 588 close(sk); 589 590 return nsk; 591} 592 593static struct { 594 char *name; 595 int flag; 596} filters[] = { 597 { "lmp", FILT_LMP }, 598 { "hci", FILT_HCI }, 599 { "sco", FILT_SCO }, 600 { "l2cap", FILT_L2CAP }, 601 { "rfcomm", FILT_RFCOMM }, 602 { "sdp", FILT_SDP }, 603 { "bnep", FILT_BNEP }, 604 { "cmtp", FILT_CMTP }, 605 { "hidp", FILT_HIDP }, 606 { "hcrp", FILT_HCRP }, 607 { "avdtp", FILT_AVDTP }, 608 { "obex", FILT_OBEX }, 609 { "capi", FILT_CAPI }, 610 { "csr", FILT_CSR }, 611 { "dga", FILT_DGA }, 612 { 0 } 613}; 614 615static void parse_filter(int argc, char **argv) 616{ 617 int i,n; 618 619 for (i = 0; i < argc; i++) { 620 for (n = 0; filters[n].name; n++) { 621 if (!strcasecmp(filters[n].name, argv[i])) { 622 filter |= filters[n].flag; 623 break; 624 } 625 } 626 } 627} 628 629static void usage(void) 630{ 631 printf( 632 "Usage: hcidump [OPTION...] [filter]\n" 633 " -i, --device=hci_dev HCI device\n" 634 " -l, --snap-len=len Snap len (in bytes)\n" 635 " -p, --psm=psm Default PSM\n" 636 " -m, --manufacturer=compid Default manufacturer\n" 637 " -w, --save-dump=file Save dump to a file\n" 638 " -r, --read-dump=file Read dump from a file\n" 639 " -s, --send-dump=host Send dump to a host\n" 640 " -n, --recv-dump=host Receive dump on a host\n" 641 " -t, --ts Display time stamps\n" 642 " -a, --ascii Dump data in ascii\n" 643 " -x, --hex Dump data in hex\n" 644 " -X, --ext Dump data in hex and ascii\n" 645 " -R, --raw Dump raw data\n" 646 " -C, --cmtp=psm PSM for CMTP\n" 647 " -H, --hcrp=psm PSM for HCRP\n" 648 " -O, --obex=channel Channel for OBEX\n" 649 " -A, --audio=file Extract SCO audio data\n" 650 " -B, --btsnoop Use BTSnoop file format\n" 651 " -V, --verbose Verbose decoding\n" 652 " -h, --help Give this help list\n" 653 " --usage Give a short usage message\n" 654 ); 655} 656 657static struct option main_options[] = { 658 { "device", 1, 0, 'i' }, 659 { "snap-len", 1, 0, 'l' }, 660 { "psm", 1, 0, 'p' }, 661 { "manufacturer", 1, 0, 'm' }, 662 { "save-dump", 1, 0, 'w' }, 663 { "read-dump", 1, 0, 'r' }, 664 { "send-dump", 1, 0, 's' }, 665 { "recv-dump", 1, 0, 'n' }, 666 { "timestamp", 0, 0, 't' }, 667 { "ascii", 0, 0, 'a' }, 668 { "hex", 0, 0, 'x' }, 669 { "ext", 0, 0, 'X' }, 670 { "raw", 0, 0, 'R' }, 671 { "cmtp", 1, 0, 'C' }, 672 { "hcrp", 1, 0, 'H' }, 673 { "obex", 1, 0, 'O' }, 674 { "audio", 1, 0, 'A' }, 675 { "btsnoop", 0, 0, 'B' }, 676 { "verbose", 0, 0, 'V' }, 677 { "help", 0, 0, 'h' }, 678 { 0 } 679}; 680 681int main(int argc, char *argv[]) 682{ 683 struct hostent *host; 684 struct in_addr addr; 685 int opt, fd = -1; 686 687 printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION); 688 689 while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRC:H:O:A:BVZh", main_options, NULL)) != -1) { 690 switch(opt) { 691 case 'i': 692 if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system")) 693 device = atoi(optarg + 3); 694 else 695 device = HCI_DEV_NONE; 696 break; 697 698 case 'l': 699 snap_len = atoi(optarg); 700 break; 701 702 case 'p': 703 defpsm = atoi(optarg); 704 break; 705 706 case 'm': 707 defcompid = atoi(optarg); 708 break; 709 710 case 'w': 711 mode = WRITE; 712 dump_file = strdup(optarg); 713 break; 714 715 case 'r': 716 mode = READ; 717 dump_file = strdup(optarg); 718 break; 719 720 case 's': 721 mode = SEND; 722 host = gethostbyname(optarg); 723 if (host) { 724 bcopy(host->h_addr, &addr, sizeof(struct in_addr)); 725 dump_addr = ntohl(addr.s_addr); 726 dump_port = DEFAULT_PORT; 727 } else { 728 dump_addr = INADDR_LOOPBACK; 729 dump_port = DEFAULT_PORT; 730 } 731 break; 732 733 case 'n': 734 mode = RECEIVE; 735 host = gethostbyname(optarg); 736 if (host) { 737 bcopy(host->h_addr, &addr, sizeof(struct in_addr)); 738 dump_addr = ntohl(addr.s_addr); 739 dump_port = DEFAULT_PORT; 740 } else { 741 dump_addr = INADDR_LOOPBACK; 742 dump_port = DEFAULT_PORT; 743 } 744 break; 745 746 case 't': 747 flags |= DUMP_TSTAMP; 748 break; 749 750 case 'a': 751 flags |= DUMP_ASCII; 752 break; 753 754 case 'x': 755 flags |= DUMP_HEX; 756 break; 757 758 case 'X': 759 flags |= DUMP_EXT; 760 break; 761 762 case 'R': 763 flags |= DUMP_RAW; 764 break; 765 766 case 'C': 767 set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP); 768 break; 769 770 case 'H': 771 set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL); 772 break; 773 774 case 'O': 775 set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX); 776 break; 777 778 case 'A': 779 audio_file = strdup(optarg); 780 break; 781 782 case 'B': 783 flags |= DUMP_BTSNOOP; 784 break; 785 786 case 'V': 787 flags |= DUMP_VERBOSE; 788 break; 789 790 case 'Z': 791 permcheck = 0; 792 break; 793 794 case 'h': 795 default: 796 usage(); 797 exit(0); 798 } 799 } 800 801 argc -= optind; 802 argv += optind; 803 optind = 0; 804 805 if (argc > 0) 806 parse_filter(argc, argv); 807 808 /* Default settings */ 809 if (!filter) 810 filter = ~0L; 811 812 if (audio_file) 813 fd = open_file(audio_file, AUDIO, flags); 814 815 switch (mode) { 816 case PARSE: 817 init_parser(flags, filter, defpsm, defcompid, fd); 818 process_frames(device, open_socket(device, flags), -1, flags); 819 break; 820 821 case READ: 822 init_parser(flags, filter, defpsm, defcompid, fd); 823 read_dump(open_file(dump_file, mode, flags)); 824 break; 825 826 case WRITE: 827 process_frames(device, open_socket(device, flags), 828 open_file(dump_file, mode, flags), flags); 829 break; 830 831 case RECEIVE: 832 init_parser(flags, filter, defpsm, defcompid, fd); 833 read_dump(wait_connection(dump_addr, dump_port)); 834 break; 835 836 case SEND: 837 process_frames(device, open_socket(device, flags), 838 open_connection(dump_addr, dump_port), flags); 839 break; 840 } 841 842 return 0; 843} 844