Date: Tue, 23 Nov 2010 23:45:05 +0100 From: Hans Petter Selasky <hselasky@c2i.net> To: Weongyo Jeong <weongyo@freebsd.org> Cc: freebsd-usb@freebsd.org, Jung-uk Kim <jkim@freebsd.org> Subject: Re: [RFC] USBdump patches Message-ID: <201011232345.05070.hselasky@c2i.net>
next in thread | raw e-mail | index | archive | help
--Boundary-00=_xPE7MXid1vdrtfA Content-Type: Text/Plain; charset="iso-8859-15" Content-Transfer-Encoding: 7bit Update patch for latest SVN. --HPS --Boundary-00=_xPE7MXid1vdrtfA Content-Type: text/plain; charset="iso-8859-15"; name="usbdump_r215783_patch.txt" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="usbdump_r215783_patch.txt" === 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); --Boundary-00=_xPE7MXid1vdrtfA--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201011232345.05070.hselasky>