[RFC] USBdump patches

Hans Petter Selasky hselasky at c2i.net
Tue Nov 23 22:18:52 UTC 2010


Hi,

Please find attached official usbdump patch from HPS trying to re-use as much 
as possible of Weongyo's code which was committed not long ago. You need to 
SVN up to the latest 9-current.

This patch should fix all USB-dump issues reported so far!

1) Fix for proper offset calculation on ISOCHRONOUS reception.
2) Fixes for device mode.
3) PF-virtual-machine is OK (and done before copy of data).
4) Can load and unload the PF-code like a module.

How to use:

cd /usr/src
cat usbdump_r215656_patch.txt | patch

You need to make new kernel, but not userland.

Install sys/dev/usb/usb_pf.h into /usr/include/dev/usb/ and make all install 
in src/usr.sbin/usbdump .

After reboot:

kldload usb_pf

usbdump -d -1 -vvv

man usbdump

--HPS
-------------- next part --------------
=== sys/conf/files
==================================================================
--- sys/conf/files	(revision 215656)
+++ sys/conf/files	(local)
@@ -1779,12 +1779,15 @@
 dev/usb/usb_mbuf.c		optional usb
 dev/usb/usb_msctest.c		optional usb
 dev/usb/usb_parse.c		optional usb
-dev/usb/usb_pf.c		optional usb
 dev/usb/usb_process.c		optional usb
 dev/usb/usb_request.c		optional usb
 dev/usb/usb_transfer.c		optional usb
 dev/usb/usb_util.c		optional usb
 #
+# USB packet filter
+#
+dev/usb/usb_pf.c		optional usb_pf
+#
 # USB network drivers
 #
 dev/usb/net/if_aue.c		optional aue
=== sys/dev/usb/controller/usb_controller.c
==================================================================
--- sys/dev/usb/controller/usb_controller.c	(revision 215656)
+++ sys/dev/usb/controller/usb_controller.c	(local)
@@ -61,7 +61,6 @@
 
 #include <dev/usb/usb_controller.h>
 #include <dev/usb/usb_bus.h>
-#include <dev/usb/usb_pf.h>
 
 /* function prototypes  */
 
@@ -548,8 +547,6 @@
 
 	TAILQ_INIT(&bus->intr_q.head);
 
-	usbpf_attach(bus, &bus->uif);
-
 #if USB_HAVE_BUSDMA
 	usb_dma_tag_setup(bus->dma_parent_tag, bus->dma_tags,
 	    dmat, &bus->bus_mtx, NULL, 32, USB_BUS_DMA_TAG_MAX);
@@ -597,34 +594,5 @@
 	usb_dma_tag_unsetup(bus->dma_parent_tag);
 #endif
 
-	usbpf_detach(bus);
-
 	mtx_destroy(&bus->bus_mtx);
 }
-
-struct usb_bus *
-usb_bus_find(const char *name)
-{
-	struct usb_bus *ubus;
-	devclass_t dc;
-	device_t *devlist;
-	int devcount, error, i;
-	const char *nameunit;
-
-	dc = devclass_find("usbus");
-	if (dc == NULL)
-		return (NULL);
-	error = devclass_get_devices(dc, &devlist, &devcount);
-	if (error != 0)
-		return (NULL);
-	for (i = 0; i < devcount; i++) {
-		nameunit = device_get_nameunit(devlist[i]);
-		if (!strncmp(name, nameunit, strlen(nameunit))) {
-			ubus = device_get_ivars(devlist[i]);
-			free(devlist, M_TEMP);
-			return (ubus);
-		}
-	}
-	free(devlist, M_TEMP);
-	return (NULL);
-}
=== sys/dev/usb/usb_bus.h
==================================================================
--- sys/dev/usb/usb_bus.h	(revision 215656)
+++ sys/dev/usb/usb_bus.h	(local)
@@ -86,8 +86,6 @@
 	struct usb_bus_methods *methods;	/* filled by HC driver */
 	struct usb_device **devices;
 
-	struct usbpf_if *uif;	/* USB Packet Filter */
-
 	usb_power_mask_t hw_power_state;	/* see USB_HW_POWER_XXX */
 	usb_size_t uframe_usage[USB_HS_MICRO_FRAMES_MAX];
 
=== sys/dev/usb/usb_controller.h
==================================================================
--- sys/dev/usb/usb_controller.h	(revision 215656)
+++ sys/dev/usb/usb_controller.h	(local)
@@ -221,6 +221,5 @@
 uint16_t usb_isoc_time_expand(struct usb_bus *bus, uint16_t isoc_time_curr);
 uint16_t usbd_fs_isoc_schedule_isoc_time_expand(struct usb_device *udev, struct usb_fs_isoc_schedule **pp_start, struct usb_fs_isoc_schedule **pp_end, uint16_t isoc_time);
 uint8_t	usbd_fs_isoc_schedule_alloc(struct usb_fs_isoc_schedule *fss, uint8_t *pstart, uint16_t len);
-struct usb_bus *usb_bus_find(const char *name);
 
 #endif					/* _USB_CONTROLLER_H_ */
=== sys/dev/usb/usb_dynamic.c
==================================================================
--- sys/dev/usb/usb_dynamic.c	(revision 215656)
+++ sys/dev/usb/usb_dynamic.c	(local)
@@ -58,6 +58,9 @@
 static usb_temp_unsetup_t usb_temp_unsetup_w;
 static usb_test_quirk_t usb_test_quirk_w;
 static usb_quirk_ioctl_t usb_quirk_ioctl_w;
+#if USB_HAVE_PF
+static usb_pf_xfertap_t usb_pf_xfertap_w;
+#endif
 
 /* global variables */
 usb_handle_req_t *usb_temp_get_desc_p = &usb_temp_get_desc_w;
@@ -66,6 +69,9 @@
 usb_test_quirk_t *usb_test_quirk_p = &usb_test_quirk_w;
 usb_quirk_ioctl_t *usb_quirk_ioctl_p = &usb_quirk_ioctl_w;
 devclass_t usb_devclass_ptr = NULL;
+#if USB_HAVE_PF
+usb_pf_xfertap_t *usb_pf_xfertap_p = &usb_pf_xfertap_w;
+#endif
 
 static usb_error_t
 usb_temp_setup_by_index_w(struct usb_device *udev, uint16_t index)
@@ -103,6 +109,14 @@
 	}
 }
 
+#if USB_HAVE_PF
+static void
+usb_pf_xfertap_w(struct usb_xfer *xfer, int type)
+{
+	/* NOP */
+}
+#endif
+
 void
 usb_quirk_unload(void *arg)
 {
@@ -147,3 +161,19 @@
 
 	pause("WAIT", hz);
 }
+
+#if USB_HAVE_PF
+void
+usb_pf_unload(void *arg)
+{
+	/* reset function pointers */
+
+	usb_pf_xfertap_p = &usb_pf_xfertap_w;
+
+	/* wait for CPU to exit the loaded functions, if any */
+
+	/* XXX this is a tradeoff */
+
+	pause("WAIT", hz);
+}
+#endif
=== sys/dev/usb/usb_dynamic.h
==================================================================
--- sys/dev/usb/usb_dynamic.h	(revision 215656)
+++ sys/dev/usb/usb_dynamic.h	(local)
@@ -32,6 +32,7 @@
 struct usb_device;
 struct usbd_lookup_info;
 struct usb_device_request;
+struct usb_xfer;
 
 /* typedefs */
 
@@ -42,6 +43,7 @@
 typedef int		(usb_quirk_ioctl_t)(unsigned long cmd, caddr_t data,
 			    int fflag, struct thread *td);
 typedef void		(usb_temp_unsetup_t)(struct usb_device *udev);
+typedef void		(usb_pf_xfertap_t)(struct usb_xfer *, int);
 
 /* global function pointers */
 
@@ -51,11 +53,13 @@
 extern usb_test_quirk_t *usb_test_quirk_p;
 extern usb_quirk_ioctl_t *usb_quirk_ioctl_p;
 extern devclass_t usb_devclass_ptr;
+extern usb_pf_xfertap_t *usb_pf_xfertap_p;
 
 /* function prototypes */
 
 void	usb_temp_unload(void *);
 void	usb_quirk_unload(void *);
 void	usb_bus_unload(void *);
+void	usb_pf_unload(void *);
 
 #endif					/* _USB_DYNAMIC_H_ */
=== sys/dev/usb/usb_freebsd.h
==================================================================
--- sys/dev/usb/usb_freebsd.h	(revision 215656)
+++ sys/dev/usb/usb_freebsd.h	(local)
@@ -41,6 +41,7 @@
 #define	USB_HAVE_TT_SUPPORT 1
 #define	USB_HAVE_POWERD 1
 #define	USB_HAVE_MSCTEST 1
+#define	USB_HAVE_PF 1
 
 #define	USB_TD_GET_PROC(td) (td)->td_proc
 #define	USB_PROC_GET_GID(td) (td)->p_pgid
=== sys/dev/usb/usb_pf.c
==================================================================
--- sys/dev/usb/usb_pf.c	(revision 215656)
+++ sys/dev/usb/usb_pf.c	(local)
@@ -1,11 +1,12 @@
 /*-
+ * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
  * Copyright (c) 1990, 1991, 1993
  *	The Regents of the University of California.  All rights reserved.
  *
- * This code is derived from the Stanford/CMU enet packet filter,
- * (net/enet.c) distributed as part of 4.3BSD, and code contributed
- * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
- * Berkeley Laboratory.
+ * The packet filter virtual CPU machine code is derived from the
+ * Stanford/CMU enet packet filter, (net/enet.c) distributed as part
+ * of 4.3BSD, and code contributed to Berkeley by Steven McCanne and
+ * Van Jacobson both of Lawrence Berkeley Laboratory.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -34,19 +35,23 @@
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD$");
+
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/fcntl.h>
 #include <sys/malloc.h>
+#include <sys/module.h>
 #include <sys/proc.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
+#include <sys/poll.h>
 #include <net/if.h>
 
 #include <dev/usb/usb.h>
 #include <dev/usb/usbdi.h>
 #include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_ioctl.h>
 #include <dev/usb/usb_controller.h>
 #include <dev/usb/usb_core.h>
 #include <dev/usb/usb_process.h>
@@ -54,75 +59,21 @@
 #include <dev/usb/usb_bus.h>
 #include <dev/usb/usb_pf.h>
 #include <dev/usb/usb_transfer.h>
+#include <dev/usb/usb_dynamic.h>
 
 /*
- * All usbpf implementations are extracted from bpf(9) APIs and it's
- * specialized for USB packet filtering between the driver and the host
- * controller.
+ * The virtual CPU machine code has been extracted from bpf(9).
  */
 
 MALLOC_DEFINE(M_USBPF, "USBPktFilter", "USB Packet Filter");
 
-/*
- * Rotate the packet buffers in descriptor ud.  Move the store buffer into the
- * hold slot, and the free buffer ino the store slot.  Zero the length of the
- * new store buffer.  Descriptor lock should be held.
- */
-#define	USBPF_ROTATE_BUFFERS(ud)	do {				\
-	(ud)->ud_hbuf = (ud)->ud_sbuf;					\
-	(ud)->ud_hlen = (ud)->ud_slen;					\
-	(ud)->ud_sbuf = (ud)->ud_fbuf;					\
-	(ud)->ud_slen = 0;						\
-	(ud)->ud_fbuf = NULL;						\
-	usbpf_bufheld(ud);						\
-} while (0)
+MODULE_DEPEND(usb_pf, usb, 1, 1, 1);
+MODULE_VERSION(usb_pf, 1);
 
-#ifndef __i386__
-#define	USBPF_ALIGN
-#endif
+static struct mtx usbpf_global_mtx;		/* global lock */
+static TAILQ_HEAD(, usbpf_d) usbpf_filters;	/* list of filters */
+static struct cdev *usbpf_dev;			/* our character device */
 
-#ifndef USBPF_ALIGN
-#define	USBPF_EXTRACT_SHORT(p)	((u_int16_t)ntohs(*(u_int16_t *)p))
-#define	USBPF_EXTRACT_LONG(p)	(ntohl(*(u_int32_t *)p))
-#else
-#define	USBPF_EXTRACT_SHORT(p)						\
-	((u_int16_t)							\
-	    ((u_int16_t)*((u_char *)p+0)<<8|				\
-		(u_int16_t)*((u_char *)p+1)<<0))
-#define	USBPF_EXTRACT_LONG(p)						\
-	((u_int32_t)*((u_char *)p+0)<<24|				\
-	    (u_int32_t)*((u_char *)p+1)<<16|				\
-	    (u_int32_t)*((u_char *)p+2)<<8|				\
-	    (u_int32_t)*((u_char *)p+3)<<0)
-#endif
-
-/*
- * Number of scratch memory words (for USBPF_LD|USBPF_MEM and USBPF_ST).
- */
-#define	USBPF_MEMWORDS		 16
-
-/* Values for ud_state */
-#define	USBPF_IDLE		0	/* no select in progress */
-#define	USBPF_WAITING		1	/* waiting for read timeout in select */
-#define	USBPF_TIMED_OUT		2	/* read timeout has expired in select */
-
-#define	PRIUSB			26	/* interruptible */
-
-/* Frame directions */
-enum usbpf_direction {
-	USBPF_D_IN,	/* See incoming frames */
-	USBPF_D_INOUT,	/* See incoming and outgoing frames */
-	USBPF_D_OUT	/* See outgoing frames */
-};
-
-static void	usbpf_append_bytes(struct usbpf_d *, caddr_t, u_int, void *,
-		    u_int);
-static void	usbpf_attachd(struct usbpf_d *, struct usbpf_if *);
-static void	usbpf_detachd(struct usbpf_d *);
-static int	usbpf_canfreebuf(struct usbpf_d *);
-static void	usbpf_buf_reclaimed(struct usbpf_d *);
-static int	usbpf_canwritebuf(struct usbpf_d *);
-
 static	d_open_t	usbpf_open;
 static	d_read_t	usbpf_read;
 static	d_write_t	usbpf_write;
@@ -141,106 +92,7 @@
 	.d_kqfilter =	usbpf_kqfilter,
 };
 
