usbdump.c revision 215651
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: head/usr.sbin/usbdump/usbdump.c 215651 2010-11-22 01:28:29Z weongyo $ 30215651Sweongyo */ 31215651Sweongyo 32215651Sweongyo#include <sys/param.h> 33215651Sweongyo#include <sys/endian.h> 34215651Sweongyo#include <sys/ioctl.h> 35215651Sweongyo#include <sys/stat.h> 36215651Sweongyo#include <sys/utsname.h> 37215651Sweongyo#include <dev/usb/usb.h> 38215651Sweongyo#include <dev/usb/usb_pf.h> 39215651Sweongyo#include <dev/usb/usbdi.h> 40215651Sweongyo#include <assert.h> 41215651Sweongyo#include <errno.h> 42215651Sweongyo#include <fcntl.h> 43215651Sweongyo#include <limits.h> 44215651Sweongyo#include <stdio.h> 45215651Sweongyo#include <stdlib.h> 46215651Sweongyo#include <string.h> 47215651Sweongyo#include <time.h> 48215651Sweongyo#include <unistd.h> 49215651Sweongyo 50215651Sweongyostruct usbcap { 51215651Sweongyo int fd; /* fd for /dev/usbpf */ 52215651Sweongyo u_int bufsize; 53215651Sweongyo char *buffer; 54215651Sweongyo 55215651Sweongyo /* for -w option */ 56215651Sweongyo int wfd; 57215651Sweongyo /* for -r option */ 58215651Sweongyo int rfd; 59215651Sweongyo}; 60215651Sweongyo 61215651Sweongyostruct usbcap_filehdr { 62215651Sweongyo u_int magic; 63215651Sweongyo#define USBCAP_FILEHDR_MAGIC 0x9a90000e 64215651Sweongyo u_char major; 65215651Sweongyo u_char minor; 66215651Sweongyo u_char reserved[26]; 67215651Sweongyo} __packed; 68215651Sweongyo 69215651Sweongyostatic int doexit = 0; 70215651Sweongyostatic int pkt_captured = 0; 71215651Sweongyostatic int verbose = 0; 72215651Sweongyostatic const char *i_arg = "usbus0";; 73215651Sweongyostatic const char *r_arg = NULL; 74215651Sweongyostatic const char *w_arg = NULL; 75215651Sweongyostatic const char *errstr_table[USB_ERR_MAX] = { 76215651Sweongyo [USB_ERR_NORMAL_COMPLETION] = "NORMAL_COMPLETION", 77215651Sweongyo [USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS", 78215651Sweongyo [USB_ERR_NOT_STARTED] = "NOT_STARTED", 79215651Sweongyo [USB_ERR_INVAL] = "INVAL", 80215651Sweongyo [USB_ERR_NOMEM] = "NOMEM", 81215651Sweongyo [USB_ERR_CANCELLED] = "CANCELLED", 82215651Sweongyo [USB_ERR_BAD_ADDRESS] = "BAD_ADDRESS", 83215651Sweongyo [USB_ERR_BAD_BUFSIZE] = "BAD_BUFSIZE", 84215651Sweongyo [USB_ERR_BAD_FLAG] = "BAD_FLAG", 85215651Sweongyo [USB_ERR_NO_CALLBACK] = "NO_CALLBACK", 86215651Sweongyo [USB_ERR_IN_USE] = "IN_USE", 87215651Sweongyo [USB_ERR_NO_ADDR] = "NO_ADDR", 88215651Sweongyo [USB_ERR_NO_PIPE] = "NO_PIPE", 89215651Sweongyo [USB_ERR_ZERO_NFRAMES] = "ZERO_NFRAMES", 90215651Sweongyo [USB_ERR_ZERO_MAXP] = "ZERO_MAXP", 91215651Sweongyo [USB_ERR_SET_ADDR_FAILED] = "SET_ADDR_FAILED", 92215651Sweongyo [USB_ERR_NO_POWER] = "NO_POWER", 93215651Sweongyo [USB_ERR_TOO_DEEP] = "TOO_DEEP", 94215651Sweongyo [USB_ERR_IOERROR] = "IOERROR", 95215651Sweongyo [USB_ERR_NOT_CONFIGURED] = "NOT_CONFIGURED", 96215651Sweongyo [USB_ERR_TIMEOUT] = "TIMEOUT", 97215651Sweongyo [USB_ERR_SHORT_XFER] = "SHORT_XFER", 98215651Sweongyo [USB_ERR_STALLED] = "STALLED", 99215651Sweongyo [USB_ERR_INTERRUPTED] = "INTERRUPTED", 100215651Sweongyo [USB_ERR_DMA_LOAD_FAILED] = "DMA_LOAD_FAILED", 101215651Sweongyo [USB_ERR_BAD_CONTEXT] = "BAD_CONTEXT", 102215651Sweongyo [USB_ERR_NO_ROOT_HUB] = "NO_ROOT_HUB", 103215651Sweongyo [USB_ERR_NO_INTR_THREAD] = "NO_INTR_THREAD", 104215651Sweongyo [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", 105215651Sweongyo}; 106215651Sweongyo 107215651Sweongyostatic const char *xfertype_table[] = { 108215651Sweongyo [UE_CONTROL] = "CTRL", 109215651Sweongyo [UE_ISOCHRONOUS] = "ISOC", 110215651Sweongyo [UE_BULK] = "BULK", 111215651Sweongyo [UE_INTERRUPT] = "INTR" 112215651Sweongyo}; 113215651Sweongyo 114215651Sweongyostatic void 115215651Sweongyohandle_sigint(int sig) 116215651Sweongyo{ 117215651Sweongyo 118215651Sweongyo (void)sig; 119215651Sweongyo doexit = 1; 120215651Sweongyo} 121215651Sweongyo 122215651Sweongyostatic void 123215651Sweongyoprint_flags(u_int32_t flags) 124215651Sweongyo{ 125215651Sweongyo#define PRINTFLAGS(name) \ 126215651Sweongyo if ((flags & USBPF_FLAG_##name) != 0) \ 127215651Sweongyo printf("%s ", #name); 128215651Sweongyo printf(" flags %#x", flags); 129215651Sweongyo printf(" < "); 130215651Sweongyo PRINTFLAGS(FORCE_SHORT_XFER); 131215651Sweongyo PRINTFLAGS(SHORT_XFER_OK); 132215651Sweongyo PRINTFLAGS(SHORT_FRAMES_OK); 133215651Sweongyo PRINTFLAGS(PIPE_BOF); 134215651Sweongyo PRINTFLAGS(PROXY_BUFFER); 135215651Sweongyo PRINTFLAGS(EXT_BUFFER); 136215651Sweongyo PRINTFLAGS(MANUAL_STATUS); 137215651Sweongyo PRINTFLAGS(NO_PIPE_OK); 138215651Sweongyo PRINTFLAGS(STALL_PIPE); 139215651Sweongyo printf(">\n"); 140215651Sweongyo#undef PRINTFLAGS 141215651Sweongyo} 142215651Sweongyo 143215651Sweongyostatic void 144215651Sweongyoprint_status(u_int32_t status) 145215651Sweongyo{ 146215651Sweongyo#define PRINTSTATUS(name) \ 147215651Sweongyo if ((status & USBPF_STATUS_##name) != 0) \ 148215651Sweongyo printf("%s ", #name); 149215651Sweongyo 150215651Sweongyo printf(" status %#x", status); 151215651Sweongyo printf(" < "); 152215651Sweongyo PRINTSTATUS(OPEN); 153215651Sweongyo PRINTSTATUS(TRANSFERRING); 154215651Sweongyo PRINTSTATUS(DID_DMA_DELAY); 155215651Sweongyo PRINTSTATUS(DID_CLOSE); 156215651Sweongyo PRINTSTATUS(DRAINING); 157215651Sweongyo PRINTSTATUS(STARTED); 158215651Sweongyo PRINTSTATUS(BW_RECLAIMED); 159215651Sweongyo PRINTSTATUS(CONTROL_XFR); 160215651Sweongyo PRINTSTATUS(CONTROL_HDR); 161215651Sweongyo PRINTSTATUS(CONTROL_ACT); 162215651Sweongyo PRINTSTATUS(CONTROL_STALL); 163215651Sweongyo PRINTSTATUS(SHORT_FRAMES_OK); 164215651Sweongyo PRINTSTATUS(SHORT_XFER_OK); 165215651Sweongyo#if USB_HAVE_BUSDMA 166215651Sweongyo PRINTSTATUS(BDMA_ENABLE); 167215651Sweongyo PRINTSTATUS(BDMA_NO_POST_SYNC); 168215651Sweongyo PRINTSTATUS(BDMA_SETUP); 169215651Sweongyo#endif 170215651Sweongyo PRINTSTATUS(ISOCHRONOUS_XFR); 171215651Sweongyo PRINTSTATUS(CURR_DMA_SET); 172215651Sweongyo PRINTSTATUS(CAN_CANCEL_IMMED); 173215651Sweongyo PRINTSTATUS(DOING_CALLBACK); 174215651Sweongyo printf(">\n"); 175215651Sweongyo#undef PRINTSTATUS 176215651Sweongyo} 177215651Sweongyo 178215651Sweongyo/* 179215651Sweongyo * Display a region in traditional hexdump format. 180215651Sweongyo */ 181215651Sweongyostatic void 182215651Sweongyohexdump(const char *region, size_t len) 183215651Sweongyo{ 184215651Sweongyo const char *line; 185215651Sweongyo int x, c; 186215651Sweongyo char lbuf[80]; 187215651Sweongyo#define EMIT(fmt, args...) do { \ 188215651Sweongyo sprintf(lbuf, fmt , ## args); \ 189215651Sweongyo printf("%s", lbuf); \ 190215651Sweongyo} while (0) 191215651Sweongyo 192215651Sweongyo for (line = region; line < (region + len); line += 16) { 193215651Sweongyo EMIT(" %04lx ", (long) (line - region)); 194215651Sweongyo for (x = 0; x < 16; x++) { 195215651Sweongyo if ((line + x) < (region + len)) 196215651Sweongyo EMIT("%02x ", *(const u_int8_t *)(line + x)); 197215651Sweongyo else 198215651Sweongyo EMIT("-- "); 199215651Sweongyo if (x == 7) 200215651Sweongyo EMIT(" "); 201215651Sweongyo } 202215651Sweongyo EMIT(" |"); 203215651Sweongyo for (x = 0; x < 16; x++) { 204215651Sweongyo if ((line + x) < (region + len)) { 205215651Sweongyo c = *(const u_int8_t *)(line + x); 206215651Sweongyo /* !isprint(c) */ 207215651Sweongyo if ((c < ' ') || (c > '~')) 208215651Sweongyo c = '.'; 209215651Sweongyo EMIT("%c", c); 210215651Sweongyo } else 211215651Sweongyo EMIT(" "); 212215651Sweongyo } 213215651Sweongyo EMIT("|\n"); 214215651Sweongyo } 215215651Sweongyo#undef EMIT 216215651Sweongyo} 217215651Sweongyo 218215651Sweongyostatic void 219215651Sweongyoprint_apacket(const struct usbpf_xhdr *hdr, struct usbpf_pkthdr *up, 220215651Sweongyo const char *payload) 221215651Sweongyo{ 222215651Sweongyo struct tm *tm; 223215651Sweongyo struct timeval tv; 224215651Sweongyo size_t len; 225215651Sweongyo u_int32_t framelen, x; 226215651Sweongyo const char *ptr = payload; 227215651Sweongyo char buf[64]; 228215651Sweongyo 229215651Sweongyo /* A packet from the kernel is based on little endian byte order. */ 230215651Sweongyo up->up_busunit = le32toh(up->up_busunit); 231215651Sweongyo up->up_flags = le32toh(up->up_flags); 232215651Sweongyo up->up_status = le32toh(up->up_status); 233215651Sweongyo up->up_length = le32toh(up->up_length); 234215651Sweongyo up->up_frames = le32toh(up->up_frames); 235215651Sweongyo up->up_error = le32toh(up->up_error); 236215651Sweongyo up->up_interval = le32toh(up->up_interval); 237215651Sweongyo 238215651Sweongyo tv.tv_sec = hdr->uh_tstamp.ut_sec; 239215651Sweongyo tv.tv_usec = hdr->uh_tstamp.ut_frac; 240215651Sweongyo tm = localtime(&tv.tv_sec); 241215651Sweongyo 242215651Sweongyo len = strftime(buf, sizeof(buf), "%H:%M:%S", tm); 243215651Sweongyo printf("%.*s.%06ju", (int)len, buf, tv.tv_usec); 244215651Sweongyo printf(" usbus%d.%d 0x%02x %s %s", up->up_busunit, up->up_address, 245215651Sweongyo up->up_endpoint, 246215651Sweongyo xfertype_table[up->up_xfertype], 247215651Sweongyo up->up_type == USBPF_XFERTAP_SUBMIT ? ">" : "<"); 248215651Sweongyo printf(" (%d/%d)", up->up_frames, up->up_length); 249215651Sweongyo if (up->up_type == USBPF_XFERTAP_DONE) 250215651Sweongyo printf(" %s", errstr_table[up->up_error]); 251215651Sweongyo if (up->up_xfertype == UE_BULK || up->up_xfertype == UE_ISOCHRONOUS) 252215651Sweongyo printf(" %d", up->up_interval); 253215651Sweongyo printf("\n"); 254215651Sweongyo 255215651Sweongyo if (verbose >= 1) { 256215651Sweongyo for (x = 0; x < up->up_frames; x++) { 257215651Sweongyo framelen = le32toh(*((const u_int32_t *)ptr)); 258215651Sweongyo ptr += sizeof(u_int32_t); 259215651Sweongyo printf(" frame[%u] len %d\n", x, framelen); 260215651Sweongyo assert(framelen < (1024 * 4)); 261215651Sweongyo hexdump(ptr, framelen); 262215651Sweongyo ptr += framelen; 263215651Sweongyo } 264215651Sweongyo } 265215651Sweongyo if (verbose >= 2) { 266215651Sweongyo print_flags(up->up_flags); 267215651Sweongyo print_status(up->up_status); 268215651Sweongyo } 269215651Sweongyo} 270215651Sweongyo 271215651Sweongyo 272215651Sweongyostatic void 273215651Sweongyoprint_packets(char *data, const int datalen) 274215651Sweongyo{ 275215651Sweongyo struct usbpf_pkthdr *up; 276215651Sweongyo const struct usbpf_xhdr *hdr; 277215651Sweongyo u_int32_t framelen, x; 278215651Sweongyo char *ptr, *next; 279215651Sweongyo 280215651Sweongyo for (ptr = data; ptr < (data + datalen); ptr = next) { 281215651Sweongyo hdr = (const struct usbpf_xhdr *)ptr; 282215651Sweongyo up = (struct usbpf_pkthdr *)(ptr + hdr->uh_hdrlen); 283215651Sweongyo next = ptr + USBPF_WORDALIGN(hdr->uh_hdrlen + hdr->uh_caplen); 284215651Sweongyo 285215651Sweongyo ptr = ((char *)up) + sizeof(struct usbpf_pkthdr); 286215651Sweongyo if (w_arg == NULL) 287215651Sweongyo print_apacket(hdr, up, ptr); 288215651Sweongyo pkt_captured++; 289215651Sweongyo for (x = 0; x < up->up_frames; x++) { 290215651Sweongyo framelen = le32toh(*((const u_int32_t *)ptr)); 291215651Sweongyo ptr += sizeof(u_int32_t) + framelen; 292215651Sweongyo } 293215651Sweongyo } 294215651Sweongyo} 295215651Sweongyo 296215651Sweongyostatic void 297215651Sweongyowrite_packets(struct usbcap *p, const char *data, const int datalen) 298215651Sweongyo{ 299215651Sweongyo int len = htole32(datalen), ret; 300215651Sweongyo 301215651Sweongyo ret = write(p->wfd, &len, sizeof(int)); 302215651Sweongyo assert(ret == sizeof(int)); 303215651Sweongyo ret = write(p->wfd, data, datalen); 304215651Sweongyo assert(ret == datalen); 305215651Sweongyo} 306215651Sweongyo 307215651Sweongyostatic void 308215651Sweongyoread_file(struct usbcap *p) 309215651Sweongyo{ 310215651Sweongyo int datalen, ret; 311215651Sweongyo char *data; 312215651Sweongyo 313215651Sweongyo while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) { 314215651Sweongyo datalen = le32toh(datalen); 315215651Sweongyo data = malloc(datalen); 316215651Sweongyo assert(data != NULL); 317215651Sweongyo ret = read(p->rfd, data, datalen); 318215651Sweongyo assert(ret == datalen); 319215651Sweongyo print_packets(data, datalen); 320215651Sweongyo free(data); 321215651Sweongyo } 322215651Sweongyo if (ret == -1) 323215651Sweongyo fprintf(stderr, "read: %s\n", strerror(errno)); 324215651Sweongyo} 325215651Sweongyo 326215651Sweongyostatic void 327215651Sweongyodo_loop(struct usbcap *p) 328215651Sweongyo{ 329215651Sweongyo int cc; 330215651Sweongyo 331215651Sweongyo while (doexit == 0) { 332215651Sweongyo cc = read(p->fd, (char *)p->buffer, p->bufsize); 333215651Sweongyo if (cc < 0) { 334215651Sweongyo switch (errno) { 335215651Sweongyo case EINTR: 336215651Sweongyo break; 337215651Sweongyo default: 338215651Sweongyo fprintf(stderr, "read: %s\n", strerror(errno)); 339215651Sweongyo return; 340215651Sweongyo } 341215651Sweongyo continue; 342215651Sweongyo } 343215651Sweongyo if (cc == 0) 344215651Sweongyo continue; 345215651Sweongyo if (w_arg != NULL) 346215651Sweongyo write_packets(p, p->buffer, cc); 347215651Sweongyo print_packets(p->buffer, cc); 348215651Sweongyo } 349215651Sweongyo} 350215651Sweongyo 351215651Sweongyostatic void 352215651Sweongyoinit_rfile(struct usbcap *p) 353215651Sweongyo{ 354215651Sweongyo struct usbcap_filehdr uf; 355215651Sweongyo int ret; 356215651Sweongyo 357215651Sweongyo p->rfd = open(r_arg, O_RDONLY); 358215651Sweongyo if (p->rfd < 0) { 359215651Sweongyo fprintf(stderr, "open: %s (%s)\n", r_arg, strerror(errno)); 360215651Sweongyo exit(EXIT_FAILURE); 361215651Sweongyo } 362215651Sweongyo ret = read(p->rfd, &uf, sizeof(uf)); 363215651Sweongyo assert(ret == sizeof(uf)); 364215651Sweongyo assert(le32toh(uf.magic) == USBCAP_FILEHDR_MAGIC); 365215651Sweongyo assert(uf.major == 0); 366215651Sweongyo assert(uf.minor == 1); 367215651Sweongyo} 368215651Sweongyo 369215651Sweongyostatic void 370215651Sweongyoinit_wfile(struct usbcap *p) 371215651Sweongyo{ 372215651Sweongyo struct usbcap_filehdr uf; 373215651Sweongyo int ret; 374215651Sweongyo 375215651Sweongyo p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); 376215651Sweongyo if (p->wfd < 0) { 377215651Sweongyo fprintf(stderr, "open: %s (%s)\n", w_arg, strerror(errno)); 378215651Sweongyo exit(EXIT_FAILURE); 379215651Sweongyo } 380215651Sweongyo bzero(&uf, sizeof(uf)); 381215651Sweongyo uf.magic = htole32(USBCAP_FILEHDR_MAGIC); 382215651Sweongyo uf.major = 0; 383215651Sweongyo uf.minor = 1; 384215651Sweongyo ret = write(p->wfd, (const void *)&uf, sizeof(uf)); 385215651Sweongyo assert(ret == sizeof(uf)); 386215651Sweongyo} 387215651Sweongyo 388215651Sweongyostatic void 389215651Sweongyousage(void) 390215651Sweongyo{ 391215651Sweongyo 392215651Sweongyo#define FMT " %-14s %s\n" 393215651Sweongyo fprintf(stderr, "usage: usbdump [options]\n"); 394215651Sweongyo fprintf(stderr, FMT, "-i ifname", "Listen on USB bus interface"); 395215651Sweongyo fprintf(stderr, FMT, "-r file", "Read the raw packets from file"); 396215651Sweongyo fprintf(stderr, FMT, "-s snaplen", "Snapshot bytes from each packet"); 397215651Sweongyo fprintf(stderr, FMT, "-v", "Increases the verbose level"); 398215651Sweongyo fprintf(stderr, FMT, "-w file", "Write the raw packets to file"); 399215651Sweongyo#undef FMT 400215651Sweongyo exit(1); 401215651Sweongyo} 402215651Sweongyo 403215651Sweongyoint 404215651Sweongyomain(int argc, char *argv[]) 405215651Sweongyo{ 406215651Sweongyo struct timeval tv; 407215651Sweongyo struct usbpf_insn total_insn; 408215651Sweongyo struct usbpf_program total_prog; 409215651Sweongyo struct usbpf_stat us; 410215651Sweongyo struct usbpf_version uv; 411215651Sweongyo struct usbcap uc, *p = &uc; 412215651Sweongyo struct usbpf_ifreq ufr; 413215651Sweongyo long snapshot = 192; 414215651Sweongyo u_int v; 415215651Sweongyo int fd, o; 416215651Sweongyo const char *optstring; 417215651Sweongyo 418215651Sweongyo bzero(&uc, sizeof(struct usbcap)); 419215651Sweongyo 420215651Sweongyo optstring = "i:r:s:vw:"; 421215651Sweongyo while ((o = getopt(argc, argv, optstring)) != -1) { 422215651Sweongyo switch (o) { 423215651Sweongyo case 'i': 424215651Sweongyo i_arg = optarg; 425215651Sweongyo break; 426215651Sweongyo case 'r': 427215651Sweongyo r_arg = optarg; 428215651Sweongyo init_rfile(p); 429215651Sweongyo break; 430215651Sweongyo case 's': 431215651Sweongyo snapshot = strtol(optarg, NULL, 10); 432215651Sweongyo errno = 0; 433215651Sweongyo if (snapshot == 0 && errno == EINVAL) 434215651Sweongyo usage(); 435215651Sweongyo /* snapeshot == 0 is special */ 436215651Sweongyo if (snapshot == 0) 437215651Sweongyo snapshot = -1; 438215651Sweongyo break; 439215651Sweongyo case 'v': 440215651Sweongyo verbose++; 441215651Sweongyo break; 442215651Sweongyo case 'w': 443215651Sweongyo w_arg = optarg; 444215651Sweongyo init_wfile(p); 445215651Sweongyo break; 446215651Sweongyo default: 447215651Sweongyo usage(); 448215651Sweongyo /* NOTREACHED */ 449215651Sweongyo } 450215651Sweongyo } 451215651Sweongyo 452215651Sweongyo if (r_arg != NULL) { 453215651Sweongyo read_file(p); 454215651Sweongyo exit(EXIT_SUCCESS); 455215651Sweongyo } 456215651Sweongyo 457215651Sweongyo p->fd = fd = open("/dev/usbpf", O_RDONLY); 458215651Sweongyo if (p->fd < 0) { 459215651Sweongyo fprintf(stderr, "(no devices found)\n"); 460215651Sweongyo return (EXIT_FAILURE); 461215651Sweongyo } 462215651Sweongyo 463215651Sweongyo if (ioctl(fd, UIOCVERSION, (caddr_t)&uv) < 0) { 464215651Sweongyo fprintf(stderr, "UIOCVERSION: %s\n", strerror(errno)); 465215651Sweongyo return (EXIT_FAILURE); 466215651Sweongyo } 467215651Sweongyo if (uv.uv_major != USBPF_MAJOR_VERSION || 468215651Sweongyo uv.uv_minor < USBPF_MINOR_VERSION) { 469215651Sweongyo fprintf(stderr, "kernel bpf filter out of date"); 470215651Sweongyo return (EXIT_FAILURE); 471215651Sweongyo } 472215651Sweongyo 473215651Sweongyo if ((ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) || v < 65536) 474215651Sweongyo v = 65536; 475215651Sweongyo for ( ; v != 0; v >>= 1) { 476215651Sweongyo (void)ioctl(fd, UIOCSBLEN, (caddr_t)&v); 477215651Sweongyo (void)strncpy(ufr.ufr_name, i_arg, sizeof(ufr.ufr_name)); 478215651Sweongyo if (ioctl(fd, UIOCSETIF, (caddr_t)&ufr) >= 0) 479215651Sweongyo break; 480215651Sweongyo } 481215651Sweongyo if (v == 0) { 482215651Sweongyo fprintf(stderr, "UIOCSBLEN: %s: No buffer size worked", i_arg); 483215651Sweongyo return (EXIT_FAILURE); 484215651Sweongyo } 485215651Sweongyo 486215651Sweongyo if (ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) { 487215651Sweongyo fprintf(stderr, "UIOCGBLEN: %s", strerror(errno)); 488215651Sweongyo return (EXIT_FAILURE); 489215651Sweongyo } 490215651Sweongyo 491215651Sweongyo p->bufsize = v; 492215651Sweongyo p->buffer = (u_char *)malloc(p->bufsize); 493215651Sweongyo if (p->buffer == NULL) { 494215651Sweongyo fprintf(stderr, "malloc: %s", strerror(errno)); 495215651Sweongyo return (EXIT_FAILURE); 496215651Sweongyo } 497215651Sweongyo 498215651Sweongyo /* XXX no read filter rules yet so at this moment accept everything */ 499215651Sweongyo total_insn.code = (u_short)(USBPF_RET | USBPF_K); 500215651Sweongyo total_insn.jt = 0; 501215651Sweongyo total_insn.jf = 0; 502215651Sweongyo total_insn.k = snapshot; 503215651Sweongyo 504215651Sweongyo total_prog.uf_len = 1; 505215651Sweongyo total_prog.uf_insns = &total_insn; 506215651Sweongyo if (ioctl(p->fd, UIOCSETF, (caddr_t)&total_prog) < 0) { 507215651Sweongyo fprintf(stderr, "UIOCSETF: %s", strerror(errno)); 508215651Sweongyo return (EXIT_FAILURE); 509215651Sweongyo } 510215651Sweongyo 511215651Sweongyo /* 1 second read timeout */ 512215651Sweongyo tv.tv_sec = 1; 513215651Sweongyo tv.tv_usec = 0; 514215651Sweongyo if (ioctl(p->fd, UIOCSRTIMEOUT, (caddr_t)&tv) < 0) { 515215651Sweongyo fprintf(stderr, "UIOCSRTIMEOUT: %s", strerror(errno)); 516215651Sweongyo return (EXIT_FAILURE); 517215651Sweongyo } 518215651Sweongyo 519215651Sweongyo (void)signal(SIGINT, handle_sigint); 520215651Sweongyo 521215651Sweongyo do_loop(p); 522215651Sweongyo 523215651Sweongyo if (ioctl(fd, UIOCGSTATS, (caddr_t)&us) < 0) { 524215651Sweongyo fprintf(stderr, "UIOCGSTATS: %s", strerror(errno)); 525215651Sweongyo return (EXIT_FAILURE); 526215651Sweongyo } 527215651Sweongyo 528215651Sweongyo /* XXX what's difference between pkt_captured and us.us_recv? */ 529215651Sweongyo printf("\n"); 530215651Sweongyo printf("%d packets captured\n", pkt_captured); 531215651Sweongyo printf("%d packets received by filter\n", us.us_recv); 532215651Sweongyo printf("%d packets dropped by kernel\n", us.us_drop); 533215651Sweongyo 534215651Sweongyo if (p->fd > 0) 535215651Sweongyo close(p->fd); 536215651Sweongyo if (p->rfd > 0) 537215651Sweongyo close(p->rfd); 538215651Sweongyo if (p->wfd > 0) 539215651Sweongyo close(p->wfd); 540215651Sweongyo 541215651Sweongyo return (EXIT_SUCCESS); 542215651Sweongyo} 543