diff options
author | dim <dim@FreeBSD.org> | 2010-11-22 20:52:18 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2010-11-22 20:52:18 +0000 |
commit | 71b42433f68a7680bcd07cef6c81b5a9bbe4e948 (patch) | |
tree | 09b00ba0fbac964aa5e3af51d7a50e20465b2577 /usr.sbin | |
parent | 29458224998b52266f5d890a3d9bff4c1f5d3ccb (diff) | |
parent | 11b4830687fabb0a27817feb05bf835db82f3147 (diff) | |
download | FreeBSD-src-71b42433f68a7680bcd07cef6c81b5a9bbe4e948.zip FreeBSD-src-71b42433f68a7680bcd07cef6c81b5a9bbe4e948.tar.gz |
Sync: merge r215464 through r215708 from ^/head.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/apmd/apmdlex.l | 1 | ||||
-rw-r--r-- | usr.sbin/bluetooth/bthidd/lexer.l | 2 | ||||
-rw-r--r-- | usr.sbin/bluetooth/hcsecd/lexer.l | 2 | ||||
-rw-r--r-- | usr.sbin/config/lang.l | 1 | ||||
-rw-r--r-- | usr.sbin/kbdcontrol/lex.l | 1 | ||||
-rw-r--r-- | usr.sbin/mfiutil/mfi_config.c | 28 | ||||
-rw-r--r-- | usr.sbin/mfiutil/mfi_evt.c | 4 | ||||
-rw-r--r-- | usr.sbin/mfiutil/mfi_flash.c | 4 | ||||
-rw-r--r-- | usr.sbin/mptutil/mpt_config.c | 2 | ||||
-rw-r--r-- | usr.sbin/newsyslog/newsyslog.c | 2 | ||||
-rw-r--r-- | usr.sbin/sysinstall/dispatch.c | 32 | ||||
-rw-r--r-- | usr.sbin/usbdump/Makefile | 8 | ||||
-rw-r--r-- | usr.sbin/usbdump/usbdump.8 | 77 | ||||
-rw-r--r-- | usr.sbin/usbdump/usbdump.c | 542 |
14 files changed, 692 insertions, 14 deletions
diff --git a/usr.sbin/apmd/apmdlex.l b/usr.sbin/apmd/apmdlex.l index 0f95574..dc7664d 100644 --- a/usr.sbin/apmd/apmdlex.l +++ b/usr.sbin/apmd/apmdlex.l @@ -38,6 +38,7 @@ /* We don't need it, avoid the warning. */ #define YY_NO_UNPUT +#define YY_NO_INPUT int lineno; int first_time; diff --git a/usr.sbin/bluetooth/bthidd/lexer.l b/usr.sbin/bluetooth/bthidd/lexer.l index a25ae92..54821da 100644 --- a/usr.sbin/bluetooth/bthidd/lexer.l +++ b/usr.sbin/bluetooth/bthidd/lexer.l @@ -39,7 +39,7 @@ int yylex (void); %} -%option yylineno noyywrap nounput +%option yylineno noyywrap nounput noinput delim [ \t\n] ws {delim}+ diff --git a/usr.sbin/bluetooth/hcsecd/lexer.l b/usr.sbin/bluetooth/hcsecd/lexer.l index 2430d7e..578b42f 100644 --- a/usr.sbin/bluetooth/hcsecd/lexer.l +++ b/usr.sbin/bluetooth/hcsecd/lexer.l @@ -34,7 +34,7 @@ #include "parser.h" %} -%option yylineno noyywrap nounput +%option yylineno noyywrap nounput noinput delim [ \t\n] ws {delim}+ diff --git a/usr.sbin/config/lang.l b/usr.sbin/config/lang.l index 4eb94da..81f820f 100644 --- a/usr.sbin/config/lang.l +++ b/usr.sbin/config/lang.l @@ -39,6 +39,7 @@ #include "config.h" #define YY_NO_UNPUT +#define YY_NO_INPUT /* * Data for returning to previous files from include files. diff --git a/usr.sbin/kbdcontrol/lex.l b/usr.sbin/kbdcontrol/lex.l index 7d9fd53..e9ca2bc 100644 --- a/usr.sbin/kbdcontrol/lex.l +++ b/usr.sbin/kbdcontrol/lex.l @@ -32,6 +32,7 @@ #include "lex.h" #define YY_NO_UNPUT +#define YY_NO_INPUT %} diff --git a/usr.sbin/mfiutil/mfi_config.c b/usr.sbin/mfiutil/mfi_config.c index fc03aa7..fdda117 100644 --- a/usr.sbin/mfiutil/mfi_config.c +++ b/usr.sbin/mfiutil/mfi_config.c @@ -328,6 +328,10 @@ parse_array(int fd, int raid_type, char *array_str, struct array_info *info) /* Validate each drive. */ info->drives = calloc(count, sizeof(struct mfi_pd_info)); + if (info->drives == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } info->drive_count = count; for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL; pinfo++) { @@ -638,6 +642,10 @@ create_volume(int ac, char **av) break; } arrays = calloc(narrays, sizeof(*arrays)); + if (arrays == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } for (i = 0; i < narrays; i++) { error = parse_array(fd, raid_type, av[i], &arrays[i]); if (error) @@ -673,6 +681,10 @@ create_volume(int ac, char **av) state.array_count = config->array_count; if (config->array_count > 0) { state.arrays = calloc(config->array_count, sizeof(int)); + if (state.arrays == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } for (i = 0; i < config->array_count; i++) { ar = (struct mfi_array *)p; state.arrays[i] = ar->array_ref; @@ -685,6 +697,10 @@ create_volume(int ac, char **av) state.log_drv_count = config->log_drv_count; if (config->log_drv_count) { state.volumes = calloc(config->log_drv_count, sizeof(int)); + if (state.volumes == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } for (i = 0; i < config->log_drv_count; i++) { ld = (struct mfi_ld_config *)p; state.volumes[i] = ld->properties.ld.v.target_id; @@ -721,6 +737,10 @@ create_volume(int ac, char **av) config_size = sizeof(struct mfi_config_data) + sizeof(struct mfi_ld_config) * nvolumes + MFI_ARRAY_SIZE * narrays; config = calloc(1, config_size); + if (config == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } config->size = config_size; config->array_count = narrays; config->array_size = MFI_ARRAY_SIZE; /* XXX: Firmware hardcode */ @@ -902,6 +922,10 @@ add_spare(int ac, char **av) spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) * config->array_count); + if (spare == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } bzero(spare, sizeof(struct mfi_spare)); spare->ref = info.ref; @@ -1170,6 +1194,10 @@ dump(int ac, char **av) } config = malloc(len); + if (config == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } if (sysctlbyname(buf, config, &len, NULL, 0) < 0) { error = errno; warn("Failed to read debug command"); diff --git a/usr.sbin/mfiutil/mfi_evt.c b/usr.sbin/mfiutil/mfi_evt.c index 31c5ec3..b9288d8 100644 --- a/usr.sbin/mfiutil/mfi_evt.c +++ b/usr.sbin/mfiutil/mfi_evt.c @@ -624,6 +624,10 @@ show_events(int ac, char **av) } list = malloc(size); + if (list == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } for (seq = start;;) { if (mfi_get_events(fd, list, num_events, filter, seq, &status) < 0) { diff --git a/usr.sbin/mfiutil/mfi_flash.c b/usr.sbin/mfiutil/mfi_flash.c index 87bdaca..4039beb 100644 --- a/usr.sbin/mfiutil/mfi_flash.c +++ b/usr.sbin/mfiutil/mfi_flash.c @@ -163,6 +163,10 @@ flash_adapter(int ac, char **av) /* Upload the file 64k at a time. */ buf = malloc(FLASH_BUF_SIZE); + if (buf == NULL) { + warnx("malloc failed"); + return (ENOMEM); + } offset = 0; while (sb.st_size > 0) { nread = read(flash, buf, FLASH_BUF_SIZE); diff --git a/usr.sbin/mptutil/mpt_config.c b/usr.sbin/mptutil/mpt_config.c index 6247bb4..d914d66 100644 --- a/usr.sbin/mptutil/mpt_config.c +++ b/usr.sbin/mptutil/mpt_config.c @@ -50,8 +50,6 @@ __RCSID("$FreeBSD$"); static void dump_config(CONFIG_PAGE_RAID_VOL_0 *vol); #endif -#define powerof2(x) ((((x)-1)&(x))==0) - static long dehumanize(const char *value) { diff --git a/usr.sbin/newsyslog/newsyslog.c b/usr.sbin/newsyslog/newsyslog.c index 7ba6cb8..46158ef 100644 --- a/usr.sbin/newsyslog/newsyslog.c +++ b/usr.sbin/newsyslog/newsyslog.c @@ -163,7 +163,7 @@ struct include_entry { struct oldlog_entry { char *fname; /* Filename of the log file */ - time_t t; /* Parses timestamp of the logfile */ + time_t t; /* Parsed timestamp of the logfile */ }; typedef enum { diff --git a/usr.sbin/sysinstall/dispatch.c b/usr.sbin/sysinstall/dispatch.c index 0e4a634..44aa0fa 100644 --- a/usr.sbin/sysinstall/dispatch.c +++ b/usr.sbin/sysinstall/dispatch.c @@ -136,8 +136,12 @@ typedef struct command_buffer_ { static void dispatch_free_command(command_buffer *item) { - REMQUE(item); - free(item->string); + if (item != NULL) { + REMQUE(item); + free(item->string); + item->string = NULL; + } + free(item); } @@ -155,19 +159,29 @@ dispatch_free_all(qelement *head) static command_buffer * dispatch_add_command(qelement *head, char *string) { - command_buffer *new; + command_buffer *new = NULL; new = malloc(sizeof(command_buffer)); - if (!new) - return NULL; + if (new != NULL) { - new->string = strdup(string); - INSQUEUE(new, head->q_back); + new->string = strdup(string); + + /* + * We failed to copy `string'; clean up the allocated + * resources. + */ + if (new->string == NULL) { + free(new); + new = NULL; + } else { + INSQUEUE(new, head->q_back); + } + } return new; } - + /* * Command processing */ @@ -280,7 +294,7 @@ dispatchCommand(char *str) return i; } - + /* * File processing */ diff --git a/usr.sbin/usbdump/Makefile b/usr.sbin/usbdump/Makefile new file mode 100644 index 0000000..5188901 --- /dev/null +++ b/usr.sbin/usbdump/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG= usbdump +SRCS= usbdump.c +MAN= usbdump.8 +WARNS?= 4 + +.include <bsd.prog.mk> diff --git a/usr.sbin/usbdump/usbdump.8 b/usr.sbin/usbdump/usbdump.8 new file mode 100644 index 0000000..edd883a --- /dev/null +++ b/usr.sbin/usbdump/usbdump.8 @@ -0,0 +1,77 @@ +.\" +.\" Copyright (c) 2010 Weongyo Jeong. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd October 14, 2010 +.Dt usbdump 8 +.Os +.Sh NAME +.Nm usbdump +.Nd "dump traffic on USB host controller" +.Sh SYNOPSIS +.Nm +.Op Fl i Ar ifname +.Op Fl r Ar file +.Op Fl s Ar snaplen +.Op Fl v +.Op Fl w Ar file +.Sh DESCRIPTION +The +.Nm +utility provides a way to dump USB packets on each host controller. +.Pp +The following options are accepted. +.Bl -tag -width ".Fl f Ar file" +.It Fl i Ar ifname +Listen on USB bus interface. +.It Fl r Ar file +Read the raw packets from file. +.It Fl s Ar snaplen +Snapshot bytes from each packet. +.It Fl v +Enable debugging messages. +When it defined multiple times the verbose level increases. +.It Fl w Ar file +Write the raw packets to file. +.El +.Sh EXAMPLES +Captures the USB raw packets alive on usbus2: +.Pp +.Dl "usbdump -i usbus2 -s 256 -v" +.Pp +Dumps the USB raw packets of usbus2 into the file without packet +size limit: +.Pp +.Dl "usbdump -i usbus2 -s 0 -w /tmp/dump_pkts" +.Pp +Read the USB raw packets from the file: +.Pp +.Dl "usbdump -r /tmp/dump_pkts -v" +.Sh SEE ALSO +.Xr usbconfig 8 +.Sh AUTHORS +.An Weongyo Jeong +.Aq weongyo@FreeBSD.org . diff --git a/usr.sbin/usbdump/usbdump.c b/usr.sbin/usbdump/usbdump.c new file mode 100644 index 0000000..6545f1c --- /dev/null +++ b/usr.sbin/usbdump/usbdump.c @@ -0,0 +1,542 @@ +/*- + * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <sys/endian.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/utsname.h> +#include <dev/usb/usb.h> +#include <dev/usb/usb_pf.h> +#include <dev/usb/usbdi.h> +#include <assert.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +struct usbcap { + int fd; /* fd for /dev/usbpf */ + u_int bufsize; + char *buffer; + + /* for -w option */ + int wfd; + /* for -r option */ + int rfd; +}; + +struct usbcap_filehdr { + u_int magic; +#define USBCAP_FILEHDR_MAGIC 0x9a90000e + u_char major; + u_char minor; + u_char reserved[26]; +} __packed; + +static int doexit = 0; +static int pkt_captured = 0; +static int verbose = 0; +static const char *i_arg = "usbus0";; +static const char *r_arg = NULL; +static const char *w_arg = NULL; +static const char *errstr_table[USB_ERR_MAX] = { + [USB_ERR_NORMAL_COMPLETION] = "NORMAL_COMPLETION", + [USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS", + [USB_ERR_NOT_STARTED] = "NOT_STARTED", + [USB_ERR_INVAL] = "INVAL", + [USB_ERR_NOMEM] = "NOMEM", + [USB_ERR_CANCELLED] = "CANCELLED", + [USB_ERR_BAD_ADDRESS] = "BAD_ADDRESS", + [USB_ERR_BAD_BUFSIZE] = "BAD_BUFSIZE", + [USB_ERR_BAD_FLAG] = "BAD_FLAG", + [USB_ERR_NO_CALLBACK] = "NO_CALLBACK", + [USB_ERR_IN_USE] = "IN_USE", + [USB_ERR_NO_ADDR] = "NO_ADDR", + [USB_ERR_NO_PIPE] = "NO_PIPE", + [USB_ERR_ZERO_NFRAMES] = "ZERO_NFRAMES", + [USB_ERR_ZERO_MAXP] = "ZERO_MAXP", + [USB_ERR_SET_ADDR_FAILED] = "SET_ADDR_FAILED", + [USB_ERR_NO_POWER] = "NO_POWER", + [USB_ERR_TOO_DEEP] = "TOO_DEEP", + [USB_ERR_IOERROR] = "IOERROR", + [USB_ERR_NOT_CONFIGURED] = "NOT_CONFIGURED", + [USB_ERR_TIMEOUT] = "TIMEOUT", + [USB_ERR_SHORT_XFER] = "SHORT_XFER", + [USB_ERR_STALLED] = "STALLED", + [USB_ERR_INTERRUPTED] = "INTERRUPTED", + [USB_ERR_DMA_LOAD_FAILED] = "DMA_LOAD_FAILED", + [USB_ERR_BAD_CONTEXT] = "BAD_CONTEXT", + [USB_ERR_NO_ROOT_HUB] = "NO_ROOT_HUB", + [USB_ERR_NO_INTR_THREAD] = "NO_INTR_THREAD", + [USB_ERR_NOT_LOCKED] = "NOT_LOCKED", +}; + +static const char *xfertype_table[] = { + [UE_CONTROL] = "CTRL", + [UE_ISOCHRONOUS] = "ISOC", + [UE_BULK] = "BULK", + [UE_INTERRUPT] = "INTR" +}; + +static void +handle_sigint(int sig) +{ + + (void)sig; + doexit = 1; +} + +static void +print_flags(u_int32_t flags) +{ +#define PRINTFLAGS(name) \ + if ((flags & USBPF_FLAG_##name) != 0) \ + printf("%s ", #name); + printf(" flags %#x", flags); + printf(" < "); + PRINTFLAGS(FORCE_SHORT_XFER); + PRINTFLAGS(SHORT_XFER_OK); + PRINTFLAGS(SHORT_FRAMES_OK); + PRINTFLAGS(PIPE_BOF); + PRINTFLAGS(PROXY_BUFFER); + PRINTFLAGS(EXT_BUFFER); + PRINTFLAGS(MANUAL_STATUS); + PRINTFLAGS(NO_PIPE_OK); + PRINTFLAGS(STALL_PIPE); + printf(">\n"); +#undef PRINTFLAGS +} + +static void +print_status(u_int32_t status) +{ +#define PRINTSTATUS(name) \ + if ((status & USBPF_STATUS_##name) != 0) \ + printf("%s ", #name); + + printf(" status %#x", status); + printf(" < "); + PRINTSTATUS(OPEN); + PRINTSTATUS(TRANSFERRING); + PRINTSTATUS(DID_DMA_DELAY); + PRINTSTATUS(DID_CLOSE); + PRINTSTATUS(DRAINING); + PRINTSTATUS(STARTED); + PRINTSTATUS(BW_RECLAIMED); + PRINTSTATUS(CONTROL_XFR); + PRINTSTATUS(CONTROL_HDR); + PRINTSTATUS(CONTROL_ACT); + PRINTSTATUS(CONTROL_STALL); + PRINTSTATUS(SHORT_FRAMES_OK); + PRINTSTATUS(SHORT_XFER_OK); +#if USB_HAVE_BUSDMA + PRINTSTATUS(BDMA_ENABLE); + PRINTSTATUS(BDMA_NO_POST_SYNC); + PRINTSTATUS(BDMA_SETUP); +#endif + PRINTSTATUS(ISOCHRONOUS_XFR); + PRINTSTATUS(CURR_DMA_SET); + PRINTSTATUS(CAN_CANCEL_IMMED); + PRINTSTATUS(DOING_CALLBACK); + printf(">\n"); +#undef PRINTSTATUS +} + +/* + * Display a region in traditional hexdump format. + */ +static void +hexdump(const char *region, size_t len) +{ + const char *line; + int x, c; + char lbuf[80]; +#define EMIT(fmt, args...) do { \ + sprintf(lbuf, fmt , ## args); \ + printf("%s", lbuf); \ +} while (0) + + for (line = region; line < (region + len); line += 16) { + EMIT(" %04lx ", (long) (line - region)); + for (x = 0; x < 16; x++) { + if ((line + x) < (region + len)) + EMIT("%02x ", *(const u_int8_t *)(line + x)); + else + EMIT("-- "); + if (x == 7) + EMIT(" "); + } + EMIT(" |"); + for (x = 0; x < 16; x++) { + if ((line + x) < (region + len)) { + c = *(const u_int8_t *)(line + x); + /* !isprint(c) */ + if ((c < ' ') || (c > '~')) + c = '.'; + EMIT("%c", c); + } else + EMIT(" "); + } + EMIT("|\n"); + } +#undef EMIT +} + +static void +print_apacket(const struct usbpf_xhdr *hdr, struct usbpf_pkthdr *up, + const char *payload) +{ + struct tm *tm; + struct timeval tv; + size_t len; + u_int32_t framelen, x; + const char *ptr = payload; + char buf[64]; + + /* A packet from the kernel is based on little endian byte order. */ + up->up_busunit = le32toh(up->up_busunit); + up->up_flags = le32toh(up->up_flags); + up->up_status = le32toh(up->up_status); + up->up_length = le32toh(up->up_length); + up->up_frames = le32toh(up->up_frames); + up->up_error = le32toh(up->up_error); + up->up_interval = le32toh(up->up_interval); + + tv.tv_sec = hdr->uh_tstamp.ut_sec; + tv.tv_usec = hdr->uh_tstamp.ut_frac; + tm = localtime(&tv.tv_sec); + + len = strftime(buf, sizeof(buf), "%H:%M:%S", tm); + printf("%.*s.%06ju", (int)len, buf, tv.tv_usec); + printf(" usbus%d.%d 0x%02x %s %s", up->up_busunit, up->up_address, + up->up_endpoint, + xfertype_table[up->up_xfertype], + up->up_type == USBPF_XFERTAP_SUBMIT ? ">" : "<"); + printf(" (%d/%d)", up->up_frames, up->up_length); + if (up->up_type == USBPF_XFERTAP_DONE) + printf(" %s", errstr_table[up->up_error]); + if (up->up_xfertype == UE_BULK || up->up_xfertype == UE_ISOCHRONOUS) + printf(" %d", up->up_interval); + printf("\n"); + + if (verbose >= 1) { + for (x = 0; x < up->up_frames; x++) { + framelen = le32toh(*((const u_int32_t *)ptr)); + ptr += sizeof(u_int32_t); + printf(" frame[%u] len %d\n", x, framelen); + assert(framelen < (1024 * 4)); + hexdump(ptr, framelen); + ptr += framelen; + } + } + if (verbose >= 2) { + print_flags(up->up_flags); + print_status(up->up_status); + } +} + + +static void +print_packets(char *data, const int datalen) +{ + struct usbpf_pkthdr *up; + const struct usbpf_xhdr *hdr; + u_int32_t framelen, x; + char *ptr, *next; + + for (ptr = data; ptr < (data + datalen); ptr = next) { + hdr = (const struct usbpf_xhdr *)ptr; + up = (struct usbpf_pkthdr *)(ptr + hdr->uh_hdrlen); + next = ptr + USBPF_WORDALIGN(hdr->uh_hdrlen + hdr->uh_caplen); + + ptr = ((char *)up) + sizeof(struct usbpf_pkthdr); + if (w_arg == NULL) + print_apacket(hdr, up, ptr); + pkt_captured++; + for (x = 0; x < up->up_frames; x++) { + framelen = le32toh(*((const u_int32_t *)ptr)); + ptr += sizeof(u_int32_t) + framelen; + } + } +} + +static void +write_packets(struct usbcap *p, const char *data, const int datalen) +{ + int len = htole32(datalen), ret; + + ret = write(p->wfd, &len, sizeof(int)); + assert(ret == sizeof(int)); + ret = write(p->wfd, data, datalen); + assert(ret == datalen); +} + +static void +read_file(struct usbcap *p) +{ + int datalen, ret; + char *data; + + while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) { + datalen = le32toh(datalen); + data = malloc(datalen); + assert(data != NULL); + ret = read(p->rfd, data, datalen); + assert(ret == datalen); + print_packets(data, datalen); + free(data); + } + if (ret == -1) + fprintf(stderr, "read: %s\n", strerror(errno)); +} + +static void +do_loop(struct usbcap *p) +{ + int cc; + + while (doexit == 0) { + cc = read(p->fd, (char *)p->buffer, p->bufsize); + if (cc < 0) { + switch (errno) { + case EINTR: + break; + default: + fprintf(stderr, "read: %s\n", strerror(errno)); + return; + } + continue; + } + if (cc == 0) + continue; + if (w_arg != NULL) + write_packets(p, p->buffer, cc); + print_packets(p->buffer, cc); + } +} + +static void +init_rfile(struct usbcap *p) +{ + struct usbcap_filehdr uf; + int ret; + + p->rfd = open(r_arg, O_RDONLY); + if (p->rfd < 0) { + fprintf(stderr, "open: %s (%s)\n", r_arg, strerror(errno)); + exit(EXIT_FAILURE); + } + ret = read(p->rfd, &uf, sizeof(uf)); + assert(ret == sizeof(uf)); + assert(le32toh(uf.magic) == USBCAP_FILEHDR_MAGIC); + assert(uf.major == 0); + assert(uf.minor == 1); +} + +static void +init_wfile(struct usbcap *p) +{ + struct usbcap_filehdr uf; + int ret; + + p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); + if (p->wfd < 0) { + fprintf(stderr, "open: %s (%s)\n", w_arg, strerror(errno)); + exit(EXIT_FAILURE); + } + bzero(&uf, sizeof(uf)); + uf.magic = htole32(USBCAP_FILEHDR_MAGIC); + uf.major = 0; + uf.minor = 1; + ret = write(p->wfd, (const void *)&uf, sizeof(uf)); + assert(ret == sizeof(uf)); +} + +static void +usage(void) +{ + +#define FMT " %-14s %s\n" + fprintf(stderr, "usage: usbdump [options]\n"); + fprintf(stderr, FMT, "-i ifname", "Listen on USB bus interface"); + fprintf(stderr, FMT, "-r file", "Read the raw packets from file"); + fprintf(stderr, FMT, "-s snaplen", "Snapshot bytes from each packet"); + fprintf(stderr, FMT, "-v", "Increases the verbose level"); + fprintf(stderr, FMT, "-w file", "Write the raw packets to file"); +#undef FMT + exit(1); +} + +int +main(int argc, char *argv[]) +{ + struct timeval tv; + struct usbpf_insn total_insn; + struct usbpf_program total_prog; + struct usbpf_stat us; + struct usbpf_version uv; + struct usbcap uc, *p = &uc; + struct usbpf_ifreq ufr; + long snapshot = 192; + u_int v; + int fd, o; + const char *optstring; + + bzero(&uc, sizeof(struct usbcap)); + + optstring = "i:r:s:vw:"; + while ((o = getopt(argc, argv, optstring)) != -1) { + switch (o) { + case 'i': + i_arg = optarg; + break; + case 'r': + r_arg = optarg; + init_rfile(p); + break; + case 's': + snapshot = strtol(optarg, NULL, 10); + errno = 0; + if (snapshot == 0 && errno == EINVAL) + usage(); + /* snapeshot == 0 is special */ + if (snapshot == 0) + snapshot = -1; + break; + case 'v': + verbose++; + break; + case 'w': + w_arg = optarg; + init_wfile(p); + break; + default: + usage(); + /* NOTREACHED */ + } + } + + if (r_arg != NULL) { + read_file(p); + exit(EXIT_SUCCESS); + } + + p->fd = fd = open("/dev/usbpf", O_RDONLY); + if (p->fd < 0) { + fprintf(stderr, "(no devices found)\n"); + return (EXIT_FAILURE); + } + + if (ioctl(fd, UIOCVERSION, (caddr_t)&uv) < 0) { + fprintf(stderr, "UIOCVERSION: %s\n", strerror(errno)); + return (EXIT_FAILURE); + } + if (uv.uv_major != USBPF_MAJOR_VERSION || + uv.uv_minor < USBPF_MINOR_VERSION) { + fprintf(stderr, "kernel bpf filter out of date"); + return (EXIT_FAILURE); + } + + if ((ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) || v < 65536) + v = 65536; + for ( ; v != 0; v >>= 1) { + (void)ioctl(fd, UIOCSBLEN, (caddr_t)&v); + (void)strncpy(ufr.ufr_name, i_arg, sizeof(ufr.ufr_name)); + if (ioctl(fd, UIOCSETIF, (caddr_t)&ufr) >= 0) + break; + } + if (v == 0) { + fprintf(stderr, "UIOCSBLEN: %s: No buffer size worked", i_arg); + return (EXIT_FAILURE); + } + + if (ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) { + fprintf(stderr, "UIOCGBLEN: %s", strerror(errno)); + return (EXIT_FAILURE); + } + + p->bufsize = v; + p->buffer = (u_char *)malloc(p->bufsize); + if (p->buffer == NULL) { + fprintf(stderr, "malloc: %s", strerror(errno)); + return (EXIT_FAILURE); + } + + /* XXX no read filter rules yet so at this moment accept everything */ + total_insn.code = (u_short)(USBPF_RET | USBPF_K); + total_insn.jt = 0; + total_insn.jf = 0; + total_insn.k = snapshot; + + total_prog.uf_len = 1; + total_prog.uf_insns = &total_insn; + if (ioctl(p->fd, UIOCSETF, (caddr_t)&total_prog) < 0) { + fprintf(stderr, "UIOCSETF: %s", strerror(errno)); + return (EXIT_FAILURE); + } + + /* 1 second read timeout */ + tv.tv_sec = 1; + tv.tv_usec = 0; + if (ioctl(p->fd, UIOCSRTIMEOUT, (caddr_t)&tv) < 0) { + fprintf(stderr, "UIOCSRTIMEOUT: %s", strerror(errno)); + return (EXIT_FAILURE); + } + + (void)signal(SIGINT, handle_sigint); + + do_loop(p); + + if (ioctl(fd, UIOCGSTATS, (caddr_t)&us) < 0) { + fprintf(stderr, "UIOCGSTATS: %s", strerror(errno)); + return (EXIT_FAILURE); + } + + /* XXX what's difference between pkt_captured and us.us_recv? */ + printf("\n"); + printf("%d packets captured\n", pkt_captured); + printf("%d packets received by filter\n", us.us_recv); + printf("%d packets dropped by kernel\n", us.us_drop); + + if (p->fd > 0) + close(p->fd); + if (p->rfd > 0) + close(p->rfd); + if (p->wfd > 0) + close(p->wfd); + + return (EXIT_SUCCESS); +} |