-static LIST_HEAD(, usbpf_if)	usbpf_iflist;
-static struct mtx	usbpf_mtx;		/* global lock */
-static int usbpf_uifd_cnt;
-
-static int usbpf_bufsize = 4096;
-#define	USBPF_MINBUFSIZE 32
-#define	USBPF_MAXBUFSIZE 0x80000
-static int usbpf_maxbufsize = USBPF_MAXBUFSIZE;
-#define	USBPF_MAXINSNS 512
-static int usbpf_maxinsns = USBPF_MAXINSNS;
-
-static void
-usbpf_buffer_init(struct usbpf_d *ud)
-{
-
-	ud->ud_bufsize = usbpf_bufsize;
-}
-
-/*
- * Free USBPF kernel buffers on device close.
- */
-static void
-usbpf_buffer_free(struct usbpf_d *ud)
-{
-
-	if (ud->ud_sbuf != NULL)
-		free(ud->ud_sbuf, M_USBPF);
-	if (ud->ud_hbuf != NULL)
-		free(ud->ud_hbuf, M_USBPF);
-	if (ud->ud_fbuf != NULL)
-		free(ud->ud_fbuf, M_USBPF);
-
-#ifdef INVARIANTS
-	ud->ud_sbuf = ud->ud_hbuf = ud->ud_fbuf = (caddr_t)~0;
-#endif
-}
-
-static void
-usbpf_buffer_alloc(struct usbpf_d *ud)
-{
-
-	KASSERT(ud->ud_fbuf == NULL, ("%s: ud_fbuf != NULL", __func__));
-	KASSERT(ud->ud_sbuf == NULL, ("%s: ud_sbuf != NULL", __func__));
-	KASSERT(ud->ud_hbuf == NULL, ("%s: ud_hbuf != NULL", __func__));
-
-	ud->ud_fbuf = (caddr_t)malloc(ud->ud_bufsize, M_USBPF, M_WAITOK);
-	ud->ud_sbuf = (caddr_t)malloc(ud->ud_bufsize, M_USBPF, M_WAITOK);
-	ud->ud_hbuf = NULL;
-	ud->ud_slen = 0;
-	ud->ud_hlen = 0;
-}
-
-/*
- * Copy buffer storage to user space in read().
- */
-static int
-usbpf_buffer_uiomove(struct usbpf_d *ud, caddr_t buf, u_int len,
-    struct uio *uio)
-{
-
-	return (uiomove(buf, len, uio));
-}
-
-/*
- * Simple data copy to the current kernel buffer.
- */
-static void
-usbpf_buffer_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset,
-    void *src, u_int len)
-{
-	u_char *src_bytes;
-
-	src_bytes = (u_char *)src;
-	bcopy(src_bytes, buf + offset, len);
-}
-
-/*
- * Allocate or resize buffers.
- */
-static int
-usbpf_buffer_ioctl_sblen(struct usbpf_d *ud, u_int *i)
-{
-	u_int size;
-
-	USBPFD_LOCK(ud);
-	if (ud->ud_bif != NULL) {
-		USBPFD_UNLOCK(ud);
-		return (EINVAL);
-	}
-	size = *i;
-	if (size > usbpf_maxbufsize)
-		*i = size = usbpf_maxbufsize;
-	else if (size < USBPF_MINBUFSIZE)
-		*i = size = USBPF_MINBUFSIZE;
-	ud->ud_bufsize = size;
-	USBPFD_UNLOCK(ud);
-	return (0);
-}
-
-static const u_short	usbpf_code_map[] = {
+static const uint16_t usbpf_code_map[] = {
 	0x10ff,	/* 0x00-0x0f: 1111111100001000 */
 	0x3070,	/* 0x10-0x1f: 0000111000001100 */
 	0x3131,	/* 0x20-0x2f: 1000110010001100 */
@@ -270,7 +122,7 @@
  * The kernel needs to be able to verify an application's filter code.
  * Otherwise, a bogus program could easily crash the system.
  */
-static int
+static uint8_t
 usbpf_validate(const struct usbpf_insn *f, int len)
 {
 	register int i;
@@ -296,13 +148,13 @@
 		 * the code block.
 		 */
 		if (USBPF_CLASS(p->code) == USBPF_JMP) {
-			register u_int offset;
+			uint32_t offset;
 
 			if (p->code == (USBPF_JMP|USBPF_JA))
 				offset = p->k;
 			else
 				offset = p->jt > p->jf ? p->jt : p->jf;
-			if (offset >= (u_int)(len - i) - 1)
+			if (offset >= (uint32_t)(len - i - 1))
 				return (0);
 			continue;
 		}
@@ -325,295 +177,128 @@
 	return (USBPF_CLASS(f[len - 1].code) == USBPF_RET);
 }
 
-#ifdef _KERNEL
-#define	MINDEX(m, k) \
-{ \
-	register int len = m->m_len; \
- \
-	while (k >= len) { \
-		k -= len; \
-		m = m->m_next; \
-		if (m == 0) \
-			return (0); \
-		len = m->m_len; \
-	} \
-}
-
-static u_int16_t	m_xhalf(struct mbuf *m, usbpf_u_int32 k, int *err);
-static u_int32_t	m_xword(struct mbuf *m, usbpf_u_int32 k, int *err);
-
-static u_int32_t
-m_xword(struct mbuf *m, usbpf_u_int32 k, int *err)
-{
-	size_t len;
-	u_char *cp, *np;
-	struct mbuf *m0;
-
-	len = m->m_len;
-	while (k >= len) {
-		k -= len;
-		m = m->m_next;
-		if (m == 0)
-			goto bad;
-		len = m->m_len;
-	}
-	cp = mtod(m, u_char *) + k;
-	if (len - k >= 4) {
-		*err = 0;
-		return (USBPF_EXTRACT_LONG(cp));
-	}
-	m0 = m->m_next;
-	if (m0 == 0 || m0->m_len + len - k < 4)
-		goto bad;
-	*err = 0;
-	np = mtod(m0, u_char *);
-	switch (len - k) {
-	case 1:
-		return (((u_int32_t)cp[0] << 24) |
-		    ((u_int32_t)np[0] << 16) |
-		    ((u_int32_t)np[1] << 8)  |
-		    (u_int32_t)np[2]);
-
-	case 2:
-		return (((u_int32_t)cp[0] << 24) |
-		    ((u_int32_t)cp[1] << 16) |
-		    ((u_int32_t)np[0] << 8) |
-		    (u_int32_t)np[1]);
-
-	default:
-		return (((u_int32_t)cp[0] << 24) |
-		    ((u_int32_t)cp[1] << 16) |
-		    ((u_int32_t)cp[2] << 8) |
-		    (u_int32_t)np[0]);
-	}
-    bad:
-	*err = 1;
-	return (0);
-}
-
-static u_int16_t
-m_xhalf(struct mbuf *m, usbpf_u_int32 k, int *err)
-{
-	size_t len;
-	u_char *cp;
-	struct mbuf *m0;
-
-	len = m->m_len;
-	while (k >= len) {
-		k -= len;
-		m = m->m_next;
-		if (m == 0)
-			goto bad;
-		len = m->m_len;
-	}
-	cp = mtod(m, u_char *) + k;
-	if (len - k >= 2) {
-		*err = 0;
-		return (USBPF_EXTRACT_SHORT(cp));
-	}
-	m0 = m->m_next;
-	if (m0 == 0)
-		goto bad;
-	*err = 0;
-	return ((cp[0] << 8) | mtod(m0, u_char *)[0]);
- bad:
-	*err = 1;
-	return (0);
-}
-#endif
-
 /*
  * Execute the filter program starting at pc on the packet p
  * wirelen is the length of the original packet
  * buflen is the amount of data present
  */
-static u_int
-usbpf_filter(const struct usbpf_insn *pc, u_char *p, u_int wirelen,
-    u_int buflen)
+static uint32_t
+usbpf_filter_sub(const struct usbpf_insn *pc,
+    struct usb_page_cache *upc, uint32_t offset, uint32_t buflen)
 {
-	u_int32_t A = 0, X = 0;
-	usbpf_u_int32 k;
-	u_int32_t mem[USBPF_MEMWORDS];
+	uint32_t A = 0;
+	uint32_t X = 0;
+	uint32_t k;
+	uint32_t mem[USBPF_MEMWORDS];
+	uint8_t temp[8];
 
-	/*
-	 * XXX temporarily the filter system is disabled because currently it
-	 * could not handle the some machine code properly that leads to
-	 * kernel crash by invalid usage.
-	 */
-	return ((u_int)-1);
-
 	if (pc == NULL)
 		/*
 		 * No filter means accept all.
 		 */
-		return ((u_int)-1);
+		return ((uint32_t)-1);
 
 	--pc;
 	while (1) {
 		++pc;
 		switch (pc->code) {
-		default:
-#ifdef _KERNEL
-			return (0);
-#else
-			abort();
-#endif
-
 		case USBPF_RET|USBPF_K:
-			return ((u_int)pc->k);
+			return ((uint32_t)pc->k);
 
 		case USBPF_RET|USBPF_A:
-			return ((u_int)A);
+			return ((uint32_t)A);
 
 		case USBPF_LD|USBPF_W|USBPF_ABS:
 			k = pc->k;
-			if (k > buflen || sizeof(int32_t) > buflen - k) {
-#ifdef _KERNEL
-				int merr;
-
-				if (buflen != 0)
-					return (0);
-				A = m_xword((struct mbuf *)p, k, &merr);
-				if (merr != 0)
-					return (0);
-				continue;
-#else
+			if (k > buflen || sizeof(uint32_t) > buflen - k)
 				return (0);
-#endif
-			}
-#ifdef USBPF_ALIGN
-			if (((intptr_t)(p + k) & 3) != 0)
-				A = USBPF_EXTRACT_LONG(&p[k]);
-			else
-#endif
-				A = ntohl(*(int32_t *)(p + k));
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 4);
+
+			/* get unsigned little endian 32-bit value */
+			A = UGETDW(temp);
 			continue;
 
 		case USBPF_LD|USBPF_H|USBPF_ABS:
 			k = pc->k;
-			if (k > buflen || sizeof(int16_t) > buflen - k) {
-#ifdef _KERNEL
-				int merr;
-
-				if (buflen != 0)
-					return (0);
-				A = m_xhalf((struct mbuf *)p, k, &merr);
-				continue;
-#else
+			if (k > buflen || sizeof(uint16_t) > buflen - k)
 				return (0);
-#endif
-			}
-			A = USBPF_EXTRACT_SHORT(&p[k]);
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 2);
+
+			/* get unsigned little endian 16-bit value */
+			A = UGETW(temp);
 			continue;
 
 		case USBPF_LD|USBPF_B|USBPF_ABS:
 			k = pc->k;
-			if (k >= buflen) {
-#ifdef _KERNEL
-				struct mbuf *m;
-
-				if (buflen != 0)
-					return (0);
-				m = (struct mbuf *)p;
-				MINDEX(m, k);
-				A = mtod(m, u_char *)[k];
-				continue;
-#else
+			if (k >= buflen)
 				return (0);
-#endif
-			}
-			A = p[k];
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 1);
+
+			A = temp[0];
 			continue;
 
 		case USBPF_LD|USBPF_W|USBPF_LEN:
-			A = wirelen;
+			A = buflen;
 			continue;
 
 		case USBPF_LDX|USBPF_W|USBPF_LEN:
-			X = wirelen;
+			X = buflen;
 			continue;
 
 		case USBPF_LD|USBPF_W|USBPF_IND:
 			k = X + pc->k;
 			if (pc->k > buflen || X > buflen - pc->k ||
-			    sizeof(int32_t) > buflen - k) {
-#ifdef _KERNEL
-				int merr;
-
-				if (buflen != 0)
-					return (0);
-				A = m_xword((struct mbuf *)p, k, &merr);
-				if (merr != 0)
-					return (0);
-				continue;
-#else
+			    sizeof(uint32_t) > buflen - k)
 				return (0);
-#endif
-			}
-#ifdef USBPF_ALIGN
-			if (((intptr_t)(p + k) & 3) != 0)
-				A = USBPF_EXTRACT_LONG(&p[k]);
-			else
-#endif
-				A = ntohl(*(int32_t *)(p + k));
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 4);
+
+			/* get unsigned little endian 32-bit value */
+			A = UGETDW(temp);
 			continue;
 
 		case USBPF_LD|USBPF_H|USBPF_IND:
 			k = X + pc->k;
 			if (X > buflen || pc->k > buflen - X ||
-			    sizeof(int16_t) > buflen - k) {
-#ifdef _KERNEL
-				int merr;
-
-				if (buflen != 0)
-					return (0);
-				A = m_xhalf((struct mbuf *)p, k, &merr);
-				if (merr != 0)
-					return (0);
-				continue;
-#else
+			    sizeof(uint16_t) > buflen - k)
 				return (0);
-#endif
-			}
-			A = USBPF_EXTRACT_SHORT(&p[k]);
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 2);
+
+			/* get unsigned little endian 16-bit value */
+			A = UGETW(temp);
 			continue;
 
 		case USBPF_LD|USBPF_B|USBPF_IND:
 			k = X + pc->k;
-			if (pc->k >= buflen || X >= buflen - pc->k) {
-#ifdef _KERNEL
-				struct mbuf *m;
-
-				if (buflen != 0)
-					return (0);
-				m = (struct mbuf *)p;
-				MINDEX(m, k);
-				A = mtod(m, u_char *)[k];
-				continue;
-#else
+			if (pc->k >= buflen || X >= buflen - pc->k)
 				return (0);
-#endif
-			}
-			A = p[k];
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 1);
+
+			/* get 8-bit value */
+			A = temp[0];
 			continue;
 
 		case USBPF_LDX|USBPF_MSH|USBPF_B:
 			k = pc->k;
-			if (k >= buflen) {
-#ifdef _KERNEL
-				register struct mbuf *m;
-
-				if (buflen != 0)
-					return (0);
-				m = (struct mbuf *)p;
-				MINDEX(m, k);
-				X = (mtod(m, u_char *)[k] & 0xf) << 2;
-				continue;
-#else
+			if (k >= buflen)
 				return (0);
-#endif
-			}
-			X = (p[pc->k] & 0xf) << 2;
+
+			/* get the actual data */
+			usbd_copy_out(upc, offset + k, &temp, 1);
+
+			/* get 4-bit value */
+			X = (temp[0] & 0xf) << 2;
 			continue;
 
 		case USBPF_LD|USBPF_IMM:
@@ -753,51 +438,39 @@
 		case USBPF_MISC|USBPF_TXA:
 			A = X;
 			continue;
+		default:
+			return (0);
 		}
 	}
 }
 
-static void
-usbpf_free(struct usbpf_d *ud)
+static uint8_t
+usbpf_filter(struct usbpf_d *ud, struct usbpf_pkthdr_first *hdr)
 {
+	if (ud->ud_running == 0)
+		return (0);
 
-	switch (ud->ud_bufmode) {
-	case USBPF_BUFMODE_BUFFER:
-		return (usbpf_buffer_free(ud));
-	default:
-		panic("usbpf_buf_free");
-	}
-}
+	/* match bus unit */
+	if (ud->ud_filter.ua_bus_unit != USBPF_IFREQ_ANY &&
+	    ud->ud_filter.ua_bus_unit != hdr->up_busunit)
+		return (0);
 
