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