usbdump.c revision 215651
1127474Stjr/*- 2127474Stjr * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org> 3127474Stjr * All rights reserved. 4127474Stjr * 5127474Stjr * Redistribution and use in source and binary forms, with or without 6127474Stjr * modification, are permitted provided that the following conditions 7127474Stjr * are met: 8127474Stjr * 1. Redistributions of source code must retain the above copyright 9127474Stjr * notice, this list of conditions and the following disclaimer, 10127474Stjr * without modification. 11127474Stjr * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12127474Stjr * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13127474Stjr * redistribution must be conditioned upon including a substantially 14127474Stjr * similar Disclaimer requirement for further binary redistribution. 15127474Stjr * 16127474Stjr * NO WARRANTY 17127474Stjr * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18127474Stjr * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19127474Stjr * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20127474Stjr * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21127474Stjr * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22127474Stjr * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23127474Stjr * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24127474Stjr * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25127474Stjr * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26127474Stjr * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27127474Stjr * THE POSSIBILITY OF SUCH DAMAGES. 28127474Stjr * 29127474Stjr * $FreeBSD: head/usr.sbin/usbdump/usbdump.c 215651 2010-11-22 01:28:29Z weongyo $ 30127474Stjr */ 31127474Stjr 32127474Stjr#include <sys/param.h> 33127474Stjr#include <sys/endian.h> 34127474Stjr#include <sys/ioctl.h> 35127474Stjr#include <sys/stat.h> 36127474Stjr#include <sys/utsname.h> 37#include <dev/usb/usb.h> 38#include <dev/usb/usb_pf.h> 39#include <dev/usb/usbdi.h> 40#include <assert.h> 41#include <errno.h> 42#include <fcntl.h> 43#include <limits.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <string.h> 47#include <time.h> 48#include <unistd.h> 49 50struct usbcap { 51 int fd; /* fd for /dev/usbpf */ 52 u_int bufsize; 53 char *buffer; 54 55 /* for -w option */ 56 int wfd; 57 /* for -r option */ 58 int rfd; 59}; 60 61struct usbcap_filehdr { 62 u_int magic; 63#define USBCAP_FILEHDR_MAGIC 0x9a90000e 64 u_char major; 65 u_char minor; 66 u_char reserved[26]; 67} __packed; 68 69static int doexit = 0; 70static int pkt_captured = 0; 71static int verbose = 0; 72static const char *i_arg = "usbus0";; 73static const char *r_arg = NULL; 74static const char *w_arg = NULL; 75static const char *errstr_table[USB_ERR_MAX] = { 76 [USB_ERR_NORMAL_COMPLETION] = "NORMAL_COMPLETION", 77 [USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS", 78 [USB_ERR_NOT_STARTED] = "NOT_STARTED", 79 [USB_ERR_INVAL] = "INVAL", 80 [USB_ERR_NOMEM] = "NOMEM", 81 [USB_ERR_CANCELLED] = "CANCELLED", 82 [USB_ERR_BAD_ADDRESS] = "BAD_ADDRESS", 83 [USB_ERR_BAD_BUFSIZE] = "BAD_BUFSIZE", 84 [USB_ERR_BAD_FLAG] = "BAD_FLAG", 85 [USB_ERR_NO_CALLBACK] = "NO_CALLBACK", 86 [USB_ERR_IN_USE] = "IN_USE", 87 [USB_ERR_NO_ADDR] = "NO_ADDR", 88 [USB_ERR_NO_PIPE] = "NO_PIPE", 89 [USB_ERR_ZERO_NFRAMES] = "ZERO_NFRAMES", 90 [USB_ERR_ZERO_MAXP] = "ZERO_MAXP", 91 [USB_ERR_SET_ADDR_FAILED] = "SET_ADDR_FAILED", 92 [USB_ERR_NO_POWER] = "NO_POWER", 93 [USB_ERR_TOO_DEEP] = "TOO_DEEP", 94 [USB_ERR_IOERROR] = "IOERROR", 95 [USB_ERR_NOT_CONFIGURED] = "NOT_CONFIGURED", 96 [USB_ERR_TIMEOUT] = "TIMEOUT", 97 [USB_ERR_SHORT_XFER] = "SHORT_XFER", 98 [USB_ERR_STALLED] = "STALLED", 99 [USB_ERR_INTERRUPTED] = "INTERRUPTED", 100 [USB_ERR_DMA_LOAD_FAILED] = "DMA_LOAD_FAILED", 101 [USB_ERR_BAD_CONTEXT] = "BAD_CONTEXT", 102 [USB_ERR_NO_ROOT_HUB] = "NO_ROOT_HUB", 103 [USB_ERR_NO_INTR_THREAD] = "NO_INTR_THREAD", 104 [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", 105}; 106 107static const char *xfertype_table[] = { 108 [UE_CONTROL] = "CTRL", 109 [UE_ISOCHRONOUS] = "ISOC", 110 [UE_BULK] = "BULK", 111 [UE_INTERRUPT] = "INTR" 112}; 113 114static void 115handle_sigint(int sig) 116{ 117 118 (void)sig; 119 doexit = 1; 120} 121 122static void 123print_flags(u_int32_t flags) 124{ 125#define PRINTFLAGS(name) \ 126 if ((flags & USBPF_FLAG_##name) != 0) \ 127 printf("%s ", #name); 128 printf(" flags %#x", flags); 129 printf(" < "); 130 PRINTFLAGS(FORCE_SHORT_XFER); 131 PRINTFLAGS(SHORT_XFER_OK); 132 PRINTFLAGS(SHORT_FRAMES_OK); 133 PRINTFLAGS(PIPE_BOF); 134 PRINTFLAGS(PROXY_BUFFER); 135 PRINTFLAGS(EXT_BUFFER); 136 PRINTFLAGS(MANUAL_STATUS); 137 PRINTFLAGS(NO_PIPE_OK); 138 PRINTFLAGS(STALL_PIPE); 139 printf(">\n"); 140#undef PRINTFLAGS 141} 142 143static void 144print_status(u_int32_t status) 145{ 146#define PRINTSTATUS(name) \ 147 if ((status & USBPF_STATUS_##name) != 0) \ 148 printf("%s ", #name); 149 150 printf(" status %#x", status); 151 printf(" < "); 152 PRINTSTATUS(OPEN); 153 PRINTSTATUS(TRANSFERRING); 154 PRINTSTATUS(DID_DMA_DELAY); 155 PRINTSTATUS(DID_CLOSE); 156 PRINTSTATUS(DRAINING); 157 PRINTSTATUS(STARTED); 158 PRINTSTATUS(BW_RECLAIMED); 159 PRINTSTATUS(CONTROL_XFR); 160 PRINTSTATUS(CONTROL_HDR); 161 PRINTSTATUS(CONTROL_ACT); 162 PRINTSTATUS(CONTROL_STALL); 163 PRINTSTATUS(SHORT_FRAMES_OK); 164 PRINTSTATUS(SHORT_XFER_OK); 165#if USB_HAVE_BUSDMA 166 PRINTSTATUS(BDMA_ENABLE); 167 PRINTSTATUS(BDMA_NO_POST_SYNC); 168 PRINTSTATUS(BDMA_SETUP); 169#endif 170 PRINTSTATUS(ISOCHRONOUS_XFR); 171 PRINTSTATUS(CURR_DMA_SET); 172 PRINTSTATUS(CAN_CANCEL_IMMED); 173 PRINTSTATUS(DOING_CALLBACK); 174 printf(">\n"); 175#undef PRINTSTATUS 176} 177 178/* 179 * Display a region in traditional hexdump format. 180 */ 181static void 182hexdump(const char *region, size_t len) 183{ 184 const char *line; 185 int x, c; 186 char lbuf[80]; 187#define EMIT(fmt, args...) do { \ 188 sprintf(lbuf, fmt , ## args); \ 189 printf("%s", lbuf); \ 190} while (0) 191 192 for (line = region; line < (region + len); line += 16) { 193 EMIT(" %04lx ", (long) (line - region)); 194 for (x = 0; x < 16; x++) { 195 if ((line + x) < (region + len)) 196 EMIT("%02x ", *(const u_int8_t *)(line + x)); 197 else 198 EMIT("-- "); 199 if (x == 7) 200 EMIT(" "); 201 } 202 EMIT(" |"); 203 for (x = 0; x < 16; x++) { 204 if ((line + x) < (region + len)) { 205 c = *(const u_int8_t *)(line + x); 206 /* !isprint(c) */ 207 if ((c < ' ') || (c > '~')) 208 c = '.'; 209 EMIT("%c", c); 210 } else 211 EMIT(" "); 212 } 213 EMIT("|\n"); 214 } 215#undef EMIT 216} 217 218static void 219print_apacket(const struct usbpf_xhdr *hdr, struct usbpf_pkthdr *up, 220 const char *payload) 221{ 222 struct tm *tm; 223 struct timeval tv; 224 size_t len; 225 u_int32_t framelen, x; 226 const char *ptr = payload; 227 char buf[64]; 228 229 /* A packet from the kernel is based on little endian byte order. */ 230 up->up_busunit = le32toh(up->up_busunit); 231 up->up_flags = le32toh(up->up_flags); 232 up->up_status = le32toh(up->up_status); 233 up->up_length = le32toh(up->up_length); 234 up->up_frames = le32toh(up->up_frames); 235 up->up_error = le32toh(up->up_error); 236 up->up_interval = le32toh(up->up_interval); 237 238 tv.tv_sec = hdr->uh_tstamp.ut_sec; 239 tv.tv_usec = hdr->uh_tstamp.ut_frac; 240 tm = localtime(&tv.tv_sec); 241 242 len = strftime(buf, sizeof(buf), "%H:%M:%S", tm); 243 printf("%.*s.%06ju", (int)len, buf, tv.tv_usec); 244 printf(" usbus%d.%d 0x%02x %s %s", up->up_busunit, up->up_address, 245 up->up_endpoint, 246 xfertype_table[up->up_xfertype], 247 up->up_type == USBPF_XFERTAP_SUBMIT ? ">" : "<"); 248 printf(" (%d/%d)", up->up_frames, up->up_length); 249 if (up->up_type == USBPF_XFERTAP_DONE) 250 printf(" %s", errstr_table[up->up_error]); 251 if (up->up_xfertype == UE_BULK || up->up_xfertype == UE_ISOCHRONOUS) 252 printf(" %d", up->up_interval); 253 printf("\n"); 254 255 if (verbose >= 1) { 256 for (x = 0; x < up->up_frames; x++) { 257 framelen = le32toh(*((const u_int32_t *)ptr)); 258 ptr += sizeof(u_int32_t); 259 printf(" frame[%u] len %d\n", x, framelen); 260 assert(framelen < (1024 * 4)); 261 hexdump(ptr, framelen); 262 ptr += framelen; 263 } 264 } 265 if (verbose >= 2) { 266 print_flags(up->up_flags); 267 print_status(up->up_status); 268 } 269} 270 271 272static void 273print_packets(char *data, const int datalen) 274{ 275 struct usbpf_pkthdr *up; 276 const struct usbpf_xhdr *hdr; 277 u_int32_t framelen, x; 278 char *ptr, *next; 279 280 for (ptr = data; ptr < (data + datalen); ptr = next) { 281 hdr = (const struct usbpf_xhdr *)ptr; 282 up = (struct usbpf_pkthdr *)(ptr + hdr->uh_hdrlen); 283 next = ptr + USBPF_WORDALIGN(hdr->uh_hdrlen + hdr->uh_caplen); 284 285 ptr = ((char *)up) + sizeof(struct usbpf_pkthdr); 286 if (w_arg == NULL) 287 print_apacket(hdr, up, ptr); 288 pkt_captured++; 289 for (x = 0; x < up->up_frames; x++) { 290 framelen = le32toh(*((const u_int32_t *)ptr)); 291 ptr += sizeof(u_int32_t) + framelen; 292 } 293 } 294} 295 296static void 297write_packets(struct usbcap *p, const char *data, const int datalen) 298{ 299 int len = htole32(datalen), ret; 300 301 ret = write(p->wfd, &len, sizeof(int)); 302 assert(ret == sizeof(int)); 303 ret = write(p->wfd, data, datalen); 304 assert(ret == datalen); 305} 306 307static void 308read_file(struct usbcap *p) 309{ 310 int datalen, ret; 311 char *data; 312 313 while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) { 314 datalen = le32toh(datalen); 315 data = malloc(datalen); 316 assert(data != NULL); 317 ret = read(p->rfd, data, datalen); 318 assert(ret == datalen); 319 print_packets(data, datalen); 320 free(data); 321 } 322 if (ret == -1) 323 fprintf(stderr, "read: %s\n", strerror(errno)); 324} 325 326static void 327do_loop(struct usbcap *p) 328{ 329 int cc; 330 331 while (doexit == 0) { 332 cc = read(p->fd, (char *)p->buffer, p->bufsize); 333 if (cc < 0) { 334 switch (errno) { 335 case EINTR: 336 break; 337 default: 338 fprintf(stderr, "read: %s\n", strerror(errno)); 339 return; 340 } 341 continue; 342 } 343 if (cc == 0) 344 continue; 345 if (w_arg != NULL) 346 write_packets(p, p->buffer, cc); 347 print_packets(p->buffer, cc); 348 } 349} 350 351static void 352init_rfile(struct usbcap *p) 353{ 354 struct usbcap_filehdr uf; 355 int ret; 356 357 p->rfd = open(r_arg, O_RDONLY); 358 if (p->rfd < 0) { 359 fprintf(stderr, "open: %s (%s)\n", r_arg, strerror(errno)); 360 exit(EXIT_FAILURE); 361 } 362 ret = read(p->rfd, &uf, sizeof(uf)); 363 assert(ret == sizeof(uf)); 364 assert(le32toh(uf.magic) == USBCAP_FILEHDR_MAGIC); 365 assert(uf.major == 0); 366 assert(uf.minor == 1); 367} 368 369static void 370init_wfile(struct usbcap *p) 371{ 372 struct usbcap_filehdr uf; 373 int ret; 374 375 p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 376 if (p->wfd < 0) { 377 fprintf(stderr, "open: %s (%s)\n", w_arg, strerror(errno)); 378 exit(EXIT_FAILURE); 379 } 380 bzero(&uf, sizeof(uf)); 381 uf.magic = htole32(USBCAP_FILEHDR_MAGIC); 382 uf.major = 0; 383 uf.minor = 1; 384 ret = write(p->wfd, (const void *)&uf, sizeof(uf)); 385 assert(ret == sizeof(uf)); 386} 387 388static void 389usage(void) 390{ 391 392#define FMT " %-14s %s\n" 393 fprintf(stderr, "usage: usbdump [options]\n"); 394 fprintf(stderr, FMT, "-i ifname", "Listen on USB bus interface"); 395 fprintf(stderr, FMT, "-r file", "Read the raw packets from file"); 396 fprintf(stderr, FMT, "-s snaplen", "Snapshot bytes from each packet"); 397 fprintf(stderr, FMT, "-v", "Increases the verbose level"); 398 fprintf(stderr, FMT, "-w file", "Write the raw packets to file"); 399#undef FMT 400 exit(1); 401} 402 403int 404main(int argc, char *argv[]) 405{ 406 struct timeval tv; 407 struct usbpf_insn total_insn; 408 struct usbpf_program total_prog; 409 struct usbpf_stat us; 410 struct usbpf_version uv; 411 struct usbcap uc, *p = &uc; 412 struct usbpf_ifreq ufr; 413 long snapshot = 192; 414 u_int v; 415 int fd, o; 416 const char *optstring; 417 418 bzero(&uc, sizeof(struct usbcap)); 419 420 optstring = "i:r:s:vw:"; 421 while ((o = getopt(argc, argv, optstring)) != -1) { 422 switch (o) { 423 case 'i': 424 i_arg = optarg; 425 break; 426 case 'r': 427 r_arg = optarg; 428 init_rfile(p); 429 break; 430 case 's': 431 snapshot = strtol(optarg, NULL, 10); 432 errno = 0; 433 if (snapshot == 0 && errno == EINVAL) 434 usage(); 435 /* snapeshot == 0 is special */ 436 if (snapshot == 0) 437 snapshot = -1; 438 break; 439 case 'v': 440 verbose++; 441 break; 442 case 'w': 443 w_arg = optarg; 444 init_wfile(p); 445 break; 446 default: 447 usage(); 448 /* NOTREACHED */ 449 } 450 } 451 452 if (r_arg != NULL) { 453 read_file(p); 454 exit(EXIT_SUCCESS); 455 } 456 457 p->fd = fd = open("/dev/usbpf", O_RDONLY); 458 if (p->fd < 0) { 459 fprintf(stderr, "(no devices found)\n"); 460 return (EXIT_FAILURE); 461 } 462 463 if (ioctl(fd, UIOCVERSION, (caddr_t)&uv) < 0) { 464 fprintf(stderr, "UIOCVERSION: %s\n", strerror(errno)); 465 return (EXIT_FAILURE); 466 } 467 if (uv.uv_major != USBPF_MAJOR_VERSION || 468 uv.uv_minor < USBPF_MINOR_VERSION) { 469 fprintf(stderr, "kernel bpf filter out of date"); 470 return (EXIT_FAILURE); 471 } 472 473 if ((ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) || v < 65536) 474 v = 65536; 475 for ( ; v != 0; v >>= 1) { 476 (void)ioctl(fd, UIOCSBLEN, (caddr_t)&v); 477 (void)strncpy(ufr.ufr_name, i_arg, sizeof(ufr.ufr_name)); 478 if (ioctl(fd, UIOCSETIF, (caddr_t)&ufr) >= 0) 479 break; 480 } 481 if (v == 0) { 482 fprintf(stderr, "UIOCSBLEN: %s: No buffer size worked", i_arg); 483 return (EXIT_FAILURE); 484 } 485 486 if (ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) { 487 fprintf(stderr, "UIOCGBLEN: %s", strerror(errno)); 488 return (EXIT_FAILURE); 489 } 490 491 p->bufsize = v; 492 p->buffer = (u_char *)malloc(p->bufsize); 493 if (p->buffer == NULL) { 494 fprintf(stderr, "malloc: %s", strerror(errno)); 495 return (EXIT_FAILURE); 496 } 497 498 /* XXX no read filter rules yet so at this moment accept everything */ 499 total_insn.code = (u_short)(USBPF_RET | USBPF_K); 500 total_insn.jt = 0; 501 total_insn.jf = 0; 502 total_insn.k = snapshot; 503 504 total_prog.uf_len = 1; 505 total_prog.uf_insns = &total_insn; 506 if (ioctl(p->fd, UIOCSETF, (caddr_t)&total_prog) < 0) { 507 fprintf(stderr, "UIOCSETF: %s", strerror(errno)); 508 return (EXIT_FAILURE); 509 } 510 511 /* 1 second read timeout */ 512 tv.tv_sec = 1; 513 tv.tv_usec = 0; 514 if (ioctl(p->fd, UIOCSRTIMEOUT, (caddr_t)&tv) < 0) { 515 fprintf(stderr, "UIOCSRTIMEOUT: %s", strerror(errno)); 516 return (EXIT_FAILURE); 517 } 518 519 (void)signal(SIGINT, handle_sigint); 520 521 do_loop(p); 522 523 if (ioctl(fd, UIOCGSTATS, (caddr_t)&us) < 0) { 524 fprintf(stderr, "UIOCGSTATS: %s", strerror(errno)); 525 return (EXIT_FAILURE); 526 } 527 528 /* XXX what's difference between pkt_captured and us.us_recv? */ 529 printf("\n"); 530 printf("%d packets captured\n", pkt_captured); 531 printf("%d packets received by filter\n", us.us_recv); 532 printf("%d packets dropped by kernel\n", us.us_drop); 533 534 if (p->fd > 0) 535 close(p->fd); 536 if (p->rfd > 0) 537 close(p->rfd); 538 if (p->wfd > 0) 539 close(p->wfd); 540 541 return (EXIT_SUCCESS); 542} 543