-/*
- * Notify the buffer model that a buffer has moved into the hold position.
- */
-static void
-usbpf_bufheld(struct usbpf_d *ud)
-{
+	/* match device unit (this is not the device address) */
+	if (ud->ud_filter.ua_dev_unit != USBPF_IFREQ_ANY &&
+	    ud->ud_filter.ua_dev_unit != hdr->up_devunit)
+		return (0);
 
-	USBPFD_LOCK_ASSERT(ud);
-}
+	/* match endpoint */
+	if (ud->ud_filter.ua_endpoint_mask != USBPF_IFREQ_ANY) {
+		uint8_t shift;
 
-/*
- * Free buffers currently in use by a descriptor.
- * Called on close.
- */
-static void
-usbpf_freed(struct usbpf_d *ud)
-{
+		shift = (2 * (hdr->up_endpoint & UE_ADDR)) |
+		    ((hdr->up_endpoint & (UE_DIR_IN | UE_DIR_OUT)) ? 1 : 0);
 
-	/*
-	 * We don't need to lock out interrupts since this descriptor has
-	 * been detached from its interface and it yet hasn't been marked
-	 * free.
-	 */
-	usbpf_free(ud);
-	if (ud->ud_rfilter != NULL)
-		free((caddr_t)ud->ud_rfilter, M_USBPF);
-	if (ud->ud_wfilter != NULL)
-		free((caddr_t)ud->ud_wfilter, M_USBPF);
-	mtx_destroy(&ud->ud_mtx);
+		if (!(ud->ud_filter.ua_endpoint_mask & (1U << shift)))
+			return (0);
+	}
+	return (1);	/* accept */
 }
 
 /*
@@ -808,28 +481,32 @@
 usbpf_dtor(void *data)
 {
 	struct usbpf_d *ud = data;
+	struct usbpf_pkthdr *phdr;
 
-	USBPFD_LOCK(ud);
-	if (ud->ud_state == USBPF_WAITING)
-		callout_stop(&ud->ud_callout);
-	ud->ud_state = USBPF_IDLE;
-	USBPFD_UNLOCK(ud);
-	funsetown(&ud->ud_sigio);
-	mtx_lock(&usbpf_mtx);
-	if (ud->ud_bif)
-		usbpf_detachd(ud);
-	mtx_unlock(&usbpf_mtx);
-	selwakeuppri(&ud->ud_sel, PRIUSB);
+	USBPFD_GLOBAL_LOCK();
+
+	ud->ud_running = 0;
+
+	while ((phdr = TAILQ_FIRST(&ud->ud_head)) != NULL) {
+		TAILQ_REMOVE(&ud->ud_head, phdr, reserved.entry);
+		ud->ud_queue_len--;
+		free(phdr, M_USBPF);
+	}
+
+	TAILQ_REMOVE(&usbpf_filters, ud, ud_next);
+
+	USBPFD_GLOBAL_UNLOCK();
+
+	selwakeup(&ud->ud_sel);
+
 	knlist_destroy(&ud->ud_sel.si_note);
-	callout_drain(&ud->ud_callout);
-	usbpf_freed(ud);
+
+	if (ud->ud_filter_code)
+		free(ud->ud_filter_code, M_USBPF);
+
 	free(ud, M_USBPF);
 }
 
-/*
- * Open device.  Returns ENXIO for illegal minor device number,
- * EBUSY if file is open by another process.
- */
 /* ARGSUSED */
 static	int
 usbpf_open(struct cdev *dev, int flags, int fmt, struct thread *td)
@@ -844,25 +521,15 @@
 		return (error);
 	}
 
-	usbpf_buffer_init(ud);
-	ud->ud_bufmode = USBPF_BUFMODE_BUFFER;
-	ud->ud_sig = SIGIO;
-	ud->ud_direction = USBPF_D_INOUT;
-	ud->ud_pid = td->td_proc->p_pid;
-	mtx_init(&ud->ud_mtx, devtoname(dev), "usbpf cdev lock", MTX_DEF);
-	callout_init_mtx(&ud->ud_callout, &ud->ud_mtx, 0);
-	knlist_init_mtx(&ud->ud_sel.si_note, &ud->ud_mtx);
+	TAILQ_INIT(&ud->ud_head);
 
-	return (0);
-}
+	knlist_init_mtx(&ud->ud_sel.si_note, &usbpf_global_mtx);
 
-static int
-usbpf_uiomove(struct usbpf_d *ud, caddr_t buf, u_int len, struct uio *uio)
-{
+	USBPFD_GLOBAL_LOCK();
+	TAILQ_INSERT_TAIL(&usbpf_filters, ud, ud_next);
+	USBPFD_GLOBAL_UNLOCK();
 
-	if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER)
-		return (EOPNOTSUPP);
-	return (usbpf_buffer_uiomove(ud, buf, len, uio));
+	return (0);
 }
 
 /*
@@ -872,120 +539,75 @@
 usbpf_read(struct cdev *dev, struct uio *uio, int ioflag)
 {
 	struct usbpf_d *ud;
+	struct usbpf_pkthdr *phdr;
 	int error;
 	int non_block;
-	int timed_out;
+	int moved_data;
 
 	error = devfs_get_cdevpriv((void **)&ud);
 	if (error != 0)
 		return (error);
 
-	/*
-	 * Restrict application to use a buffer the same size as
-	 * as kernel buffers.
-	 */
-	if (uio->uio_resid != ud->ud_bufsize)
-		return (EINVAL);
-
 	non_block = ((ioflag & O_NONBLOCK) != 0);
+	moved_data = 0;
 
-	USBPFD_LOCK(ud);
-	ud->ud_pid = curthread->td_proc->p_pid;
-	if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER) {
-		USBPFD_UNLOCK(ud);
-		return (EOPNOTSUPP);
-	}
-	if (ud->ud_state == USBPF_WAITING)
-		callout_stop(&ud->ud_callout);
-	timed_out = (ud->ud_state == USBPF_TIMED_OUT);
-	ud->ud_state = USBPF_IDLE;
-	/*
-	 * If the hold buffer is empty, then do a timed sleep, which
-	 * ends when the timeout expires or when enough packets
-	 * have arrived to fill the store buffer.
-	 */
-	while (ud->ud_hbuf == NULL) {
-		if (ud->ud_slen != 0) {
-			/*
-			 * A packet(s) either arrived since the previous
-			 * read or arrived while we were asleep.
-			 */
-			if (ud->ud_immediate || non_block || timed_out) {
-				/*
-				 * Rotate the buffers and return what's here
-				 * if we are in immediate mode, non-blocking
-				 * flag is set, or this descriptor timed out.
-				 */
-				USBPF_ROTATE_BUFFERS(ud);
+	USBPFD_GLOBAL_LOCK();
+
+	while (1) {
+		while ((phdr = TAILQ_FIRST(&ud->ud_head)) != NULL) {
+
+			int totlen;
+
+			totlen = le32toh(phdr->hdr.up_totlen);
+
+			if (uio->uio_resid >= totlen) {
+
+				TAILQ_REMOVE(&ud->ud_head, phdr, reserved.entry);
+				ud->ud_queue_len--;
+
+				memset(&phdr->reserved.entry, 0, sizeof(phdr->reserved.entry));
+
+				USBPFD_GLOBAL_UNLOCK();
+
+				error = uiomove(phdr, totlen, uio);
+
+				USBPFD_GLOBAL_LOCK();
+
+				free(phdr, M_USBPF);
+
+				moved_data = 1;
+
+				if (error)
+					break;
+
+			} else if (moved_data == 0) {
+
+				/* size too big */
+
+				ud->ud_dcount++;
+
+				TAILQ_REMOVE(&ud->ud_head, phdr, reserved.entry);
+				ud->ud_queue_len--;
+
+				free(phdr, M_USBPF);
+			} else {
 				break;
 			}
 		}
 
-		/*
-		 * No data is available, check to see if the usbpf device
-		 * is still pointed at a real interface.  If not, return
-		 * ENXIO so that the userland process knows to rebind
-		 * it before using it again.
-		 */
-		if (ud->ud_bif == NULL) {
-			USBPFD_UNLOCK(ud);
-			return (ENXIO);
-		}
+		if (moved_data || non_block || ud->ud_running == 0)
+			break;
 
-		if (non_block) {
-			USBPFD_UNLOCK(ud);
-			return (EWOULDBLOCK);
-		}
-		error = msleep(ud, &ud->ud_mtx, PRIUSB|PCATCH,
-		    "uff", ud->ud_rtout);
-		if (error == EINTR || error == ERESTART) {
-			USBPFD_UNLOCK(ud);
-			return (error);
-		}
-		if (error == EWOULDBLOCK) {
-			/*
-			 * On a timeout, return what's in the buffer,
-			 * which may be nothing.  If there is something
-			 * in the store buffer, we can rotate the buffers.
-			 */
-			if (ud->ud_hbuf)
-				/*
-				 * We filled up the buffer in between
-				 * getting the timeout and arriving
-				 * here, so we don't need to rotate.
-				 */
-				break;
+		error = msleep(ud, &usbpf_global_mtx, PCATCH, "upf", ud->ud_rtout);
 
-			if (ud->ud_slen == 0) {
-				USBPFD_UNLOCK(ud);
-				return (0);
-			}
-			USBPF_ROTATE_BUFFERS(ud);
+		if (error || ud->ud_running == 0)
 			break;
-		}
 	}
-	/*
-	 * At this point, we know we have something in the hold slot.
-	 */
-	USBPFD_UNLOCK(ud);
 
-	/*
-	 * Move data from hold buffer into user space.
-	 * We know the entire buffer is transferred since
-	 * we checked above that the read buffer is usbpf_bufsize bytes.
-	 *
-	 * XXXRW: More synchronization needed here: what if a second thread
-	 * issues a read on the same fd at the same time?  Don't want this
-	 * getting invalidated.
-	 */
-	error = usbpf_uiomove(ud, ud->ud_hbuf, ud->ud_hlen, uio);
+	if (ud->ud_running == 0)
+		error = EINVAL;
 
-	USBPFD_LOCK(ud);
-	ud->ud_fbuf = ud->ud_hbuf;
-	ud->ud_hbuf = NULL;
-	ud->ud_hlen = 0;
-	usbpf_buf_reclaimed(ud);
-	USBPFD_UNLOCK(ud);
+	USBPFD_GLOBAL_UNLOCK();
 
 	return (error);
 }
@@ -998,141 +620,58 @@
 	return (ENOSYS);
 }
 
-static int
-usbpf_ioctl_sblen(struct usbpf_d *ud, u_int *i)
-{
-
-	if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER)
-		return (EOPNOTSUPP);
-	return (usbpf_buffer_ioctl_sblen(ud, i));
-}
-
-/*
- * Reset a descriptor by flushing its packet buffer and clearing the receive
- * and drop counts.  This is doable for kernel-only buffers, but with
- * zero-copy buffers, we can't write to (or rotate) buffers that are
- * currently owned by userspace.  It would be nice if we could encapsulate
- * this logic in the buffer code rather than here.
- */
 static void
 usbpf_reset_d(struct usbpf_d *ud)
 {
+	USBPFD_GLOBAL_ASSERT_LOCKED();
 
-	USBPFD_LOCK_ASSERT(ud);
-
-	if ((ud->ud_hbuf != NULL) &&
-	    (ud->ud_bufmode != USBPF_BUFMODE_ZBUF || usbpf_canfreebuf(ud))) {
-		/* Free the hold buffer. */
-		ud->ud_fbuf = ud->ud_hbuf;
-		ud->ud_hbuf = NULL;
-		ud->ud_hlen = 0;
-		usbpf_buf_reclaimed(ud);
-	}
-	if (usbpf_canwritebuf(ud))
-		ud->ud_slen = 0;
 	ud->ud_rcount = 0;
 	ud->ud_dcount = 0;
-	ud->ud_fcount = 0;
-	ud->ud_wcount = 0;
-	ud->ud_wfcount = 0;
-	ud->ud_wdcount = 0;
-	ud->ud_zcopy = 0;
 }
 
 static int
 usbpf_setif(struct usbpf_d *ud, struct usbpf_ifreq *ufr)
 {
-	struct usbpf_if *uif;
-	struct usb_bus *theywant;
+	struct usbpf_insn *pfilt;
+	struct usbpf_insn *ofilt;
+	uint32_t lfilt;
+	uint32_t size;
 
-	theywant = usb_bus_find(ufr->ufr_name);
-	if (theywant == NULL || theywant->uif == NULL)
-		return (ENXIO);
+	if (ufr->ua_filter_len != 0) {
+		lfilt = ufr->ua_filter_len;
+		if (lfilt > USBPF_MAX_FILTER)
+			return (E2BIG);
+		size = lfilt * sizeof(struct usbpf_insn);
+		pfilt = malloc(size, M_USBPF, M_WAITOK);
+		if (pfilt == NULL)
+			return (ENOMEM);
+		if (copyin(ufr->ua_filter_ptr, pfilt, size) != 0) {
+			free(pfilt, M_USBPF);
+			return (EFAULT);
+		}
+		if (usbpf_validate(pfilt, lfilt) != 0) {
+			free(pfilt, M_USBPF);
+			return (EINVAL);
+		}
+	} else {
+		pfilt = NULL;
+	}
 
-	uif = theywant->uif;
+	USBPFD_GLOBAL_LOCK();
 
-	switch (ud->ud_bufmode) {
-	case USBPF_BUFMODE_BUFFER:
-		if (ud->ud_sbuf == NULL)
-			usbpf_buffer_alloc(ud);
-		KASSERT(ud->ud_sbuf != NULL, ("%s: ud_sbuf == NULL", __func__));
-		break;
+	ofilt = ud->ud_filter_code;
+	ud->ud_filter_code = pfilt;
 
-	default:
-		panic("usbpf_setif: bufmode %d", ud->ud_bufmode);
-	}
-	if (uif != ud->ud_bif) {
-		if (ud->ud_bif)
-			/*
-			 * Detach if attached to something else.
-			 */
-			usbpf_detachd(ud);
+	ud->ud_filter = *ufr;
+	ud->ud_running = 1;
 
-		usbpf_attachd(ud, uif);
-	}
-	USBPFD_LOCK(ud);
 	usbpf_reset_d(ud);
-	USBPFD_UNLOCK(ud);
-	return (0);
-}
 
