summaryrefslogtreecommitdiffstats
path: root/usr.sbin/usbdump
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2011-04-03 20:03:45 +0000
committerhselasky <hselasky@FreeBSD.org>2011-04-03 20:03:45 +0000
commit13be006e1bb536e29069e6e03768185ab1003c1c (patch)
treed88f5b3979243ce915a1916907dffb3f7911eb11 /usr.sbin/usbdump
parente95ea389566188409a5acd3a88207d354b098ec5 (diff)
downloadFreeBSD-src-13be006e1bb536e29069e6e03768185ab1003c1c.zip
FreeBSD-src-13be006e1bb536e29069e6e03768185ab1003c1c.tar.gz
- Improvements to USB PF solution
- Add more fields for USB device and host mode - Add more information to USB PF header so that decoding can easily be done by software analyzer tools like Wireshark. - Optimise usbdump to display USB streams in text format more efficiently. - Software using USB PF must be recompiled after this commit, due to structure changes. MFC after: 7 days Approved by: thompsa (mentor)
Diffstat (limited to 'usr.sbin/usbdump')
-rw-r--r--usr.sbin/usbdump/usbdump.c361
1 files changed, 237 insertions, 124 deletions
diff --git a/usr.sbin/usbdump/usbdump.c b/usr.sbin/usbdump/usbdump.c
index c142f59..2b3da33 100644
--- a/usr.sbin/usbdump/usbdump.c
+++ b/usr.sbin/usbdump/usbdump.c
@@ -52,8 +52,8 @@
struct usbcap {
int fd; /* fd for /dev/usbpf */
- u_int bufsize;
- char *buffer;
+ uint32_t bufsize;
+ uint8_t *buffer;
/* for -w option */
int wfd;
@@ -62,11 +62,11 @@ struct usbcap {
};
struct usbcap_filehdr {
- u_int magic;
+ uint32_t magic;
#define USBCAP_FILEHDR_MAGIC 0x9a90000e
- u_char major;
- u_char minor;
- u_char reserved[26];
+ uint8_t major;
+ uint8_t minor;
+ uint8_t reserved[26];
} __packed;
static int doexit = 0;
@@ -76,7 +76,7 @@ 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_NORMAL_COMPLETION] = "0",
[USB_ERR_PENDING_REQUESTS] = "PENDING_REQUESTS",
[USB_ERR_NOT_STARTED] = "NOT_STARTED",
[USB_ERR_INVAL] = "INVAL",
@@ -107,13 +107,21 @@ static const char *errstr_table[USB_ERR_MAX] = {
[USB_ERR_NOT_LOCKED] = "NOT_LOCKED",
};
-static const char *xfertype_table[] = {
+static const char *xfertype_table[4] = {
[UE_CONTROL] = "CTRL",
[UE_ISOCHRONOUS] = "ISOC",
[UE_BULK] = "BULK",
[UE_INTERRUPT] = "INTR"
};
+static const char *speed_table[USB_SPEED_MAX] = {
+ [USB_SPEED_FULL] = "FULL",
+ [USB_SPEED_HIGH] = "HIGH",
+ [USB_SPEED_LOW] = "LOW",
+ [USB_SPEED_VARIABLE] = "VARI",
+ [USB_SPEED_SUPER] = "SUPER",
+};
+
static void
handle_sigint(int sig)
{
@@ -122,182 +130,282 @@ handle_sigint(int sig)
doexit = 1;
}
+#define FLAGS(x, name) \
+ (((x) & USBPF_FLAG_##name) ? #name "|" : "")
+
+#define STATUS(x, name) \
+ (((x) & USBPF_STATUS_##name) ? #name "|" : "")
+
+static const char *
+usb_errstr(uint32_t error)
+{
+ if (error >= USB_ERR_MAX || errstr_table[error] == NULL)
+ return ("UNKNOWN");
+ else
+ return (errstr_table[error]);
+}
+
+static const char *
+usb_speedstr(uint8_t speed)
+{
+ if (speed >= USB_SPEED_MAX || speed_table[speed] == NULL)
+ return ("UNKNOWN");
+ else
+ return (speed_table[speed]);
+}
+
+static void
+print_flags(uint32_t flags)
+{
+ printf(" flags %#x <%s%s%s%s%s%s%s%s%s0>\n",
+ flags,
+ FLAGS(flags, FORCE_SHORT_XFER),
+ FLAGS(flags, SHORT_XFER_OK),
+ FLAGS(flags, SHORT_FRAMES_OK),
+ FLAGS(flags, PIPE_BOF),
+ FLAGS(flags, PROXY_BUFFER),
+ FLAGS(flags, EXT_BUFFER),
+ FLAGS(flags, MANUAL_STATUS),
+ FLAGS(flags, NO_PIPE_OK),
+ FLAGS(flags, STALL_PIPE));
+}
+
static void
-print_flags(u_int32_t flags)
+print_status(uint32_t status)
{
-#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
+ printf(" status %#x <%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s0>\n",
+ status,
+ STATUS(status, OPEN),
+ STATUS(status, TRANSFERRING),
+ STATUS(status, DID_DMA_DELAY),
+ STATUS(status, DID_CLOSE),
+ STATUS(status, DRAINING),
+ STATUS(status, STARTED),
+ STATUS(status, BW_RECLAIMED),
+ STATUS(status, CONTROL_XFR),
+ STATUS(status, CONTROL_HDR),
+ STATUS(status, CONTROL_ACT),
+ STATUS(status, CONTROL_STALL),
+ STATUS(status, SHORT_FRAMES_OK),
+ STATUS(status, SHORT_XFER_OK),
+ STATUS(status, BDMA_ENABLE),
+ STATUS(status, BDMA_NO_POST_SYNC),
+ STATUS(status, BDMA_SETUP),
+ STATUS(status, ISOCHRONOUS_XFR),
+ STATUS(status, CURR_DMA_SET),
+ STATUS(status, CAN_CANCEL_IMMED),
+ STATUS(status, DOING_CALLBACK));
}
+/*
+ * Dump a byte into hex format.
+ */
static void
-print_status(u_int32_t status)
+hexbyte(char *buf, uint8_t temp)
{
-#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
+ uint8_t lo;
+ uint8_t hi;
+
+ lo = temp & 0xF;
+ hi = temp >> 4;
+
+ if (hi < 10)
+ buf[0] = '0' + hi;
+ else
+ buf[0] = 'A' + hi - 10;
+
+ if (lo < 10)
+ buf[1] = '0' + lo;
+ else
+ buf[1] = 'A' + lo - 10;
}
/*
* Display a region in traditional hexdump format.
*/
static void
-hexdump(const char *region, size_t len)
+hexdump(const uint8_t *region, uint32_t len)
{
- const char *line;
+ const uint8_t *line;
+ char linebuf[128];
+ int i;
int x;
int c;
-#define EMIT(fmt, ...) do { \
- printf(fmt,## __VA_ARGS__); \
-} while (0)
for (line = region; line < (region + len); line += 16) {
- EMIT(" %04lx ", (long) (line - region));
+
+ i = 0;
+
+ linebuf[i] = ' ';
+ hexbyte(linebuf + i + 1, ((line - region) >> 8) & 0xFF);
+ hexbyte(linebuf + i + 3, (line - region) & 0xFF);
+ linebuf[i + 5] = ' ';
+ linebuf[i + 6] = ' ';
+ i += 7;
+
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(" ");
+ if ((line + x) < (region + len)) {
+ hexbyte(linebuf + i,
+ *(const u_int8_t *)(line + x));
+ } else {
+ linebuf[i] = '-';
+ linebuf[i + 1] = '-';
+ }
+ linebuf[i + 2] = ' ';
+ if (x == 7) {
+ linebuf[i + 3] = ' ';
+ i += 4;
+ } else {
+ i += 3;
+ }
}
- EMIT(" |");
+ linebuf[i] = ' ';
+ linebuf[i + 1] = '|';
+ i += 2;
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(" ");
+ linebuf[i] = c;
+ } else {
+ linebuf[i] = ' ';
+ }
+ i++;
}
- EMIT("|\n");
+ linebuf[i] = '|';
+ linebuf[i + 1] = 0;
+ i += 2;
+ puts(linebuf);
}
-#undef EMIT
}
static void
-print_apacket(const struct bpf_xhdr *hdr, struct usbpf_pkthdr *up,
- const char *payload)
+print_apacket(const struct bpf_xhdr *hdr, const uint8_t *ptr, int ptr_len)
{
struct tm *tm;
+ struct usbpf_pkthdr up_temp;
+ struct usbpf_pkthdr *up;
struct timeval tv;
size_t len;
- u_int32_t framelen, x;
- const char *ptr = payload;
+ uint32_t x;
char buf[64];
- /* A packet from the kernel is based on little endian byte order. */
+ ptr += USBPF_HDR_LEN;
+ ptr_len -= USBPF_HDR_LEN;
+ if (ptr_len < 0)
+ return;
+
+ /* make sure we don't change the source buffer */
+ memcpy(&up_temp, ptr - USBPF_HDR_LEN, sizeof(up_temp));
+ up = &up_temp;
+
+ /*
+ * A packet from the kernel is based on little endian byte
+ * order.
+ */
+ up->up_totlen = le32toh(up->up_totlen);
up->up_busunit = le32toh(up->up_busunit);
+ up->up_address = le32toh(up->up_address);
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);
+ up->up_frames = le32toh(up->up_frames);
+ up->up_packet_size = le32toh(up->up_packet_size);
+ up->up_packet_count = le32toh(up->up_packet_count);
+ up->up_endpoint = le32toh(up->up_endpoint);
tv.tv_sec = hdr->bh_tstamp.bt_sec;
tv.tv_usec = hdr->bh_tstamp.bt_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,
+
+ printf("%.*s.%06ju usbus%d.%d %s-%s-EP=%08x,SPD=%s,NFR=%d,SLEN=%d,IVAL=%d%s%s\n",
+ (int)len, buf, tv.tv_usec,
+ (int)up->up_busunit, (int)up->up_address,
+ (up->up_type == USBPF_XFERTAP_SUBMIT) ? "SUBM" : "DONE",
xfertype_table[up->up_xfertype],
- up->up_type == USBPF_XFERTAP_SUBMIT ? "S" : "D");
- 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");
+ (unsigned int)up->up_endpoint,
+ usb_speedstr(up->up_speed),
+ (int)up->up_frames,
+ (int)(up->up_totlen - USBPF_HDR_LEN -
+ (USBPF_FRAME_HDR_LEN * up->up_frames)),
+ (int)up->up_interval,
+ (up->up_type == USBPF_XFERTAP_DONE) ? ",ERR=" : "",
+ (up->up_type == USBPF_XFERTAP_DONE) ?
+ usb_errstr(up->up_error) : "");
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;
+ for (x = 0; x != up->up_frames; x++) {
+ const struct usbpf_framehdr *uf;
+ uint32_t framelen;
+ uint32_t flags;
+
+ uf = (const struct usbpf_framehdr *)ptr;
+ ptr += USBPF_FRAME_HDR_LEN;
+ ptr_len -= USBPF_FRAME_HDR_LEN;
+ if (ptr_len < 0)
+ return;
+
+ framelen = le32toh(uf->length);
+ flags = le32toh(uf->flags);
+
+ printf(" frame[%u] %s %d bytes\n",
+ (unsigned int)x,
+ (flags & USBPF_FRAMEFLAG_READ) ? "READ" : "WRITE",
+ (int)framelen);
+
+ if (flags & USBPF_FRAMEFLAG_DATA_FOLLOWS) {
+
+ int tot_frame_len;
+
+ tot_frame_len = USBPF_FRAME_ALIGN(framelen);
+
+ ptr_len -= tot_frame_len;
+
+ if (tot_frame_len < 0 ||
+ (int)framelen < 0 || (int)ptr_len < 0)
+ break;
+
+ hexdump(ptr, framelen);
+
+ ptr += tot_frame_len;
+ }
}
}
- if (verbose >= 2) {
+ if (verbose >= 2)
print_flags(up->up_flags);
+ if (verbose >= 3)
print_status(up->up_status);
- }
}
static void
-print_packets(char *data, const int datalen)
+print_packets(uint8_t *data, const int datalen)
{
- struct usbpf_pkthdr *up;
const struct bpf_xhdr *hdr;
- u_int32_t framelen, x;
- char *ptr, *next;
+ uint8_t *ptr;
+ uint8_t *next;
for (ptr = data; ptr < (data + datalen); ptr = next) {
hdr = (const struct bpf_xhdr *)ptr;
- up = (struct usbpf_pkthdr *)(ptr + hdr->bh_hdrlen);
next = ptr + BPF_WORDALIGN(hdr->bh_hdrlen + hdr->bh_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;
+ if (w_arg == NULL) {
+ print_apacket(hdr, ptr +
+ hdr->bh_hdrlen, hdr->bh_caplen);
}
+ pkt_captured++;
}
}
static void
-write_packets(struct usbcap *p, const char *data, const int datalen)
+write_packets(struct usbcap *p, const uint8_t *data, const int datalen)
{
- int len = htole32(datalen), ret;
+ int len = htole32(datalen);
+ int ret;
ret = write(p->wfd, &len, sizeof(int));
assert(ret == sizeof(int));
@@ -308,8 +416,9 @@ write_packets(struct usbcap *p, const char *data, const int datalen)
static void
read_file(struct usbcap *p)
{
- int datalen, ret;
- char *data;
+ int datalen;
+ int ret;
+ uint8_t *data;
while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) {
datalen = le32toh(datalen);
@@ -330,7 +439,7 @@ do_loop(struct usbcap *p)
int cc;
while (doexit == 0) {
- cc = read(p->fd, (char *)p->buffer, p->bufsize);
+ cc = read(p->fd, (uint8_t *)p->buffer, p->bufsize);
if (cc < 0) {
switch (errno) {
case EINTR:
@@ -364,7 +473,7 @@ init_rfile(struct usbcap *p)
assert(ret == sizeof(uf));
assert(le32toh(uf.magic) == USBCAP_FILEHDR_MAGIC);
assert(uf.major == 0);
- assert(uf.minor == 1);
+ assert(uf.minor == 2);
}
static void
@@ -381,7 +490,7 @@ init_wfile(struct usbcap *p)
bzero(&uf, sizeof(uf));
uf.magic = htole32(USBCAP_FILEHDR_MAGIC);
uf.major = 0;
- uf.minor = 1;
+ uf.minor = 2;
ret = write(p->wfd, (const void *)&uf, sizeof(uf));
assert(ret == sizeof(uf));
}
@@ -412,7 +521,7 @@ main(int argc, char *argv[])
struct usbcap uc, *p = &uc;
struct ifreq ifr;
long snapshot = 192;
- u_int v;
+ uint32_t v;
int fd, o;
const char *optstring;
@@ -471,9 +580,13 @@ main(int argc, char *argv[])
return (EXIT_FAILURE);
}
- if ((ioctl(fd, BIOCGBLEN, (caddr_t)&v) < 0) || v < 4096)
- v = 4096;
- for ( ; v != 0; v >>= 1) {
+ /* USB transfers can be greater than 64KByte */
+ v = 1U << 16;
+
+ /* clear ifr structure */
+ memset(&ifr, 0, sizeof(ifr));
+
+ for ( ; v >= USBPF_HDR_LEN; v >>= 1) {
(void)ioctl(fd, BIOCSBLEN, (caddr_t)&v);
(void)strncpy(ifr.ifr_name, i_arg, sizeof(ifr.ifr_name));
if (ioctl(fd, BIOCSETIF, (caddr_t)&ifr) >= 0)
@@ -490,7 +603,7 @@ main(int argc, char *argv[])
}
p->bufsize = v;
- p->buffer = (u_char *)malloc(p->bufsize);
+ p->buffer = (uint8_t *)malloc(p->bufsize);
if (p->buffer == NULL) {
fprintf(stderr, "malloc: %s", strerror(errno));
return (EXIT_FAILURE);
OpenPOWER on IntegriCloud