1215651Sweongyo/*- 2215651Sweongyo * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org> 3215651Sweongyo * All rights reserved. 4215651Sweongyo * 5215651Sweongyo * Redistribution and use in source and binary forms, with or without 6215651Sweongyo * modification, are permitted provided that the following conditions 7215651Sweongyo * are met: 8215651Sweongyo * 1. Redistributions of source code must retain the above copyright 9215651Sweongyo * notice, this list of conditions and the following disclaimer, 10215651Sweongyo * without modification. 11215651Sweongyo * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12215651Sweongyo * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13215651Sweongyo * redistribution must be conditioned upon including a substantially 14215651Sweongyo * similar Disclaimer requirement for further binary redistribution. 15215651Sweongyo * 16215651Sweongyo * NO WARRANTY 17215651Sweongyo * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18215651Sweongyo * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19215651Sweongyo * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20215651Sweongyo * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21215651Sweongyo * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22215651Sweongyo * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23215651Sweongyo * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24215651Sweongyo * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25215651Sweongyo * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26215651Sweongyo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27215651Sweongyo * THE POSSIBILITY OF SUCH DAMAGES. 28215651Sweongyo * 29215651Sweongyo * $FreeBSD$ 30215651Sweongyo */ 31215651Sweongyo 32215651Sweongyo#include <sys/param.h> 33215651Sweongyo#include <sys/endian.h> 34215651Sweongyo#include <sys/ioctl.h> 35215803Sweongyo#include <sys/socket.h> 36215651Sweongyo#include <sys/stat.h> 37215651Sweongyo#include <sys/utsname.h> 38231835Shselasky#include <sys/queue.h> 39215803Sweongyo#include <net/if.h> 40215803Sweongyo#include <net/bpf.h> 41215651Sweongyo#include <dev/usb/usb.h> 42215651Sweongyo#include <dev/usb/usb_pf.h> 43215651Sweongyo#include <dev/usb/usbdi.h> 44215651Sweongyo#include <errno.h> 45215651Sweongyo#include <fcntl.h> 46215651Sweongyo#include <limits.h> 47215651Sweongyo#include <stdio.h> 48215651Sweongyo#include <stdlib.h> 49231835Shselasky#include <stdint.h> 50215651Sweongyo#include <string.h> 51215651Sweongyo#include <time.h> 52215651Sweongyo#include <unistd.h> 53221604Shselasky#include <sysexits.h> 54221604Shselasky#include <err.h> 55215651Sweongyo 56231835Shselasky#define BPF_STORE_JUMP(x,_c,_k,_jt,_jf) do { \ 57231835Shselasky (x).code = (_c); \ 58231835Shselasky (x).k = (_k); \ 59231835Shselasky (x).jt = (_jt); \ 60231835Shselasky (x).jf = (_jf); \ 61231835Shselasky} while (0) 62231835Shselasky 63231835Shselasky#define BPF_STORE_STMT(x,_c,_k) do { \ 64231835Shselasky (x).code = (_c); \ 65231835Shselasky (x).k = (_k); \ 66231835Shselasky (x).jt = 0; \ 67231835Shselasky (x).jf = 0; \ 68231835Shselasky} while (0) 69231835Shselasky 70231835Shselaskystruct usb_filt { 71231835Shselasky STAILQ_ENTRY(usb_filt) entry; 72231835Shselasky int unit; 73231835Shselasky int endpoint; 74231835Shselasky}; 75231835Shselasky 76215651Sweongyostruct usbcap { 77215651Sweongyo int fd; /* fd for /dev/usbpf */ 78220301Shselasky uint32_t bufsize; 79220301Shselasky uint8_t *buffer; 80215651Sweongyo 81215651Sweongyo /* for -w option */ 82215651Sweongyo int wfd; 83215651Sweongyo /* for -r option */ 84215651Sweongyo int rfd; 85234636Shselasky /* for -b option */ 86234636Shselasky int bfd; 87215651Sweongyo}; 88215651Sweongyo 89215651Sweongyostruct usbcap_filehdr { 90220301Shselasky uint32_t magic; 91215651Sweongyo#define USBCAP_FILEHDR_MAGIC 0x9a90000e 92220301Shselasky uint8_t major; 93220301Shselasky uint8_t minor; 94220301Shselasky uint8_t reserved[26]; 95215651Sweongyo} __packed; 96215651Sweongyo 97233037Shselasky#define HEADER_ALIGN(x,a) (((x) + (a) - 1) & ~((a) - 1)) 98233037Shselasky 99233037Shselaskystruct header_32 { 100233039Shselasky /* capture timestamp */ 101233037Shselasky uint32_t ts_sec; 102233037Shselasky uint32_t ts_usec; 103233039Shselasky /* data length and alignment information */ 104233037Shselasky uint32_t caplen; 105233037Shselasky uint32_t datalen; 106233039Shselasky uint8_t hdrlen; 107233039Shselasky uint8_t align; 108233037Shselasky} __packed; 109233037Shselasky 110215651Sweongyostatic int doexit = 0; 111215651Sweongyostatic int pkt_captured = 0; 112215651Sweongyostatic int verbose = 0; 113233039Shselaskystatic int uf_minor; 114218010Shselaskystatic const char *i_arg = "usbus0"; 115215651Sweongyostatic const char *r_arg = NULL; 116215651Sweongyostatic const char *w_arg = NULL; 117234636Shselaskystatic const char *b_arg = NULL; 118234636Shselaskystatic struct usbcap uc; 119215651Sweongyostatic const char *errstr_table[USB_ERR_MAX] = { 120220301Shselasky [USB_ERR_NORMAL_COMPLETION] = "0", 121215651Sweongyo [USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS", 122215651Sweongyo [USB_ERR_NOT_STARTED] = "NOT_STARTED", 123215651Sweongyo [USB_ERR_INVAL] = "INVAL", 124215651Sweongyo [USB_ERR_NOMEM] = "NOMEM", 125215651Sweongyo [USB_ERR_CANCELLED] = "CANCELLED", 126215651Sweongyo [USB_ERR_BAD_ADDRESS] = "BAD_ADDRESS", 127215651Sweongyo [USB_ERR_BAD_BUFSIZE] = "BAD_BUFSIZE", 128215651Sweongyo [USB_ERR_BAD_FLAG] = "BAD_FLAG", 129215651Sweongyo [USB_ERR_NO_CALLBACK] = "NO_CALLBACK", 130215651Sweongyo [USB_ERR_IN_USE] = "IN_USE", 131215651Sweongyo [USB_ERR_NO_ADDR] = "NO_ADDR", 132215651Sweongyo [USB_ERR_NO_PIPE] = "NO_PIPE", 133215651Sweongyo [USB_ERR_ZERO_NFRAMES] = "ZERO_NFRAMES", 134215651Sweongyo [USB_ERR_ZERO_MAXP] = "ZERO_MAXP", 135215651Sweongyo [USB_ERR_SET_ADDR_FAILED] = "SET_ADDR_FAILED", 136215651Sweongyo [USB_ERR_NO_POWER] = "NO_POWER", 137215651Sweongyo [USB_ERR_TOO_DEEP] = "TOO_DEEP", 138215651Sweongyo [USB_ERR_IOERROR] = "IOERROR", 139215651Sweongyo [USB_ERR_NOT_CONFIGURED] = "NOT_CONFIGURED", 140215651Sweongyo [USB_ERR_TIMEOUT] = "TIMEOUT", 141215651Sweongyo [USB_ERR_SHORT_XFER] = "SHORT_XFER", 142215651Sweongyo [USB_ERR_STALLED] = "STALLED", 143215651Sweongyo [USB_ERR_INTERRUPTED] = "INTERRUPTED", 144215651Sweongyo [USB_ERR_DMA_LOAD_FAILED] = "DMA_LOAD_FAILED", 145215651Sweongyo [USB_ERR_BAD_CONTEXT] = "BAD_CONTEXT", 146215651Sweongyo [USB_ERR_NO_ROOT_HUB] = "NO_ROOT_HUB", 147215651Sweongyo [USB_ERR_NO_INTR_THREAD] = "NO_INTR_THREAD", 148215651Sweongyo [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", 149215651Sweongyo}; 150215651Sweongyo 151220301Shselaskystatic const char *xfertype_table[4] = { 152215651Sweongyo [UE_CONTROL] = "CTRL", 153215651Sweongyo [UE_ISOCHRONOUS] = "ISOC", 154215651Sweongyo [UE_BULK] = "BULK", 155215651Sweongyo [UE_INTERRUPT] = "INTR" 156215651Sweongyo}; 157215651Sweongyo 158220301Shselaskystatic const char *speed_table[USB_SPEED_MAX] = { 159220301Shselasky [USB_SPEED_FULL] = "FULL", 160220301Shselasky [USB_SPEED_HIGH] = "HIGH", 161220301Shselasky [USB_SPEED_LOW] = "LOW", 162220301Shselasky [USB_SPEED_VARIABLE] = "VARI", 163220301Shselasky [USB_SPEED_SUPER] = "SUPER", 164220301Shselasky}; 165220301Shselasky 166231835Shselaskystatic STAILQ_HEAD(,usb_filt) usb_filt_head = 167231835Shselasky STAILQ_HEAD_INITIALIZER(usb_filt_head); 168231835Shselasky 169215651Sweongyostatic void 170231835Shselaskyadd_filter(int usb_filt_unit, int usb_filt_ep) 171231835Shselasky{ 172231835Shselasky struct usb_filt *puf; 173231835Shselasky 174231835Shselasky puf = malloc(sizeof(struct usb_filt)); 175231835Shselasky if (puf == NULL) 176231835Shselasky errx(EX_SOFTWARE, "Out of memory."); 177231835Shselasky 178231835Shselasky puf->unit = usb_filt_unit; 179231835Shselasky puf->endpoint = usb_filt_ep; 180231835Shselasky 181231835Shselasky STAILQ_INSERT_TAIL(&usb_filt_head, puf, entry); 182231835Shselasky} 183231835Shselasky 184231835Shselaskystatic void 185231835Shselaskymake_filter(struct bpf_program *pprog, int snapshot) 186231835Shselasky{ 187231835Shselasky struct usb_filt *puf; 188231835Shselasky struct bpf_insn *dynamic_insn; 189231835Shselasky int len; 190231835Shselasky 191231835Shselasky len = 0; 192231835Shselasky 193231835Shselasky STAILQ_FOREACH(puf, &usb_filt_head, entry) 194231835Shselasky len++; 195231835Shselasky 196231835Shselasky dynamic_insn = malloc(((len * 5) + 1) * sizeof(struct bpf_insn)); 197231835Shselasky 198231835Shselasky if (dynamic_insn == NULL) 199231835Shselasky errx(EX_SOFTWARE, "Out of memory."); 200231835Shselasky 201231835Shselasky len++; 202231835Shselasky 203231835Shselasky if (len == 1) { 204231835Shselasky /* accept all packets */ 205231835Shselasky 206231835Shselasky BPF_STORE_STMT(dynamic_insn[0], BPF_RET | BPF_K, snapshot); 207231835Shselasky 208231835Shselasky goto done; 209231835Shselasky } 210231835Shselasky 211231835Shselasky len = 0; 212231835Shselasky 213231835Shselasky STAILQ_FOREACH(puf, &usb_filt_head, entry) { 214231835Shselasky const int addr_off = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_address; 215231835Shselasky const int addr_ep = (uintptr_t)&((struct usbpf_pkthdr *)0)->up_endpoint; 216231835Shselasky 217231835Shselasky if (puf->unit != -1) { 218231835Shselasky if (puf->endpoint != -1) { 219231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 220231835Shselasky BPF_LD | BPF_B | BPF_ABS, addr_off); 221231835Shselasky len++; 222231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 223231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 3); 224231835Shselasky len++; 225231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 226231835Shselasky BPF_LD | BPF_W | BPF_ABS, addr_ep); 227231835Shselasky len++; 228231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 229231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1); 230231835Shselasky len++; 231231835Shselasky } else { 232231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 233231835Shselasky BPF_LD | BPF_B | BPF_ABS, addr_off); 234231835Shselasky len++; 235231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 236231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, (uint8_t)puf->unit, 0, 1); 237231835Shselasky len++; 238231835Shselasky } 239231835Shselasky } else { 240231835Shselasky if (puf->endpoint != -1) { 241231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 242231835Shselasky BPF_LD | BPF_W | BPF_ABS, addr_ep); 243231835Shselasky len++; 244231835Shselasky BPF_STORE_JUMP(dynamic_insn[len], 245231835Shselasky BPF_JMP | BPF_JEQ | BPF_K, htobe32(puf->endpoint), 0, 1); 246231835Shselasky len++; 247231835Shselasky } 248231835Shselasky } 249231835Shselasky BPF_STORE_STMT(dynamic_insn[len], 250231835Shselasky BPF_RET | BPF_K, snapshot); 251231835Shselasky len++; 252231835Shselasky } 253231835Shselasky 254231835Shselasky BPF_STORE_STMT(dynamic_insn[len], BPF_RET | BPF_K, 0); 255231835Shselasky len++; 256231835Shselasky 257231835Shselaskydone: 258231835Shselasky pprog->bf_len = len; 259231835Shselasky pprog->bf_insns = dynamic_insn; 260231835Shselasky} 261231835Shselasky 262234636Shselaskystatic int 263234636Shselaskymatch_filter(int unit, int endpoint) 264234636Shselasky{ 265234636Shselasky struct usb_filt *puf; 266234636Shselasky 267234636Shselasky if (STAILQ_FIRST(&usb_filt_head) == NULL) 268234636Shselasky return (1); 269234636Shselasky 270234636Shselasky STAILQ_FOREACH(puf, &usb_filt_head, entry) { 271234636Shselasky if ((puf->unit == -1 || puf->unit == unit) && 272234636Shselasky (puf->endpoint == -1 || puf->endpoint == endpoint)) 273234636Shselasky return (1); 274234636Shselasky } 275234636Shselasky return (0); 276234636Shselasky} 277234636Shselasky 278231835Shselaskystatic void 279231835Shselaskyfree_filter(struct bpf_program *pprog) 280231835Shselasky{ 281231835Shselasky struct usb_filt *puf; 282231835Shselasky 283231835Shselasky while ((puf = STAILQ_FIRST(&usb_filt_head)) != NULL) { 284231835Shselasky STAILQ_REMOVE_HEAD(&usb_filt_head, entry); 285231835Shselasky free(puf); 286231835Shselasky } 287231835Shselasky free(pprog->bf_insns); 288231835Shselasky} 289231835Shselasky 290231835Shselaskystatic void 291215651Sweongyohandle_sigint(int sig) 292215651Sweongyo{ 293215651Sweongyo 294215651Sweongyo (void)sig; 295215651Sweongyo doexit = 1; 296215651Sweongyo} 297215651Sweongyo 298220301Shselasky#define FLAGS(x, name) \ 299220301Shselasky (((x) & USBPF_FLAG_##name) ? #name "|" : "") 300220301Shselasky 301220301Shselasky#define STATUS(x, name) \ 302220301Shselasky (((x) & USBPF_STATUS_##name) ? #name "|" : "") 303220301Shselasky 304220301Shselaskystatic const char * 305220301Shselaskyusb_errstr(uint32_t error) 306220301Shselasky{ 307220301Shselasky if (error >= USB_ERR_MAX || errstr_table[error] == NULL) 308220301Shselasky return ("UNKNOWN"); 309220301Shselasky else 310220301Shselasky return (errstr_table[error]); 311220301Shselasky} 312220301Shselasky 313220301Shselaskystatic const char * 314220301Shselaskyusb_speedstr(uint8_t speed) 315220301Shselasky{ 316220301Shselasky if (speed >= USB_SPEED_MAX || speed_table[speed] == NULL) 317220301Shselasky return ("UNKNOWN"); 318220301Shselasky else 319220301Shselasky return (speed_table[speed]); 320220301Shselasky} 321220301Shselasky 322215651Sweongyostatic void 323220301Shselaskyprint_flags(uint32_t flags) 324215651Sweongyo{ 325220301Shselasky printf(" flags %#x <%s%s%s%s%s%s%s%s%s0>\n", 326220301Shselasky flags, 327220301Shselasky FLAGS(flags, FORCE_SHORT_XFER), 328220301Shselasky FLAGS(flags, SHORT_XFER_OK), 329220301Shselasky FLAGS(flags, SHORT_FRAMES_OK), 330220301Shselasky FLAGS(flags, PIPE_BOF), 331220301Shselasky FLAGS(flags, PROXY_BUFFER), 332220301Shselasky FLAGS(flags, EXT_BUFFER), 333220301Shselasky FLAGS(flags, MANUAL_STATUS), 334220301Shselasky FLAGS(flags, NO_PIPE_OK), 335220301Shselasky FLAGS(flags, STALL_PIPE)); 336215651Sweongyo} 337215651Sweongyo 338215651Sweongyostatic void 339220301Shselaskyprint_status(uint32_t status) 340215651Sweongyo{ 341220301Shselasky printf(" status %#x <%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s0>\n", 342220301Shselasky status, 343220301Shselasky STATUS(status, OPEN), 344220301Shselasky STATUS(status, TRANSFERRING), 345220301Shselasky STATUS(status, DID_DMA_DELAY), 346220301Shselasky STATUS(status, DID_CLOSE), 347220301Shselasky STATUS(status, DRAINING), 348220301Shselasky STATUS(status, STARTED), 349220301Shselasky STATUS(status, BW_RECLAIMED), 350220301Shselasky STATUS(status, CONTROL_XFR), 351220301Shselasky STATUS(status, CONTROL_HDR), 352220301Shselasky STATUS(status, CONTROL_ACT), 353220301Shselasky STATUS(status, CONTROL_STALL), 354220301Shselasky STATUS(status, SHORT_FRAMES_OK), 355220301Shselasky STATUS(status, SHORT_XFER_OK), 356220301Shselasky STATUS(status, BDMA_ENABLE), 357220301Shselasky STATUS(status, BDMA_NO_POST_SYNC), 358220301Shselasky STATUS(status, BDMA_SETUP), 359220301Shselasky STATUS(status, ISOCHRONOUS_XFR), 360220301Shselasky STATUS(status, CURR_DMA_SET), 361220301Shselasky STATUS(status, CAN_CANCEL_IMMED), 362220301Shselasky STATUS(status, DOING_CALLBACK)); 363220301Shselasky} 364215651Sweongyo 365220301Shselasky/* 366220301Shselasky * Dump a byte into hex format. 367220301Shselasky */ 368220301Shselaskystatic void 369220301Shselaskyhexbyte(char *buf, uint8_t temp) 370220301Shselasky{ 371220301Shselasky uint8_t lo; 372220301Shselasky uint8_t hi; 373220301Shselasky 374220301Shselasky lo = temp & 0xF; 375220301Shselasky hi = temp >> 4; 376220301Shselasky 377220301Shselasky if (hi < 10) 378220301Shselasky buf[0] = '0' + hi; 379220301Shselasky else 380220301Shselasky buf[0] = 'A' + hi - 10; 381220301Shselasky 382220301Shselasky if (lo < 10) 383220301Shselasky buf[1] = '0' + lo; 384220301Shselasky else 385220301Shselasky buf[1] = 'A' + lo - 10; 386215651Sweongyo} 387215651Sweongyo 388215651Sweongyo/* 389215651Sweongyo * Display a region in traditional hexdump format. 390215651Sweongyo */ 391215651Sweongyostatic void 392220301Shselaskyhexdump(const uint8_t *region, uint32_t len) 393215651Sweongyo{ 394220301Shselasky const uint8_t *line; 395220301Shselasky char linebuf[128]; 396220301Shselasky int i; 397218010Shselasky int x; 398218010Shselasky int c; 399215651Sweongyo 400215651Sweongyo for (line = region; line < (region + len); line += 16) { 401220301Shselasky 402220301Shselasky i = 0; 403220301Shselasky 404220301Shselasky linebuf[i] = ' '; 405220301Shselasky hexbyte(linebuf + i + 1, ((line - region) >> 8) & 0xFF); 406220301Shselasky hexbyte(linebuf + i + 3, (line - region) & 0xFF); 407220301Shselasky linebuf[i + 5] = ' '; 408220301Shselasky linebuf[i + 6] = ' '; 409220301Shselasky i += 7; 410220301Shselasky 411215651Sweongyo for (x = 0; x < 16; x++) { 412220301Shselasky if ((line + x) < (region + len)) { 413220301Shselasky hexbyte(linebuf + i, 414220301Shselasky *(const u_int8_t *)(line + x)); 415220301Shselasky } else { 416220301Shselasky linebuf[i] = '-'; 417220301Shselasky linebuf[i + 1] = '-'; 418220301Shselasky } 419220301Shselasky linebuf[i + 2] = ' '; 420220301Shselasky if (x == 7) { 421220301Shselasky linebuf[i + 3] = ' '; 422220301Shselasky i += 4; 423220301Shselasky } else { 424220301Shselasky i += 3; 425220301Shselasky } 426215651Sweongyo } 427220301Shselasky linebuf[i] = ' '; 428220301Shselasky linebuf[i + 1] = '|'; 429220301Shselasky i += 2; 430215651Sweongyo for (x = 0; x < 16; x++) { 431215651Sweongyo if ((line + x) < (region + len)) { 432215651Sweongyo c = *(const u_int8_t *)(line + x); 433215651Sweongyo /* !isprint(c) */ 434215651Sweongyo if ((c < ' ') || (c > '~')) 435215651Sweongyo c = '.'; 436220301Shselasky linebuf[i] = c; 437220301Shselasky } else { 438220301Shselasky linebuf[i] = ' '; 439220301Shselasky } 440220301Shselasky i++; 441215651Sweongyo } 442220301Shselasky linebuf[i] = '|'; 443220301Shselasky linebuf[i + 1] = 0; 444220301Shselasky i += 2; 445220301Shselasky puts(linebuf); 446215651Sweongyo } 447215651Sweongyo} 448215651Sweongyo 449215651Sweongyostatic void 450233037Shselaskyprint_apacket(const struct header_32 *hdr, const uint8_t *ptr, int ptr_len) 451215651Sweongyo{ 452215651Sweongyo struct tm *tm; 453220301Shselasky struct usbpf_pkthdr up_temp; 454220301Shselasky struct usbpf_pkthdr *up; 455215651Sweongyo struct timeval tv; 456215651Sweongyo size_t len; 457220301Shselasky uint32_t x; 458215651Sweongyo char buf[64]; 459215651Sweongyo 460220301Shselasky ptr += USBPF_HDR_LEN; 461220301Shselasky ptr_len -= USBPF_HDR_LEN; 462220301Shselasky if (ptr_len < 0) 463220301Shselasky return; 464220301Shselasky 465220301Shselasky /* make sure we don't change the source buffer */ 466220301Shselasky memcpy(&up_temp, ptr - USBPF_HDR_LEN, sizeof(up_temp)); 467220301Shselasky up = &up_temp; 468220301Shselasky 469220301Shselasky /* 470220301Shselasky * A packet from the kernel is based on little endian byte 471220301Shselasky * order. 472220301Shselasky */ 473220301Shselasky up->up_totlen = le32toh(up->up_totlen); 474215651Sweongyo up->up_busunit = le32toh(up->up_busunit); 475215651Sweongyo up->up_flags = le32toh(up->up_flags); 476215651Sweongyo up->up_status = le32toh(up->up_status); 477215651Sweongyo up->up_error = le32toh(up->up_error); 478215651Sweongyo up->up_interval = le32toh(up->up_interval); 479220301Shselasky up->up_frames = le32toh(up->up_frames); 480220301Shselasky up->up_packet_size = le32toh(up->up_packet_size); 481220301Shselasky up->up_packet_count = le32toh(up->up_packet_count); 482220301Shselasky up->up_endpoint = le32toh(up->up_endpoint); 483215651Sweongyo 484234636Shselasky if (!match_filter(up->up_address, up->up_endpoint)) 485234636Shselasky return; 486234636Shselasky 487233037Shselasky tv.tv_sec = hdr->ts_sec; 488233037Shselasky tv.tv_usec = hdr->ts_usec; 489215651Sweongyo tm = localtime(&tv.tv_sec); 490215651Sweongyo 491215651Sweongyo len = strftime(buf, sizeof(buf), "%H:%M:%S", tm); 492220301Shselasky 493234636Shselasky if (verbose >= 0) { 494234636Shselasky printf("%.*s.%06ld usbus%d.%d %s-%s-EP=%08x,SPD=%s,NFR=%d,SLEN=%d,IVAL=%d%s%s\n", 495234636Shselasky (int)len, buf, tv.tv_usec, 496234636Shselasky (int)up->up_busunit, (int)up->up_address, 497234636Shselasky (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE", 498234636Shselasky xfertype_table[up->up_xfertype], 499234636Shselasky (unsigned int)up->up_endpoint, 500234636Shselasky usb_speedstr(up->up_speed), 501234636Shselasky (int)up->up_frames, 502234636Shselasky (int)(up->up_totlen - USBPF_HDR_LEN - 503234636Shselasky (USBPF_FRAME_HDR_LEN * up->up_frames)), 504234636Shselasky (int)up->up_interval, 505234636Shselasky (up->up_type == USBPF_XFERTAP_DONE) ? ",ERR=" : "", 506234636Shselasky (up->up_type == USBPF_XFERTAP_DONE) ? 507234636Shselasky usb_errstr(up->up_error) : ""); 508234636Shselasky } 509215651Sweongyo 510234636Shselasky if (verbose >= 1 || b_arg != NULL) { 511220301Shselasky for (x = 0; x != up->up_frames; x++) { 512220301Shselasky const struct usbpf_framehdr *uf; 513220301Shselasky uint32_t framelen; 514220301Shselasky uint32_t flags; 515220301Shselasky 516220301Shselasky uf = (const struct usbpf_framehdr *)ptr; 517220301Shselasky ptr += USBPF_FRAME_HDR_LEN; 518220301Shselasky ptr_len -= USBPF_FRAME_HDR_LEN; 519220301Shselasky if (ptr_len < 0) 520220301Shselasky return; 521220301Shselasky 522220301Shselasky framelen = le32toh(uf->length); 523220301Shselasky flags = le32toh(uf->flags); 524220301Shselasky 525234636Shselasky if (verbose >= 1) { 526234636Shselasky printf(" frame[%u] %s %d bytes\n", 527234636Shselasky (unsigned int)x, 528234636Shselasky (flags & USBPF_FRAMEFLAG_READ) ? "READ" : "WRITE", 529234636Shselasky (int)framelen); 530234636Shselasky } 531220301Shselasky 532220301Shselasky if (flags & USBPF_FRAMEFLAG_DATA_FOLLOWS) { 533220301Shselasky 534220301Shselasky int tot_frame_len; 535220301Shselasky 536220301Shselasky tot_frame_len = USBPF_FRAME_ALIGN(framelen); 537220301Shselasky 538220301Shselasky ptr_len -= tot_frame_len; 539220301Shselasky 540220301Shselasky if (tot_frame_len < 0 || 541220301Shselasky (int)framelen < 0 || (int)ptr_len < 0) 542220301Shselasky break; 543220301Shselasky 544234636Shselasky if (b_arg != NULL) { 545234636Shselasky struct usbcap *p = &uc; 546234636Shselasky int ret; 547234636Shselasky ret = write(p->bfd, ptr, framelen); 548234636Shselasky if (ret != (int)framelen) 549234636Shselasky err(EXIT_FAILURE, "Could not write binary data"); 550234636Shselasky } 551234636Shselasky if (verbose >= 1) 552234636Shselasky hexdump(ptr, framelen); 553220301Shselasky 554220301Shselasky ptr += tot_frame_len; 555220301Shselasky } 556215651Sweongyo } 557215651Sweongyo } 558220301Shselasky if (verbose >= 2) 559215651Sweongyo print_flags(up->up_flags); 560220301Shselasky if (verbose >= 3) 561215651Sweongyo print_status(up->up_status); 562215651Sweongyo} 563215651Sweongyo 564215651Sweongyostatic void 565233039Shselaskyfix_packets(uint8_t *data, const int datalen) 566215651Sweongyo{ 567233037Shselasky struct header_32 temp; 568220301Shselasky uint8_t *ptr; 569220301Shselasky uint8_t *next; 570233039Shselasky uint32_t hdrlen; 571233039Shselasky uint32_t caplen; 572215651Sweongyo 573215651Sweongyo for (ptr = data; ptr < (data + datalen); ptr = next) { 574215651Sweongyo 575233039Shselasky const struct bpf_hdr *hdr; 576233037Shselasky 577233039Shselasky hdr = (const struct bpf_hdr *)ptr; 578233037Shselasky 579233039Shselasky temp.ts_sec = htole32(hdr->bh_tstamp.tv_sec); 580233039Shselasky temp.ts_usec = htole32(hdr->bh_tstamp.tv_usec); 581233039Shselasky temp.caplen = htole32(hdr->bh_caplen); 582233039Shselasky temp.datalen = htole32(hdr->bh_datalen); 583233039Shselasky temp.hdrlen = hdr->bh_hdrlen; 584233039Shselasky temp.align = BPF_WORDALIGN(1); 585233037Shselasky 586233039Shselasky hdrlen = hdr->bh_hdrlen; 587233039Shselasky caplen = hdr->bh_caplen; 588233037Shselasky 589233039Shselasky if ((hdrlen >= sizeof(temp)) && (hdrlen <= 255) && 590233039Shselasky ((ptr + hdrlen) <= (data + datalen))) { 591233039Shselasky memcpy(ptr, &temp, sizeof(temp)); 592233039Shselasky memset(ptr + sizeof(temp), 0, hdrlen - sizeof(temp)); 593233039Shselasky } else { 594233039Shselasky err(EXIT_FAILURE, "Invalid header length %d", hdrlen); 595233039Shselasky } 596233037Shselasky 597233039Shselasky next = ptr + BPF_WORDALIGN(hdrlen + caplen); 598233037Shselasky 599233039Shselasky if (next <= ptr) 600233039Shselasky err(EXIT_FAILURE, "Invalid length"); 601233039Shselasky } 602233039Shselasky} 603233037Shselasky 604233039Shselaskystatic void 605233039Shselaskyprint_packets(uint8_t *data, const int datalen) 606233039Shselasky{ 607233039Shselasky struct header_32 temp; 608233039Shselasky uint8_t *ptr; 609233039Shselasky uint8_t *next; 610233037Shselasky 611233039Shselasky for (ptr = data; ptr < (data + datalen); ptr = next) { 612233037Shselasky 613233039Shselasky const struct header_32 *hdr32; 614233037Shselasky 615233039Shselasky hdr32 = (const struct header_32 *)ptr; 616233039Shselasky 617233039Shselasky temp.ts_sec = le32toh(hdr32->ts_sec); 618233039Shselasky temp.ts_usec = le32toh(hdr32->ts_usec); 619233039Shselasky temp.caplen = le32toh(hdr32->caplen); 620233039Shselasky temp.datalen = le32toh(hdr32->datalen); 621233039Shselasky temp.hdrlen = hdr32->hdrlen; 622233039Shselasky temp.align = hdr32->align; 623233039Shselasky 624233039Shselasky next = ptr + HEADER_ALIGN(temp.hdrlen + temp.caplen, temp.align); 625233039Shselasky 626233037Shselasky if (next <= ptr) 627233039Shselasky err(EXIT_FAILURE, "Invalid length"); 628233037Shselasky 629234636Shselasky if (verbose >= 0 || r_arg != NULL || b_arg != NULL) { 630233037Shselasky print_apacket(&temp, ptr + 631233037Shselasky temp.hdrlen, temp.caplen); 632220301Shselasky } 633215651Sweongyo pkt_captured++; 634215651Sweongyo } 635215651Sweongyo} 636215651Sweongyo 637215651Sweongyostatic void 638220301Shselaskywrite_packets(struct usbcap *p, const uint8_t *data, const int datalen) 639215651Sweongyo{ 640220301Shselasky int len = htole32(datalen); 641220301Shselasky int ret; 642215651Sweongyo 643215651Sweongyo ret = write(p->wfd, &len, sizeof(int)); 644221604Shselasky if (ret != sizeof(int)) { 645221604Shselasky err(EXIT_FAILURE, "Could not write length " 646221604Shselasky "field of USB data payload"); 647221604Shselasky } 648215651Sweongyo ret = write(p->wfd, data, datalen); 649221604Shselasky if (ret != datalen) { 650221604Shselasky err(EXIT_FAILURE, "Could not write " 651221604Shselasky "complete USB data payload"); 652221604Shselasky } 653215651Sweongyo} 654215651Sweongyo 655215651Sweongyostatic void 656215651Sweongyoread_file(struct usbcap *p) 657215651Sweongyo{ 658220301Shselasky int datalen; 659220301Shselasky int ret; 660220301Shselasky uint8_t *data; 661215651Sweongyo 662215651Sweongyo while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) { 663215651Sweongyo datalen = le32toh(datalen); 664215651Sweongyo data = malloc(datalen); 665221604Shselasky if (data == NULL) 666221604Shselasky errx(EX_SOFTWARE, "Out of memory."); 667215651Sweongyo ret = read(p->rfd, data, datalen); 668221604Shselasky if (ret != datalen) { 669221604Shselasky err(EXIT_FAILURE, "Could not read complete " 670221604Shselasky "USB data payload"); 671221604Shselasky } 672233039Shselasky if (uf_minor == 2) 673233039Shselasky fix_packets(data, datalen); 674233039Shselasky 675215651Sweongyo print_packets(data, datalen); 676215651Sweongyo free(data); 677215651Sweongyo } 678215651Sweongyo} 679215651Sweongyo 680215651Sweongyostatic void 681215651Sweongyodo_loop(struct usbcap *p) 682215651Sweongyo{ 683215651Sweongyo int cc; 684215651Sweongyo 685215651Sweongyo while (doexit == 0) { 686220301Shselasky cc = read(p->fd, (uint8_t *)p->buffer, p->bufsize); 687215651Sweongyo if (cc < 0) { 688215651Sweongyo switch (errno) { 689215651Sweongyo case EINTR: 690215651Sweongyo break; 691215651Sweongyo default: 692215651Sweongyo fprintf(stderr, "read: %s\n", strerror(errno)); 693215651Sweongyo return; 694215651Sweongyo } 695215651Sweongyo continue; 696215651Sweongyo } 697215651Sweongyo if (cc == 0) 698215651Sweongyo continue; 699233039Shselasky 700233039Shselasky fix_packets(p->buffer, cc); 701233039Shselasky 702215651Sweongyo if (w_arg != NULL) 703215651Sweongyo write_packets(p, p->buffer, cc); 704215651Sweongyo print_packets(p->buffer, cc); 705215651Sweongyo } 706215651Sweongyo} 707215651Sweongyo 708215651Sweongyostatic void 709215651Sweongyoinit_rfile(struct usbcap *p) 710215651Sweongyo{ 711215651Sweongyo struct usbcap_filehdr uf; 712215651Sweongyo int ret; 713215651Sweongyo 714215651Sweongyo p->rfd = open(r_arg, O_RDONLY); 715215651Sweongyo if (p->rfd < 0) { 716221604Shselasky err(EXIT_FAILURE, "Could not open " 717221604Shselasky "'%s' for read", r_arg); 718215651Sweongyo } 719215651Sweongyo ret = read(p->rfd, &uf, sizeof(uf)); 720221604Shselasky if (ret != sizeof(uf)) { 721221604Shselasky err(EXIT_FAILURE, "Could not read USB capture " 722221604Shselasky "file header"); 723221604Shselasky } 724221604Shselasky if (le32toh(uf.magic) != USBCAP_FILEHDR_MAGIC) { 725221604Shselasky errx(EX_SOFTWARE, "Invalid magic field(0x%08x) " 726221604Shselasky "in USB capture file header.", 727221604Shselasky (unsigned int)le32toh(uf.magic)); 728221604Shselasky } 729221604Shselasky if (uf.major != 0) { 730221604Shselasky errx(EX_SOFTWARE, "Invalid major version(%d) " 731221604Shselasky "field in USB capture file header.", (int)uf.major); 732221604Shselasky } 733233039Shselasky 734233039Shselasky uf_minor = uf.minor; 735233039Shselasky 736233039Shselasky if (uf.minor != 3 && uf.minor != 2) { 737221604Shselasky errx(EX_SOFTWARE, "Invalid minor version(%d) " 738221604Shselasky "field in USB capture file header.", (int)uf.minor); 739221604Shselasky } 740215651Sweongyo} 741215651Sweongyo 742215651Sweongyostatic void 743215651Sweongyoinit_wfile(struct usbcap *p) 744215651Sweongyo{ 745215651Sweongyo struct usbcap_filehdr uf; 746215651Sweongyo int ret; 747215651Sweongyo 748215651Sweongyo p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 749215651Sweongyo if (p->wfd < 0) { 750221604Shselasky err(EXIT_FAILURE, "Could not open " 751233039Shselasky "'%s' for write", w_arg); 752215651Sweongyo } 753221604Shselasky memset(&uf, 0, sizeof(uf)); 754215651Sweongyo uf.magic = htole32(USBCAP_FILEHDR_MAGIC); 755215651Sweongyo uf.major = 0; 756233039Shselasky uf.minor = 3; 757215651Sweongyo ret = write(p->wfd, (const void *)&uf, sizeof(uf)); 758221604Shselasky if (ret != sizeof(uf)) { 759221604Shselasky err(EXIT_FAILURE, "Could not write " 760221604Shselasky "USB capture header"); 761221604Shselasky } 762215651Sweongyo} 763215651Sweongyo 764215651Sweongyostatic void 765215651Sweongyousage(void) 766215651Sweongyo{ 767215651Sweongyo 768215651Sweongyo#define FMT " %-14s %s\n" 769215651Sweongyo fprintf(stderr, "usage: usbdump [options]\n"); 770221604Shselasky fprintf(stderr, FMT, "-i <usbusX>", "Listen on USB bus interface"); 771231835Shselasky fprintf(stderr, FMT, "-f <unit[.endpoint]>", "Specify a device and endpoint filter"); 772221604Shselasky fprintf(stderr, FMT, "-r <file>", "Read the raw packets from file"); 773221604Shselasky fprintf(stderr, FMT, "-s <snaplen>", "Snapshot bytes from each packet"); 774221604Shselasky fprintf(stderr, FMT, "-v", "Increase the verbose level"); 775234636Shselasky fprintf(stderr, FMT, "-b <file>", "Save raw version of all recorded data to file"); 776221604Shselasky fprintf(stderr, FMT, "-w <file>", "Write the raw packets to file"); 777234655Shselasky fprintf(stderr, FMT, "-h", "Display summary of command line options"); 778215651Sweongyo#undef FMT 779221604Shselasky exit(EX_USAGE); 780215651Sweongyo} 781215651Sweongyo 782215651Sweongyoint 783215651Sweongyomain(int argc, char *argv[]) 784215651Sweongyo{ 785215651Sweongyo struct timeval tv; 786215803Sweongyo struct bpf_program total_prog; 787215803Sweongyo struct bpf_stat us; 788215803Sweongyo struct bpf_version bv; 789234636Shselasky struct usbcap *p = &uc; 790215803Sweongyo struct ifreq ifr; 791215651Sweongyo long snapshot = 192; 792220301Shselasky uint32_t v; 793231835Shselasky int fd; 794231835Shselasky int o; 795231835Shselasky int filt_unit; 796231835Shselasky int filt_ep; 797238279Shrs int s; 798238279Shrs int ifindex; 799215651Sweongyo const char *optstring; 800231835Shselasky char *pp; 801215651Sweongyo 802234655Shselasky optstring = "b:hi:r:s:vw:f:"; 803215651Sweongyo while ((o = getopt(argc, argv, optstring)) != -1) { 804215651Sweongyo switch (o) { 805215651Sweongyo case 'i': 806215651Sweongyo i_arg = optarg; 807215651Sweongyo break; 808215651Sweongyo case 'r': 809215651Sweongyo r_arg = optarg; 810215651Sweongyo init_rfile(p); 811215651Sweongyo break; 812215651Sweongyo case 's': 813231835Shselasky snapshot = strtol(optarg, &pp, 10); 814215651Sweongyo errno = 0; 815231835Shselasky if (pp != NULL && *pp != 0) 816231835Shselasky usage(); 817215651Sweongyo if (snapshot == 0 && errno == EINVAL) 818215651Sweongyo usage(); 819215651Sweongyo /* snapeshot == 0 is special */ 820215651Sweongyo if (snapshot == 0) 821215651Sweongyo snapshot = -1; 822215651Sweongyo break; 823234636Shselasky case 'b': 824234636Shselasky b_arg = optarg; 825234636Shselasky break; 826215651Sweongyo case 'v': 827215651Sweongyo verbose++; 828215651Sweongyo break; 829215651Sweongyo case 'w': 830215651Sweongyo w_arg = optarg; 831215651Sweongyo init_wfile(p); 832215651Sweongyo break; 833231835Shselasky case 'f': 834231835Shselasky filt_unit = strtol(optarg, &pp, 10); 835231835Shselasky filt_ep = -1; 836231835Shselasky if (pp != NULL) { 837231835Shselasky if (*pp == '.') { 838231835Shselasky filt_ep = strtol(pp + 1, &pp, 10); 839231835Shselasky if (pp != NULL && *pp != 0) 840231835Shselasky usage(); 841231835Shselasky } else if (*pp != 0) { 842231835Shselasky usage(); 843231835Shselasky } 844231835Shselasky } 845231835Shselasky add_filter(filt_unit, filt_ep); 846231835Shselasky break; 847215651Sweongyo default: 848215651Sweongyo usage(); 849215651Sweongyo /* NOTREACHED */ 850215651Sweongyo } 851215651Sweongyo } 852215651Sweongyo 853234636Shselasky if (b_arg != NULL) { 854234636Shselasky p->bfd = open(b_arg, O_CREAT | O_TRUNC | 855234636Shselasky O_WRONLY, S_IRUSR | S_IWUSR); 856234636Shselasky if (p->bfd < 0) { 857234636Shselasky err(EXIT_FAILURE, "Could not open " 858234636Shselasky "'%s' for write", b_arg); 859234636Shselasky } 860234636Shselasky } 861234636Shselasky 862234636Shselasky /* 863234636Shselasky * Require more verbosity to print anything when -w or -b is 864234636Shselasky * specified on the command line: 865234636Shselasky */ 866234636Shselasky if (w_arg != NULL || b_arg != NULL) 867234636Shselasky verbose--; 868234636Shselasky 869215651Sweongyo if (r_arg != NULL) { 870215651Sweongyo read_file(p); 871215651Sweongyo exit(EXIT_SUCCESS); 872215651Sweongyo } 873215651Sweongyo 874215803Sweongyo p->fd = fd = open("/dev/bpf", O_RDONLY); 875221604Shselasky if (p->fd < 0) 876221604Shselasky err(EXIT_FAILURE, "Could not open BPF device"); 877215651Sweongyo 878221604Shselasky if (ioctl(fd, BIOCVERSION, (caddr_t)&bv) < 0) 879221604Shselasky err(EXIT_FAILURE, "BIOCVERSION ioctl failed"); 880221604Shselasky 881215803Sweongyo if (bv.bv_major != BPF_MAJOR_VERSION || 882221604Shselasky bv.bv_minor < BPF_MINOR_VERSION) 883221604Shselasky errx(EXIT_FAILURE, "Kernel BPF filter out of date"); 884215651Sweongyo 885220301Shselasky /* USB transfers can be greater than 64KByte */ 886220301Shselasky v = 1U << 16; 887220301Shselasky 888220301Shselasky /* clear ifr structure */ 889220301Shselasky memset(&ifr, 0, sizeof(ifr)); 890220301Shselasky 891238279Shrs /* Try to create usbusN interface if it is not available. */ 892238279Shrs s = socket(AF_LOCAL, SOCK_DGRAM, 0); 893238279Shrs if (s < 0) 894238279Shrs errx(EXIT_FAILURE, "Could not open a socket"); 895238279Shrs ifindex = if_nametoindex(i_arg); 896238279Shrs if (ifindex == 0) { 897238279Shrs (void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 898238279Shrs if (ioctl(s, SIOCIFCREATE2, &ifr) < 0) 899238279Shrs errx(EXIT_FAILURE, "Invalid bus interface: %s", i_arg); 900238279Shrs } 901238279Shrs 902220301Shselasky for ( ; v >= USBPF_HDR_LEN; v >>= 1) { 903215803Sweongyo (void)ioctl(fd, BIOCSBLEN, (caddr_t)&v); 904238279Shrs (void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 905215803Sweongyo if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0) 906215651Sweongyo break; 907215651Sweongyo } 908221604Shselasky if (v == 0) 909221604Shselasky errx(EXIT_FAILURE, "No buffer size worked."); 910215651Sweongyo 911221604Shselasky if (ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) 912221604Shselasky err(EXIT_FAILURE, "BIOCGBLEN ioctl failed"); 913215651Sweongyo 914215651Sweongyo p->bufsize = v; 915220301Shselasky p->buffer = (uint8_t *)malloc(p->bufsize); 916221604Shselasky if (p->buffer == NULL) 917221604Shselasky errx(EX_SOFTWARE, "Out of memory."); 918215651Sweongyo 919231835Shselasky make_filter(&total_prog, snapshot); 920215651Sweongyo 921221604Shselasky if (ioctl(p->fd, BIOCSETF, (caddr_t)&total_prog) < 0) 922221604Shselasky err(EXIT_FAILURE, "BIOCSETF ioctl failed"); 923215651Sweongyo 924231835Shselasky free_filter(&total_prog); 925231835Shselasky 926215651Sweongyo /* 1 second read timeout */ 927215651Sweongyo tv.tv_sec = 1; 928215651Sweongyo tv.tv_usec = 0; 929221604Shselasky if (ioctl(p->fd, BIOCSRTIMEOUT, (caddr_t)&tv) < 0) 930221604Shselasky err(EXIT_FAILURE, "BIOCSRTIMEOUT ioctl failed"); 931215651Sweongyo 932215651Sweongyo (void)signal(SIGINT, handle_sigint); 933215651Sweongyo 934215651Sweongyo do_loop(p); 935215651Sweongyo 936221604Shselasky if (ioctl(fd, BIOCGSTATS, (caddr_t)&us) < 0) 937221604Shselasky err(EXIT_FAILURE, "BIOCGSTATS ioctl failed"); 938215651Sweongyo 939215651Sweongyo /* XXX what's difference between pkt_captured and us.us_recv? */ 940215651Sweongyo printf("\n"); 941215651Sweongyo printf("%d packets captured\n", pkt_captured); 942215803Sweongyo printf("%d packets received by filter\n", us.bs_recv); 943215803Sweongyo printf("%d packets dropped by kernel\n", us.bs_drop); 944215651Sweongyo 945238279Shrs /* 946238279Shrs * Destroy the usbusN interface only if it was created by 947238279Shrs * usbdump(8). Ignore when it was already destroyed. 948238279Shrs */ 949238279Shrs if (ifindex == 0 && if_nametoindex(i_arg) > 0) { 950238279Shrs (void)strlcpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name)); 951238279Shrs if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) 952238279Shrs warn("SIOCIFDESTROY ioctl failed"); 953238279Shrs } 954238279Shrs close(s); 955238279Shrs 956215651Sweongyo if (p->fd > 0) 957215651Sweongyo close(p->fd); 958215651Sweongyo if (p->rfd > 0) 959215651Sweongyo close(p->rfd); 960215651Sweongyo if (p->wfd > 0) 961215651Sweongyo close(p->wfd); 962234636Shselasky if (p->bfd > 0) 963234636Shselasky close(p->bfd); 964215651Sweongyo 965215651Sweongyo return (EXIT_SUCCESS); 966215651Sweongyo} 967