-/*
- * Set d's packet filter program to fp.  If this file already has a filter,
- * free it and replace it.  Returns EINVAL for bogus requests.
- */
-static int
-usbpf_setf(struct usbpf_d *ud, struct usbpf_program *fp, u_long cmd)
-{
-	struct usbpf_insn *fcode, *old;
-	u_int wfilter, flen, size;
+	USBPFD_GLOBAL_UNLOCK();
 
-	if (cmd == UIOCSETWF) {
-		old = ud->ud_wfilter;
-		wfilter = 1;
-	} else {
-		wfilter = 0;
-		old = ud->ud_rfilter;
-	}
-	if (fp->uf_insns == NULL) {
-		if (fp->uf_len != 0)
-			return (EINVAL);
-		USBPFD_LOCK(ud);
-		if (wfilter)
-			ud->ud_wfilter = NULL;
-		else {
-			ud->ud_rfilter = NULL;
-			if (cmd == UIOCSETF)
-				usbpf_reset_d(ud);
-		}
-		USBPFD_UNLOCK(ud);
-		if (old != NULL)
-			free((caddr_t)old, M_USBPF);
-		return (0);
-	}
-	flen = fp->uf_len;
-	if (flen > usbpf_maxinsns)
-		return (EINVAL);
+	free(ofilt, M_USBPF);
 
-	size = flen * sizeof(*fp->uf_insns);
-	fcode = (struct usbpf_insn *)malloc(size, M_USBPF, M_WAITOK);
-	if (copyin((caddr_t)fp->uf_insns, (caddr_t)fcode, size) == 0 &&
-	    usbpf_validate(fcode, (int)flen)) {
-		USBPFD_LOCK(ud);
-		if (wfilter)
-			ud->ud_wfilter = fcode;
-		else {
-			ud->ud_rfilter = fcode;
-			if (cmd == UIOCSETF)
-				usbpf_reset_d(ud);
-		}
-		USBPFD_UNLOCK(ud);
-		if (old != NULL)
-			free((caddr_t)old, M_USBPF);
-
-		return (0);
-	}
-	free((caddr_t)fcode, M_USBPF);
-	return (EINVAL);
+	return (0);
 }
 
 static int
@@ -1146,55 +685,15 @@
 	if (error != 0)
 		return (error);
 
-	/*
-	 * Refresh PID associated with this descriptor.
-	 */
-	USBPFD_LOCK(ud);
-	ud->ud_pid = td->td_proc->p_pid;
-	if (ud->ud_state == USBPF_WAITING)
-		callout_stop(&ud->ud_callout);
-	ud->ud_state = USBPF_IDLE;
-	USBPFD_UNLOCK(ud);
-
-	if (ud->ud_locked == 1) {
-		switch (cmd) {
-		case UIOCGBLEN:
-		case UIOCSBLEN:
-		case UIOCVERSION:
-			break;
-		default:
-			return (EPERM);
-		}
-	}
-
 	switch (cmd) {
-
-	default:
-		error = EINVAL;
-		break;
-
 	/*
-	 * Get buffer len [for read()].
+	 * Get maximum data length including packet header.
 	 */
 	case UIOCGBLEN:
-		*(u_int *)addr = ud->ud_bufsize;
+		*(long *)addr = USBPF_MAX_BUFFER_LEN;
 		break;
 
 	/*
-	 * Set buffer length.
-	 */
-	case UIOCSBLEN:
-		error = usbpf_ioctl_sblen(ud, (u_int *)addr);
-		break;
-
-	/*
-	 * Set read filter.
-	 */
-	case UIOCSETF:
-		error = usbpf_setf(ud, (struct usbpf_program *)addr, cmd);
-		break;
-
-	/*
 	 * Set read timeout.
 	 */
 	case UIOCSRTIMEOUT:
@@ -1229,7 +728,6 @@
 		{
 			struct usbpf_stat *us = (struct usbpf_stat *)addr;
 
-			/* XXXCSJP overflow */
 			us->us_recv = ud->ud_rcount;
 			us->us_drop = ud->ud_dcount;
 			break;
@@ -1251,6 +749,9 @@
 		error = usbpf_setif(ud, (struct usbpf_ifreq *)addr);
 		break;
 
+	default:
+		error = ENOTTY;
+		break;
 	}
 	return (error);
 }
@@ -1264,9 +765,9 @@
 static int
 usbpf_poll(struct cdev *dev, int events, struct thread *td)
 {
-
 	/* NOT IMPLEMENTED */
-	return (ENOSYS);
+	/* NOTE: This function does not return an error code! */
+	return (events & (POLLHUP | POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM));
 }
 
 /*
@@ -1282,581 +783,319 @@
 }
 
 /*
- * Attach file to the usbpf interface, i.e. make d listen on bp.
+ * If there are processes sleeping on this descriptor, wake them up.
  */
 static void
-usbpf_attachd(struct usbpf_d *ud, struct usbpf_if *uif)
+usbpf_wakeup(struct usbpf_d *ud)
 {
+	USBPFD_GLOBAL_ASSERT_LOCKED();
 
-	USBPFIF_LOCK(uif);
-	ud->ud_bif = uif;
-	LIST_INSERT_HEAD(&uif->uif_dlist, ud, ud_next);
+	wakeup(ud);
 
-	usbpf_uifd_cnt++;
-	USBPFIF_UNLOCK(uif);
-}
+	selwakeup(&ud->ud_sel);
 
-/*
- * Detach a file from its interface.
- */
-static void
-usbpf_detachd(struct usbpf_d *ud)
-{
-	struct usbpf_if *uif;
-	struct usb_bus *ubus;
-
-	uif = ud->ud_bif;
-	USBPFIF_LOCK(uif);
-	USBPFD_LOCK(ud);
-	ubus = ud->ud_bif->uif_ubus;
-
-	/*
-	 * Remove d from the interface's descriptor list.
-	 */
-	LIST_REMOVE(ud, ud_next);
-
-	usbpf_uifd_cnt--;
-	ud->ud_bif = NULL;
-	USBPFD_UNLOCK(ud);
-	USBPFIF_UNLOCK(uif);
+	KNOTE_LOCKED(&ud->ud_sel.si_note, 0);
 }
 
-void
-usbpf_attach(struct usb_bus *ubus, struct usbpf_if **driverp)
+static uint32_t
+usbpf_get_xfer_flags(struct usb_xfer *xfer, uint32_t frame)
 {
-	struct usbpf_if *uif;
+	uint32_t temp = 0;
+	uint8_t isread;
 
-	uif = malloc(sizeof(*uif), M_USBPF, M_WAITOK | M_ZERO);
-	LIST_INIT(&uif->uif_dlist);
-	uif->uif_ubus = ubus;
-	mtx_init(&uif->uif_mtx, "usbpf interface lock", NULL, MTX_DEF);
-	KASSERT(*driverp == NULL,
-	    ("usbpf_attach: driverp already initialized"));
-	*driverp = uif;
+	if ((frame == 0) && xfer->flags_int.control_xfr &&
+	    xfer->flags_int.control_hdr) {
+		/* special case */
+		if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) {
+			/* The device controller writes to memory */
+			isread = 1;
+		} else {
+			/* The host controller reads from memory */
+			isread = 0;
+		}
+	} else {
+		isread = USB_GET_DATA_ISREAD(xfer);
+	}
 
-	mtx_lock(&usbpf_mtx);
-	LIST_INSERT_HEAD(&usbpf_iflist, uif, uif_next);
-	mtx_unlock(&usbpf_mtx);
+	if (isread)
+		temp |= USBPF_XFERFLAG_READ;
+	if (xfer->flags.short_xfer_ok)
+		temp |= USBPF_XFERFLAG_SHORT_OK;
+	if (xfer->flags.short_frames_ok)
+		temp |= USBPF_XFERFLAG_MULTI_SHORT_OK;
+	if (xfer->flags.force_short_xfer)
+		temp |= USBPF_XFERFLAG_FORCE_SHORT;
+	if (xfer->flags.stall_pipe)
+		temp |= USBPF_XFERFLAG_STALL_PIPE;
+	if (xfer->flags_int.control_act == 1)
+		temp |= USBPF_XFERFLAG_CONTROL_ACT;
 
-	if (bootverbose)
-		device_printf(ubus->parent, "usbpf attached\n");
+	return (temp);
 }
 
