hcidump.c revision ebcc23ce2362fafd9f14703081c544f49b6853eb
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 <stdlib.h> 35#include <unistd.h> 36#include <termios.h> 37#include <string.h> 38#include <getopt.h> 39#include <pwd.h> 40 41#include <sys/types.h> 42#include <sys/socket.h> 43#include <sys/ioctl.h> 44#include <sys/uio.h> 45#include <sys/stat.h> 46#include <arpa/inet.h> 47#include <netinet/in.h> 48#include <netdb.h> 49 50#include <bluetooth/bluetooth.h> 51#include <bluetooth/hci.h> 52#include <bluetooth/hci_lib.h> 53 54#include "parser/parser.h" 55#include "parser/sdp.h" 56 57#define SNAP_LEN HCI_MAX_FRAME_SIZE 58#define DEFAULT_PORT 10839; 59 60/* Modes */ 61enum { 62 PARSE, 63 READ, 64 WRITE, 65 RECEIVE, 66 SEND 67}; 68 69/* Default options */ 70static int device; 71static int snap_len = SNAP_LEN; 72static int defpsm = 0; 73static int defcompid = DEFAULT_COMPID; 74static int mode = PARSE; 75static long flags; 76static long filter; 77static char *dump_file; 78static in_addr_t dump_addr = INADDR_LOOPBACK; 79static in_port_t dump_port = DEFAULT_PORT; 80 81struct dump_hdr { 82 uint16_t len; 83 uint8_t in; 84 uint8_t pad; 85 uint32_t ts_sec; 86 uint32_t ts_usec; 87} __attribute__ ((packed)); 88#define DUMP_HDR_SIZE (sizeof(struct dump_hdr)) 89 90static inline int read_n(int fd, char *buf, int len) 91{ 92 register int t = 0, w; 93 94 while (len > 0) { 95 if ((w = read(fd, buf, len)) < 0) { 96 if (errno == EINTR || errno == EAGAIN) 97 continue; 98 return -1; 99 } 100 if (!w) 101 return 0; 102 len -= w; buf += w; t += w; 103 } 104 return t; 105} 106 107static inline int write_n(int fd, char *buf, int len) 108{ 109 register int t = 0, w; 110 111 while (len > 0) { 112 if ((w = write(fd, buf, len)) < 0) { 113 if (errno == EINTR || errno == EAGAIN) 114 continue; 115 return -1; 116 } 117 if (!w) 118 return 0; 119 len -= w; buf += w; t += w; 120 } 121 return t; 122} 123 124static void process_frames(int dev, int sock, int file) 125{ 126 struct cmsghdr *cmsg; 127 struct msghdr msg; 128 struct iovec iv; 129 struct dump_hdr *dh; 130 struct frame frm; 131 char *buf, *ctrl; 132 133 if (snap_len < SNAP_LEN) 134 snap_len = SNAP_LEN; 135 136 if (!(buf = malloc(snap_len + DUMP_HDR_SIZE))) { 137 perror("Can't allocate data buffer"); 138 exit(1); 139 } 140 141 dh = (void *) buf; 142 frm.data = buf + DUMP_HDR_SIZE; 143 144 if (!(ctrl = malloc(100))) { 145 perror("Can't allocate control buffer"); 146 exit(1); 147 } 148 149 printf("device: hci%d snap_len: %d filter: 0x%lx\n", 150 dev, snap_len, filter); 151 152 memset(&msg, 0, sizeof(msg)); 153 154 while (1) { 155 iv.iov_base = frm.data; 156 iv.iov_len = snap_len; 157 158 msg.msg_iov = &iv; 159 msg.msg_iovlen = 1; 160 msg.msg_control = ctrl; 161 msg.msg_controllen = 100; 162 163 if ((frm.data_len = recvmsg(sock, &msg, 0)) < 0) { 164 perror("Receive failed"); 165 exit(1); 166 } 167 168 /* Process control message */ 169 frm.in = 0; 170 cmsg = CMSG_FIRSTHDR(&msg); 171 while (cmsg) { 172 switch (cmsg->cmsg_type) { 173 case HCI_CMSG_DIR: 174 frm.in = *((int *)CMSG_DATA(cmsg)); 175 break; 176 case HCI_CMSG_TSTAMP: 177 frm.ts = *((struct timeval *)CMSG_DATA(cmsg)); 178 break; 179 } 180 cmsg = CMSG_NXTHDR(&msg, cmsg); 181 } 182 183 frm.ptr = frm.data; 184 frm.len = frm.data_len; 185 186 switch (mode) { 187 case WRITE: 188 case SEND: 189 /* Save or send dump */ 190 dh->len = htobs(frm.data_len); 191 dh->in = frm.in; 192 dh->ts_sec = htobl(frm.ts.tv_sec); 193 dh->ts_usec = htobl(frm.ts.tv_usec); 194 if (write_n(file, buf, frm.data_len + DUMP_HDR_SIZE) < 0) { 195 perror("Write error"); 196 exit(1); 197 } 198 break; 199 200 default: 201 /* Parse and print */ 202 parse(&frm); 203 break; 204 } 205 } 206} 207 208static void read_dump(int file) 209{ 210 struct dump_hdr dh; 211 struct frame frm; 212 int err; 213 214 if (!(frm.data = malloc(HCI_MAX_FRAME_SIZE))) { 215 perror("Can't allocate data buffer"); 216 exit(1); 217 } 218 219 while (1) { 220 if ((err = read_n(file, (void *) &dh, DUMP_HDR_SIZE)) < 0) 221 goto failed; 222 if (!err) return; 223 224 frm.data_len = btohs(dh.len); 225 226 if ((err = read_n(file, frm.data, frm.data_len)) < 0) 227 goto failed; 228 if (!err) return; 229 230 frm.ptr = frm.data; 231 frm.len = frm.data_len; 232 frm.in = dh.in; 233 frm.ts.tv_sec = btohl(dh.ts_sec); 234 frm.ts.tv_usec = btohl(dh.ts_usec); 235 236 parse(&frm); 237 } 238 239failed: 240 perror("Read failed"); 241 exit(1); 242} 243 244static int open_file(char *file, int mode) 245{ 246 int f, flags; 247 248 if (mode == WRITE) 249 flags = O_WRONLY | O_CREAT | O_APPEND; 250 else 251 flags = O_RDONLY; 252 253 if ((f = open(file, flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { 254 perror("Can't open output file"); 255 exit(1); 256 } 257 return f; 258} 259 260static int open_socket(int dev, unsigned long flags) 261{ 262 struct sockaddr_hci addr; 263 struct hci_filter flt; 264 int sk, opt; 265 266 /* Create HCI socket */ 267 if ((sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) { 268 perror("Can't create HCI socket"); 269 exit(1); 270 } 271 272 opt = 1; 273 if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) { 274 perror("Can't enable data direction info"); 275 exit(1); 276 } 277 278 opt = 1; 279 if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) { 280 perror("Can't enable time stamp"); 281 exit(1); 282 } 283 284 /* Setup filter */ 285 hci_filter_clear(&flt); 286 if (flags & DUMP_BPA) { 287 hci_filter_set_ptype(HCI_VENDOR_PKT, &flt); 288 hci_filter_set_ptype(HCI_EVENT_PKT, &flt); 289 hci_filter_set_event(EVT_VENDOR, &flt); 290 } else { 291 hci_filter_all_ptypes(&flt); 292 hci_filter_all_events(&flt); 293 hci_filter_clear_ptype(HCI_VENDOR_PKT, &flt); 294 } 295 if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) { 296 perror("Can't set HCI filter"); 297 exit(1); 298 } 299 300 /* Bind socket to the HCI device */ 301 addr.hci_family = AF_BLUETOOTH; 302 addr.hci_dev = dev; 303 if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 304 printf("Can't attach to device hci%d. %s(%d)\n", 305 dev, strerror(errno), errno); 306 exit(1); 307 } 308 309 return sk; 310} 311 312static int open_connection(in_addr_t addr, in_port_t port) 313{ 314 struct sockaddr_in sa; 315 int sk, opt; 316 317 if ((sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 318 perror("Can't create inet socket"); 319 exit(1); 320 } 321 322 opt = 1; 323 setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 324 325 sa.sin_family = AF_INET; 326 sa.sin_addr.s_addr = htonl(INADDR_ANY); 327 sa.sin_port = htons(0); 328 if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 329 perror("Can't bind inet socket"); 330 close(sk); 331 exit(1); 332 } 333 334 sa.sin_family = AF_INET; 335 sa.sin_addr.s_addr = htonl(addr); 336 sa.sin_port = htons(port); 337 if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 338 perror("Can't connect inet socket"); 339 close(sk); 340 exit(1); 341 } 342 343 return sk; 344} 345 346static int wait_connection(in_addr_t addr, in_port_t port) 347{ 348 struct sockaddr_in sa; 349 struct hostent *host; 350 int sk, nsk, opt, len; 351 352 if ((sk = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 353 perror("Can't create inet socket"); 354 exit(1); 355 } 356 357 opt = 1; 358 setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 359 360 sa.sin_family = AF_INET; 361 sa.sin_addr.s_addr = htonl(addr); 362 sa.sin_port = htons(port); 363 if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) { 364 perror("Can't bind inet socket"); 365 close(sk); 366 exit(1); 367 } 368 369 host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET); 370 printf("device: %s:%d snap_len: %d filter: 0x%lx\n", 371 host ? host->h_name : inet_ntoa(sa.sin_addr), 372 ntohs(sa.sin_port), snap_len, filter); 373 374 if (listen(sk, 1)) { 375 perror("Can't listen on inet socket"); 376 close(sk); 377 exit(1); 378 } 379 380 len = sizeof(sa); 381 if ((nsk = accept(sk, (struct sockaddr *) &sa, &len)) < 0) { 382 perror("Can't accept new inet socket"); 383 close(sk); 384 exit(1); 385 } 386 387 host = gethostbyaddr(&sa.sin_addr, sizeof(sa.sin_addr), AF_INET); 388 printf("device: %s snap_len: %d filter: 0x%lx\n", 389 host ? host->h_name : inet_ntoa(sa.sin_addr), snap_len, filter); 390 391 close(sk); 392 393 return nsk; 394} 395 396static struct { 397 char *name; 398 int flag; 399} filters[] = { 400 { "hci", FILT_HCI }, 401 { "sco", FILT_SCO }, 402 { "l2cap", FILT_L2CAP }, 403 { "rfcomm", FILT_RFCOMM }, 404 { "sdp", FILT_SDP }, 405 { "bnep", FILT_BNEP }, 406 { "cmtp", FILT_CMTP }, 407 { "hidp", FILT_HIDP }, 408 { "hcrp", FILT_HCRP }, 409 { "avdtp", FILT_AVDTP }, 410 { "obex", FILT_OBEX }, 411 { "capi", FILT_CAPI }, 412 { 0 } 413}; 414 415static void parse_filter(int argc, char **argv) 416{ 417 int i,n; 418 419 for (i = 0; i < argc; i++) { 420 for (n = 0; filters[n].name; n++) { 421 if (!strcasecmp(filters[n].name, argv[i])) { 422 filter |= filters[n].flag; 423 break; 424 } 425 } 426 } 427} 428 429static void usage(void) 430{ 431 printf( 432 "Usage: hcidump [OPTION...] [filter]\n" 433 " -i, --device=hci_dev HCI device\n" 434 " -l, --snap-len=len Snap len (in bytes)\n" 435 " -p, --psm=psm Default PSM\n" 436 " -m, --manufacturer=compid Default manufacturer\n" 437 " -w, --save-dump=file Save dump to a file\n" 438 " -r, --read-dump=file Read dump from a file\n" 439 " -s, --send-dump=host Send dump to a host\n" 440 " -n, --recv-dump=host Receive dump on a host\n" 441 " -t, --ts Display time stamps\n" 442 " -a, --ascii Dump data in ascii\n" 443 " -x, --hex Dump data in hex\n" 444 " -X, --ext Dump data in hex and ascii\n" 445 " -R, --raw Raw mode\n" 446 " -B, --bpa BPA mode\n" 447 " -C, --cmtp=psm PSM for CMTP\n" 448 " -H, --hcrp=psm PSM for HCRP\n" 449 " -O, --obex=channel Channel for OBEX\n" 450 " -V, --verbose Verbose decoding\n" 451 " -h, --help Give this help list\n" 452 " --usage Give a short usage message\n" 453 ); 454} 455 456static struct option main_options[] = { 457 { "device", 1, 0, 'i' }, 458 { "snap-len", 1, 0, 'l' }, 459 { "psm", 1, 0, 'p' }, 460 { "manufacturer", 1, 0, 'm' }, 461 { "save-dump", 1, 0, 'w' }, 462 { "read-dump", 1, 0, 'r' }, 463 { "send-dump", 1, 0, 's' }, 464 { "recv-dump", 1, 0, 'n' }, 465 { "timestamp", 0, 0, 't' }, 466 { "ascii", 0, 0, 'a' }, 467 { "hex", 0, 0, 'x' }, 468 { "ext", 0, 0, 'X' }, 469 { "raw", 0, 0, 'R' }, 470 { "bpa", 0, 0, 'B' }, 471 { "cmtp", 1, 0, 'C' }, 472 { "hcrp", 1, 0, 'H' }, 473 { "obex", 1, 0, 'O' }, 474 { "verbose", 0, 0, 'V' }, 475 { "help", 0, 0, 'h' }, 476 { 0 } 477}; 478 479int main(int argc, char *argv[]) 480{ 481 struct hostent *host; 482 struct in_addr addr; 483 int opt; 484 485 printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION); 486 487 while ((opt=getopt_long(argc, argv, "i:l:p:m:w:r:s:n:taxXRBC:H:O:Vh", main_options, NULL)) != -1) { 488 switch(opt) { 489 case 'i': 490 device = atoi(optarg + 3); 491 break; 492 493 case 'l': 494 snap_len = atoi(optarg); 495 break; 496 497 case 'p': 498 defpsm = atoi(optarg); 499 break; 500 501 case 'm': 502 defcompid = atoi(optarg); 503 break; 504 505 case 'w': 506 mode = WRITE; 507 dump_file = strdup(optarg); 508 break; 509 510 case 'r': 511 mode = READ; 512 dump_file = strdup(optarg); 513 break; 514 515 case 's': 516 mode = SEND; 517 host = gethostbyname(optarg); 518 if (host) { 519 bcopy(host->h_addr, &addr, sizeof(struct in_addr)); 520 dump_addr = ntohl(addr.s_addr); 521 dump_port = DEFAULT_PORT; 522 } else { 523 dump_addr = INADDR_LOOPBACK; 524 dump_port = DEFAULT_PORT; 525 } 526 break; 527 528 case 'n': 529 mode = RECEIVE; 530 host = gethostbyname(optarg); 531 if (host) { 532 bcopy(host->h_addr, &addr, sizeof(struct in_addr)); 533 dump_addr = ntohl(addr.s_addr); 534 dump_port = DEFAULT_PORT; 535 } else { 536 dump_addr = INADDR_LOOPBACK; 537 dump_port = DEFAULT_PORT; 538 } 539 break; 540 541 case 't': 542 flags |= DUMP_TSTAMP; 543 break; 544 545 case 'a': 546 flags |= DUMP_ASCII; 547 break; 548 549 case 'x': 550 flags |= DUMP_HEX; 551 break; 552 553 case 'X': 554 flags |= DUMP_EXT; 555 break; 556 557 case 'R': 558 flags |= DUMP_RAW; 559 break; 560 561 case 'B': 562 flags |= DUMP_BPA; 563 if (defcompid == DEFAULT_COMPID) 564 defcompid = 12; 565 break; 566 567 case 'C': 568 set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP); 569 break; 570 571 case 'H': 572 set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL); 573 break; 574 575 case 'O': 576 set_proto(0, 0, atoi(optarg), SDP_UUID_OBEX); 577 break; 578 579 case 'V': 580 flags |= DUMP_VERBOSE; 581 break; 582 583 case 'h': 584 default: 585 usage(); 586 exit(0); 587 } 588 } 589 590 argc -= optind; 591 argv += optind; 592 optind = 0; 593 594 if (argc > 0) 595 parse_filter(argc, argv); 596 597 /* Default settings */ 598 if (!filter) 599 filter = ~0L; 600 601 switch (mode) { 602 case PARSE: 603 init_parser(flags, filter, defpsm, defcompid); 604 process_frames(device, open_socket(device, flags), -1); 605 break; 606 607 case READ: 608 init_parser(flags, filter, defpsm, defcompid); 609 read_dump(open_file(dump_file, mode)); 610 break; 611 612 case WRITE: 613 process_frames(device, open_socket(device, flags), open_file(dump_file, mode)); 614 break; 615 616 case RECEIVE: 617 init_parser(flags, filter, defpsm, defcompid); 618 read_dump(wait_connection(dump_addr, dump_port)); 619 break; 620 621 case SEND: 622 process_frames(device, open_socket(device, flags), open_connection(dump_addr, dump_port)); 623 break; 624 } 625 626 return 0; 627} 628