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