-/*
- * If there are processes sleeping on this descriptor, wake them up.
- */
-static __inline void
-usbpf_wakeup(struct usbpf_d *ud)
+static void
+usbpf_xfertap_sub(struct usb_xfer *xfer, struct usbpf_d *ud,
+    struct usbpf_pkthdr_first *fhdr, int type)
 {
+	struct usbpf_pkthdr *hdr;
+	uint32_t *ptr;
+	uint32_t x;
+	uint32_t offset;
+	uint32_t frame;
+	uint32_t filter_length;
 
-	USBPFD_LOCK_ASSERT(ud);
-	if (ud->ud_state == USBPF_WAITING) {
-		callout_stop(&ud->ud_callout);
-		ud->ud_state = USBPF_IDLE;
+	if (ud->ud_queue_len >= USBPF_MAX_QUEUE_LEN) {
+		ud->ud_dcount++;
+		return;
 	}
-	wakeup(ud);
-	if (ud->ud_async && ud->ud_sig && ud->ud_sigio)
-		pgsigio(&ud->ud_sigio, ud->ud_sig, 0);
 
-	selwakeuppri(&ud->ud_sel, PRIUSB);
-	KNOTE_LOCKED(&ud->ud_sel.si_note, 0);
-}
-
-void
-usbpf_detach(struct usb_bus *ubus)
-{
-	struct usbpf_if	*uif;
-	struct usbpf_d	*ud;
-
-	/* Locate USBPF interface information */
-	mtx_lock(&usbpf_mtx);
-	LIST_FOREACH(uif, &usbpf_iflist, uif_next) {
-		if (ubus == uif->uif_ubus)
-			break;
-	}
-
-	/* Interface wasn't attached */
-	if ((uif == NULL) || (uif->uif_ubus == NULL)) {
-		mtx_unlock(&usbpf_mtx);
-		printf("usbpf_detach: not attached\n");	/* XXX */
+	ptr = malloc(fhdr->up_totlen, M_USBPF, M_NOWAIT);
+	if (ptr == NULL) {
+		ud->ud_dcount++;
 		return;
 	}
 
-	LIST_REMOVE(uif, uif_next);
-	mtx_unlock(&usbpf_mtx);
+	hdr = (struct usbpf_pkthdr *)ptr;
 
-	while ((ud = LIST_FIRST(&uif->uif_dlist)) != NULL) {
-		usbpf_detachd(ud);
-		USBPFD_LOCK(ud);
-		usbpf_wakeup(ud);
-		USBPFD_UNLOCK(ud);
-	}
+	/* do endian conversion of header */
 
-	mtx_destroy(&uif->uif_mtx);
-	free(uif, M_USBPF);
-}
+	hdr->hdr.up_sec = htole64(fhdr->up_sec);
+	hdr->hdr.up_frac = htole64(fhdr->up_frac);
+	hdr->hdr.up_busunit = htole32(fhdr->up_busunit);
+	hdr->hdr.up_frames = htole32(fhdr->up_frames);
+	hdr->hdr.up_hdrlen = htole32(sizeof(hdr->hdr));
+	hdr->hdr.up_interval = htole32(fhdr->up_interval);
+	hdr->hdr.up_status = htole32(fhdr->up_status);
+	hdr->hdr.up_totlen = htole32(fhdr->up_totlen);
+ 	hdr->hdr.up_error = htole32(fhdr->up_error);
+	hdr->hdr.up_packet_size = htole32(fhdr->up_packet_size);
+	hdr->hdr.up_packet_count = htole32(fhdr->up_packet_count);
+	hdr->hdr.up_devunit = fhdr->up_devunit;
+	hdr->hdr.up_dmode = fhdr->up_dmode;
+	hdr->hdr.up_endpoint = fhdr->up_endpoint;
+	hdr->hdr.up_type = fhdr->up_type;
+	hdr->hdr.up_xfertype = fhdr->up_xfertype;
 
-/* Time stamping functions */
-#define	USBPF_T_MICROTIME	0x0000
-#define	USBPF_T_NANOTIME	0x0001
-#define	USBPF_T_BINTIME		0x0002
-#define	USBPF_T_NONE		0x0003
-#define	USBPF_T_FORMAT_MASK	0x0003
-#define	USBPF_T_NORMAL		0x0000
-#define	USBPF_T_FAST		0x0100
-#define	USBPF_T_MONOTONIC	0x0200
-#define	USBPF_T_FORMAT(t)	((t) & USBPF_T_FORMAT_MASK)
+	ptr = (uint32_t *)(hdr + 1);
 
-#define	USBPF_TSTAMP_NONE	0
-#define	USBPF_TSTAMP_FAST	1
-#define	USBPF_TSTAMP_NORMAL	2
+	/* copy all data last */
 
-static int
-usbpf_ts_quality(int tstype)
-{
+	offset = 0;
+	frame = 0;
 
-	if (tstype == USBPF_T_NONE)
-		return (USBPF_TSTAMP_NONE);
-	if ((tstype & USBPF_T_FAST) != 0)
-		return (USBPF_TSTAMP_FAST);
+	for (x = 0; x != xfer->nframes; x++) {
+		uint32_t length;
+		uint32_t temp;
 
-	return (USBPF_TSTAMP_NORMAL);
-}
+		/* get length and flags */
+		length = xfer->frlengths[x];
+		temp = usbpf_get_xfer_flags(xfer, x);
 
-static int
-usbpf_gettime(struct bintime *bt, int tstype)
-{
-	int quality;
+		/* check if we need to copy any data */
+		if (temp & USBPF_XFERFLAG_READ) {
+			if (type == USBPF_XFERTAP_SUBMIT)
+				length = 0;
+		} else {
+			if (type != USBPF_XFERTAP_SUBMIT)
+				length = 0;
+		}
 
-	quality = usbpf_ts_quality(tstype);
-	if (quality == USBPF_TSTAMP_NONE)
-		return (quality);
-	if (quality == USBPF_TSTAMP_NORMAL)
-		binuptime(bt);
-	else
-		getbinuptime(bt);
+		/* fill out packet header */
+		ptr[0] = htole32(length);
+		ptr[1] = htole32(temp);
 
-	return (quality);
-}
+		/* copy USB data, if any */
+		if (length != 0) {
+			/* there is a data buffer after the length and flags */
+			ptr[1] |= htole32(USBPF_XFERFLAG_DATA_FOLLOWS);
 
-/*
- * If the buffer mechanism has a way to decide that a held buffer can be made
- * free, then it is exposed via the usbpf_canfreebuf() interface.  (1) is
- * returned if the buffer can be discarded, (0) is returned if it cannot.
- */
-static int
-usbpf_canfreebuf(struct usbpf_d *ud)
-{
+			/* run filter */
+			filter_length = usbpf_filter_sub(ud->ud_filter_code,
+			    &xfer->frbuffers[frame], offset, length);
 
-	USBPFD_LOCK_ASSERT(ud);
+			/* get actual amount of data to copy */
+			if (filter_length >= length)
+				filter_length = length;
+			else {
+				uint32_t totlen;
+				/* update total length */
+				totlen = le32toh(hdr->hdr.up_totlen);
+				totlen -= USBPF_LENGTH_ALIGN(length);
+				totlen += USBPF_LENGTH_ALIGN(filter_length);
+				hdr->hdr.up_totlen = htole32(totlen);
+			}
 
-	return (0);
-}
+			ptr[2] = htole32(filter_length);
+			ptr += USBPF_FRAMEHDR_SIZE;
 
-/*
- * Allow the buffer model to indicate that the current store buffer is
- * immutable, regardless of the appearance of space.  Return (1) if the
- * buffer is writable, and (0) if not.
- */
-static int
-usbpf_canwritebuf(struct usbpf_d *ud)
-{
+			/* zero-pad the last 32-bits in case of aligment */
+			ptr[(filter_length - 1) / 4] = 0;
 
-	USBPFD_LOCK_ASSERT(ud);
-	return (1);
-}
+			/* copy data */
+			usbd_copy_out(&xfer->frbuffers[frame], offset, ptr, filter_length);
 
-/*
- * Notify buffer model that an attempt to write to the store buffer has
- * resulted in a dropped packet, in which case the buffer may be considered
- * full.
- */
-static void
-usbpf_buffull(struct usbpf_d *ud)
-{
+			/* align length */
+			length = USBPF_LENGTH_ALIGN(filter_length);
 
-	USBPFD_LOCK_ASSERT(ud);
-}
+			/* advance data pointer */
+			ptr += length / 4;
+		} else {
+			ptr[2] = 0;
+			ptr += USBPF_FRAMEHDR_SIZE;
+		}
 
-/*
- * This function gets called when the free buffer is re-assigned.
- */
-static void
-usbpf_buf_reclaimed(struct usbpf_d *ud)
-{
-
-	USBPFD_LOCK_ASSERT(ud);
-
-	switch (ud->ud_bufmode) {
-	case USBPF_BUFMODE_BUFFER:
-		return;
-
-	default:
-		panic("usbpf_buf_reclaimed");
+		if (xfer->flags_int.isochronous_xfr) {
+#if USB_HAVE_PF
+			offset += xfer->frlengths[x + xfer->max_frame_count];
+#endif
+		} else {
+			frame ++;
+		}
 	}
-}
 
-#define	SIZEOF_USBPF_HDR(type)	\
-    (offsetof(type, uh_hdrlen) + sizeof(((type *)0)->uh_hdrlen))
+	/* clear reserved area */
+	memset(&hdr->reserved, 0, sizeof(hdr->reserved));
 
-static int
-usbpf_hdrlen(struct usbpf_d *ud)
-{
-	int hdrlen;
+	/* enqueue header */
+	TAILQ_INSERT_TAIL(&ud->ud_head, hdr, reserved.entry);
+	ud->ud_queue_len++;
 
-	hdrlen = ud->ud_bif->uif_hdrlen;
-	hdrlen += SIZEOF_USBPF_HDR(struct usbpf_xhdr);
-	hdrlen = USBPF_WORDALIGN(hdrlen);
-
-	return (hdrlen - ud->ud_bif->uif_hdrlen);
+	/* wakeup any sleeping receiver */
+	usbpf_wakeup(ud);
 }
 
 static void
-usbpf_bintime2ts(struct bintime *bt, struct usbpf_ts *ts, int tstype)
+usbpf_xfertap(struct usb_xfer *xfer, int type)
 {
-	struct bintime bt2;
+	struct usbpf_pkthdr_first fhdr;
+	struct usb_xfer_root *info;
+	struct usb_bus *bus;
+	struct usbpf_d *ud;
 	struct timeval tsm;
-	struct timespec tsn;
+	struct bintime bt;
+	uint32_t totlen;
+	uint32_t x;
 
-	if ((tstype & USBPF_T_MONOTONIC) == 0) {
-		bt2 = *bt;
-		bintime_add(&bt2, &boottimebin);
-		bt = &bt2;
+	USBPFD_GLOBAL_LOCK();
+	if (TAILQ_FIRST(&usbpf_filters) == NULL) {
+		USBPFD_GLOBAL_UNLOCK();
+		/* no filters no work */
+		return;
 	}
-	switch (USBPF_T_FORMAT(tstype)) {
-	case USBPF_T_MICROTIME:
-		bintime2timeval(bt, &tsm);
-		ts->ut_sec = tsm.tv_sec;
-		ts->ut_frac = tsm.tv_usec;
-		break;
-	case USBPF_T_NANOTIME:
-		bintime2timespec(bt, &tsn);
-		ts->ut_sec = tsn.tv_sec;
-		ts->ut_frac = tsn.tv_nsec;
-		break;
-	case USBPF_T_BINTIME:
-		ts->ut_sec = bt->sec;
-		ts->ut_frac = bt->frac;
-		break;
-	}
-}
 
-/*
- * Move the packet data from interface memory (pkt) into the
- * store buffer.  "cpfn" is the routine called to do the actual data
- * transfer.  bcopy is passed in to copy contiguous chunks, while
- * usbpf_append_mbuf is passed in to copy mbuf chains.  In the latter case,
- * pkt is really an mbuf.
- */
-static void
-catchpacket(struct usbpf_d *ud, u_char *pkt, u_int pktlen, u_int snaplen,
-    void (*cpfn)(struct usbpf_d *, caddr_t, u_int, void *, u_int),
-    struct bintime *bt)
-{
-	struct usbpf_xhdr hdr;
-	int caplen, curlen, hdrlen, totlen;
-	int do_wakeup = 0;
-	int do_timestamp;
-	int tstype;
+	info = xfer->xroot;
+	bus = info->bus;
 
-	USBPFD_LOCK_ASSERT(ud);
-
-	/*
-	 * Detect whether user space has released a buffer back to us, and if
-	 * so, move it from being a hold buffer to a free buffer.  This may
-	 * not be the best place to do it (for example, we might only want to
-	 * run this check if we need the space), but for now it's a reliable
-	 * spot to do it.
+	/* 
+	 * It would be better to get the 125us-frame
+	 * count from the USB hardware.
 	 */
-	if (ud->ud_fbuf == NULL && usbpf_canfreebuf(ud)) {
-		ud->ud_fbuf = ud->ud_hbuf;
-		ud->ud_hbuf = NULL;
-		ud->ud_hlen = 0;
-		usbpf_buf_reclaimed(ud);
-	}
+	getbinuptime(&bt);
+	bintime2timeval(&bt, &tsm);
 
-	/*
-	 * Figure out how many bytes to move.  If the packet is
-	 * greater or equal to the snapshot length, transfer that
-	 * much.  Otherwise, transfer the whole packet (unless
-	 * we hit the buffer size limit).
-	 */
-	hdrlen = usbpf_hdrlen(ud);
-	totlen = hdrlen + min(snaplen, pktlen);
-	if (totlen > ud->ud_bufsize)
-		totlen = ud->ud_bufsize;
+	/* timestamp */
+	fhdr.up_sec = tsm.tv_sec;
+	fhdr.up_frac = tsm.tv_usec;
 
-	/*
-	 * Round up the end of the previous packet to the next longword.
-	 *
-	 * Drop the packet if there's no room and no hope of room
-	 * If the packet would overflow the storage buffer or the storage
-	 * buffer is considered immutable by the buffer model, try to rotate
-	 * the buffer and wakeup pending processes.
-	 */
-	curlen = USBPF_WORDALIGN(ud->ud_slen);
-	if (curlen + totlen > ud->ud_bufsize || !usbpf_canwritebuf(ud)) {
-		if (ud->ud_fbuf == NULL) {
-			/*
-			 * There's no room in the store buffer, and no
-			 * prospect of room, so drop the packet.  Notify the
-			 * buffer model.
-			 */
-			usbpf_buffull(ud);
-			++ud->ud_dcount;
-			return;
-		}
-		USBPF_ROTATE_BUFFERS(ud);
-		do_wakeup = 1;
-		curlen = 0;
-	} else if (ud->ud_immediate || ud->ud_state == USBPF_TIMED_OUT)
-		/*
-		 * Immediate mode is set, or the read timeout has already
-		 * expired during a select call.  A packet arrived, so the
-		 * reader should be woken up.
-		 */
-		do_wakeup = 1;
-	caplen = totlen - hdrlen;
-	tstype = ud->ud_tstamp;
-	do_timestamp = tstype != USBPF_T_NONE;
+	/* transfer information */
+	fhdr.up_busunit = device_get_unit(bus->bdev);
+	fhdr.up_interval = xfer->interval;
+	fhdr.up_status = xfer->usb_state;
+	fhdr.up_packet_size = xfer->max_packet_size;
+	fhdr.up_packet_count = xfer->max_packet_count;
+	fhdr.up_frames = xfer->nframes;
 
-	/*
-	 * Append the usbpf header.  Note we append the actual header size, but
-	 * move forward the length of the header plus padding.
-	 */
-	bzero(&hdr, sizeof(hdr));
-	if (do_timestamp)
-		usbpf_bintime2ts(bt, &hdr.uh_tstamp, tstype);
-	hdr.uh_datalen = pktlen;
-	hdr.uh_hdrlen = hdrlen;
-	hdr.uh_caplen = caplen;
-	usbpf_append_bytes(ud, ud->ud_sbuf, curlen, &hdr, sizeof(hdr));
+	/* compute total header overhead length */
+	totlen = USBPF_PKTHDR_SIZE + ((USBPF_FRAMEHDR_SIZE * 4) * xfer->nframes);
 
-	/*
-	 * Copy the packet data into the store buffer and update its length.
-	 */
-	(*cpfn)(ud, ud->ud_sbuf, curlen + hdrlen, pkt, caplen);
-	ud->ud_slen = curlen + totlen;
+	/* precompute all trace lengths */
+	for (x = 0; x != xfer->nframes; x++) {
+		uint32_t temp;
+		temp = usbpf_get_xfer_flags(xfer, x);
 
-	if (do_wakeup)
-		usbpf_wakeup(ud);
-}
+		if (temp & USBPF_XFERFLAG_READ) {
+			if (type != USBPF_XFERTAP_SUBMIT)
+				totlen += USBPF_LENGTH_ALIGN(xfer->frlengths[x]);
+		} else {
+			if (type == USBPF_XFERTAP_SUBMIT)
+				totlen += USBPF_LENGTH_ALIGN(xfer->frlengths[x]);
+		}
+	}
 
-/*
- * Incoming linkage from device drivers.  Process the packet pkt, of length
- * pktlen, which is stored in a contiguous buffer.  The packet is parsed
- * by each process' filter, and if accepted, stashed into the corresponding
- * buffer.
- */
-static void
-usbpf_tap(struct usbpf_if *uif, u_char *pkt, u_int pktlen)
-{
-	struct bintime bt;
-	struct usbpf_d *ud;
-	u_int slen;
-	int gottime;
+	/* sanity check */
+	if (totlen >= USBPF_MAX_BUFFER_LEN) {
+		static int once;
+		USBPFD_GLOBAL_UNLOCK();
 
-	gottime = USBPF_TSTAMP_NONE;
-	USBPFIF_LOCK(uif);
-	LIST_FOREACH(ud, &uif->uif_dlist, ud_next) {
-		USBPFD_LOCK(ud);
-		++ud->ud_rcount;
-		slen = usbpf_filter(ud->ud_rfilter, pkt, pktlen, pktlen);
-		if (slen != 0) {
-			ud->ud_fcount++;
-			if (gottime < usbpf_ts_quality(ud->ud_tstamp))
-				gottime = usbpf_gettime(&bt, ud->ud_tstamp);
-			catchpacket(ud, pkt, pktlen, slen,
-			    usbpf_append_bytes, &bt);
+		if (once == 0) {
+			printf("usb_pf: Total trace length(%u) "
+			    "exceeds maximum(%u).\n",
+			    totlen, USBPF_MAX_BUFFER_LEN);
+			once = 1;
 		}
-		USBPFD_UNLOCK(ud);
+
+		/* too much data */
+		return;
 	}
-	USBPFIF_UNLOCK(uif);
-}
 
-static uint32_t
-usbpf_aggregate_xferflags(struct usb_xfer_flags *flags)
-{
-	uint32_t val = 0;
+	fhdr.up_totlen = totlen;
+	fhdr.up_error = xfer->error;
+	fhdr.up_xfertype = xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE;
+	fhdr.up_devunit = info->udev->device_index;
+	fhdr.up_endpoint = xfer->endpointno;
+	fhdr.up_dmode = (xfer->flags_int.usb_mode == USB_MODE_DEVICE);
+	fhdr.up_type = type;
 
-	if (flags->force_short_xfer == 1)
-		val |= USBPF_FLAG_FORCE_SHORT_XFER;
-	if (flags->short_xfer_ok == 1)
-		val |= USBPF_FLAG_SHORT_XFER_OK;
-	if (flags->short_frames_ok == 1)
-		val |= USBPF_FLAG_SHORT_FRAMES_OK;
-	if (flags->pipe_bof == 1)
-		val |= USBPF_FLAG_PIPE_BOF;
-	if (flags->proxy_buffer == 1)
-		val |= USBPF_FLAG_PROXY_BUFFER;
-	if (flags->ext_buffer == 1)
-		val |= USBPF_FLAG_EXT_BUFFER;
-	if (flags->manual_status == 1)
-		val |= USBPF_FLAG_MANUAL_STATUS;
-	if (flags->no_pipe_ok == 1)
-		val |= USBPF_FLAG_NO_PIPE_OK;
-	if (flags->stall_pipe == 1)
-		val |= USBPF_FLAG_STALL_PIPE;
-	return (val);
+	TAILQ_FOREACH(ud, &usbpf_filters, ud_next) {
+		if (usbpf_filter(ud, &fhdr))
+			usbpf_xfertap_sub(xfer, ud, &fhdr, type);
+	}
+
+	USBPFD_GLOBAL_UNLOCK();
 }
 
-static uint32_t
-usbpf_aggregate_status(struct usb_xfer_flags_int *flags)
+static void
+usbpf_drvinit(void *unused)
 {
-	uint32_t val = 0;
+	mtx_init(&usbpf_global_mtx, "USB packet filter global lock",
+	    NULL, MTX_DEF);
 
-	if (flags->open == 1)
-		val |= USBPF_STATUS_OPEN;
-	if (flags->transferring == 1)
-		val |= USBPF_STATUS_TRANSFERRING;
-	if (flags->did_dma_delay == 1)
-		val |= USBPF_STATUS_DID_DMA_DELAY;
-	if (flags->did_close == 1)
-		val |= USBPF_STATUS_DID_CLOSE;
-	if (flags->draining == 1)
-		val |= USBPF_STATUS_DRAINING;
-	if (flags->started == 1)
-		val |= USBPF_STATUS_STARTED;
-	if (flags->bandwidth_reclaimed == 1)
-		val |= USBPF_STATUS_BW_RECLAIMED;
-	if (flags->control_xfr == 1)
-		val |= USBPF_STATUS_CONTROL_XFR;
-	if (flags->control_hdr == 1)
-		val |= USBPF_STATUS_CONTROL_HDR;
-	if (flags->control_act == 1)
-		val |= USBPF_STATUS_CONTROL_ACT;
-	if (flags->control_stall == 1)
-		val |= USBPF_STATUS_CONTROL_STALL;
-	if (flags->short_frames_ok == 1)
-		val |= USBPF_STATUS_SHORT_FRAMES_OK;
-	if (flags->short_xfer_ok == 1)
-		val |= USBPF_STATUS_SHORT_XFER_OK;
-#if USB_HAVE_BUSDMA
-	if (flags->bdma_enable == 1)
-		val |= USBPF_STATUS_BDMA_ENABLE;
-	if (flags->bdma_no_post_sync == 1)
-		val |= USBPF_STATUS_BDMA_NO_POST_SYNC;
-	if (flags->bdma_setup == 1)
-		val |= USBPF_STATUS_BDMA_SETUP;
-#endif
-	if (flags->isochronous_xfr == 1)
-		val |= USBPF_STATUS_ISOCHRONOUS_XFR;
-	if (flags->curr_dma_set == 1)
-		val |= USBPF_STATUS_CURR_DMA_SET;
-	if (flags->can_cancel_immed == 1)
-		val |= USBPF_STATUS_CAN_CANCEL_IMMED;
-	if (flags->doing_callback == 1)
-		val |= USBPF_STATUS_DOING_CALLBACK;
+	TAILQ_INIT(&usbpf_filters);
 
-	return (val);
-}
+	usbpf_dev = make_dev(&usbpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "usbpf");
 
-void
-usbpf_xfertap(struct usb_xfer *xfer, int type)
-{
-	struct usb_endpoint *ep = xfer->endpoint;
-	struct usb_page_search res;
-	struct usb_xfer_root *info = xfer->xroot;
-	struct usb_bus *bus = info->bus;
-	struct usbpf_pkthdr *up;
-	usb_frlength_t isoc_offset = 0;
-	int i;
-	char *buf, *ptr, *end;
+	/* Set our function pointer callback */
 
-	/*
-	 * NB: usbpf_uifd_cnt isn't protected by USBPFIF_LOCK() because it's
-	 * not harmful.
-	 */
-	if (usbpf_uifd_cnt == 0)
-		return;
+	usb_pf_xfertap_p = &usbpf_xfertap;
 
-	/*
-	 * XXX TODO
-	 * Allocating the buffer here causes copy operations twice what's
-	 * really inefficient. Copying usbpf_pkthdr and data is for USB packet
-	 * read filter to pass a virtually linear buffer.
-	 */
-	buf = ptr = malloc(sizeof(struct usbpf_pkthdr) + (USB_PAGE_SIZE * 5),
-	    M_USBPF, M_NOWAIT);
-	if (buf == NULL) {
-		printf("usbpf_xfertap: out of memory\n");	/* XXX */
-		return;
-	}
-	end = buf + sizeof(struct usbpf_pkthdr) + (USB_PAGE_SIZE * 5);
+	printf("usb_pf: USB packet filter v%u.%u.\n",
+	    USBPF_MAJOR_VERSION, USBPF_MINOR_VERSION);
+}
+SYSINIT(usbpf_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvinit, NULL);
 
-	bzero(ptr, sizeof(struct usbpf_pkthdr));
-	up = (struct usbpf_pkthdr *)ptr;
-	up->up_busunit = htole32(device_get_unit(bus->bdev));
-	up->up_type = type;
-	up->up_xfertype = ep->edesc->bmAttributes & UE_XFERTYPE;
-	up->up_address = xfer->address;
-	up->up_endpoint = xfer->endpointno;
-	up->up_flags = htole32(usbpf_aggregate_xferflags(&xfer->flags));
-	up->up_status = htole32(usbpf_aggregate_status(&xfer->flags_int));
-	switch (type) {
-	case USBPF_XFERTAP_SUBMIT:
-		up->up_length = htole32(xfer->sumlen);
-		up->up_frames = htole32(xfer->nframes);
-		break;
-	case USBPF_XFERTAP_DONE:
-		up->up_length = htole32(xfer->actlen);
-		up->up_frames = htole32(xfer->aframes);
-		break;
-	default:
-		panic("wrong usbpf type (%d)", type);
-	}
+static void
+usbpf_drvuninit(void *arg)
+{
+	usb_pf_unload(arg);
 
-	up->up_error = htole32(xfer->error);
-	up->up_interval = htole32(xfer->interval);
-	ptr += sizeof(struct usbpf_pkthdr);
+	if (usbpf_dev != NULL)
+		destroy_dev(usbpf_dev);
 
-	for (i = 0; i < up->up_frames; i++) {
-		if (ptr + sizeof(u_int32_t) >= end)
-			goto done;
-		*((u_int32_t *)ptr) = htole32(xfer->frlengths[i]);
-		ptr += sizeof(u_int32_t);
+	USBPFD_GLOBAL_LOCK();
 
-		if (ptr + xfer->frlengths[i] >= end)
-			goto done;
-		if (xfer->flags_int.isochronous_xfr == 1) {
-			usbd_get_page(&xfer->frbuffers[0], isoc_offset, &res);
-			isoc_offset += xfer->frlengths[i];
-		} else
-			usbd_get_page(&xfer->frbuffers[i], 0, &res);
-		bcopy(res.buffer, ptr, xfer->frlengths[i]);
-		ptr += xfer->frlengths[i];
-	}
+	while (TAILQ_FIRST(&usbpf_filters) != NULL) {
 
-	usbpf_tap(bus->uif, buf, ptr - buf);
-done:
-	free(buf, M_USBPF);
-}
+		USBPFD_GLOBAL_UNLOCK();
 
-static void
-usbpf_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset, void *src,
-    u_int len)
-{
+		printf("usb_pf: Please close all device instances\n");
 
-	USBPFD_LOCK_ASSERT(ud);
+		pause("WAIT", 2 * hz);
 
-	switch (ud->ud_bufmode) {
-	case USBPF_BUFMODE_BUFFER:
-		return (usbpf_buffer_append_bytes(ud, buf, offset, src, len));
-	default:
-		panic("usbpf_buf_append_bytes");
+		USBPFD_GLOBAL_LOCK();
 	}
-}
 
-static void
-usbpf_drvinit(void *unused)
-{
-	struct cdev *dev;
+	USBPFD_GLOBAL_UNLOCK();
 
-	mtx_init(&usbpf_mtx, "USB packet filter global lock", NULL,
-	    MTX_DEF);
-	LIST_INIT(&usbpf_iflist);
-
-	dev = make_dev(&usbpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "usbpf");
+	mtx_destroy(&usbpf_global_mtx);
 }
-
-SYSINIT(usbpf_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvinit, NULL);
+SYSUNINIT(usbpf_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvuninit, NULL);
=== sys/dev/usb/usb_pf.h
==================================================================
--- sys/dev/usb/usb_pf.h	(revision 215656)
+++ sys/dev/usb/usb_pf.h	(local)
@@ -1,12 +1,7 @@
 /*-
- * Copyright (c) 1990, 1991, 1993
- *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2010 Weongyo Jeong. All rights reserved.
+ * Copyright (c) 2010 Hans Petter Selasky. All rights reserved.
  *
- * This code is derived from the Stanford/CMU enet packet filter,
- * (net/enet.c) distributed as part of 4.3BSD, and code contributed
- * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
- * Berkeley Laboratory.
- *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -15,9 +10,6 @@
  * 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.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
@@ -44,20 +36,53 @@
 #include <sys/conf.h>
 #endif
 
-typedef	int32_t	  usbpf_int32;
-typedef	u_int32_t usbpf_u_int32;
-typedef	int64_t	  usbpf_int64;
-typedef	u_int64_t usbpf_u_int64;
-
+struct usb_xfer;
 struct usbpf_if;
+struct usbpf_pkthdr;
 
+#define	USBPF_MAX_BUFFER_LEN (1U << 20)	/* maximum tap length */
+#define	USBPF_MAX_QUEUE_LEN 64 /* maximum number of unread transfers */
+#define	USBPF_PKTHDR_SIZE 128 /* bytes */
+#define	USBPF_LENGTH_ALIGN(x)	(((x) + 3) & ~(uint32_t)3)
+#define	USBPF_FRAMEHDR_SIZE 3 /* dwords */
+#define	USBPF_MAX_FILTER 65536 /* instructions */
+
+/* scratch size in 32-bits for (for USBPF_LD|USBPF_MEM and USBPF_ST) */
+#define	USBPF_MEMWORDS 16
+
 /*
- * Alignment macros.  USBPF_WORDALIGN rounds up to the next
- * even multiple of USBPF_ALIGNMENT.
+ * Structure prepended to each packet.
  */
-#define	USBPF_ALIGNMENT sizeof(long)
-#define	USBPF_WORDALIGN(x) (((x)+(USBPF_ALIGNMENT-1))&~(USBPF_ALIGNMENT-1))
+struct usbpf_pkthdr_first {
+	uint64_t	up_sec;		/* timestamp seconds */
+	uint64_t	up_frac;	/* timestamp fraction */
+	uint32_t	up_busunit;	/* Host controller unit number */
+	uint32_t	up_frames;	/* USB frame number (submit/actual) */
+	uint32_t	up_hdrlen;	/* total header length */
+	uint32_t	up_interval;	/* for interrupt and isoc */
+	uint32_t	up_nframes;	/* number of USB frames */
+	uint32_t	up_status;	/* transfer status */
+	uint32_t	up_totlen;	/* total packet length (including data) */
+ 	uint32_t	up_error;	/* usb_error_t */
+ 	uint32_t	up_packet_size;	/* USB packet size */
+ 	uint32_t	up_packet_count;/* USB packet count */
+	uint8_t		up_devunit;	/* USB device unit number */
+	uint8_t		up_dmode;	/* set if device mode, else host */
+	uint8_t		up_endpoint;	/* USB endpoint */
+	uint8_t		up_type;	/* type: SUBMIT or DONE */
+	uint8_t		up_xfertype;	/* USB transfer type */
+} __packed;
 
+struct usbpf_pkthdr {
+	struct usbpf_pkthdr_first hdr;
+	union {
+#ifdef _KERNEL
+		TAILQ_ENTRY(usbpf_pkthdr) entry;	/* for internal use */
+#endif
+		uint8_t dummy[USBPF_PKTHDR_SIZE - sizeof(struct usbpf_pkthdr_first)];
+	} __packed reserved;
+} __packed;
+
 /*
  * The instruction encodings.
  */
@@ -119,201 +144,93 @@
  * The instruction data structure.
  */
 struct usbpf_insn {
-	u_short		code;
-	u_char		jt;
-	u_char		jf;
-	usbpf_u_int32	k;
+	uint16_t	code;
+	uint8_t		jt;
+	uint8_t		jf;
+	uint32_t	k;
 };
 
-#ifdef _KERNEL
+struct usbpf_version {
+	uint16_t		uv_major;
+	uint16_t		uv_minor;
+};
+#define	USBPF_MAJOR_VERSION	1
+#define	USBPF_MINOR_VERSION	2
 
+struct usbpf_ifreq {
+	/* pre-filter parameters */
+	uint32_t	ua_bus_unit;		/* must match, if not ANY */
+	uint32_t	ua_dev_unit;		/* must match, if not ANY */
+	uint32_t	ua_endpoint_mask;	/* must match, if not ANY */
+#define	USBPF_IFREQ_ANY		0xFFFFFFFFU	/* ANY bus, device or endpoint unit */
+	/* post-filter parameters */
+	uint32_t	ua_filter_len;		/* number of filter entries */
+	const struct usbpf_insn	*ua_filter_ptr;
+};
+
 /*
- * Descriptor associated with each open uff file.
+ * Struct returned by UIOCGSTATS.
  */
+struct usbpf_stat {
+	uint64_t us_recv;		/* number of packets received */
+	uint64_t us_drop;		/* number of packets dropped */
+};
 
-struct usbpf_d {
-	LIST_ENTRY(usbpf_d) ud_next;	/* Linked list of descriptors */
-	/*
-	 * Buffer slots: two memory buffers store the incoming packets.
-	 *   The model has three slots.  Sbuf is always occupied.
-	 *   sbuf (store) - Receive interrupt puts packets here.
-	 *   hbuf (hold) - When sbuf is full, put buffer here and
-	 *                 wakeup read (replace sbuf with fbuf).
-	 *   fbuf (free) - When read is done, put buffer here.
-	 * On receiving, if sbuf is full and fbuf is 0, packet is dropped.
-	 */
-	caddr_t		ud_sbuf;	/* store slot */
-	caddr_t		ud_hbuf;	/* hold slot */
-	caddr_t		ud_fbuf;	/* free slot */
-	int		ud_slen;	/* current length of store buffer */
-	int		ud_hlen;	/* current length of hold buffer */
+#define	UIOCSETIF	_IOW('U', 108, struct usbpf_ifreq)
+#define	UIOCSRTIMEOUT	_IOW('U', 109, struct timeval)
+#define	UIOCGRTIMEOUT	_IOR('U', 110, struct timeval)
+#define	UIOCGSTATS	_IOR('U', 111, struct usbpf_stat)
+#define	UIOCVERSION	_IOR('U', 112, struct usbpf_version)
+#define	UIOCGBLEN	_IOR('U', 113, long)
 
-	int		ud_bufsize;	/* absolute length of buffers */
+/* definition of second parameter in usb_pf_xfertap_t function */
 
-	struct usbpf_if *ud_bif;	/* interface descriptor */
-	u_long		ud_rtout;	/* Read timeout in 'ticks' */
-	struct usbpf_insn *ud_rfilter;	/* read filter code */
-	struct usbpf_insn *ud_wfilter;	/* write filter code */
-	void		*ud_bfilter;	/* binary filter code */
-	u_int64_t	ud_rcount;	/* number of packets received */
-	u_int64_t	ud_dcount;	/* number of packets dropped */
+#define	USBPF_XFERTAP_SUBMIT	0
+#define	USBPF_XFERTAP_DONE	1
 
-	u_char		ud_promisc;	/* true if listening promiscuously */
-	u_char		ud_state;	/* idle, waiting, or timed out */
-	u_char		ud_immediate;	/* true to return on packet arrival */
-	int		ud_hdrcmplt;	/* false to fill in src lladdr automatically */
-	int		ud_direction;	/* select packet direction */
-	int		ud_tstamp;	/* select time stamping function */
-	int		ud_feedback;	/* true to feed back sent packets */
-	int		ud_async;	/* non-zero if packet reception should generate signal */
-	int		ud_sig;		/* signal to send upon packet reception */
-	struct sigio *	ud_sigio;	/* information for async I/O */
-	struct selinfo	ud_sel;		/* bsd select info */
-	struct mtx	ud_mtx;		/* mutex for this descriptor */
-	struct callout	ud_callout;	/* for USBPF timeouts with select */
-	struct label	*ud_label;	/* MAC label for descriptor */
-	u_int64_t	ud_fcount;	/* number of packets which matched filter */
-	pid_t		ud_pid;		/* PID which created descriptor */
-	int		ud_locked;	/* true if descriptor is locked */
-	u_int		ud_bufmode;	/* Current buffer mode. */
-	u_int64_t	ud_wcount;	/* number of packets written */
-	u_int64_t	ud_wfcount;	/* number of packets that matched write filter */
-	u_int64_t	ud_wdcount;	/* number of packets dropped during a write */
-	u_int64_t	ud_zcopy;	/* number of zero copy operations */
-	u_char		ud_compat32;	/* 32-bit stream on LP64 system */
-};
+/* definition of USB transfer flags */
 
-#define	USBPFD_LOCK(ud)		mtx_lock(&(ud)->ud_mtx)
-#define	USBPFD_UNLOCK(ud)	mtx_unlock(&(ud)->ud_mtx)
-#define	USBPFD_LOCK_ASSERT(ud)	mtx_assert(&(ud)->ud_mtx, MA_OWNED)
+#define	USBPF_XFERFLAG_READ		0x00000001U
+#define	USBPF_XFERFLAG_SHORT_OK		0x00000002U
+#define	USBPF_XFERFLAG_MULTI_SHORT_OK	0x00000004U
+#define	USBPF_XFERFLAG_FORCE_SHORT	0x00000008U
+#define	USBPF_XFERFLAG_STALL_PIPE	0x00000010U
+#define	USBPF_XFERFLAG_CONTROL_ACT	0x00000020U
+#define	USBPF_XFERFLAG_DATA_FOLLOWS	0x00000040U
 
+#ifdef _KERNEL
+
 /*
- * Descriptor associated with each attached hardware interface.
+ * Descriptor associated with each open upf file.
  */
-struct usbpf_if {
-	LIST_ENTRY(usbpf_if) uif_next; /* list of all interfaces */
-	LIST_HEAD(, usbpf_d) uif_dlist;	/* descriptor list */
-	u_int uif_hdrlen;		/* length of link header */
-	struct usb_bus *uif_ubus;	/* corresponding interface */
-	struct mtx	uif_mtx;	/* mutex for interface */
-};
+struct usbpf_d {
+	TAILQ_ENTRY(usbpf_d) ud_next;	/* Linked list of descriptors */
 
-#define	USBPFIF_LOCK(uif)	mtx_lock(&(uif)->uif_mtx)
-#define	USBPFIF_UNLOCK(uif)	mtx_unlock(&(uif)->uif_mtx)
+	TAILQ_HEAD(, usbpf_pkthdr) ud_head;
 
-#endif
+	uint32_t	ud_queue_len;	/* number of packets queued */
+	uint32_t	ud_rtout;	/* Read timeout in 'ticks' */
 
-/*
- * Structure prepended to each packet.
- */
-struct usbpf_ts {
-	usbpf_int64	ut_sec;		/* seconds */
-	usbpf_u_int64	ut_frac;	/* fraction */
-};
-struct usbpf_xhdr {
-	struct usbpf_ts	uh_tstamp;	/* time stamp */
-	usbpf_u_int32	uh_caplen;	/* length of captured portion */
-	usbpf_u_int32	uh_datalen;	/* original length of packet */
-	u_short		uh_hdrlen;	/* length of uff header (this struct
-					   plus alignment padding) */
-};
+	struct usbpf_insn *ud_filter_code;	/* post-filter code */
 
-#define	USBPF_BUFMODE_BUFFER	1	/* Kernel buffers with read(). */
-#define	USBPF_BUFMODE_ZBUF	2	/* Zero-copy buffers. */
+	uint64_t	ud_rcount;	/* number of packets received */
+	uint64_t	ud_dcount;	/* number of packets dropped */
 
-struct usbpf_pkthdr {
-	int		up_busunit;	/* Host controller unit number */
-	u_char		up_address;	/* USB device address */
-	u_char		up_endpoint;	/* USB endpoint */
-	u_char		up_type;	/* points SUBMIT / DONE */
-	u_char		up_xfertype;	/* Transfer type */
-	u_int32_t	up_flags;	/* Transfer flags */
-#define	USBPF_FLAG_FORCE_SHORT_XFER	(1 << 0)
-#define	USBPF_FLAG_SHORT_XFER_OK	(1 << 1)
-#define	USBPF_FLAG_SHORT_FRAMES_OK	(1 << 2)
-#define	USBPF_FLAG_PIPE_BOF		(1 << 3)
-#define	USBPF_FLAG_PROXY_BUFFER		(1 << 4)
-#define	USBPF_FLAG_EXT_BUFFER		(1 << 5)
-#define	USBPF_FLAG_MANUAL_STATUS	(1 << 6)
-#define	USBPF_FLAG_NO_PIPE_OK		(1 << 7)
-#define	USBPF_FLAG_STALL_PIPE		(1 << 8)
-	u_int32_t	up_status;	/* Transfer status */
-#define	USBPF_STATUS_OPEN		(1 << 0)
-#define	USBPF_STATUS_TRANSFERRING	(1 << 1)
-#define	USBPF_STATUS_DID_DMA_DELAY	(1 << 2)
-#define	USBPF_STATUS_DID_CLOSE		(1 << 3)
-#define	USBPF_STATUS_DRAINING		(1 << 4)
-#define	USBPF_STATUS_STARTED		(1 << 5)
-#define	USBPF_STATUS_BW_RECLAIMED	(1 << 6)
-#define	USBPF_STATUS_CONTROL_XFR	(1 << 7)
-#define	USBPF_STATUS_CONTROL_HDR	(1 << 8)
-#define	USBPF_STATUS_CONTROL_ACT	(1 << 9)
-#define	USBPF_STATUS_CONTROL_STALL	(1 << 10)
-#define	USBPF_STATUS_SHORT_FRAMES_OK	(1 << 11)
-#define	USBPF_STATUS_SHORT_XFER_OK	(1 << 12)
-#if USB_HAVE_BUSDMA
-#define	USBPF_STATUS_BDMA_ENABLE	(1 << 13)
-#define	USBPF_STATUS_BDMA_NO_POST_SYNC	(1 << 14)
-#define	USBPF_STATUS_BDMA_SETUP		(1 << 15)
-#endif
-#define	USBPF_STATUS_ISOCHRONOUS_XFR	(1 << 16)
-#define	USBPF_STATUS_CURR_DMA_SET	(1 << 17)
-#define	USBPF_STATUS_CAN_CANCEL_IMMED	(1 << 18)
-#define	USBPF_STATUS_DOING_CALLBACK	(1 << 19)
-	u_int32_t	up_length;	/* Total data length (submit/actual) */
-	u_int32_t	up_frames;	/* USB frame number (submit/actual) */
-	u_int32_t	up_error;	/* usb_error_t */
-	u_int32_t	up_interval;	/* for interrupt and isoc */
-	/* sizeof(struct usbpf_pkthdr) == 128 bytes */
-	u_char		up_reserved[96];
-};
+	int		ud_tstamp;	/* select time stamping function */
 
-struct usbpf_version {
-	u_short		uv_major;
-	u_short		uv_minor;
-};
-#define	USBPF_MAJOR_VERSION	1
-#define	USBPF_MINOR_VERSION	1
+	struct selinfo	ud_sel;		/* BSD select info */
 
-#define	USBPF_IFNAMSIZ	32
-struct usbpf_ifreq {
-	/* bus name, e.g. "usbus0" */
-	char		ufr_name[USBPF_IFNAMSIZ];
-};
+	uint64_t	ud_fcount;	/* number of packets which matched filter */
 
-/*
- *  Structure for UIOCSETF.
- */
-struct usbpf_program {
-	u_int			uf_len;
-	struct usbpf_insn	*uf_insns;
-};
+	int		ud_running;	/* set if running */
 
-/*
- * Struct returned by UIOCGSTATS.
- */
-struct usbpf_stat {
-	u_int us_recv;		/* number of packets received */
-	u_int us_drop;		/* number of packets dropped */
+	struct usbpf_ifreq ud_filter;	/* data filter */
 };
 
-#define	UIOCGBLEN	_IOR('U', 102, u_int)
-#define	UIOCSBLEN	_IOWR('U', 102, u_int)
-#define	UIOCSETF	_IOW('U', 103, struct usbpf_program)
-#define	UIOCSETIF	_IOW('U', 108, struct usbpf_ifreq)
-#define	UIOCSRTIMEOUT	_IOW('U', 109, struct timeval)
-#define	UIOCGRTIMEOUT	_IOR('U', 110, struct timeval)
-#define	UIOCGSTATS	_IOR('U', 111, struct usbpf_stat)
-#define	UIOCVERSION	_IOR('U', 113, struct usbpf_version)
-#define	UIOCSETWF	_IOW('U', 123, struct usbpf_program)
+#define	USBPFD_GLOBAL_LOCK()	mtx_lock(&usbpf_global_mtx)
+#define	USBPFD_GLOBAL_UNLOCK()	mtx_unlock(&usbpf_global_mtx)
+#define	USBPFD_GLOBAL_ASSERT_LOCKED()	mtx_assert(&usbpf_global_mtx, MA_OWNED)
 
-#define	USBPF_XFERTAP_SUBMIT	0
-#define	USBPF_XFERTAP_DONE	1
-
-#ifdef _KERNEL
-void	usbpf_attach(struct usb_bus *, struct usbpf_if **);
-void	usbpf_detach(struct usb_bus *);
-void	usbpf_xfertap(struct usb_xfer *, int);
 #endif
 
 #endif
=== sys/dev/usb/usb_transfer.c
==================================================================
--- sys/dev/usb/usb_transfer.c	(revision 215656)
+++ sys/dev/usb/usb_transfer.c	(local)
@@ -57,10 +57,13 @@
 #include <dev/usb/usb_device.h>
 #include <dev/usb/usb_debug.h>
 #include <dev/usb/usb_util.h>
+#if USB_HAVE_PF
+#include <dev/usb/usb_dynamic.h>
+#include <dev/usb/usb_pf.h>
+#endif
 
 #include <dev/usb/usb_controller.h>
 #include <dev/usb/usb_bus.h>
-#include <dev/usb/usb_pf.h>
 
 struct usb_std_packet_size {
 	struct {
@@ -666,6 +669,14 @@
 	/* setup "frlengths" */
 	xfer->frlengths = parm->xfer_length_ptr;
 	parm->xfer_length_ptr += n_frlengths;
+#if USB_HAVE_PF
+	/*
+	 * We need extra room to store the initial
+	 * length values in case of isochronous
+	 * transfers.
+	 */
+	parm->xfer_length_ptr += n_frlengths;
+#endif
 
 	/* setup "frbuffers" */
 	xfer->frbuffers = parm->xfer_page_cache_ptr;
@@ -1587,6 +1598,10 @@
 			USB_BUS_UNLOCK(bus);
 			return;
 		}
+#if USB_HAVE_PF
+		/* Make a copy of the initial frame lengths */
+		xfer->frlengths[x + xfer->max_frame_count] = xfer->frlengths[x];
+#endif
 	}
 
 	/* clear some internal flags */
@@ -1636,7 +1651,15 @@
 			}
 		}
 	}
+
 	/*
+	 * Tap frames to the USB packet filter before
+	 * any BUSDMA operations.
+	 */
+#if USB_HAVE_PF
+	usb_pf_xfertap_p(xfer, USBPF_XFERTAP_SUBMIT);
+#endif
+   	/*
 	 * Check if BUS-DMA support is enabled and try to load virtual
 	 * buffers into DMA, if any:
 	 */
@@ -2195,11 +2218,11 @@
 			}
 #endif
 		}
+#if USB_HAVE_PF
+		usb_pf_xfertap_p(xfer, USBPF_XFERTAP_DONE);
+#endif
 	}
 
-	if (xfer->usb_state != USB_ST_SETUP)
-		usbpf_xfertap(xfer, USBPF_XFERTAP_DONE);
-
 	/* call processing routine */
 	(xfer->callback) (xfer, xfer->error);
 
@@ -2387,8 +2410,6 @@
 
 	DPRINTF("start\n");
 
-	usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
-
 	/* start the transfer */
 	(ep->methods->start) (xfer);
 
@@ -2566,8 +2587,6 @@
 	}
 	DPRINTF("start\n");
 
