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