usbdump.c revision 234655
128219Smsmith/*- 255939Snsouch * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org> 328219Smsmith * All rights reserved. 428219Smsmith * 528219Smsmith * Redistribution and use in source and binary forms, with or without 628219Smsmith * modification, are permitted provided that the following conditions 728219Smsmith * are met: 828219Smsmith * 1. Redistributions of source code must retain the above copyright 928219Smsmith * notice, this list of conditions and the following disclaimer, 1028219Smsmith * without modification. 1128219Smsmith * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1228219Smsmith * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 1328219Smsmith * redistribution must be conditioned upon including a substantially 1428219Smsmith * similar Disclaimer requirement for further binary redistribution. 1528219Smsmith * 1628219Smsmith * NO WARRANTY 1728219Smsmith * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1828219Smsmith * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1928219Smsmith * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 2028219Smsmith * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 2128219Smsmith * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 2228219Smsmith * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2328219Smsmith * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2428219Smsmith * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2528219Smsmith * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2650477Speter * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 2728219Smsmith * THE POSSIBILITY OF SUCH DAMAGES. 2828219Smsmith * 2928219Smsmith * $FreeBSD: head/usr.sbin/usbdump/usbdump.c 234655 2012-04-24 14:06:07Z hselasky $ 3028219Smsmith */ 3128219Smsmith 32188093Sjhb#include <sys/param.h> 33188093Sjhb#include <sys/endian.h> 34188093Sjhb#include <sys/ioctl.h> 35188093Sjhb#include <sys/socket.h> 36188093Sjhb#include <sys/stat.h> 37188093Sjhb#include <sys/utsname.h> 38188093Sjhb#include <sys/queue.h> 39188093Sjhb#include <net/if.h> 40188093Sjhb#include <net/bpf.h> 41188093Sjhb#include <dev/usb/usb.h> 42188093Sjhb#include <dev/usb/usb_pf.h> 43188093Sjhb#include <dev/usb/usbdi.h> 44188093Sjhb#include <errno.h> 45188093Sjhb#include <fcntl.h> 46188093Sjhb#include <limits.h> 47188093Sjhb#include <stdio.h> 48188093Sjhb#include <stdlib.h> 49188093Sjhb#include <stdint.h> 50188093Sjhb#include <string.h> 51188093Sjhb#include <time.h> 52188093Sjhb#include <unistd.h> 53188093Sjhb#include <sysexits.h> 54188093Sjhb#include <err.h> 55188093Sjhb 56188093Sjhb#define BPF_STORE_JUMP(x,_c,_k,_jt,_jf) do { \ 57188093Sjhb (x).code = (_c); \ 58188093Sjhb (x).k = (_k); \ 59188093Sjhb (x).jt = (_jt); \ 60188093Sjhb (x).jf = (_jf); \ 6129020Sbde} while (0) 6229020Sbde 6328219Smsmith#define BPF_STORE_STMT(x,_c,_k) do { \ 6428257Smsmith (x).code = (_c); \ 6528257Smsmith (x).k = (_k); \ 6643293Sdillon (x).jt = 0; \ 6728257Smsmith (x).jf = 0; \ 6828257Smsmith} while (0) 6938061Smsmith 7038061Smsmithstruct usb_filt { 7128219Smsmith STAILQ_ENTRY(usb_filt) entry; 7238061Smsmith int unit; 7338061Smsmith int endpoint; 7438061Smsmith}; 7528219Smsmith 7638061Smsmithstruct usbcap { 7738061Smsmith int fd; /* fd for /dev/usbpf */ 7828219Smsmith uint32_t bufsize; 7942475Snsouch uint8_t *buffer; 8042475Snsouch 8142475Snsouch /* for -w option */ 8228219Smsmith int wfd; 8342475Snsouch /* for -r option */ 8442475Snsouch int rfd; 8542475Snsouch /* for -b option */ 8638061Smsmith int bfd; 8755939Snsouch}; 8855939Snsouch 8955939Snsouchstruct usbcap_filehdr { 9028219Smsmith uint32_t magic; 9128219Smsmith#define USBCAP_FILEHDR_MAGIC 0x9a90000e 9228219Smsmith uint8_t major; 9328219Smsmith uint8_t minor; 9428219Smsmith uint8_t reserved[26]; 9528219Smsmith} __packed; 9628219Smsmith 9728219Smsmith#define HEADER_ALIGN(x,a) (((x) + (a) - 1) & ~((a) - 1)) 9828219Smsmith 9928219Smsmithstruct header_32 { 10028219Smsmith /* capture timestamp */ 10128219Smsmith uint32_t ts_sec; 10228219Smsmith uint32_t ts_usec; 10328219Smsmith /* data length and alignment information */ 10428219Smsmith uint32_t caplen; 10555939Snsouch uint32_t datalen; 10655939Snsouch uint8_t hdrlen; 10755939Snsouch uint8_t align; 10855939Snsouch} __packed; 10955939Snsouch 11055939Snsouchstatic int doexit = 0; 11155939Snsouchstatic int pkt_captured = 0; 11255939Snsouchstatic int verbose = 0; 11355939Snsouchstatic int uf_minor; 11455939Snsouchstatic const char *i_arg = "usbus0"; 11555939Snsouchstatic const char *r_arg = NULL; 11655939Snsouchstatic const char *w_arg = NULL; 11755939Snsouchstatic const char *b_arg = NULL; 11855939Snsouchstatic struct usbcap uc; 11955939Snsouchstatic const char *errstr_table[USB_ERR_MAX] = { 12055939Snsouch [USB_ERR_NORMAL_COMPLETION] = "0", 12155939Snsouch [USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS", 12255939Snsouch [USB_ERR_NOT_STARTED] = "NOT_STARTED", 12355939Snsouch [USB_ERR_INVAL] = "INVAL", 12455939Snsouch [USB_ERR_NOMEM] = "NOMEM", 12555939Snsouch [USB_ERR_CANCELLED] = "CANCELLED", 12655939Snsouch [USB_ERR_BAD_ADDRESS] = "BAD_ADDRESS", 12728219Smsmith [USB_ERR_BAD_BUFSIZE] = "BAD_BUFSIZE", 12838061Smsmith [USB_ERR_BAD_FLAG] = "BAD_FLAG", 12928219Smsmith [USB_ERR_NO_CALLBACK] = "NO_CALLBACK", 13028219Smsmith [USB_ERR_IN_USE] = "IN_USE", 13128219Smsmith [USB_ERR_NO_ADDR] = "NO_ADDR", 13228219Smsmith [USB_ERR_NO_PIPE] = "NO_PIPE", 13328219Smsmith [USB_ERR_ZERO_NFRAMES] = "ZERO_NFRAMES", 13442475Snsouch [USB_ERR_ZERO_MAXP] = "ZERO_MAXP", 13542475Snsouch [USB_ERR_SET_ADDR_FAILED] = "SET_ADDR_FAILED", 13628219Smsmith [USB_ERR_NO_POWER] = "NO_POWER", 13738061Smsmith [USB_ERR_TOO_DEEP] = "TOO_DEEP", 13838061Smsmith [USB_ERR_IOERROR] = "IOERROR", 13938061Smsmith [USB_ERR_NOT_CONFIGURED] = "NOT_CONFIGURED", 14038061Smsmith [USB_ERR_TIMEOUT] = "TIMEOUT", 14138061Smsmith [USB_ERR_SHORT_XFER] = "SHORT_XFER", 14228219Smsmith [USB_ERR_STALLED] = "STALLED", 14338061Smsmith [USB_ERR_INTERRUPTED] = "INTERRUPTED", 14438061Smsmith [USB_ERR_DMA_LOAD_FAILED] = "DMA_LOAD_FAILED", 14538061Smsmith [USB_ERR_BAD_CONTEXT] = "BAD_CONTEXT", 14638061Smsmith [USB_ERR_NO_ROOT_HUB] = "NO_ROOT_HUB", 14738061Smsmith [USB_ERR_NO_INTR_THREAD] = "NO_INTR_THREAD", 14838061Smsmith [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", 14938061Smsmith}; 15038061Smsmith 15145342Speterstatic const char *xfertype_table[4] = { 15238061Smsmith [UE_CONTROL] = "CTRL", 15338061Smsmith [UE_ISOCHRONOUS] = "ISOC", 15438061Smsmith [UE_BULK] = "BULK", 15538061Smsmith [UE_INTERRUPT] = "INTR" 15638061Smsmith}; 15738061Smsmith 15838061Smsmithstatic const char *speed_table[USB_SPEED_MAX] = { 15938061Smsmith [USB_SPEED_FULL] = "FULL", 16038061Smsmith [USB_SPEED_HIGH] = "HIGH", 16138061Smsmith [USB_SPEED_LOW] = "LOW", 16238061Smsmith [USB_SPEED_VARIABLE] = "VARI", 16338061Smsmith [USB_SPEED_SUPER] = "SUPER", 16438061Smsmith}; 16528219Smsmith 16628219Smsmithstatic STAILQ_HEAD(,usb_filt) usb_filt_head = 16728219Smsmith STAILQ_HEAD_INITIALIZER(usb_filt_head); 16838061Smsmith 16938061Smsmithstatic void 17038061Smsmithadd_filter(int usb_filt_unit, int usb_filt_ep) 17138061Smsmith{ 17238061Smsmith struct usb_filt *puf; 17338061Smsmith 17438061Smsmith puf = malloc(sizeof(struct usb_filt)); 17538061Smsmith if (puf == NULL) 17638061Smsmith errx(EX_SOFTWARE, "Out of memory."); 17738061Smsmith 17855939Snsouch puf->unit = usb_filt_unit; 17955939Snsouch puf->endpoint = usb_filt_ep; 18055939Snsouch 18155939Snsouch STAILQ_INSERT_TAIL(&usb_filt_head, puf, entry); 18255939Snsouch} 18355939Snsouch 18455939Snsouchstatic void 18528219Smsmithmake_filter(struct bpf_program *pprog, int snapshot) 18628219Smsmith{ 18755939Snsouch struct usb_filt *puf; 18828219Smsmith struct bpf_insn *dynamic_insn; 189118607Sjhb int len; 19038061Smsmith 19138061Smsmith len = 0; 19238061Smsmith 19338061Smsmith STAILQ_FOREACH(puf, &usb_filt_head, entry) 19438061Smsmith len++; 19538061Smsmith 19638061Smsmith dynamic_insn = malloc(((len * 5) + 1) * sizeof(struct bpf_insn)); 19738061Smsmith 19838061Smsmith if (dynamic_insn == NULL) 19938061Smsmith errx(EX_SOFTWARE, "Out of memory."); 20038061Smsmith 20138061Smsmith len++; 202185003Sjhb 203187576Sjhb if (len == 1) { 204187576Sjhb /* accept all packets */ 20528219Smsmith 20628219Smsmith BPF_STORE_STMT(dynamic_insn[0], BPF_RET | BPF_K, snapshot); 20755939Snsouch 20828219Smsmith goto done; 20928219Smsmith } 210185003Sjhb 21155939Snsouch len = 0; 21255939Snsouch 213187576Sjhb STAILQ_FOREACH(puf, &usb_filt_head, entry) { 214187576Sjhb const int addr_off = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_address; 215185003Sjhb const int addr_ep = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_endpoint; 21628219Smsmith 21728257Smsmith if (puf->unit != -1) { 21828257Smsmith if (puf->endpoint != -1) { 21942475Snsouch BPF_STORE_STMT(dynamic_insn[len], 22028257Smsmith BPF_LD | BPF_B | BPF_ABS, addr_off); 22128257Smsmith len++; 22228219Smsmith BPF_STORE_JUMP(dynamic_insn[len], 22328219Smsmith BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 3); 22428219Smsmith len++; 22528219Smsmith BPF_STORE_STMT(dynamic_insn[len], 22628257Smsmith BPF_LD | BPF_W | BPF_ABS, addr_ep); 22728257Smsmith len++; 22828257Smsmith BPF_STORE_JUMP(dynamic_insn[len], 22928257Smsmith BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1); 23028257Smsmith len++; 23128257Smsmith } else { 23228257Smsmith BPF_STORE_STMT(dynamic_insn[len], 23328257Smsmith BPF_LD | BPF_B | BPF_ABS, addr_off); 23428257Smsmith len++; 23528257Smsmith BPF_STORE_JUMP(dynamic_insn[len], 23628257Smsmith BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 1); 23755939Snsouch len++; 23828257Smsmith } 23955939Snsouch } else { 24055939Snsouch if (puf->endpoint != -1) { 24142475Snsouch BPF_STORE_STMT(dynamic_insn[len], 24255939Snsouch BPF_LD | BPF_W | BPF_ABS, addr_ep); 24355939Snsouch len++; 24438061Smsmith BPF_STORE_JUMP(dynamic_insn[len], 245187576Sjhb BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1); 246187576Sjhb len++; 247187576Sjhb } 248187576Sjhb } 24928219Smsmith BPF_STORE_STMT(dynamic_insn[len], 25028219Smsmith BPF_RET | BPF_K, snapshot); 251187576Sjhb len++; 252187576Sjhb } 253187576Sjhb 254187576Sjhb BPF_STORE_STMT(dynamic_insn[len], BPF_RET | BPF_K, 0); 25555939Snsouch len++; 25655939Snsouch 25755939Snsouchdone: 25828219Smsmith pprog->bf_len = len; 25955939Snsouch pprog->bf_insns = dynamic_insn; 260187576Sjhb} 261187576Sjhb 262187576Sjhbstatic int 263187576Sjhbmatch_filter(int unit, int endpoint) 264187576Sjhb{ 26555939Snsouch struct usb_filt *puf; 266305555Sdim 26755939Snsouch if (STAILQ_FIRST(&usb_filt_head) == NULL) 26855939Snsouch return (1); 26955939Snsouch 27055939Snsouch STAILQ_FOREACH(puf, &usb_filt_head, entry) { 27155939Snsouch if ((puf->unit == -1 || puf->unit == unit) && 27255939Snsouch (puf->endpoint == -1 || puf->endpoint == endpoint)) 273187576Sjhb return (1); 274187576Sjhb } 275187576Sjhb return (0); 276187576Sjhb} 277187576Sjhb 278187576Sjhbstatic void 27959712Sn_hibmafree_filter(struct bpf_program *pprog) 28028219Smsmith{ 281187576Sjhb struct usb_filt *puf; 282 283 while ((puf = STAILQ_FIRST(&usb_filt_head)) != NULL) { 284 STAILQ_REMOVE_HEAD(&usb_filt_head, entry); 285 free(puf); 286 } 287 free(pprog->bf_insns); 288} 289 290static void 291handle_sigint(int sig) 292{ 293 294 (void)sig; 295 doexit = 1; 296} 297 298#define FLAGS(x, name) \ 299 (((x) & USBPF_FLAG_##name) ? #name "|" : "") 300 301#define STATUS(x, name) \ 302 (((x) & USBPF_STATUS_##name) ? #name "|" : "") 303 304static const char * 305usb_errstr(uint32_t error) 306{ 307 if (error >= USB_ERR_MAX || errstr_table[error] == NULL) 308 return ("UNKNOWN"); 309 else 310 return (errstr_table[error]); 311} 312 313static const char * 314usb_speedstr(uint8_t speed) 315{ 316 if (speed >= USB_SPEED_MAX || speed_table[speed] == NULL) 317 return ("UNKNOWN"); 318 else 319 return (speed_table[speed]); 320} 321 322static void 323print_flags(uint32_t flags) 324{ 325 printf(" flags %#x <%s%s%s%s%s%s%s%s%s0>\n", 326 flags, 327 FLAGS(flags, FORCE_SHORT_XFER), 328 FLAGS(flags, SHORT_XFER_OK), 329 FLAGS(flags, SHORT_FRAMES_OK), 330 FLAGS(flags, PIPE_BOF), 331 FLAGS(flags, PROXY_BUFFER), 332 FLAGS(flags, EXT_BUFFER), 333 FLAGS(flags, MANUAL_STATUS), 334 FLAGS(flags, NO_PIPE_OK), 335 FLAGS(flags, STALL_PIPE)); 336} 337 338static void 339print_status(uint32_t status) 340{ 341 printf(" status %#x <%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s0>\n", 342 status, 343 STATUS(status, OPEN), 344 STATUS(status, TRANSFERRING), 345 STATUS(status, DID_DMA_DELAY), 346 STATUS(status, DID_CLOSE), 347 STATUS(status, DRAINING), 348 STATUS(status, STARTED), 349 STATUS(status, BW_RECLAIMED), 350 STATUS(status, CONTROL_XFR), 351 STATUS(status, CONTROL_HDR), 352 STATUS(status, CONTROL_ACT), 353 STATUS(status, CONTROL_STALL), 354 STATUS(status, SHORT_FRAMES_OK), 355 STATUS(status, SHORT_XFER_OK), 356 STATUS(status, BDMA_ENABLE), 357 STATUS(status, BDMA_NO_POST_SYNC), 358 STATUS(status, BDMA_SETUP), 359 STATUS(status, ISOCHRONOUS_XFR), 360 STATUS(status, CURR_DMA_SET), 361 STATUS(status, CAN_CANCEL_IMMED), 362 STATUS(status, DOING_CALLBACK)); 363} 364 365/* 366 * Dump a byte into hex format. 367 */ 368static void 369hexbyte(char *buf, uint8_t temp) 370{ 371 uint8_t lo; 372 uint8_t hi; 373 374 lo = temp & 0xF; 375 hi = temp >> 4; 376 377 if (hi < 10) 378 buf[0] = '0' + hi; 379 else 380 buf[0] = 'A' + hi - 10; 381 382 if (lo < 10) 383 buf[1] = '0' + lo; 384 else 385 buf[1] = 'A' + lo - 10; 386} 387 388/* 389 * Display a region in traditional hexdump format. 390 */ 391static void 392hexdump(const uint8_t *region, uint32_t len) 393{ 394 const uint8_t *line; 395 char linebuf[128]; 396 int i; 397 int x; 398 int c; 399 400 for (line = region; line < (region + len); line += 16) { 401 402 i = 0; 403 404 linebuf[i] = ' '; 405 hexbyte(linebuf + i + 1, ((line - region) >> 8) & 0xFF); 406 hexbyte(linebuf + i + 3, (line - region) & 0xFF); 407 linebuf[i + 5] = ' '; 408 linebuf[i + 6] = ' '; 409 i += 7; 410 411 for (x = 0; x < 16; x++) { 412 if ((line + x) < (region + len)) { 413 hexbyte(linebuf + i, 414 *(const u_int8_t *)(line + x)); 415 } else { 416 linebuf[i] = '-'; 417 linebuf[i + 1] = '-'; 418 } 419 linebuf[i + 2] = ' '; 420 if (x == 7) { 421 linebuf[i + 3] = ' '; 422 i += 4; 423 } else { 424 i += 3; 425 } 426 } 427 linebuf[i] = ' '; 428 linebuf[i + 1] = '|'; 429 i += 2; 430 for (x = 0; x < 16; x++) { 431 if ((line + x) < (region + len)) { 432 c = *(const u_int8_t *)(line + x); 433 /* !isprint(c) */ 434 if ((c < ' ') || (c > '~')) 435 c = '.'; 436 linebuf[i] = c; 437 } else { 438 linebuf[i] = ' '; 439 } 440 i++; 441 } 442 linebuf[i] = '|'; 443 linebuf[i + 1] = 0; 444 i += 2; 445 puts(linebuf); 446 } 447} 448 449static void 450print_apacket(const struct header_32 *hdr, const uint8_t *ptr, int ptr_len) 451{ 452 struct tm *tm; 453 struct usbpf_pkthdr up_temp; 454 struct usbpf_pkthdr *up; 455 struct timeval tv; 456 size_t len; 457 uint32_t x; 458 char buf[64]; 459 460 ptr += USBPF_HDR_LEN; 461 ptr_len -= USBPF_HDR_LEN; 462 if (ptr_len < 0) 463 return; 464 465 /* make sure we don't change the source buffer */ 466 memcpy(&up_temp, ptr - USBPF_HDR_LEN, sizeof(up_temp)); 467 up = &up_temp; 468 469 /* 470 * A packet from the kernel is based on little endian byte 471 * order. 472 */ 473 up->up_totlen = le32toh(up->up_totlen); 474 up->up_busunit = le32toh(up->up_busunit); 475 up->up_address = le32toh(up->up_address); 476 up->up_flags = le32toh(up->up_flags); 477 up->up_status = le32toh(up->up_status); 478 up->up_error = le32toh(up->up_error); 479 up->up_interval = le32toh(up->up_interval); 480 up->up_frames = le32toh(up->up_frames); 481 up->up_packet_size = le32toh(up->up_packet_size); 482 up->up_packet_count = le32toh(up->up_packet_count); 483 up->up_endpoint = le32toh(up->up_endpoint); 484 485 if (!match_filter(up->up_address, up->up_endpoint)) 486 return; 487 488 tv.tv_sec = hdr->ts_sec; 489 tv.tv_usec = hdr->ts_usec; 490 tm = localtime(&tv.tv_sec); 491 492 len = strftime(buf, sizeof(buf), "%H:%M:%S", tm); 493 494 if (verbose >= 0) { 495 printf("%.*s.%06ld usbus%d.%d %s-%s-EP=%08x,SPD=%s,NFR=%d,SLEN=%d,IVAL=%d%s%s\n", 496 (int)len, buf, tv.tv_usec, 497 (int)up->up_busunit, (int)up->up_address, 498 (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE", 499 xfertype_table[up->up_xfertype], 500 (unsigned int)up->up_endpoint, 501 usb_speedstr(up->up_speed), 502 (int)up->up_frames, 503 (int)(up->up_totlen - USBPF_HDR_LEN - 504 (USBPF_FRAME_HDR_LEN * up->up_frames)), 505 (int)up->up_interval, 506 (up->up_type == USBPF_XFERTAP_DONE) ? ",ERR=" : "", 507 (up->up_type == USBPF_XFERTAP_DONE) ? 508 usb_errstr(up->up_error) : ""); 509 } 510 511 if (verbose >= 1 || b_arg != NULL) { 512 for (x = 0; x != up->up_frames; x++) { 513 const struct usbpf_framehdr *uf; 514 uint32_t framelen; 515 uint32_t flags; 516 517 uf = (const struct usbpf_framehdr *)ptr; 518 ptr += USBPF_FRAME_HDR_LEN; 519 ptr_len -= USBPF_FRAME_HDR_LEN; 520 if (ptr_len < 0) 521 return; 522 523 framelen = le32toh(uf->length); 524 flags = le32toh(uf->flags); 525 526 if (verbose >= 1) { 527 printf(" frame[%u] %s %d bytes\n", 528 (unsigned int)x, 529 (flags & USBPF_FRAMEFLAG_READ) ? "READ" : "WRITE", 530 (int)framelen); 531 } 532 533 if (flags & USBPF_FRAMEFLAG_DATA_FOLLOWS) { 534 535 int tot_frame_len; 536 537 tot_frame_len = USBPF_FRAME_ALIGN(framelen); 538 539 ptr_len -= tot_frame_len; 540 541 if (tot_frame_len < 0 || 542 (int)framelen < 0 || (int)ptr_len < 0) 543 break; 544 545 if (b_arg != NULL) { 546 struct usbcap *p = &uc; 547 int ret; 548 ret = write(p->bfd, ptr, framelen); 549 if (ret != (int)framelen) 550 err(EXIT_FAILURE, "Could not write binary data"); 551 } 552 if (verbose >= 1) 553 hexdump(ptr, framelen); 554 555 ptr += tot_frame_len; 556 } 557 } 558 } 559 if (verbose >= 2) 560 print_flags(up->up_flags); 561 if (verbose >= 3) 562 print_status(up->up_status); 563} 564 565static void 566fix_packets(uint8_t *data, const int datalen) 567{ 568 struct header_32 temp; 569 uint8_t *ptr; 570 uint8_t *next; 571 uint32_t hdrlen; 572 uint32_t caplen; 573 574 for (ptr = data; ptr < (data + datalen); ptr = next) { 575 576 const struct bpf_hdr *hdr; 577 578 hdr = (const struct bpf_hdr *)ptr; 579 580 temp.ts_sec = htole32(hdr->bh_tstamp.tv_sec); 581 temp.ts_usec = htole32(hdr->bh_tstamp.tv_usec); 582 temp.caplen = htole32(hdr->bh_caplen); 583 temp.datalen = htole32(hdr->bh_datalen); 584 temp.hdrlen = hdr->bh_hdrlen; 585 temp.align = BPF_WORDALIGN(1); 586 587 hdrlen = hdr->bh_hdrlen; 588 caplen = hdr->bh_caplen; 589 590 if ((hdrlen >= sizeof(temp)) && (hdrlen <= 255) && 591 ((ptr + hdrlen) <= (data + datalen))) { 592 memcpy(ptr, &temp, sizeof(temp)); 593 memset(ptr + sizeof(temp), 0, hdrlen - sizeof(temp)); 594 } else { 595 err(EXIT_FAILURE, "Invalid header length %d", hdrlen); 596 } 597 598 next = ptr + BPF_WORDALIGN(hdrlen + caplen); 599 600 if (next <= ptr) 601 err(EXIT_FAILURE, "Invalid length"); 602 } 603} 604 605static void 606print_packets(uint8_t *data, const int datalen) 607{ 608 struct header_32 temp; 609 uint8_t *ptr; 610 uint8_t *next; 611 612 for (ptr = data; ptr < (data + datalen); ptr = next) { 613 614 const struct header_32 *hdr32; 615 616 hdr32 = (const struct header_32 *)ptr; 617 618 temp.ts_sec = le32toh(hdr32->ts_sec); 619 temp.ts_usec = le32toh(hdr32->ts_usec); 620 temp.caplen = le32toh(hdr32->caplen); 621 temp.datalen = le32toh(hdr32->datalen); 622 temp.hdrlen = hdr32->hdrlen; 623 temp.align = hdr32->align; 624 625 next = ptr + HEADER_ALIGN(temp.hdrlen + temp.caplen, temp.align); 626 627 if (next <= ptr) 628 err(EXIT_FAILURE, "Invalid length"); 629 630 if (verbose >= 0 || r_arg != NULL || b_arg != NULL) { 631 print_apacket(&temp, ptr + 632 temp.hdrlen, temp.caplen); 633 } 634 pkt_captured++; 635 } 636} 637 638static void 639write_packets(struct usbcap *p, const uint8_t *data, const int datalen) 640{ 641 int len = htole32(datalen); 642 int ret; 643 644 ret = write(p->wfd, &len, sizeof(int)); 645 if (ret != sizeof(int)) { 646 err(EXIT_FAILURE, "Could not write length " 647 "field of USB data payload"); 648 } 649 ret = write(p->wfd, data, datalen); 650 if (ret != datalen) { 651 err(EXIT_FAILURE, "Could not write " 652 "complete USB data payload"); 653 } 654} 655 656static void 657read_file(struct usbcap *p) 658{ 659 int datalen; 660 int ret; 661 uint8_t *data; 662 663 while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) { 664 datalen = le32toh(datalen); 665 data = malloc(datalen); 666 if (data == NULL) 667 errx(EX_SOFTWARE, "Out of memory."); 668 ret = read(p->rfd, data, datalen); 669 if (ret != datalen) { 670 err(EXIT_FAILURE, "Could not read complete " 671 "USB data payload"); 672 } 673 if (uf_minor == 2) 674 fix_packets(data, datalen); 675 676 print_packets(data, datalen); 677 free(data); 678 } 679} 680 681static void 682do_loop(struct usbcap *p) 683{ 684 int cc; 685 686 while (doexit == 0) { 687 cc = read(p->fd, (uint8_t *)p->buffer, p->bufsize); 688 if (cc < 0) { 689 switch (errno) { 690 case EINTR: 691 break; 692 default: 693 fprintf(stderr, "read: %s\n", strerror(errno)); 694 return; 695 } 696 continue; 697 } 698 if (cc == 0) 699 continue; 700 701 fix_packets(p->buffer, cc); 702 703 if (w_arg != NULL) 704 write_packets(p, p->buffer, cc); 705 print_packets(p->buffer, cc); 706 } 707} 708 709static void 710init_rfile(struct usbcap *p) 711{ 712 struct usbcap_filehdr uf; 713 int ret; 714 715 p->rfd = open(r_arg, O_RDONLY); 716 if (p->rfd < 0) { 717 err(EXIT_FAILURE, "Could not open " 718 "'%s' for read", r_arg); 719 } 720 ret = read(p->rfd, &uf, sizeof(uf)); 721 if (ret != sizeof(uf)) { 722 err(EXIT_FAILURE, "Could not read USB capture " 723 "file header"); 724 } 725 if (le32toh(uf.magic) != USBCAP_FILEHDR_MAGIC) { 726 errx(EX_SOFTWARE, "Invalid magic field(0x%08x) " 727 "in USB capture file header.", 728 (unsigned int)le32toh(uf.magic)); 729 } 730 if (uf.major != 0) { 731 errx(EX_SOFTWARE, "Invalid major version(%d) " 732 "field in USB capture file header.", (int)uf.major); 733 } 734 735 uf_minor = uf.minor; 736 737 if (uf.minor != 3 && uf.minor != 2) { 738 errx(EX_SOFTWARE, "Invalid minor version(%d) " 739 "field in USB capture file header.", (int)uf.minor); 740 } 741} 742 743static void 744init_wfile(struct usbcap *p) 745{ 746 struct usbcap_filehdr uf; 747 int ret; 748 749 p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 750 if (p->wfd < 0) { 751 err(EXIT_FAILURE, "Could not open " 752 "'%s' for write", w_arg); 753 } 754 memset(&uf, 0, sizeof(uf)); 755 uf.magic = htole32(USBCAP_FILEHDR_MAGIC); 756 uf.major = 0; 757 uf.minor = 3; 758 ret = write(p->wfd, (const void *)&uf, sizeof(uf)); 759 if (ret != sizeof(uf)) { 760 err(EXIT_FAILURE, "Could not write " 761 "USB capture header"); 762 } 763} 764 765static void 766usage(void) 767{ 768 769#define FMT " %-14s %s\n" 770 fprintf(stderr, "usage: usbdump [options]\n"); 771 fprintf(stderr, FMT, "-i <usbusX>", "Listen on USB bus interface"); 772 fprintf(stderr, FMT, "-f <unit[.endpoint]>", "Specify a device and endpoint filter"); 773 fprintf(stderr, FMT, "-r <file>", "Read the raw packets from file"); 774 fprintf(stderr, FMT, "-s <snaplen>", "Snapshot bytes from each packet"); 775 fprintf(stderr, FMT, "-v", "Increase the verbose level"); 776 fprintf(stderr, FMT, "-b <file>", "Save raw version of all recorded data to file"); 777 fprintf(stderr, FMT, "-w <file>", "Write the raw packets to file"); 778 fprintf(stderr, FMT, "-h", "Display summary of command line options"); 779#undef FMT 780 exit(EX_USAGE); 781} 782 783int 784main(int argc, char *argv[]) 785{ 786 struct timeval tv; 787 struct bpf_program total_prog; 788 struct bpf_stat us; 789 struct bpf_version bv; 790 struct usbcap *p = &uc; 791 struct ifreq ifr; 792 long snapshot = 192; 793 uint32_t v; 794 int fd; 795 int o; 796 int filt_unit; 797 int filt_ep; 798 const char *optstring; 799 char *pp; 800 801 optstring = "b:hi:r:s:vw:f:"; 802 while ((o = getopt(argc, argv, optstring)) != -1) { 803 switch (o) { 804 case 'i': 805 i_arg = optarg; 806 break; 807 case 'r': 808 r_arg = optarg; 809 init_rfile(p); 810 break; 811 case 's': 812 snapshot = strtol(optarg, &pp, 10); 813 errno = 0; 814 if (pp != NULL && *pp != 0) 815 usage(); 816 if (snapshot == 0 && errno == EINVAL) 817 usage(); 818 /* snapeshot == 0 is special */ 819 if (snapshot == 0) 820 snapshot = -1; 821 break; 822 case 'b': 823 b_arg = optarg; 824 break; 825 case 'v': 826 verbose++; 827 break; 828 case 'w': 829 w_arg = optarg; 830 init_wfile(p); 831 break; 832 case 'f': 833 filt_unit = strtol(optarg, &pp, 10); 834 filt_ep = -1; 835 if (pp != NULL) { 836 if (*pp == '.') { 837 filt_ep = strtol(pp + 1, &pp, 10); 838 if (pp != NULL && *pp != 0) 839 usage(); 840 } else if (*pp != 0) { 841 usage(); 842 } 843 } 844 add_filter(filt_unit, filt_ep); 845 break; 846 default: 847 usage(); 848 /* NOTREACHED */ 849 } 850 } 851 852 if (b_arg != NULL) { 853 p->bfd = open(b_arg, O_CREAT | O_TRUNC | 854 O_WRONLY, S_IRUSR | S_IWUSR); 855 if (p->bfd < 0) { 856 err(EXIT_FAILURE, "Could not open " 857 "'%s' for write", b_arg); 858 } 859 } 860 861 /* 862 * Require more verbosity to print anything when -w or -b is 863 * specified on the command line: 864 */ 865 if (w_arg != NULL || b_arg != NULL) 866 verbose--; 867 868 if (r_arg != NULL) { 869 read_file(p); 870 exit(EXIT_SUCCESS); 871 } 872 873 p->fd = fd = open("/dev/bpf", O_RDONLY); 874 if (p->fd < 0) 875 err(EXIT_FAILURE, "Could not open BPF device"); 876 877 if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) 878 err(EXIT_FAILURE, "BIOCVERSION ioctl failed"); 879 880 if (bv.bv_major != BPF_MAJOR_VERSION || 881 bv.bv_minor < BPF_MINOR_VERSION) 882 errx(EXIT_FAILURE, "Kernel BPF filter out of date"); 883 884 /* USB transfers can be greater than 64KByte */ 885 v = 1U << 16; 886 887 /* clear ifr structure */ 888 memset(&ifr, 0, sizeof(ifr)); 889 890 for ( ; v >= USBPF_HDR_LEN; v >>= 1) { 891 (void)ioctl(fd, BIOCSBLEN, (caddr_t)&v); 892 (void)strncpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 893 if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) 894 break; 895 } 896 if (v == 0) 897 errx(EXIT_FAILURE, "No buffer size worked."); 898 899 if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) 900 err(EXIT_FAILURE, "BIOCGBLEN ioctl failed"); 901 902 p->bufsize = v; 903 p->buffer = (uint8_t *)malloc(p->bufsize); 904 if (p->buffer == NULL) 905 errx(EX_SOFTWARE, "Out of memory."); 906 907 make_filter(&total_prog, snapshot); 908 909 if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) 910 err(EXIT_FAILURE, "BIOCSETF ioctl failed"); 911 912 free_filter(&total_prog); 913 914 /* 1 second read timeout */ 915 tv.tv_sec = 1; 916 tv.tv_usec = 0; 917 if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&tv) < 0) 918 err(EXIT_FAILURE, "BIOCSRTIMEOUT ioctl failed"); 919 920 (void)signal(SIGINT, handle_sigint); 921 922 do_loop(p); 923 924 if (ioctl(fd, BIOCGSTATS, (caddr_t)&us) < 0) 925 err(EXIT_FAILURE, "BIOCGSTATS ioctl failed"); 926 927 /* XXX what's difference between pkt_captured and us.us_recv? */ 928 printf("\n"); 929 printf("%d packets captured\n", pkt_captured); 930 printf("%d packets received by filter\n", us.bs_recv); 931 printf("%d packets dropped by kernel\n", us.bs_drop); 932 933 if (p->fd > 0) 934 close(p->fd); 935 if (p->rfd > 0) 936 close(p->rfd); 937 if (p->wfd > 0) 938 close(p->wfd); 939 if (p->bfd > 0) 940 close(p->bfd); 941 942 return (EXIT_SUCCESS); 943} 944