-	usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT);
-
 	/* start USB transfer */
 	(ep->methods->start) (xfer);
 
=== sys/modules/usb/Makefile
==================================================================
--- sys/modules/usb/Makefile	(revision 215656)
+++ sys/modules/usb/Makefile	(local)
@@ -34,6 +34,7 @@
 SUBDIR += uether aue axe cdce cue kue rue udav uhso ipheth
 SUBDIR += usfs umass urio
 SUBDIR += quirk template
+SUBDIR += upf
 
 .if ${MACHINE_CPUARCH} == "amd64"
 _urtw=		urtw
=== sys/modules/usb/upf	(new directory)
==================================================================
=== sys/modules/usb/upf/Makefile
==================================================================
--- sys/modules/usb/upf/Makefile	(revision 215656)
+++ sys/modules/usb/upf/Makefile	(local)
@@ -0,0 +1,37 @@
+#
+# $FreeBSD$
+#
+# Copyright (c) 2010 Hans Petter Selasky. 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.
+#
+
+S=     ${.CURDIR}/../../..
+
+.PATH: $S/dev/usb
+
+KMOD=	usb_pf
+SRCS=	opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h \
+	usb_pf.c
+
+.include <bsd.kmod.mk>
+

Property changes on: sys/modules/usb/upf/Makefile
___________________________________________________________________
Name: svn:eol-style
 +native
