1215651Sweongyo/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4215651Sweongyo * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org> 5215651Sweongyo * All rights reserved. 6215651Sweongyo * 7215651Sweongyo * Redistribution and use in source and binary forms, with or without 8215651Sweongyo * modification, are permitted provided that the following conditions 9215651Sweongyo * are met: 10215651Sweongyo * 1. Redistributions of source code must retain the above copyright 11215651Sweongyo * notice, this list of conditions and the following disclaimer, 12215651Sweongyo * without modification. 13215651Sweongyo * 2. Redistributions in binary form must reproduce at minimum a disclaimer 14215651Sweongyo * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 15215651Sweongyo * redistribution must be conditioned upon including a substantially 16215651Sweongyo * similar Disclaimer requirement for further binary redistribution. 17215651Sweongyo * 18215651Sweongyo * NO WARRANTY 19215651Sweongyo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20215651Sweongyo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21215651Sweongyo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 22215651Sweongyo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 23215651Sweongyo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 24215651Sweongyo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25215651Sweongyo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26215651Sweongyo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27215651Sweongyo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28215651Sweongyo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 29215651Sweongyo * THE POSSIBILITY OF SUCH DAMAGES. 30215651Sweongyo * 31215651Sweongyo * $FreeBSD: stable/11/usr.sbin/usbdump/usbdump.c 349665 2019-07-03 18:18:42Z hselasky $ 32215651Sweongyo */ 33215651Sweongyo 34215651Sweongyo#include <sys/param.h> 35215651Sweongyo#include <sys/endian.h> 36215651Sweongyo#include <sys/ioctl.h> 37215803Sweongyo#include <sys/socket.h> 38215651Sweongyo#include <sys/stat.h> 39260978Shselasky#include <sys/sysctl.h> 40215651Sweongyo#include <sys/utsname.h> 41231835Shselasky#include <sys/queue.h> 42215803Sweongyo#include <net/if.h> 43215803Sweongyo#include <net/bpf.h> 44215651Sweongyo#include <dev/usb/usb.h> 45215651Sweongyo#include <dev/usb/usb_pf.h> 46215651Sweongyo#include <dev/usb/usbdi.h> 47215651Sweongyo#include <errno.h> 48215651Sweongyo#include <fcntl.h> 49215651Sweongyo#include <limits.h> 50215651Sweongyo#include <stdio.h> 51215651Sweongyo#include <stdlib.h> 52231835Shselasky#include <stdint.h> 53215651Sweongyo#include <string.h> 54215651Sweongyo#include <time.h> 55215651Sweongyo#include <unistd.h> 56221604Shselasky#include <sysexits.h> 57221604Shselasky#include <err.h> 58215651Sweongyo 59231835Shselasky#define BPF_STORE_JUMP(x,_c,_k,_jt,_jf) do { \ 60231835Shselasky (x).code = (_c); \ 61231835Shselasky (x).k = (_k); \ 62231835Shselasky (x).jt = (_jt); \ 63231835Shselasky (x).jf = (_jf); \ 64231835Shselasky} while (0) 65231835Shselasky 66231835Shselasky#define BPF_STORE_STMT(x,_c,_k) do { \ 67231835Shselasky (x).code = (_c); \ 68231835Shselasky (x).k = (_k); \ 69231835Shselasky (x).jt = 0; \ 70231835Shselasky (x).jf = 0; \ 71231835Shselasky} while (0) 72231835Shselasky 73231835Shselaskystruct usb_filt { 74231835Shselasky STAILQ_ENTRY(usb_filt) entry; 75231835Shselasky int unit; 76231835Shselasky int endpoint; 77231835Shselasky}; 78231835Shselasky 79215651Sweongyostruct usbcap { 80215651Sweongyo int fd; /* fd for /dev/usbpf */ 81220301Shselasky uint32_t bufsize; 82220301Shselasky uint8_t *buffer; 83215651Sweongyo 84215651Sweongyo /* for -w option */ 85215651Sweongyo int wfd; 86215651Sweongyo /* for -r option */ 87215651Sweongyo int rfd; 88234636Shselasky /* for -b option */ 89234636Shselasky int bfd; 90215651Sweongyo}; 91215651Sweongyo 92215651Sweongyostruct usbcap_filehdr { 93220301Shselasky uint32_t magic; 94215651Sweongyo#define USBCAP_FILEHDR_MAGIC 0x9a90000e 95220301Shselasky uint8_t major; 96220301Shselasky uint8_t minor; 97220301Shselasky uint8_t reserved[26]; 98215651Sweongyo} __packed; 99215651Sweongyo 100233037Shselaskystruct header_32 { 101233039Shselasky /* capture timestamp */ 102233037Shselasky uint32_t ts_sec; 103233037Shselasky uint32_t ts_usec; 104233039Shselasky /* data length and alignment information */ 105233037Shselasky uint32_t caplen; 106233037Shselasky uint32_t datalen; 107233039Shselasky uint8_t hdrlen; 108233039Shselasky uint8_t align; 109233037Shselasky} __packed; 110233037Shselasky 111215651Sweongyostatic int doexit = 0; 112215651Sweongyostatic int pkt_captured = 0; 113215651Sweongyostatic int verbose = 0; 114233039Shselaskystatic int uf_minor; 115218010Shselaskystatic const char *i_arg = "usbus0"; 116215651Sweongyostatic const char *r_arg = NULL; 117215651Sweongyostatic const char *w_arg = NULL; 118234636Shselaskystatic const char *b_arg = NULL; 119234636Shselaskystatic struct usbcap uc; 120215651Sweongyostatic const char *errstr_table[USB_ERR_MAX] = { 121220301Shselasky [USB_ERR_NORMAL_COMPLETION] = "0", 122215651Sweongyo [USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS", 123215651Sweongyo [USB_ERR_NOT_STARTED] = "NOT_STARTED", 124215651Sweongyo [USB_ERR_INVAL] = "INVAL", 125215651Sweongyo [USB_ERR_NOMEM] = "NOMEM", 126215651Sweongyo [USB_ERR_CANCELLED] = "CANCELLED", 127215651Sweongyo [USB_ERR_BAD_ADDRESS] = "BAD_ADDRESS", 128215651Sweongyo [USB_ERR_BAD_BUFSIZE] = "BAD_BUFSIZE", 129215651Sweongyo [USB_ERR_BAD_FLAG] = "BAD_FLAG", 130215651Sweongyo [USB_ERR_NO_CALLBACK] = "NO_CALLBACK", 131215651Sweongyo [USB_ERR_IN_USE] = "IN_USE", 132215651Sweongyo [USB_ERR_NO_ADDR] = "NO_ADDR", 133215651Sweongyo [USB_ERR_NO_PIPE] = "NO_PIPE", 134215651Sweongyo [USB_ERR_ZERO_NFRAMES] = "ZERO_NFRAMES", 135215651Sweongyo [USB_ERR_ZERO_MAXP] = "ZERO_MAXP", 136215651Sweongyo [USB_ERR_SET_ADDR_FAILED] = "SET_ADDR_FAILED", 137215651Sweongyo [USB_ERR_NO_POWER] = "NO_POWER", 138215651Sweongyo [USB_ERR_TOO_DEEP] = "TOO_DEEP", 139215651Sweongyo [USB_ERR_IOERROR] = "IOERROR", 140215651Sweongyo [USB_ERR_NOT_CONFIGURED] = "NOT_CONFIGURED", 141215651Sweongyo [USB_ERR_TIMEOUT] = "TIMEOUT", 142215651Sweongyo [USB_ERR_SHORT_XFER] = "SHORT_XFER", 143215651Sweongyo [USB_ERR_STALLED] = "STALLED", 144215651Sweongyo [USB_ERR_INTERRUPTED] = "INTERRUPTED", 145215651Sweongyo [USB_ERR_DMA_LOAD_FAILED] = "DMA_LOAD_FAILED", 146215651Sweongyo [USB_ERR_BAD_CONTEXT] = "BAD_CONTEXT", 147215651Sweongyo [USB_ERR_NO_ROOT_HUB] = "NO_ROOT_HUB", 148215651Sweongyo [USB_ERR_NO_INTR_THREAD] = "NO_INTR_THREAD", 149215651Sweongyo [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", 150215651Sweongyo}; 151215651Sweongyo 152349665Shselasky#define USB_XFERTYPE_MAX 4 153349665Shselasky 154349665Shselaskystatic const char *xfertype_table[USB_XFERTYPE_MAX] = { 155215651Sweongyo [UE_CONTROL] = "CTRL", 156215651Sweongyo [UE_ISOCHRONOUS] = "ISOC", 157215651Sweongyo [UE_BULK] = "BULK", 158215651Sweongyo [UE_INTERRUPT] = "INTR" 159215651Sweongyo}; 160215651Sweongyo 161220301Shselaskystatic const char *speed_table[USB_SPEED_MAX] = { 162220301Shselasky [USB_SPEED_FULL] = "FULL", 163220301Shselasky [USB_SPEED_HIGH] = "HIGH", 164220301Shselasky [USB_SPEED_LOW] = "LOW", 165220301Shselasky [USB_SPEED_VARIABLE] = "VARI", 166220301Shselasky [USB_SPEED_SUPER] = "SUPER", 167220301Shselasky}; 168220301Shselasky 169231835Shselaskystatic STAILQ_HEAD(,usb_filt) usb_filt_head = 170231835Shselasky STAILQ_HEAD_INITIALIZER(usb_filt_head); 171231835Shselasky 172215651Sweongyostatic void 173231835Shselaskyadd_filter(int usb_filt_unit, int usb_filt_ep) 174231835Shselasky{ 175231835Shselasky struct usb_filt *puf; 176231835Shselasky 177231835Shselasky puf = malloc(sizeof(struct usb_filt)); 178231835Shselasky if (puf == NULL) 179231835Shselasky errx(EX_SOFTWARE, "Out of memory."); 180231835Shselasky 181231835Shselasky puf->unit = usb_filt_unit; 182231835Shselasky puf->endpoint = usb_filt_ep; 183231835Shselasky 184231835Shselasky STAILQ_INSERT_TAIL(&usb_filt_head, puf, entry); 185231835Shselasky} 186231835Shselasky 187231835Shselaskystatic void 188231835Shselaskymake_filter(struct bpf_program *pprog, int snapshot) 189231835Shselasky{ 190231835Shselasky struct usb_filt *puf; 191231835Shselasky struct bpf_insn *dynamic_insn; 192231835Shselasky int len; 193231835Shselasky 194231835Shselasky len = 0; 195231835Shselasky 196231835Shselasky STAILQ_FOREACH(puf, &usb_filt_head, entry) 197231835Shselasky len++; 198231835Shselasky 199231835Shselasky dynamic_insn = malloc(((len * 5) + 1) * sizeof(struct bpf_insn)); 200231835Shselasky 201231835Shselasky if (dynamic_insn == NULL) 202231835Shselasky errx(EX_SOFTWARE, "Out of memory."); 203231835Shselasky 204231835Shselasky len++; 205231835Shselasky 206231835Shselasky if (len == 1) { 207231835Shselasky /* accept all packets */ 208231835Shselasky 209231835Shselasky BPF_STORE_STMT(dynamic_insn[0], BPF_RET | BPF_K, snapshot); 210231835Shselasky 211231835Shselasky goto done; 212231835Shselasky } 213231835Shselasky 214231835Shselasky len = 0; 215231835Shselasky 216231835Shselasky STAILQ_FOREACH(puf, &usb_filt_head, entry) { 217231835Shselasky const int addr_off = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_address; 218231835Shselasky const int addr_ep = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_endpoint; 219231835Shselasky 220231835Shselasky if (puf->unit != -1) { 221231835Shselasky if (puf->endpoint != -1) { 222231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 223231835Shselasky BPF_LD | BPF_B | BPF_ABS, addr_off); 224231835Shselasky len++; 225231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 226231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 3); 227231835Shselasky len++; 228231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 229231835Shselasky BPF_LD | BPF_W | BPF_ABS, addr_ep); 230231835Shselasky len++; 231231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 232231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1); 233231835Shselasky len++; 234231835Shselasky } else { 235231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 236231835Shselasky BPF_LD | BPF_B | BPF_ABS, addr_off); 237231835Shselasky len++; 238231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 239231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 1); 240231835Shselasky len++; 241231835Shselasky } 242231835Shselasky } else { 243231835Shselasky if (puf->endpoint != -1) { 244231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 245231835Shselasky BPF_LD | BPF_W | BPF_ABS, addr_ep); 246231835Shselasky len++; 247231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 248231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1); 249231835Shselasky len++; 250231835Shselasky } 251231835Shselasky } 252231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 253231835Shselasky BPF_RET | BPF_K, snapshot); 254231835Shselasky len++; 255231835Shselasky } 256231835Shselasky 257231835Shselasky BPF_STORE_STMT(dynamic_insn[len], BPF_RET | BPF_K, 0); 258231835Shselasky len++; 259231835Shselasky 260231835Shselaskydone: 261231835Shselasky pprog->bf_len = len; 262231835Shselasky pprog->bf_insns = dynamic_insn; 263231835Shselasky} 264231835Shselasky 265234636Shselaskystatic int 266234636Shselaskymatch_filter(int unit, int endpoint) 267234636Shselasky{ 268234636Shselasky struct usb_filt *puf; 269234636Shselasky 270234636Shselasky if (STAILQ_FIRST(&usb_filt_head) == NULL) 271234636Shselasky return (1); 272234636Shselasky 273234636Shselasky STAILQ_FOREACH(puf, &usb_filt_head, entry) { 274234636Shselasky if ((puf->unit == -1 || puf->unit == unit) && 275234636Shselasky (puf->endpoint == -1 || puf->endpoint == endpoint)) 276234636Shselasky return (1); 277234636Shselasky } 278234636Shselasky return (0); 279234636Shselasky} 280234636Shselasky 281231835Shselaskystatic void 282231835Shselaskyfree_filter(struct bpf_program *pprog) 283231835Shselasky{ 284231835Shselasky struct usb_filt *puf; 285231835Shselasky 286231835Shselasky while ((puf = STAILQ_FIRST(&usb_filt_head)) != NULL) { 287231835Shselasky STAILQ_REMOVE_HEAD(&usb_filt_head, entry); 288231835Shselasky free(puf); 289231835Shselasky } 290231835Shselasky free(pprog->bf_insns); 291231835Shselasky} 292231835Shselasky 293231835Shselaskystatic void 294215651Sweongyohandle_sigint(int sig) 295215651Sweongyo{ 296215651Sweongyo 297215651Sweongyo (void)sig; 298215651Sweongyo doexit = 1; 299215651Sweongyo} 300215651Sweongyo 301220301Shselasky#define FLAGS(x, name) \ 302220301Shselasky (((x) & USBPF_FLAG_##name) ? #name "|" : "") 303220301Shselasky 304220301Shselasky#define STATUS(x, name) \ 305220301Shselasky (((x) & USBPF_STATUS_##name) ? #name "|" : "") 306220301Shselasky 307220301Shselaskystatic const char * 308220301Shselaskyusb_errstr(uint32_t error) 309220301Shselasky{ 310220301Shselasky if (error >= USB_ERR_MAX || errstr_table[error] == NULL) 311220301Shselasky return ("UNKNOWN"); 312220301Shselasky else 313220301Shselasky return (errstr_table[error]); 314220301Shselasky} 315220301Shselasky 316220301Shselaskystatic const char * 317220301Shselaskyusb_speedstr(uint8_t speed) 318220301Shselasky{ 319220301Shselasky if (speed >= USB_SPEED_MAX || speed_table[speed] == NULL) 320220301Shselasky return ("UNKNOWN"); 321220301Shselasky else 322220301Shselasky return (speed_table[speed]); 323220301Shselasky} 324220301Shselasky 325349665Shselaskystatic const char * 326349665Shselaskyusb_xferstr(uint8_t type) 327349665Shselasky{ 328349665Shselasky if (type >= USB_XFERTYPE_MAX || xfertype_table[type] == NULL) 329349665Shselasky return ("UNKN"); 330349665Shselasky else 331349665Shselasky return (xfertype_table[type]); 332349665Shselasky} 333349665Shselasky 334215651Sweongyostatic void 335220301Shselaskyprint_flags(uint32_t flags) 336215651Sweongyo{ 337220301Shselasky printf(" flags %#x <%s%s%s%s%s%s%s%s%s0>\n", 338220301Shselasky flags, 339220301Shselasky FLAGS(flags, FORCE_SHORT_XFER), 340220301Shselasky FLAGS(flags, SHORT_XFER_OK), 341220301Shselasky FLAGS(flags, SHORT_FRAMES_OK), 342220301Shselasky FLAGS(flags, PIPE_BOF), 343220301Shselasky FLAGS(flags, PROXY_BUFFER), 344220301Shselasky FLAGS(flags, EXT_BUFFER), 345220301Shselasky FLAGS(flags, MANUAL_STATUS), 346220301Shselasky FLAGS(flags, NO_PIPE_OK), 347220301Shselasky FLAGS(flags, STALL_PIPE)); 348215651Sweongyo} 349215651Sweongyo 350215651Sweongyostatic void 351220301Shselaskyprint_status(uint32_t status) 352215651Sweongyo{ 353220301Shselasky printf(" status %#x <%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s0>\n", 354220301Shselasky status, 355220301Shselasky STATUS(status, OPEN), 356220301Shselasky STATUS(status, TRANSFERRING), 357220301Shselasky STATUS(status, DID_DMA_DELAY), 358220301Shselasky STATUS(status, DID_CLOSE), 359220301Shselasky STATUS(status, DRAINING), 360220301Shselasky STATUS(status, STARTED), 361220301Shselasky STATUS(status, BW_RECLAIMED), 362220301Shselasky STATUS(status, CONTROL_XFR), 363220301Shselasky STATUS(status, CONTROL_HDR), 364220301Shselasky STATUS(status, CONTROL_ACT), 365220301Shselasky STATUS(status, CONTROL_STALL), 366220301Shselasky STATUS(status, SHORT_FRAMES_OK), 367220301Shselasky STATUS(status, SHORT_XFER_OK), 368220301Shselasky STATUS(status, BDMA_ENABLE), 369220301Shselasky STATUS(status, BDMA_NO_POST_SYNC), 370220301Shselasky STATUS(status, BDMA_SETUP), 371220301Shselasky STATUS(status, ISOCHRONOUS_XFR), 372220301Shselasky STATUS(status, CURR_DMA_SET), 373220301Shselasky STATUS(status, CAN_CANCEL_IMMED), 374220301Shselasky STATUS(status, DOING_CALLBACK)); 375220301Shselasky} 376215651Sweongyo 377220301Shselasky/* 378220301Shselasky * Dump a byte into hex format. 379220301Shselasky */ 380220301Shselaskystatic void 381220301Shselaskyhexbyte(char *buf, uint8_t temp) 382220301Shselasky{ 383220301Shselasky uint8_t lo; 384220301Shselasky uint8_t hi; 385220301Shselasky 386220301Shselasky lo = temp & 0xF; 387220301Shselasky hi = temp >> 4; 388220301Shselasky 389220301Shselasky if (hi < 10) 390220301Shselasky buf[0] = '0' + hi; 391220301Shselasky else 392220301Shselasky buf[0] = 'A' + hi - 10; 393220301Shselasky 394220301Shselasky if (lo < 10) 395220301Shselasky buf[1] = '0' + lo; 396220301Shselasky else 397220301Shselasky buf[1] = 'A' + lo - 10; 398215651Sweongyo} 399215651Sweongyo 400215651Sweongyo/* 401215651Sweongyo * Display a region in traditional hexdump format. 402215651Sweongyo */ 403215651Sweongyostatic void 404220301Shselaskyhexdump(const uint8_t *region, uint32_t len) 405215651Sweongyo{ 406220301Shselasky const uint8_t *line; 407220301Shselasky char linebuf[128]; 408220301Shselasky int i; 409218010Shselasky int x; 410218010Shselasky int c; 411215651Sweongyo 412215651Sweongyo for (line = region; line < (region + len); line += 16) { 413220301Shselasky 414220301Shselasky i = 0; 415220301Shselasky 416220301Shselasky linebuf[i] = ' '; 417220301Shselasky hexbyte(linebuf + i + 1, ((line - region) >> 8) & 0xFF); 418220301Shselasky hexbyte(linebuf + i + 3, (line - region) & 0xFF); 419220301Shselasky linebuf[i + 5] = ' '; 420220301Shselasky linebuf[i + 6] = ' '; 421220301Shselasky i += 7; 422220301Shselasky 423215651Sweongyo for (x = 0; x < 16; x++) { 424220301Shselasky if ((line + x) < (region + len)) { 425220301Shselasky hexbyte(linebuf + i, 426220301Shselasky *(const u_int8_t *)(line + x)); 427220301Shselasky } else { 428220301Shselasky linebuf[i] = '-'; 429220301Shselasky linebuf[i + 1] = '-'; 430220301Shselasky } 431220301Shselasky linebuf[i + 2] = ' '; 432220301Shselasky if (x == 7) { 433220301Shselasky linebuf[i + 3] = ' '; 434220301Shselasky i += 4; 435220301Shselasky } else { 436220301Shselasky i += 3; 437220301Shselasky } 438215651Sweongyo } 439220301Shselasky linebuf[i] = ' '; 440220301Shselasky linebuf[i + 1] = '|'; 441220301Shselasky i += 2; 442215651Sweongyo for (x = 0; x < 16; x++) { 443215651Sweongyo if ((line + x) < (region + len)) { 444215651Sweongyo c = *(const u_int8_t *)(line + x); 445215651Sweongyo /* !isprint(c) */ 446215651Sweongyo if ((c < ' ') || (c > '~')) 447215651Sweongyo c = '.'; 448220301Shselasky linebuf[i] = c; 449220301Shselasky } else { 450220301Shselasky linebuf[i] = ' '; 451220301Shselasky } 452220301Shselasky i++; 453215651Sweongyo } 454220301Shselasky linebuf[i] = '|'; 455220301Shselasky linebuf[i + 1] = 0; 456220301Shselasky i += 2; 457220301Shselasky puts(linebuf); 458215651Sweongyo } 459215651Sweongyo} 460215651Sweongyo 461215651Sweongyostatic void 462233037Shselaskyprint_apacket(const struct header_32 *hdr, const uint8_t *ptr, int ptr_len) 463215651Sweongyo{ 464215651Sweongyo struct tm *tm; 465220301Shselasky struct usbpf_pkthdr up_temp; 466220301Shselasky struct usbpf_pkthdr *up; 467215651Sweongyo struct timeval tv; 468215651Sweongyo size_t len; 469220301Shselasky uint32_t x; 470215651Sweongyo char buf[64]; 471215651Sweongyo 472220301Shselasky ptr += USBPF_HDR_LEN; 473220301Shselasky ptr_len -= USBPF_HDR_LEN; 474220301Shselasky if (ptr_len < 0) 475220301Shselasky return; 476220301Shselasky 477220301Shselasky /* make sure we don't change the source buffer */ 478220301Shselasky memcpy(&up_temp, ptr - USBPF_HDR_LEN, sizeof(up_temp)); 479220301Shselasky up = &up_temp; 480220301Shselasky 481220301Shselasky /* 482220301Shselasky * A packet from the kernel is based on little endian byte 483220301Shselasky * order. 484220301Shselasky */ 485220301Shselasky up->up_totlen = le32toh(up->up_totlen); 486215651Sweongyo up->up_busunit = le32toh(up->up_busunit); 487215651Sweongyo up->up_flags = le32toh(up->up_flags); 488215651Sweongyo up->up_status = le32toh(up->up_status); 489215651Sweongyo up->up_error = le32toh(up->up_error); 490215651Sweongyo up->up_interval = le32toh(up->up_interval); 491220301Shselasky up->up_frames = le32toh(up->up_frames); 492220301Shselasky up->up_packet_size = le32toh(up->up_packet_size); 493220301Shselasky up->up_packet_count = le32toh(up->up_packet_count); 494220301Shselasky up->up_endpoint = le32toh(up->up_endpoint); 495215651Sweongyo 496234636Shselasky if (!match_filter(up->up_address, up->up_endpoint)) 497234636Shselasky return; 498234636Shselasky 499233037Shselasky tv.tv_sec = hdr->ts_sec; 500233037Shselasky tv.tv_usec = hdr->ts_usec; 501215651Sweongyo tm = localtime(&tv.tv_sec); 502215651Sweongyo 503215651Sweongyo len = strftime(buf, sizeof(buf), "%H:%M:%S", tm); 504220301Shselasky 505234636Shselasky if (verbose >= 0) { 506234636Shselasky printf("%.*s.%06ld usbus%d.%d %s-%s-EP=%08x,SPD=%s,NFR=%d,SLEN=%d,IVAL=%d%s%s\n", 507234636Shselasky (int)len, buf, tv.tv_usec, 508234636Shselasky (int)up->up_busunit, (int)up->up_address, 509234636Shselasky (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE", 510349665Shselasky usb_xferstr(up->up_xfertype), 511234636Shselasky (unsigned int)up->up_endpoint, 512234636Shselasky usb_speedstr(up->up_speed), 513234636Shselasky (int)up->up_frames, 514234636Shselasky (int)(up->up_totlen - USBPF_HDR_LEN - 515234636Shselasky (USBPF_FRAME_HDR_LEN * up->up_frames)), 516234636Shselasky (int)up->up_interval, 517234636Shselasky (up->up_type == USBPF_XFERTAP_DONE) ? ",ERR=" : "", 518234636Shselasky (up->up_type == USBPF_XFERTAP_DONE) ? 519234636Shselasky usb_errstr(up->up_error) : ""); 520234636Shselasky } 521215651Sweongyo 522234636Shselasky if (verbose >= 1 || b_arg != NULL) { 523220301Shselasky for (x = 0; x != up->up_frames; x++) { 524220301Shselasky const struct usbpf_framehdr *uf; 525220301Shselasky uint32_t framelen; 526220301Shselasky uint32_t flags; 527220301Shselasky 528220301Shselasky uf = (const struct usbpf_framehdr *)ptr; 529220301Shselasky ptr += USBPF_FRAME_HDR_LEN; 530220301Shselasky ptr_len -= USBPF_FRAME_HDR_LEN; 531220301Shselasky if (ptr_len < 0) 532220301Shselasky return; 533220301Shselasky 534220301Shselasky framelen = le32toh(uf->length); 535220301Shselasky flags = le32toh(uf->flags); 536220301Shselasky 537234636Shselasky if (verbose >= 1) { 538234636Shselasky printf(" frame[%u] %s %d bytes\n", 539234636Shselasky (unsigned int)x, 540234636Shselasky (flags & USBPF_FRAMEFLAG_READ) ? "READ" : "WRITE", 541234636Shselasky (int)framelen); 542234636Shselasky } 543220301Shselasky 544220301Shselasky if (flags & USBPF_FRAMEFLAG_DATA_FOLLOWS) { 545220301Shselasky 546220301Shselasky int tot_frame_len; 547220301Shselasky 548220301Shselasky tot_frame_len = USBPF_FRAME_ALIGN(framelen); 549220301Shselasky 550220301Shselasky ptr_len -= tot_frame_len; 551220301Shselasky 552220301Shselasky if (tot_frame_len < 0 || 553220301Shselasky (int)framelen < 0 || (int)ptr_len < 0) 554220301Shselasky break; 555220301Shselasky 556234636Shselasky if (b_arg != NULL) { 557234636Shselasky struct usbcap *p = &uc; 558234636Shselasky int ret; 559234636Shselasky ret = write(p->bfd, ptr, framelen); 560234636Shselasky if (ret != (int)framelen) 561234636Shselasky err(EXIT_FAILURE, "Could not write binary data"); 562234636Shselasky } 563234636Shselasky if (verbose >= 1) 564234636Shselasky hexdump(ptr, framelen); 565220301Shselasky 566220301Shselasky ptr += tot_frame_len; 567220301Shselasky } 568215651Sweongyo } 569215651Sweongyo } 570220301Shselasky if (verbose >= 2) 571215651Sweongyo print_flags(up->up_flags); 572220301Shselasky if (verbose >= 3) 573215651Sweongyo print_status(up->up_status); 574215651Sweongyo} 575215651Sweongyo 576215651Sweongyostatic void 577233039Shselaskyfix_packets(uint8_t *data, const int datalen) 578215651Sweongyo{ 579233037Shselasky struct header_32 temp; 580220301Shselasky uint8_t *ptr; 581220301Shselasky uint8_t *next; 582233039Shselasky uint32_t hdrlen; 583233039Shselasky uint32_t caplen; 584215651Sweongyo 585215651Sweongyo for (ptr = data; ptr < (data + datalen); ptr = next) { 586215651Sweongyo 587233039Shselasky const struct bpf_hdr *hdr; 588233037Shselasky 589233039Shselasky hdr = (const struct bpf_hdr *)ptr; 590233037Shselasky 591233039Shselasky temp.ts_sec = htole32(hdr->bh_tstamp.tv_sec); 592233039Shselasky temp.ts_usec = htole32(hdr->bh_tstamp.tv_usec); 593233039Shselasky temp.caplen = htole32(hdr->bh_caplen); 594233039Shselasky temp.datalen = htole32(hdr->bh_datalen); 595233039Shselasky temp.hdrlen = hdr->bh_hdrlen; 596233039Shselasky temp.align = BPF_WORDALIGN(1); 597233037Shselasky 598233039Shselasky hdrlen = hdr->bh_hdrlen; 599233039Shselasky caplen = hdr->bh_caplen; 600233037Shselasky 601233039Shselasky if ((hdrlen >= sizeof(temp)) && (hdrlen <= 255) && 602233039Shselasky ((ptr + hdrlen) <= (data + datalen))) { 603233039Shselasky memcpy(ptr, &temp, sizeof(temp)); 604233039Shselasky memset(ptr + sizeof(temp), 0, hdrlen - sizeof(temp)); 605233039Shselasky } else { 606233039Shselasky err(EXIT_FAILURE, "Invalid header length %d", hdrlen); 607233039Shselasky } 608233037Shselasky 609233039Shselasky next = ptr + BPF_WORDALIGN(hdrlen + caplen); 610233037Shselasky 611233039Shselasky if (next <= ptr) 612233039Shselasky err(EXIT_FAILURE, "Invalid length"); 613233039Shselasky } 614233039Shselasky} 615233037Shselasky 616233039Shselaskystatic void 617233039Shselaskyprint_packets(uint8_t *data, const int datalen) 618233039Shselasky{ 619233039Shselasky struct header_32 temp; 620233039Shselasky uint8_t *ptr; 621233039Shselasky uint8_t *next; 622233037Shselasky 623233039Shselasky for (ptr = data; ptr < (data + datalen); ptr = next) { 624233037Shselasky 625233039Shselasky const struct header_32 *hdr32; 626233037Shselasky 627233039Shselasky hdr32 = (const struct header_32 *)ptr; 628233039Shselasky 629233039Shselasky temp.ts_sec = le32toh(hdr32->ts_sec); 630233039Shselasky temp.ts_usec = le32toh(hdr32->ts_usec); 631233039Shselasky temp.caplen = le32toh(hdr32->caplen); 632233039Shselasky temp.datalen = le32toh(hdr32->datalen); 633233039Shselasky temp.hdrlen = hdr32->hdrlen; 634233039Shselasky temp.align = hdr32->align; 635233039Shselasky 636298216Spfg next = ptr + roundup2(temp.hdrlen + temp.caplen, temp.align); 637233039Shselasky 638233037Shselasky if (next <= ptr) 639233039Shselasky err(EXIT_FAILURE, "Invalid length"); 640233037Shselasky 641234636Shselasky if (verbose >= 0 || r_arg != NULL || b_arg != NULL) { 642233037Shselasky print_apacket(&temp, ptr + 643233037Shselasky temp.hdrlen, temp.caplen); 644220301Shselasky } 645215651Sweongyo pkt_captured++; 646215651Sweongyo } 647215651Sweongyo} 648215651Sweongyo 649215651Sweongyostatic void 650220301Shselaskywrite_packets(struct usbcap *p, const uint8_t *data, const int datalen) 651215651Sweongyo{ 652220301Shselasky int len = htole32(datalen); 653220301Shselasky int ret; 654215651Sweongyo 655215651Sweongyo ret = write(p->wfd, &len, sizeof(int)); 656221604Shselasky if (ret != sizeof(int)) { 657221604Shselasky err(EXIT_FAILURE, "Could not write length " 658221604Shselasky "field of USB data payload"); 659221604Shselasky } 660215651Sweongyo ret = write(p->wfd, data, datalen); 661221604Shselasky if (ret != datalen) { 662221604Shselasky err(EXIT_FAILURE, "Could not write " 663221604Shselasky "complete USB data payload"); 664221604Shselasky } 665215651Sweongyo} 666215651Sweongyo 667215651Sweongyostatic void 668215651Sweongyoread_file(struct usbcap *p) 669215651Sweongyo{ 670220301Shselasky int datalen; 671220301Shselasky int ret; 672220301Shselasky uint8_t *data; 673215651Sweongyo 674215651Sweongyo while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) { 675215651Sweongyo datalen = le32toh(datalen); 676215651Sweongyo data = malloc(datalen); 677221604Shselasky if (data == NULL) 678221604Shselasky errx(EX_SOFTWARE, "Out of memory."); 679215651Sweongyo ret = read(p->rfd, data, datalen); 680221604Shselasky if (ret != datalen) { 681221604Shselasky err(EXIT_FAILURE, "Could not read complete " 682221604Shselasky "USB data payload"); 683221604Shselasky } 684233039Shselasky if (uf_minor == 2) 685233039Shselasky fix_packets(data, datalen); 686233039Shselasky 687215651Sweongyo print_packets(data, datalen); 688215651Sweongyo free(data); 689215651Sweongyo } 690215651Sweongyo} 691215651Sweongyo 692215651Sweongyostatic void 693215651Sweongyodo_loop(struct usbcap *p) 694215651Sweongyo{ 695215651Sweongyo int cc; 696215651Sweongyo 697215651Sweongyo while (doexit == 0) { 698220301Shselasky cc = read(p->fd, (uint8_t *)p->buffer, p->bufsize); 699215651Sweongyo if (cc < 0) { 700215651Sweongyo switch (errno) { 701215651Sweongyo case EINTR: 702215651Sweongyo break; 703215651Sweongyo default: 704215651Sweongyo fprintf(stderr, "read: %s\n", strerror(errno)); 705215651Sweongyo return; 706215651Sweongyo } 707215651Sweongyo continue; 708215651Sweongyo } 709215651Sweongyo if (cc == 0) 710215651Sweongyo continue; 711233039Shselasky 712233039Shselasky fix_packets(p->buffer, cc); 713233039Shselasky 714215651Sweongyo if (w_arg != NULL) 715215651Sweongyo write_packets(p, p->buffer, cc); 716215651Sweongyo print_packets(p->buffer, cc); 717215651Sweongyo } 718215651Sweongyo} 719215651Sweongyo 720215651Sweongyostatic void 721215651Sweongyoinit_rfile(struct usbcap *p) 722215651Sweongyo{ 723215651Sweongyo struct usbcap_filehdr uf; 724215651Sweongyo int ret; 725215651Sweongyo 726215651Sweongyo p->rfd = open(r_arg, O_RDONLY); 727215651Sweongyo if (p->rfd < 0) { 728221604Shselasky err(EXIT_FAILURE, "Could not open " 729221604Shselasky "'%s' for read", r_arg); 730215651Sweongyo } 731215651Sweongyo ret = read(p->rfd, &uf, sizeof(uf)); 732221604Shselasky if (ret != sizeof(uf)) { 733221604Shselasky err(EXIT_FAILURE, "Could not read USB capture " 734221604Shselasky "file header"); 735221604Shselasky } 736221604Shselasky if (le32toh(uf.magic) != USBCAP_FILEHDR_MAGIC) { 737221604Shselasky errx(EX_SOFTWARE, "Invalid magic field(0x%08x) " 738221604Shselasky "in USB capture file header.", 739221604Shselasky (unsigned int)le32toh(uf.magic)); 740221604Shselasky } 741221604Shselasky if (uf.major != 0) { 742221604Shselasky errx(EX_SOFTWARE, "Invalid major version(%d) " 743221604Shselasky "field in USB capture file header.", (int)uf.major); 744221604Shselasky } 745233039Shselasky 746233039Shselasky uf_minor = uf.minor; 747233039Shselasky 748233039Shselasky if (uf.minor != 3 && uf.minor != 2) { 749221604Shselasky errx(EX_SOFTWARE, "Invalid minor version(%d) " 750221604Shselasky "field in USB capture file header.", (int)uf.minor); 751221604Shselasky } 752215651Sweongyo} 753215651Sweongyo 754215651Sweongyostatic void 755215651Sweongyoinit_wfile(struct usbcap *p) 756215651Sweongyo{ 757215651Sweongyo struct usbcap_filehdr uf; 758215651Sweongyo int ret; 759215651Sweongyo 760215651Sweongyo p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 761215651Sweongyo if (p->wfd < 0) { 762221604Shselasky err(EXIT_FAILURE, "Could not open " 763233039Shselasky "'%s' for write", w_arg); 764215651Sweongyo } 765221604Shselasky memset(&uf, 0, sizeof(uf)); 766215651Sweongyo uf.magic = htole32(USBCAP_FILEHDR_MAGIC); 767215651Sweongyo uf.major = 0; 768233039Shselasky uf.minor = 3; 769215651Sweongyo ret = write(p->wfd, (const void *)&uf, sizeof(uf)); 770221604Shselasky if (ret != sizeof(uf)) { 771221604Shselasky err(EXIT_FAILURE, "Could not write " 772221604Shselasky "USB capture header"); 773221604Shselasky } 774215651Sweongyo} 775215651Sweongyo 776215651Sweongyostatic void 777215651Sweongyousage(void) 778215651Sweongyo{ 779215651Sweongyo 780215651Sweongyo#define FMT " %-14s %s\n" 781215651Sweongyo fprintf(stderr, "usage: usbdump [options]\n"); 782221604Shselasky fprintf(stderr, FMT, "-i <usbusX>", "Listen on USB bus interface"); 783231835Shselasky fprintf(stderr, FMT, "-f <unit[.endpoint]>", "Specify a device and endpoint filter"); 784221604Shselasky fprintf(stderr, FMT, "-r <file>", "Read the raw packets from file"); 785221604Shselasky fprintf(stderr, FMT, "-s <snaplen>", "Snapshot bytes from each packet"); 786221604Shselasky fprintf(stderr, FMT, "-v", "Increase the verbose level"); 787234636Shselasky fprintf(stderr, FMT, "-b <file>", "Save raw version of all recorded data to file"); 788221604Shselasky fprintf(stderr, FMT, "-w <file>", "Write the raw packets to file"); 789234655Shselasky fprintf(stderr, FMT, "-h", "Display summary of command line options"); 790215651Sweongyo#undef FMT 791221604Shselasky exit(EX_USAGE); 792215651Sweongyo} 793215651Sweongyo 794260978Shselaskystatic void 795260978Shselaskycheck_usb_pf_sysctl(void) 796260978Shselasky{ 797260978Shselasky int error; 798260978Shselasky int no_pf_val = 0; 799260978Shselasky size_t no_pf_len = sizeof(int); 800260978Shselasky 801260978Shselasky /* check "hw.usb.no_pf" sysctl for 8- and 9- stable */ 802260978Shselasky 803260978Shselasky error = sysctlbyname("hw.usb.no_pf", &no_pf_val, 804260978Shselasky &no_pf_len, NULL, 0); 805260978Shselasky if (error == 0 && no_pf_val != 0) { 806260978Shselasky warnx("The USB packet filter might be disabled."); 807260978Shselasky warnx("See the \"hw.usb.no_pf\" sysctl for more information."); 808260978Shselasky } 809260978Shselasky} 810260978Shselasky 811215651Sweongyoint 812215651Sweongyomain(int argc, char *argv[]) 813215651Sweongyo{ 814215651Sweongyo struct timeval tv; 815215803Sweongyo struct bpf_program total_prog; 816215803Sweongyo struct bpf_stat us; 817215803Sweongyo struct bpf_version bv; 818234636Shselasky struct usbcap *p = &uc; 819215803Sweongyo struct ifreq ifr; 820215651Sweongyo long snapshot = 192; 821220301Shselasky uint32_t v; 822231835Shselasky int fd; 823231835Shselasky int o; 824231835Shselasky int filt_unit; 825231835Shselasky int filt_ep; 826238279Shrs int s; 827238279Shrs int ifindex; 828215651Sweongyo const char *optstring; 829231835Shselasky char *pp; 830215651Sweongyo 831234655Shselasky optstring = "b:hi:r:s:vw:f:"; 832215651Sweongyo while ((o = getopt(argc, argv, optstring)) != -1) { 833215651Sweongyo switch (o) { 834215651Sweongyo case 'i': 835215651Sweongyo i_arg = optarg; 836215651Sweongyo break; 837215651Sweongyo case 'r': 838215651Sweongyo r_arg = optarg; 839215651Sweongyo init_rfile(p); 840215651Sweongyo break; 841215651Sweongyo case 's': 842231835Shselasky snapshot = strtol(optarg, &pp, 10); 843215651Sweongyo errno = 0; 844231835Shselasky if (pp != NULL && *pp != 0) 845231835Shselasky usage(); 846215651Sweongyo if (snapshot == 0 && errno == EINVAL) 847215651Sweongyo usage(); 848215651Sweongyo /* snapeshot == 0 is special */ 849215651Sweongyo if (snapshot == 0) 850215651Sweongyo snapshot = -1; 851215651Sweongyo break; 852234636Shselasky case 'b': 853234636Shselasky b_arg = optarg; 854234636Shselasky break; 855215651Sweongyo case 'v': 856215651Sweongyo verbose++; 857215651Sweongyo break; 858215651Sweongyo case 'w': 859215651Sweongyo w_arg = optarg; 860215651Sweongyo init_wfile(p); 861215651Sweongyo break; 862231835Shselasky case 'f': 863231835Shselasky filt_unit = strtol(optarg, &pp, 10); 864231835Shselasky filt_ep = -1; 865231835Shselasky if (pp != NULL) { 866231835Shselasky if (*pp == '.') { 867231835Shselasky filt_ep = strtol(pp + 1, &pp, 10); 868231835Shselasky if (pp != NULL && *pp != 0) 869231835Shselasky usage(); 870231835Shselasky } else if (*pp != 0) { 871231835Shselasky usage(); 872231835Shselasky } 873231835Shselasky } 874231835Shselasky add_filter(filt_unit, filt_ep); 875231835Shselasky break; 876215651Sweongyo default: 877215651Sweongyo usage(); 878215651Sweongyo /* NOTREACHED */ 879215651Sweongyo } 880215651Sweongyo } 881215651Sweongyo 882234636Shselasky if (b_arg != NULL) { 883234636Shselasky p->bfd = open(b_arg, O_CREAT | O_TRUNC | 884234636Shselasky O_WRONLY, S_IRUSR | S_IWUSR); 885234636Shselasky if (p->bfd < 0) { 886234636Shselasky err(EXIT_FAILURE, "Could not open " 887234636Shselasky "'%s' for write", b_arg); 888234636Shselasky } 889234636Shselasky } 890234636Shselasky 891234636Shselasky /* 892234636Shselasky * Require more verbosity to print anything when -w or -b is 893234636Shselasky * specified on the command line: 894234636Shselasky */ 895234636Shselasky if (w_arg != NULL || b_arg != NULL) 896234636Shselasky verbose--; 897234636Shselasky 898215651Sweongyo if (r_arg != NULL) { 899215651Sweongyo read_file(p); 900215651Sweongyo exit(EXIT_SUCCESS); 901215651Sweongyo } 902215651Sweongyo 903260978Shselasky check_usb_pf_sysctl(); 904260978Shselasky 905215803Sweongyo p->fd = fd = open("/dev/bpf", O_RDONLY); 906221604Shselasky if (p->fd < 0) 907221604Shselasky err(EXIT_FAILURE, "Could not open BPF device"); 908215651Sweongyo 909221604Shselasky if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) 910221604Shselasky err(EXIT_FAILURE, "BIOCVERSION ioctl failed"); 911221604Shselasky 912215803Sweongyo if (bv.bv_major != BPF_MAJOR_VERSION || 913221604Shselasky bv.bv_minor < BPF_MINOR_VERSION) 914221604Shselasky errx(EXIT_FAILURE, "Kernel BPF filter out of date"); 915215651Sweongyo 916220301Shselasky /* USB transfers can be greater than 64KByte */ 917220301Shselasky v = 1U << 16; 918220301Shselasky 919220301Shselasky /* clear ifr structure */ 920220301Shselasky memset(&ifr, 0, sizeof(ifr)); 921220301Shselasky 922238279Shrs /* Try to create usbusN interface if it is not available. */ 923238279Shrs s = socket(AF_LOCAL, SOCK_DGRAM, 0); 924238279Shrs if (s < 0) 925238279Shrs errx(EXIT_FAILURE, "Could not open a socket"); 926238279Shrs ifindex = if_nametoindex(i_arg); 927238279Shrs if (ifindex == 0) { 928238279Shrs (void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 929238279Shrs if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) 930238279Shrs errx(EXIT_FAILURE, "Invalid bus interface: %s", i_arg); 931238279Shrs } 932238279Shrs 933220301Shselasky for ( ; v >= USBPF_HDR_LEN; v >>= 1) { 934215803Sweongyo (void)ioctl(fd, BIOCSBLEN, (caddr_t)&v); 935238279Shrs (void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 936215803Sweongyo if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) 937215651Sweongyo break; 938215651Sweongyo } 939221604Shselasky if (v == 0) 940221604Shselasky errx(EXIT_FAILURE, "No buffer size worked."); 941215651Sweongyo 942221604Shselasky if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) 943221604Shselasky err(EXIT_FAILURE, "BIOCGBLEN ioctl failed"); 944215651Sweongyo 945215651Sweongyo p->bufsize = v; 946220301Shselasky p->buffer = (uint8_t *)malloc(p->bufsize); 947221604Shselasky if (p->buffer == NULL) 948221604Shselasky errx(EX_SOFTWARE, "Out of memory."); 949215651Sweongyo 950231835Shselasky make_filter(&total_prog, snapshot); 951215651Sweongyo 952221604Shselasky if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) 953221604Shselasky err(EXIT_FAILURE, "BIOCSETF ioctl failed"); 954215651Sweongyo 955231835Shselasky free_filter(&total_prog); 956231835Shselasky 957215651Sweongyo /* 1 second read timeout */ 958215651Sweongyo tv.tv_sec = 1; 959215651Sweongyo tv.tv_usec = 0; 960221604Shselasky if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&tv) < 0) 961221604Shselasky err(EXIT_FAILURE, "BIOCSRTIMEOUT ioctl failed"); 962215651Sweongyo 963215651Sweongyo (void)signal(SIGINT, handle_sigint); 964215651Sweongyo 965215651Sweongyo do_loop(p); 966215651Sweongyo 967221604Shselasky if (ioctl(fd, BIOCGSTATS, (caddr_t)&us) < 0) 968221604Shselasky err(EXIT_FAILURE, "BIOCGSTATS ioctl failed"); 969215651Sweongyo 970215651Sweongyo /* XXX what's difference between pkt_captured and us.us_recv? */ 971215651Sweongyo printf("\n"); 972215651Sweongyo printf("%d packets captured\n", pkt_captured); 973215803Sweongyo printf("%d packets received by filter\n", us.bs_recv); 974215803Sweongyo printf("%d packets dropped by kernel\n", us.bs_drop); 975215651Sweongyo 976238279Shrs /* 977238279Shrs * Destroy the usbusN interface only if it was created by 978238279Shrs * usbdump(8). Ignore when it was already destroyed. 979238279Shrs */ 980238279Shrs if (ifindex == 0 && if_nametoindex(i_arg) > 0) { 981238279Shrs (void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 982238279Shrs if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) 983238279Shrs warn("SIOCIFDESTROY ioctl failed"); 984238279Shrs } 985238279Shrs close(s); 986238279Shrs 987215651Sweongyo if (p->fd > 0) 988215651Sweongyo close(p->fd); 989215651Sweongyo if (p->rfd > 0) 990215651Sweongyo close(p->rfd); 991215651Sweongyo if (p->wfd > 0) 992215651Sweongyo close(p->wfd); 993234636Shselasky if (p->bfd > 0) 994234636Shselasky close(p->bfd); 995215651Sweongyo 996215651Sweongyo return (EXIT_SUCCESS); 997215651Sweongyo} 998