usbdump.c revision 215651
1139738Simp/*-
284996Srobert * Copyright (c) 2010 Weongyo Jeong <weongyo@freebsd.org>
384996Srobert * All rights reserved.
484996Srobert *
584996Srobert * Redistribution and use in source and binary forms, with or without
684996Srobert * modification, are permitted provided that the following conditions
7181398Smarius * are met:
884996Srobert * 1. Redistributions of source code must retain the above copyright
9182916Smarius *    notice, this list of conditions and the following disclaimer,
10238851Smarius *    without modification.
11182916Smarius * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12182916Smarius *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13182916Smarius *    redistribution must be conditioned upon including a substantially
14182916Smarius *    similar Disclaimer requirement for further binary redistribution.
15182916Smarius *
16182916Smarius * NO WARRANTY
17182916Smarius * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18182916Smarius * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19182916Smarius * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20182916Smarius * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21182916Smarius * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22182916Smarius * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23182916Smarius * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24182916Smarius * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25182916Smarius * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26182916Smarius * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27182916Smarius * THE POSSIBILITY OF SUCH DAMAGES.
28182916Smarius *
29182916Smarius * $FreeBSD: head/usr.sbin/usbdump/usbdump.c 215651 2010-11-22 01:28:29Z weongyo $
30182916Smarius */
31182916Smarius
32182916Smarius#include <sys/param.h>
33182916Smarius#include <sys/endian.h>
34124139Sobrien#include <sys/ioctl.h>
35124139Sobrien#include <sys/stat.h>
36124139Sobrien#include <sys/utsname.h>
37182020Smarius#include <dev/usb/usb.h>
3884996Srobert#include <dev/usb/usb_pf.h>
3984996Srobert#include <dev/usb/usbdi.h>
4084996Srobert#include <assert.h>
4184996Srobert#include <errno.h>
4284996Srobert#include <fcntl.h>
4384996Srobert#include <limits.h>
4484996Srobert#include <stdio.h>
4584996Srobert#include <stdlib.h>
4684996Srobert#include <string.h>
4791139Sjake#include <time.h>
4884996Srobert#include <unistd.h>
49203829Smarius
5084996Srobertstruct usbcap {
51203829Smarius	int		fd;		/* fd for /dev/usbpf */
52102219Srobert	u_int		bufsize;
53163145Skmacy	char		*buffer;
54234898Smarius
55234898Smarius	/* for -w option */
56235364Savg	int		wfd;
57234898Smarius	/* for -r option */
5884996Srobert	int		rfd;
59163145Skmacy};
6084996Srobert
61203829Smariusstruct usbcap_filehdr {
6291139Sjake	u_int		magic;
6384996Srobert#define	USBCAP_FILEHDR_MAGIC	0x9a90000e
64203829Smarius	u_char		major;
65203829Smarius	u_char		minor;
6691110Sjake	u_char		reserved[26];
6791110Sjake} __packed;
6884996Srobert
69181398Smariusstatic int doexit = 0;
7091139Sjakestatic int pkt_captured = 0;
71182478Smariusstatic int verbose = 0;
72182877Smariusstatic const char *i_arg = "usbus0";;
7384996Srobertstatic const char *r_arg = NULL;
7484996Srobertstatic const char *w_arg = NULL;
7584996Srobertstatic const char *errstr_table[USB_ERR_MAX] = {
7685719Sjake	[USB_ERR_NORMAL_COMPLETION]	= "NORMAL_COMPLETION",
7784996Srobert	[USB_ERR_PENDING_REQUESTS]	= "PENDING_REQUESTS",
78170839Smarius	[USB_ERR_NOT_STARTED]		= "NOT_STARTED",
79170839Smarius	[USB_ERR_INVAL]			= "INVAL",
8084996Srobert	[USB_ERR_NOMEM]			= "NOMEM",
8184996Srobert	[USB_ERR_CANCELLED]		= "CANCELLED",
8284996Srobert	[USB_ERR_BAD_ADDRESS]		= "BAD_ADDRESS",
8384996Srobert	[USB_ERR_BAD_BUFSIZE]		= "BAD_BUFSIZE",
8484996Srobert	[USB_ERR_BAD_FLAG]		= "BAD_FLAG",
8584996Srobert	[USB_ERR_NO_CALLBACK]		= "NO_CALLBACK",
86203829Smarius	[USB_ERR_IN_USE]		= "IN_USE",
87203829Smarius	[USB_ERR_NO_ADDR]		= "NO_ADDR",
88203829Smarius	[USB_ERR_NO_PIPE]		= "NO_PIPE",
89170839Smarius	[USB_ERR_ZERO_NFRAMES]		= "ZERO_NFRAMES",
90163145Skmacy	[USB_ERR_ZERO_MAXP]		= "ZERO_MAXP",
91163145Skmacy	[USB_ERR_SET_ADDR_FAILED]	= "SET_ADDR_FAILED",
92163145Skmacy	[USB_ERR_NO_POWER]		= "NO_POWER",
93163145Skmacy	[USB_ERR_TOO_DEEP]		= "TOO_DEEP",
9485719Sjake	[USB_ERR_IOERROR]		= "IOERROR",
95170839Smarius	[USB_ERR_NOT_CONFIGURED]	= "NOT_CONFIGURED",
9685719Sjake	[USB_ERR_TIMEOUT]		= "TIMEOUT",
97223719Smarius	[USB_ERR_SHORT_XFER]		= "SHORT_XFER",
98203830Smarius	[USB_ERR_STALLED]		= "STALLED",
99181398Smarius	[USB_ERR_INTERRUPTED]		= "INTERRUPTED",
100223719Smarius	[USB_ERR_DMA_LOAD_FAILED]	= "DMA_LOAD_FAILED",
101203830Smarius	[USB_ERR_BAD_CONTEXT]		= "BAD_CONTEXT",
102181398Smarius	[USB_ERR_NO_ROOT_HUB]		= "NO_ROOT_HUB",
103182916Smarius	[USB_ERR_NO_INTR_THREAD]	= "NO_INTR_THREAD",
10485719Sjake	[USB_ERR_NOT_LOCKED]		= "NOT_LOCKED",
105170839Smarius};
106170839Smarius
107170839Smariusstatic const char *xfertype_table[] = {
108170854Smarius	[UE_CONTROL]			= "CTRL",
109170854Smarius	[UE_ISOCHRONOUS]		= "ISOC",
110170854Smarius	[UE_BULK]			= "BULK",
111170854Smarius	[UE_INTERRUPT]			= "INTR"
112114386Speter};
113163145Skmacy
114170839Smariusstatic void
115203829Smariushandle_sigint(int sig)
116203829Smarius{
117203829Smarius
118163145Skmacy	(void)sig;
11984996Srobert	doexit = 1;
120181398Smarius}
121181398Smarius
122181398Smariusstatic void
123181398Smariusprint_flags(u_int32_t flags)
124181398Smarius{
125181398Smarius#define	PRINTFLAGS(name)			\
126181398Smarius	if ((flags & USBPF_FLAG_##name) != 0)	\
127170839Smarius		printf("%s ", #name);
128163145Skmacy	printf(" flags %#x", flags);
129163145Skmacy	printf(" < ");
13097445Sjake	PRINTFLAGS(FORCE_SHORT_XFER);
13197445Sjake	PRINTFLAGS(SHORT_XFER_OK);
132203829Smarius	PRINTFLAGS(SHORT_FRAMES_OK);
133203829Smarius	PRINTFLAGS(PIPE_BOF);
134204152Smarius	PRINTFLAGS(PROXY_BUFFER);
135203829Smarius	PRINTFLAGS(EXT_BUFFER);
136203829Smarius	PRINTFLAGS(MANUAL_STATUS);
137223719Smarius	PRINTFLAGS(NO_PIPE_OK);
13891139Sjake	PRINTFLAGS(STALL_PIPE);
139170839Smarius	printf(">\n");
140170839Smarius#undef PRINTFLAGS
141163145Skmacy}
142236581Smarius
143170854Smariusstatic void
14484996Srobertprint_status(u_int32_t status)
14584996Srobert{
14684996Srobert#define	PRINTSTATUS(name)				\
14784996Srobert	if ((status & USBPF_STATUS_##name) != 0)	\
14884996Srobert		printf("%s ", #name);
14984996Srobert
15085719Sjake	printf(" status %#x", status);
15184996Srobert	printf(" < ");
15285719Sjake	PRINTSTATUS(OPEN);
15385719Sjake	PRINTSTATUS(TRANSFERRING);
15485719Sjake	PRINTSTATUS(DID_DMA_DELAY);
15585719Sjake	PRINTSTATUS(DID_CLOSE);
156234898Smarius	PRINTSTATUS(DRAINING);
157235364Savg	PRINTSTATUS(STARTED);
158234898Smarius	PRINTSTATUS(BW_RECLAIMED);
15984996Srobert	PRINTSTATUS(CONTROL_XFR);
16084996Srobert	PRINTSTATUS(CONTROL_HDR);
16184996Srobert	PRINTSTATUS(CONTROL_ACT);
16284996Srobert	PRINTSTATUS(CONTROL_STALL);
163170839Smarius	PRINTSTATUS(SHORT_FRAMES_OK);
164114386Speter	PRINTSTATUS(SHORT_XFER_OK);
165114386Speter#if USB_HAVE_BUSDMA
16684996Srobert	PRINTSTATUS(BDMA_ENABLE);
16784996Srobert	PRINTSTATUS(BDMA_NO_POST_SYNC);
16884996Srobert	PRINTSTATUS(BDMA_SETUP);
16984996Srobert#endif
17084996Srobert	PRINTSTATUS(ISOCHRONOUS_XFR);
171234898Smarius	PRINTSTATUS(CURR_DMA_SET);
17284996Srobert	PRINTSTATUS(CAN_CANCEL_IMMED);
17391110Sjake	PRINTSTATUS(DOING_CALLBACK);
17484996Srobert	printf(">\n");
17585719Sjake#undef PRINTSTATUS
17693606Stmm}
17793606Stmm
17893606Stmm/*
179234898Smarius * Display a region in traditional hexdump format.
180234898Smarius */
181234898Smariusstatic void
182108100Sjakehexdump(const char *region, size_t len)
183105065Sjake{
184105065Sjake	const char *line;
185108100Sjake	int x, c;
186108100Sjake	char lbuf[80];
187108100Sjake#define EMIT(fmt, args...)	do {		\
188105065Sjake	sprintf(lbuf, fmt , ## args);		\
189105065Sjake	printf("%s", lbuf);			\
190105065Sjake} while (0)
191117448Stmm
19285719Sjake	for (line = region; line < (region + len); line += 16) {
19385719Sjake		EMIT(" %04lx  ", (long) (line - region));
19491110Sjake		for (x = 0; x < 16; x++) {
19591110Sjake			if ((line + x) < (region + len))
19691110Sjake				EMIT("%02x ", *(const u_int8_t *)(line + x));
19784996Srobert			else
19884996Srobert				EMIT("-- ");
19985719Sjake			if (x == 7)
20085719Sjake				EMIT(" ");
20185719Sjake		}
20285719Sjake		EMIT(" |");
20385719Sjake		for (x = 0; x < 16; x++) {
20485719Sjake			if ((line + x) < (region + len)) {
20584996Srobert				c = *(const u_int8_t *)(line + x);
20684996Srobert				/* !isprint(c) */
20784996Srobert				if ((c < ' ') || (c > '~'))
20884996Srobert					c = '.';
20984996Srobert				EMIT("%c", c);
21084996Srobert			} else
21184996Srobert				EMIT(" ");
21291110Sjake		}
21391110Sjake		EMIT("|\n");
21491110Sjake	}
21591110Sjake#undef EMIT
21691110Sjake}
21791110Sjake
21891110Sjakestatic void
21991110Sjakeprint_apacket(const struct usbpf_xhdr *hdr, struct usbpf_pkthdr *up,
22091110Sjake    const char *payload)
22191110Sjake{
22291110Sjake	struct tm *tm;
22391110Sjake	struct timeval tv;
22491110Sjake	size_t len;
22591110Sjake	u_int32_t framelen, x;
22691110Sjake	const char *ptr = payload;
22791110Sjake	char buf[64];
22891110Sjake
22991110Sjake	/* A packet from the kernel is based on little endian byte order. */
23091110Sjake	up->up_busunit = le32toh(up->up_busunit);
23191110Sjake	up->up_flags = le32toh(up->up_flags);
23291110Sjake	up->up_status = le32toh(up->up_status);
23391110Sjake	up->up_length = le32toh(up->up_length);
23491110Sjake	up->up_frames = le32toh(up->up_frames);
23591110Sjake	up->up_error = le32toh(up->up_error);
23691110Sjake	up->up_interval = le32toh(up->up_interval);
23791110Sjake
23891110Sjake	tv.tv_sec = hdr->uh_tstamp.ut_sec;
23991110Sjake	tv.tv_usec = hdr->uh_tstamp.ut_frac;
24091110Sjake	tm = localtime(&tv.tv_sec);
24191110Sjake
24291110Sjake	len = strftime(buf, sizeof(buf), "%H:%M:%S", tm);
24391110Sjake	printf("%.*s.%06ju", (int)len, buf, tv.tv_usec);
24491110Sjake	printf(" usbus%d.%d 0x%02x %s %s", up->up_busunit, up->up_address,
24591110Sjake	    up->up_endpoint,
24691110Sjake	    xfertype_table[up->up_xfertype],
24791110Sjake	    up->up_type == USBPF_XFERTAP_SUBMIT ? ">" : "<");
24891110Sjake	printf(" (%d/%d)", up->up_frames, up->up_length);
24991110Sjake	if (up->up_type == USBPF_XFERTAP_DONE)
25091110Sjake		printf(" %s", errstr_table[up->up_error]);
25191110Sjake	if (up->up_xfertype == UE_BULK || up->up_xfertype == UE_ISOCHRONOUS)
25291110Sjake		printf(" %d", up->up_interval);
25391110Sjake	printf("\n");
25491110Sjake
25591110Sjake	if (verbose >= 1) {
25691110Sjake		for (x = 0; x < up->up_frames; x++) {
25791110Sjake			framelen = le32toh(*((const u_int32_t *)ptr));
25891110Sjake			ptr += sizeof(u_int32_t);
25991110Sjake			printf(" frame[%u] len %d\n", x, framelen);
26091110Sjake			assert(framelen < (1024 * 4));
26191110Sjake			hexdump(ptr, framelen);
26291110Sjake			ptr += framelen;
26391110Sjake		}
26491110Sjake	}
26584996Srobert	if (verbose >= 2) {
26684996Srobert		print_flags(up->up_flags);
26784996Srobert		print_status(up->up_status);
26884996Srobert	}
26984996Srobert}
27084996Srobert
271170839Smarius
272170839Smariusstatic void
27384996Srobertprint_packets(char *data, const int datalen)
27484996Srobert{
27584996Srobert	struct usbpf_pkthdr *up;
27684996Srobert	const struct usbpf_xhdr *hdr;
27784996Srobert	u_int32_t framelen, x;
278170839Smarius	char *ptr, *next;
279163145Skmacy
280170839Smarius	for (ptr = data; ptr < (data + datalen); ptr = next) {
28184996Srobert		hdr = (const struct usbpf_xhdr *)ptr;
28284996Srobert		up = (struct usbpf_pkthdr *)(ptr + hdr->uh_hdrlen);
28384996Srobert		next = ptr + USBPF_WORDALIGN(hdr->uh_hdrlen + hdr->uh_caplen);
28484996Srobert
28584996Srobert		ptr = ((char *)up) + sizeof(struct usbpf_pkthdr);
286170839Smarius		if (w_arg == NULL)
287163145Skmacy			print_apacket(hdr, up, ptr);
28884996Srobert		pkt_captured++;
289170839Smarius		for (x = 0; x < up->up_frames; x++) {
29084996Srobert			framelen = le32toh(*((const u_int32_t *)ptr));
29184996Srobert			ptr += sizeof(u_int32_t) + framelen;
29284996Srobert		}
29384996Srobert	}
29484996Srobert}
295170854Smarius
296170854Smariusstatic void
297170854Smariuswrite_packets(struct usbcap *p, const char *data, const int datalen)
298170854Smarius{
299170854Smarius	int len = htole32(datalen), ret;
300170854Smarius
301170854Smarius	ret = write(p->wfd, &len, sizeof(int));
302170854Smarius	assert(ret == sizeof(int));
303170854Smarius	ret = write(p->wfd, data, datalen);
304170854Smarius	assert(ret == datalen);
305170854Smarius}
306170854Smarius
307170854Smariusstatic void
308170854Smariusread_file(struct usbcap *p)
309170854Smarius{
310170854Smarius	int datalen, ret;
311170854Smarius	char *data;
312170854Smarius
313170854Smarius	while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) {
314170854Smarius		datalen = le32toh(datalen);
315170854Smarius		data = malloc(datalen);
31684996Srobert		assert(data != NULL);
317170854Smarius		ret = read(p->rfd, data, datalen);
318170854Smarius		assert(ret == datalen);
319170854Smarius		print_packets(data, datalen);
320170854Smarius		free(data);
321170854Smarius	}
322170854Smarius	if (ret == -1)
323170854Smarius		fprintf(stderr, "read: %s\n", strerror(errno));
324170854Smarius}
325170854Smarius
326170854Smariusstatic void
327170854Smariusdo_loop(struct usbcap *p)
328170854Smarius{
329170854Smarius	int cc;
330170854Smarius
331170854Smarius	while (doexit == 0) {
332170854Smarius		cc = read(p->fd, (char *)p->buffer, p->bufsize);
333114386Speter		if (cc < 0) {
33484996Srobert			switch (errno) {
33584996Srobert			case EINTR:
33685719Sjake				break;
337116415Sjake			default:
33891139Sjake				fprintf(stderr, "read: %s\n", strerror(errno));
33985719Sjake				return;
34084996Srobert			}
341170839Smarius			continue;
342170839Smarius		}
34391139Sjake		if (cc == 0)
34484996Srobert			continue;
34585719Sjake		if (w_arg != NULL)
346170839Smarius			write_packets(p, p->buffer, cc);
34784996Srobert		print_packets(p->buffer, cc);
34891139Sjake	}
349188455Smarius}
350181398Smarius
35184996Srobertstatic void
35285719Sjakeinit_rfile(struct usbcap *p)
353200946Smarius{
354200946Smarius	struct usbcap_filehdr uf;
355116415Sjake	int ret;
356116415Sjake
357165325Skmacy	p->rfd = open(r_arg, O_RDONLY);
358116415Sjake	if (p->rfd < 0) {
359116415Sjake		fprintf(stderr, "open: %s (%s)\n", r_arg, strerror(errno));
360116415Sjake		exit(EXIT_FAILURE);
361170854Smarius	}
36284996Srobert	ret = read(p->rfd, &uf, sizeof(uf));
36384996Srobert	assert(ret == sizeof(uf));
364182478Smarius	assert(le32toh(uf.magic) == USBCAP_FILEHDR_MAGIC);
365223719Smarius	assert(uf.major == 0);
366182478Smarius	assert(uf.minor == 1);
367223719Smarius}
368182478Smarius
369223719Smariusstatic void
370182478Smariusinit_wfile(struct usbcap *p)
371223719Smarius{
372223719Smarius	struct usbcap_filehdr uf;
373182478Smarius	int ret;
374223719Smarius
375223719Smarius	p->wfd = open(w_arg, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR);
376223719Smarius	if (p->wfd < 0) {
377223719Smarius		fprintf(stderr, "open: %s (%s)\n", w_arg, strerror(errno));
378223719Smarius		exit(EXIT_FAILURE);
379223719Smarius	}
380182478Smarius	bzero(&uf, sizeof(uf));
381182478Smarius	uf.magic = htole32(USBCAP_FILEHDR_MAGIC);
382182478Smarius	uf.major = 0;
383223719Smarius	uf.minor = 1;
384182478Smarius	ret = write(p->wfd, (const void *)&uf, sizeof(uf));
385223719Smarius	assert(ret == sizeof(uf));
386182478Smarius}
387223719Smarius
388182478Smariusstatic void
389223719Smariususage(void)
390223719Smarius{
391182478Smarius
392223719Smarius#define FMT "    %-14s %s\n"
393223719Smarius	fprintf(stderr, "usage: usbdump [options]\n");
394223719Smarius	fprintf(stderr, FMT, "-i ifname", "Listen on USB bus interface");
395223719Smarius	fprintf(stderr, FMT, "-r file", "Read the raw packets from file");
396223719Smarius	fprintf(stderr, FMT, "-s snaplen", "Snapshot bytes from each packet");
397223719Smarius	fprintf(stderr, FMT, "-v", "Increases the verbose level");
398182478Smarius	fprintf(stderr, FMT, "-w file", "Write the raw packets to file");
399182478Smarius#undef FMT
400181398Smarius	exit(1);
401181398Smarius}
402181398Smarius
403182766Smariusint
404223719Smariusmain(int argc, char *argv[])
405181398Smarius{
406182766Smarius	struct timeval tv;
407182766Smarius	struct usbpf_insn total_insn;
408181398Smarius	struct usbpf_program total_prog;
409223719Smarius	struct usbpf_stat us;
410223719Smarius	struct usbpf_version uv;
411181398Smarius	struct usbcap uc, *p = &uc;
412181398Smarius	struct usbpf_ifreq ufr;
413223719Smarius	long snapshot = 192;
414182766Smarius	u_int v;
415191071Smarius	int fd, o;
416207537Smarius	const char *optstring;
417207537Smarius
418191071Smarius	bzero(&uc, sizeof(struct usbcap));
419191071Smarius
420181398Smarius	optstring = "i:r:s:vw:";
421182766Smarius	while ((o = getopt(argc, argv, optstring)) != -1) {
422181398Smarius		switch (o) {
423181398Smarius		case 'i':
424181398Smarius			i_arg = optarg;
425181398Smarius			break;
426181398Smarius		case 'r':
427181398Smarius			r_arg = optarg;
428182766Smarius			init_rfile(p);
429181398Smarius			break;
430181398Smarius		case 's':
431182766Smarius			snapshot = strtol(optarg, NULL, 10);
432182766Smarius			errno = 0;
433181398Smarius			if (snapshot == 0 && errno == EINVAL)
434223719Smarius				usage();
435223719Smarius			/* snapeshot == 0 is special */
436181398Smarius			if (snapshot == 0)
437181398Smarius				snapshot = -1;
438223719Smarius			break;
439182766Smarius		case 'v':
440191071Smarius			verbose++;
441207537Smarius			break;
442207537Smarius		case 'w':
443191071Smarius			w_arg = optarg;
444191071Smarius			init_wfile(p);
445181398Smarius			break;
446182766Smarius		default:
447181398Smarius			usage();
448181398Smarius			/* NOTREACHED */
449181398Smarius		}
450203830Smarius	}
451203830Smarius
452181398Smarius	if (r_arg != NULL) {
453181398Smarius		read_file(p);
454203830Smarius		exit(EXIT_SUCCESS);
455203830Smarius	}
456181398Smarius
457181398Smarius	p->fd = fd = open("/dev/usbpf", O_RDONLY);
458203830Smarius	if (p->fd < 0) {
459203830Smarius		fprintf(stderr, "(no devices found)\n");
460181398Smarius		return (EXIT_FAILURE);
461181398Smarius	}
462203830Smarius
463203830Smarius	if (ioctl(fd, UIOCVERSION, (caddr_t)&uv) < 0) {
464203830Smarius		fprintf(stderr, "UIOCVERSION: %s\n", strerror(errno));
465203830Smarius		return (EXIT_FAILURE);
466203830Smarius	}
467203830Smarius	if (uv.uv_major != USBPF_MAJOR_VERSION ||
468181398Smarius	    uv.uv_minor < USBPF_MINOR_VERSION) {
469181398Smarius		fprintf(stderr, "kernel bpf filter out of date");
470182916Smarius		return (EXIT_FAILURE);
471182916Smarius	}
472182916Smarius
473182916Smarius	if ((ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) || v < 65536)
474182916Smarius		v = 65536;
475182916Smarius	for ( ; v != 0; v >>= 1) {
476182916Smarius		(void)ioctl(fd, UIOCSBLEN, (caddr_t)&v);
477182916Smarius		(void)strncpy(ufr.ufr_name, i_arg, sizeof(ufr.ufr_name));
478182916Smarius		if (ioctl(fd, UIOCSETIF, (caddr_t)&ufr) >= 0)
479182916Smarius			break;
480182916Smarius	}
481182916Smarius	if (v == 0) {
482223719Smarius		fprintf(stderr, "UIOCSBLEN: %s: No buffer size worked", i_arg);
483182916Smarius		return (EXIT_FAILURE);
484182916Smarius	}
485182916Smarius
486182916Smarius	if (ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) {
487182916Smarius		fprintf(stderr, "UIOCGBLEN: %s", strerror(errno));
488182916Smarius		return (EXIT_FAILURE);
489223719Smarius	}
490182916Smarius
491182916Smarius	p->bufsize = v;
492182916Smarius	p->buffer = (u_char *)malloc(p->bufsize);
493182916Smarius	if (p->buffer == NULL) {
494182916Smarius		fprintf(stderr, "malloc: %s", strerror(errno));
495182916Smarius		return (EXIT_FAILURE);
496182916Smarius	}
497182916Smarius
498182916Smarius	/* XXX no read filter rules yet so at this moment accept everything */
499223719Smarius	total_insn.code = (u_short)(USBPF_RET | USBPF_K);
500182916Smarius	total_insn.jt = 0;
501182916Smarius	total_insn.jf = 0;
502182916Smarius	total_insn.k = snapshot;
503223719Smarius
504223719Smarius	total_prog.uf_len = 1;
505182916Smarius	total_prog.uf_insns = &total_insn;
506182916Smarius	if (ioctl(p->fd, UIOCSETF, (caddr_t)&total_prog) < 0) {
507182916Smarius		fprintf(stderr, "UIOCSETF: %s", strerror(errno));
508182916Smarius		return (EXIT_FAILURE);
509182916Smarius	}
510182916Smarius
511182916Smarius	/* 1 second read timeout */
512182916Smarius	tv.tv_sec = 1;
51384996Srobert	tv.tv_usec = 0;
514163145Skmacy	if (ioctl(p->fd, UIOCSRTIMEOUT, (caddr_t)&tv) < 0) {
51584996Srobert		fprintf(stderr, "UIOCSRTIMEOUT: %s", strerror(errno));
51691110Sjake		return (EXIT_FAILURE);
51797445Sjake	}
518203830Smarius
51984996Srobert	(void)signal(SIGINT, handle_sigint);
52084996Srobert
52184996Srobert	do_loop(p);
52284996Srobert
52391110Sjake	if (ioctl(fd, UIOCGSTATS, (caddr_t)&us) < 0) {
52485719Sjake		fprintf(stderr, "UIOCGSTATS: %s", strerror(errno));
52585719Sjake		return (EXIT_FAILURE);
52684996Srobert	}
527181398Smarius
528181398Smarius	/* XXX what's difference between pkt_captured and us.us_recv? */
529182020Smarius	printf("\n");
53091110Sjake	printf("%d packets captured\n", pkt_captured);
531170854Smarius	printf("%d packets received by filter\n", us.us_recv);
53291110Sjake	printf("%d packets dropped by kernel\n", us.us_drop);
533170854Smarius
534170854Smarius	if (p->fd > 0)
535170839Smarius		close(p->fd);
536170854Smarius	if (p->rfd > 0)
53791110Sjake		close(p->rfd);
538170854Smarius	if (p->wfd > 0)
539182020Smarius		close(p->wfd);
540182020Smarius
541182020Smarius	return (EXIT_SUCCESS);
54291110Sjake}
54391110Sjake