[RFC] USBdump patches
Hans Petter Selasky
hselasky at c2i.net
Tue Nov 23 22:44:22 UTC 2010
Update patch for latest SVN.
--HPS
-------------- next part --------------
=== sys/conf/files
==================================================================
--- sys/conf/files (revision 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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,107 +92,7 @@
.d_kqfilter = usbpf_kqfilter,
};
-static struct cdev *usbpf_cdev;
-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 */
@@ -271,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;
@@ -297,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;
}
@@ -326,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:
@@ -754,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 */
}
/*
@@ -809,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)
@@ -845,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);
}
/*
@@ -873,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);
}
@@ -999,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
@@ -1147,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:
@@ -1230,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;
@@ -1252,6 +749,9 @@
error = usbpf_setif(ud, (struct usbpf_ifreq *)addr);
break;
+ default:
+ error = ENOTTY;
+ break;
}
return (error);
}
@@ -1265,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));
}
/*
@@ -1283,594 +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);
-}
-
-/*
- * 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;
-
- 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 (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]);
}
- USBPFD_UNLOCK(ud);
}
- USBPFIF_UNLOCK(uif);
-}
-static uint32_t
-usbpf_aggregate_xferflags(struct usb_xfer_flags *flags)
-{
- uint32_t val = 0;
+ /* sanity check */
+ if (totlen >= USBPF_MAX_BUFFER_LEN) {
+ static int once;
+ USBPFD_GLOBAL_UNLOCK();
- 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);
-}
+ if (once == 0) {
+ printf("usb_pf: Total trace length(%u) "
+ "exceeds maximum(%u).\n",
+ totlen, USBPF_MAX_BUFFER_LEN);
+ once = 1;
+ }
-static uint32_t
-usbpf_aggregate_status(struct usb_xfer_flags_int *flags)
-{
- uint32_t val = 0;
+ /* too much data */
+ return;
+ }
- 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;
+ 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;
- return (val);
+ TAILQ_FOREACH(ud, &usbpf_filters, ud_next) {
+ if (usbpf_filter(ud, &fhdr))
+ usbpf_xfertap_sub(xfer, ud, &fhdr, type);
+ }
+
+ USBPFD_GLOBAL_UNLOCK();
}
-void
-usbpf_xfertap(struct usb_xfer *xfer, int type)
+static void
+usbpf_drvinit(void *unused)
{
- 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;
+ mtx_init(&usbpf_global_mtx, "USB packet filter global lock",
+ NULL, MTX_DEF);
- /*
- * NB: usbpf_uifd_cnt isn't protected by USBPFIF_LOCK() because it's
- * not harmful.
- */
- if (usbpf_uifd_cnt == 0)
- return;
+ TAILQ_INIT(&usbpf_filters);
- /*
- * 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);
+ usbpf_dev = make_dev(&usbpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "usbpf");
- 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);
- }
+ /* Set our function pointer callback */
- up->up_error = htole32(xfer->error);
- up->up_interval = htole32(xfer->interval);
- ptr += sizeof(struct usbpf_pkthdr);
+ usb_pf_xfertap_p = &usbpf_xfertap;
- 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);
-
- 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];
- }
-
- usbpf_tap(bus->uif, buf, ptr - buf);
-done:
- free(buf, M_USBPF);
+ 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);
static void
-usbpf_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset, void *src,
- u_int len)
+usbpf_drvuninit(void *arg)
{
+ usb_pf_unload(arg);
- USBPFD_LOCK_ASSERT(ud);
+ if (usbpf_dev != NULL)
+ destroy_dev(usbpf_dev);
- 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)
-{
+ while (TAILQ_FIRST(&usbpf_filters) != NULL) {
- mtx_init(&usbpf_mtx, "USB packet filter global lock", NULL,
- MTX_DEF);
- LIST_INIT(&usbpf_iflist);
+ USBPFD_GLOBAL_UNLOCK();
- usbpf_cdev = make_dev(&usbpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
- "usbpf");
-}
+ printf("usb_pf: Please close all device instances\n");
-static void
-usbpf_drvuninit(void)
-{
+ pause("WAIT", 2 * hz);
- if (usbpf_cdev != NULL) {
- destroy_dev(usbpf_cdev);
- usbpf_cdev = NULL;
+ USBPFD_GLOBAL_LOCK();
}
- mtx_destroy(&usbpf_mtx);
-}
-SYSINIT(usbpf_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvinit, NULL);
-SYSUNINIT(usbpf_undev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvuninit, NULL);
+ USBPFD_GLOBAL_UNLOCK();
+ mtx_destroy(&usbpf_global_mtx);
+}
+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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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 215787)
+++ 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,129 @@
}
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;
+ if (frameno != 0)
+ goto skip_hdr;
+
+ 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;
- }
+skip_hdr:
+ if (verbose >= 1) {
+ 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(snaplen) / 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 +312,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 +335,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 +371,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 +388,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 +397,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 +414,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 +490,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 +507,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 +564,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