Name: svn:keywords
 +FreeBSD=%H
Name: svn:mime-type
 +text/plain

=== usr.sbin/Makefile
==================================================================
--- usr.sbin/Makefile	(revision 215656)
+++ usr.sbin/Makefile	(local)
@@ -293,6 +293,7 @@
 .if ${MK_USB} != "no"
 SUBDIR+=	uathload
 SUBDIR+=	uhsoctl
+SUBDIR+=	usbdump
 SUBDIR+=	usbconfig
 .endif
 
=== usr.sbin/usbdump/usbdump.8
==================================================================
--- usr.sbin/usbdump/usbdump.8	(revision 215656)
+++ usr.sbin/usbdump/usbdump.8	(local)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd October 14, 2010
+.Dd November 23, 2010
 .Dt usbdump 8
 .Os
 .Sh NAME
@@ -33,7 +33,8 @@
 .Nd "dump traffic on USB host controller"
 .Sh SYNOPSIS
 .Nm
-.Op Fl i Ar ifname
+.Op Fl d Ar bus.dev.endpoint
+.Op Fl b Ar bufsize
 .Op Fl r Ar file
 .Op Fl s Ar snaplen
 .Op Fl v
@@ -45,27 +46,40 @@
 .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 d Ar bus.dev.endpoint
+Listen on the given bus, device and endpoint.
+This option is mandatory.
+A negative value in any of the given fields means any bus, device or endpoint.
+.It Fl b Ar bufsize
+Set internal buffer size in bytes.
+Default: -1.
 .It Fl r Ar file
 Read the raw packets from file.
+Default: Off
 .It Fl s Ar snaplen
 Snapshot bytes from each packet.
+Default: 192
 .It Fl v
 Enable debugging messages.
 When it defined multiple times the verbose level increases.
+Default: Off
 .It Fl w Ar file
 Write the raw packets to file.
+Default: Off
 .El
 .Sh EXAMPLES
-Captures the USB raw packets alive on usbus2:
+Captures the USB raw packets alive on ugen2.x:
 .Pp
-.Dl "usbdump -i usbus2 -s 256 -v"
+.Dl "usbdump -d 2 -s 256 -v"
 .Pp
-Dumps the USB raw packets of usbus2 into the file without packet
+Captures the USB raw packets alive on ugen2.1:
+.Pp
+.Dl "usbdump -d 2.1 -s 256 -v"
+.Pp
+Dumps the USB raw packets of ugen2.x into the file without packet
 size limit:
 .Pp
-.Dl "usbdump -i usbus2 -s 0 -w /tmp/dump_pkts"
+.Dl "usbdump -d 2 -s 0 -w /tmp/dump_pkts"
 .Pp
 Read the USB raw packets from the file:
 .Pp
=== usr.sbin/usbdump/usbdump.c
==================================================================
--- usr.sbin/usbdump/usbdump.c	(revision 215656)
+++ usr.sbin/usbdump/usbdump.c	(local)
@@ -49,8 +49,8 @@
 
 struct usbcap {
 	int		fd;		/* fd for /dev/usbpf */
-	u_int		bufsize;
-	char		*buffer;
+	uint32_t	bufsize;
+	void		*buffer;
 
 	/* for -w option */
 	int		wfd;
@@ -59,17 +59,21 @@
 };
 
 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;
 static int pkt_captured = 0;
 static int verbose = 0;
-static const char *i_arg = "usbus0";;
+static int bus = -1;
+static int device = -1;
+static int endpoint = -1;
+static int bufsize = -1;
+
 static const char *r_arg = NULL;
 static const char *w_arg = NULL;
 static const char *errstr_table[USB_ERR_MAX] = {
@@ -114,67 +118,29 @@
 static void
 handle_sigint(int sig)
 {
+	(void)sig;
 
-	(void)sig;
 	doexit = 1;
 }
 
 static void
-print_flags(u_int32_t flags)
+print_flags(uint32_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);
+	if ((flags & USBPF_XFERFLAG_##name) != 0)	\
+		printf("%s/", #name);
+	printf(" flags[");
+	PRINTFLAGS(READ);
+	PRINTFLAGS(SHORT_OK);
+	PRINTFLAGS(MULTI_SHORT_OK);
+	PRINTFLAGS(FORCE_SHORT);
 	PRINTFLAGS(STALL_PIPE);
-	printf(">\n");
+	PRINTFLAGS(CONTROL_ACT);
+	PRINTFLAGS(DATA_FOLLOWS);
+	printf("0x%08x]", flags);
 #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.
  */
@@ -216,90 +182,124 @@
 }
 
 static void
-print_apacket(const struct usbpf_xhdr *hdr, struct usbpf_pkthdr *up,
-    const char *payload)
+print_apacket(const struct usbpf_pkthdr *up, const uint32_t *ptr,
+    uint32_t framelen, uint32_t snaplen, uint32_t flags, uint32_t frameno)
 {
+	struct usbpf_pkthdr_first hdr;
 	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);
+	hdr.up_sec = le64toh(up->hdr.up_sec);
+	hdr.up_frac = le64toh(up->hdr.up_frac);
+	hdr.up_busunit = le32toh(up->hdr.up_busunit);
+	hdr.up_frames = le32toh(up->hdr.up_frames);
+	hdr.up_interval = le32toh(up->hdr.up_interval);
+	hdr.up_status = le32toh(up->hdr.up_status);
+	hdr.up_totlen = le32toh(up->hdr.up_totlen);
+	hdr.up_error = le32toh(up->hdr.up_error);
+	hdr.up_packet_size = le32toh(up->hdr.up_packet_size);
+	hdr.up_packet_count = le32toh(up->hdr.up_packet_count);
+	hdr.up_devunit = up->hdr.up_devunit;
+	hdr.up_dmode = up->hdr.up_dmode;
+	hdr.up_endpoint = up->hdr.up_endpoint;
+	hdr.up_type = up->hdr.up_type;
+	hdr.up_xfertype = up->hdr.up_xfertype;
 
-	tv.tv_sec = hdr->uh_tstamp.ut_sec;
-	tv.tv_usec = hdr->uh_tstamp.ut_frac;
+	tv.tv_sec = hdr.up_sec;
+	tv.tv_usec = hdr.up_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(" usbus%d.%d 0x%02x %s %s %s", hdr.up_busunit, hdr.up_devunit,
+	    hdr.up_xfertype != UE_CONTROL ? hdr.up_endpoint : hdr.up_endpoint & 0x0F,
+	    xfertype_table[hdr.up_xfertype & 3],
+	    hdr.up_type == USBPF_XFERTAP_SUBMIT ? "->" : "<-",
+	    (flags & USBPF_XFERFLAG_READ) ? "RD" : "WR");
+
+	printf(" (%d+%d)", hdr.up_frames,
+	    hdr.up_totlen - USBPF_PKTHDR_SIZE - (4 * USBPF_FRAMEHDR_SIZE * hdr.up_frames));
+
+	if (hdr.up_type == USBPF_XFERTAP_DONE) {
+		printf(" %s", (errstr_table[hdr.up_error] != NULL) ?
+		    errstr_table[hdr.up_error] : "");
+	}
+	if (hdr.up_xfertype != UE_ISOCHRONOUS)
+		printf(" %d ms", hdr.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;
-		}
+		printf(" frame[%u/%u] len[%u/%u]", frameno, hdr.up_frames, snaplen, framelen);
+		if (verbose >= 2)
+			print_flags(flags);
+		printf("\n");
+		if (flags & USBPF_XFERFLAG_DATA_FOLLOWS)
+			hexdump((const uint8_t *)ptr, snaplen);
 	}
-	if (verbose >= 2) {
-		print_flags(up->up_flags);
-		print_status(up->up_status);
-	}
 }
     
-
 static void
-print_packets(char *data, const int datalen)
+print_packets(const struct usbpf_pkthdr *up, uint32_t maxlen)
 {
-	struct usbpf_pkthdr *up;
-	const struct usbpf_xhdr *hdr;
-	u_int32_t framelen, x;
-	char *ptr, *next;
+	const uint32_t *data;
+	const uint32_t *ptr;
+	const uint32_t *next;
+	const uint32_t *end;
+	uint32_t datalen;
+	uint32_t framelen;
+	uint32_t snaplen;
+	uint32_t flags;
+	uint32_t x;
 
-	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);
+	if (maxlen < USBPF_PKTHDR_SIZE)
+		return;
 
-		ptr = ((char *)up) + sizeof(struct usbpf_pkthdr);
+	datalen = le32toh(up->hdr.up_totlen);
+
+	if (datalen > maxlen || datalen < sizeof(*up))
+		return;
+
+	data = (const uint32_t *)(up + 1);
+	end = data + ((datalen - sizeof(*up)) / 4);
+	x = 0;
+
+	for (ptr = data; ptr <= (end - USBPF_FRAMEHDR_SIZE); ptr = next, x++) {
+
+		framelen = le32toh(ptr[0]);
+		flags = le32toh(ptr[1]);
+		snaplen = le32toh(ptr[2]);
+
+		/* sanity check */
+		if (snaplen > framelen)
+			snaplen = framelen;
+
+		next = ptr + USBPF_FRAMEHDR_SIZE;
+
+		if (flags & USBPF_XFERFLAG_DATA_FOLLOWS)
+			next += (USBPF_LENGTH_ALIGN(framelen) / 4);
+		else
+			snaplen = 0;
+
+		/* Corrupt data? We are done! */
+		if (next > end || next < data)
+			return;
 		if (w_arg == NULL)
-			print_apacket(hdr, up, ptr);
+			print_apacket(up, ptr + USBPF_FRAMEHDR_SIZE,
+			    framelen, snaplen, flags, x);
 		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)
+write_packets(struct usbcap *p, const char *data, const uint32_t datalen)
 {
-	int len = htole32(datalen), ret;
+	uint32_t len = htole32(datalen), ret;
 
-	ret = write(p->wfd, &len, sizeof(int));
-	assert(ret == sizeof(int));
+	ret = write(p->wfd, &len, sizeof(uint32_t));
+	assert(ret == sizeof(uint32_t));
 	ret = write(p->wfd, data, datalen);
 	assert(ret == datalen);
 }
@@ -307,15 +307,16 @@
 static void
 read_file(struct usbcap *p)
 {
-	int datalen, ret;
-	char *data;
+	void *data;
+	uint32_t datalen;
+	int ret;
 
-	while ((ret = read(p->rfd, &datalen, sizeof(int))) == sizeof(int)) {
+	while ((ret = read(p->rfd, &datalen, sizeof(uint32_t))) == sizeof(uint32_t)) {
 		datalen = le32toh(datalen);
 		data = malloc(datalen);
 		assert(data != NULL);
 		ret = read(p->rfd, data, datalen);
-		assert(ret == datalen);
+		assert(ret == (int)datalen);
 		print_packets(data, datalen);
 		free(data);
 	}
@@ -329,18 +330,20 @@
 	int cc;
 
 	while (doexit == 0) {
-		cc = read(p->fd, (char *)p->buffer, p->bufsize);
+		cc = read(p->fd, p->buffer, p->bufsize);
 		if (cc < 0) {
 			switch (errno) {
 			case EINTR:
 				break;
+			case EWOULDBLOCK:
+				break;
 			default:
 				fprintf(stderr, "read: %s\n", strerror(errno));
 				return;
 			}
 			continue;
 		}
-		if (cc == 0)
+		if (cc < USBPF_PKTHDR_SIZE)
 			continue;
 		if (w_arg != NULL)
 			write_packets(p, p->buffer, cc);
@@ -363,7 +366,7 @@
 	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
@@ -380,7 +383,7 @@
 	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));
 }
@@ -389,11 +392,12 @@
 usage(void)
 {
 
-#define FMT "    %-14s %s\n"
-	fprintf(stderr, "usage: usbdump [options]\n");
-	fprintf(stderr, FMT, "-i ifname", "Listen on USB bus interface");
+#define FMT "	 %-14s %s\n"
+	fprintf(stderr, "usage: usbdump -d <...> [options]\n");
+	fprintf(stderr, FMT, "-d <bus.dev.endpt>", "Listen on the give bus, device and endpoint");
+	fprintf(stderr, FMT, "-b <size>", "Buffer size");
 	fprintf(stderr, FMT, "-r file", "Read the raw packets from file");
-	fprintf(stderr, FMT, "-s snaplen", "Snapshot bytes from each packet");
+	fprintf(stderr, FMT, "-s <snaplen>", "Snapshot bytes from each USB packet.");
 	fprintf(stderr, FMT, "-v", "Increases the verbose level");
 	fprintf(stderr, FMT, "-w file", "Write the raw packets to file");
 #undef FMT
@@ -405,24 +409,51 @@
 {
 	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 usbcap uc;
+	struct usbcap *p = &uc;
 	struct usbpf_ifreq ufr;
+	char *ptr;
 	long snapshot = 192;
-	u_int v;
-	int fd, o;
-	const char *optstring;
+	long v;
+	int fd;
+	int o;
+	int got_dev = 0;
 
-	bzero(&uc, sizeof(struct usbcap));
+	memset(&uc, 0, sizeof(struct usbcap));
 
-	optstring = "i:r:s:vw:";
-	while ((o = getopt(argc, argv, optstring)) != -1) {
+	while ((o = getopt(argc, argv, "b:d:r:s:vw:")) != -1) {
 		switch (o) {
-		case 'i':
-			i_arg = optarg;
+		case 'b':
+			bufsize = atoi(optarg);
 			break;
+		case 'd':
+			got_dev = 1;
+			ptr = strstr(optarg, ".");
+			if (ptr != NULL)
+				ptr[0] = 0;
+			bus = atoi(optarg);
+			if (ptr == NULL)
+				break;
+			optarg = ptr + 1;
+
+			ptr = strstr(optarg, ".");
+			if (ptr != NULL)
+				ptr[0] = 0;
+			device = atoi(optarg);
+			if (ptr == NULL)
+				break;
+			optarg = ptr + 1;
+
+			ptr = strstr(optarg, ".");
+			if (ptr != NULL)
+				ptr[0] = 0;
+			endpoint = atoi(optarg);
+			if (ptr == NULL)
+				break;
+			optarg = ptr + 1;
+			break;
 		case 'r':
 			r_arg = optarg;
 			init_rfile(p);
@@ -454,12 +485,14 @@
 		exit(EXIT_SUCCESS);
 	}
 
+	if (got_dev == 0)
+		usage();
+
 	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);
@@ -469,46 +502,44 @@
 		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);
+	if (ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) {
+		fprintf(stderr, "UIOCGBLEN: %s\n", strerror(errno));
 		return (EXIT_FAILURE);
 	}
+	if (bufsize < 0 || bufsize > v)
+		bufsize = v;
 
-	if (ioctl(fd, UIOCGBLEN, (caddr_t)&v) < 0) {
-		fprintf(stderr, "UIOCGBLEN: %s", strerror(errno));
+	/* XXX no read filter rules yet so at this moment accept everything */
+	total_insn.code = (uint16_t)(USBPF_RET | USBPF_K);
+	total_insn.jt = 0;
+	total_insn.jf = 0;
+	total_insn.k = snapshot;
+
+	memset(&ufr, 0, sizeof(ufr));
+
+	ufr.ua_bus_unit = bus;
+	ufr.ua_dev_unit = device;
+	if (endpoint < 0)
+		ufr.ua_endpoint_mask = -1;
+	else
+		ufr.ua_endpoint_mask = 3U << (2 * (endpoint & 0xF));
+
+	ufr.ua_filter_ptr = &total_insn;
+	ufr.ua_filter_len = sizeof(total_insn);
+
+	if (ioctl(fd, UIOCSETIF, (caddr_t)&ufr) < 0) {
+		fprintf(stderr, "UIOCSETIF: %s\n", strerror(errno));
 		return (EXIT_FAILURE);
 	}
 
 	p->bufsize = v;
-	p->buffer = (u_char *)malloc(p->bufsize);
+	p->buffer = 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 */
+	/* set timeout */
 	tv.tv_sec = 1;
 	tv.tv_usec = 0;
 	if (ioctl(p->fd, UIOCSRTIMEOUT, (caddr_t)&tv) < 0) {
@@ -528,8 +559,8 @@
 	/* 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);
+	printf("%lld packets received by filter\n", (long long)us.us_recv);
+	printf("%lld packets dropped by kernel\n", (long long)us.us_drop);
 
 	if (p->fd > 0)
 		close(p->fd);


More information about the freebsd-usb mailing list