diff --git a/sys/conf/files b/sys/conf/files index c859ec82b3a5..db3e5383ed1c 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1779,6 +1779,7 @@ dev/usb/usb_lookup.c optional usb 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 diff --git a/sys/dev/usb/controller/usb_controller.c b/sys/dev/usb/controller/usb_controller.c index 71e7ef1da698..afc21182bc07 100644 --- a/sys/dev/usb/controller/usb_controller.c +++ b/sys/dev/usb/controller/usb_controller.c @@ -61,6 +61,7 @@ #include #include +#include /* function prototypes */ @@ -547,6 +548,8 @@ usb_bus_mem_alloc_all(struct usb_bus *bus, bus_dma_tag_t dmat, 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); @@ -594,5 +597,34 @@ usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb) 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); +} diff --git a/sys/dev/usb/usb_bus.h b/sys/dev/usb/usb_bus.h index 99e97770665c..c5dfeff17315 100644 --- a/sys/dev/usb/usb_bus.h +++ b/sys/dev/usb/usb_bus.h @@ -86,6 +86,8 @@ struct usb_bus { 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]; diff --git a/sys/dev/usb/usb_controller.h b/sys/dev/usb/usb_controller.h index 6b15dab993d5..fb5d091335eb 100644 --- a/sys/dev/usb/usb_controller.h +++ b/sys/dev/usb/usb_controller.h @@ -221,5 +221,6 @@ void usb_bus_mem_free_all(struct usb_bus *bus, usb_bus_mem_cb_t *cb); 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_ */ diff --git a/sys/dev/usb/usb_pf.c b/sys/dev/usb/usb_pf.c new file mode 100644 index 000000000000..3f5f204d4d78 --- /dev/null +++ b/sys/dev/usb/usb_pf.c @@ -0,0 +1,1862 @@ +/*- + * 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. + * + * 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. + * 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 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. + */ + +#include +__FBSDID("$FreeBSD$"); +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * All usbpf implementations are extracted from bpf(9) APIs and it's + * specialized for USB packet filtering between the driver and the host + * controller. + */ + +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) + +#ifndef __i386__ +#define USBPF_ALIGN +#endif + +#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; +static d_ioctl_t usbpf_ioctl; +static d_poll_t usbpf_poll; +static d_kqfilter_t usbpf_kqfilter; + +static struct cdevsw usbpf_cdevsw = { + .d_version = D_VERSION, + .d_open = usbpf_open, + .d_read = usbpf_read, + .d_write = usbpf_write, + .d_ioctl = usbpf_ioctl, + .d_poll = usbpf_poll, + .d_name = "usbpf", + .d_kqfilter = usbpf_kqfilter, +}; + +static LIST_HEAD(, usbpf_if) usbpf_iflist; +static struct mtx usbpf_mtx; /* global lock */ +static int usbpf_uifd_cnt; + +static int usbpf_bufsize = 4096; +#define USBPF_MINBUFSIZE 32 +#define USBPF_MAXBUFSIZE 0x80000 +static int usbpf_maxbufsize = USBPF_MAXBUFSIZE; +#define USBPF_MAXINSNS 512 +static int usbpf_maxinsns = USBPF_MAXINSNS; + +static void +usbpf_buffer_init(struct usbpf_d *ud) +{ + + ud->ud_bufsize = usbpf_bufsize; +} + +/* + * Free USBPF kernel buffers on device close. + */ +static void +usbpf_buffer_free(struct usbpf_d *ud) +{ + + if (ud->ud_sbuf != NULL) + free(ud->ud_sbuf, M_USBPF); + if (ud->ud_hbuf != NULL) + free(ud->ud_hbuf, M_USBPF); + if (ud->ud_fbuf != NULL) + free(ud->ud_fbuf, M_USBPF); + +#ifdef INVARIANTS + ud->ud_sbuf = ud->ud_hbuf = ud->ud_fbuf = (caddr_t)~0; +#endif +} + +static void +usbpf_buffer_alloc(struct usbpf_d *ud) +{ + + KASSERT(ud->ud_fbuf == NULL, ("%s: ud_fbuf != NULL", __func__)); + KASSERT(ud->ud_sbuf == NULL, ("%s: ud_sbuf != NULL", __func__)); + KASSERT(ud->ud_hbuf == NULL, ("%s: ud_hbuf != NULL", __func__)); + + ud->ud_fbuf = (caddr_t)malloc(ud->ud_bufsize, M_USBPF, M_WAITOK); + ud->ud_sbuf = (caddr_t)malloc(ud->ud_bufsize, M_USBPF, M_WAITOK); + ud->ud_hbuf = NULL; + ud->ud_slen = 0; + ud->ud_hlen = 0; +} + +/* + * Copy buffer storage to user space in read(). + */ +static int +usbpf_buffer_uiomove(struct usbpf_d *ud, caddr_t buf, u_int len, + struct uio *uio) +{ + + return (uiomove(buf, len, uio)); +} + +/* + * Simple data copy to the current kernel buffer. + */ +static void +usbpf_buffer_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset, + void *src, u_int len) +{ + u_char *src_bytes; + + src_bytes = (u_char *)src; + bcopy(src_bytes, buf + offset, len); +} + +/* + * Allocate or resize buffers. + */ +static int +usbpf_buffer_ioctl_sblen(struct usbpf_d *ud, u_int *i) +{ + u_int size; + + USBPFD_LOCK(ud); + if (ud->ud_bif != NULL) { + USBPFD_UNLOCK(ud); + return (EINVAL); + } + size = *i; + if (size > usbpf_maxbufsize) + *i = size = usbpf_maxbufsize; + else if (size < USBPF_MINBUFSIZE) + *i = size = USBPF_MINBUFSIZE; + ud->ud_bufsize = size; + USBPFD_UNLOCK(ud); + return (0); +} + +static const u_short usbpf_code_map[] = { + 0x10ff, /* 0x00-0x0f: 1111111100001000 */ + 0x3070, /* 0x10-0x1f: 0000111000001100 */ + 0x3131, /* 0x20-0x2f: 1000110010001100 */ + 0x3031, /* 0x30-0x3f: 1000110000001100 */ + 0x3131, /* 0x40-0x4f: 1000110010001100 */ + 0x1011, /* 0x50-0x5f: 1000100000001000 */ + 0x1013, /* 0x60-0x6f: 1100100000001000 */ + 0x1010, /* 0x70-0x7f: 0000100000001000 */ + 0x0093, /* 0x80-0x8f: 1100100100000000 */ + 0x0000, /* 0x90-0x9f: 0000000000000000 */ + 0x0000, /* 0xa0-0xaf: 0000000000000000 */ + 0x0002, /* 0xb0-0xbf: 0100000000000000 */ + 0x0000, /* 0xc0-0xcf: 0000000000000000 */ + 0x0000, /* 0xd0-0xdf: 0000000000000000 */ + 0x0000, /* 0xe0-0xef: 0000000000000000 */ + 0x0000 /* 0xf0-0xff: 0000000000000000 */ +}; + +#define USBPF_VALIDATE_CODE(c) \ + ((c) <= 0xff && (usbpf_code_map[(c) >> 4] & (1 << ((c) & 0xf))) != 0) + +/* + * Return true if the 'fcode' is a valid filter program. + * The constraints are that each jump be forward and to a valid + * code. The code must terminate with either an accept or reject. + * + * The kernel needs to be able to verify an application's filter code. + * Otherwise, a bogus program could easily crash the system. + */ +static int +usbpf_validate(const struct usbpf_insn *f, int len) +{ + register int i; + register const struct usbpf_insn *p; + + /* Do not accept negative length filter. */ + if (len < 0) + return (0); + + /* An empty filter means accept all. */ + if (len == 0) + return (1); + + for (i = 0; i < len; ++i) { + p = &f[i]; + /* + * Check that the code is valid. + */ + if (!USBPF_VALIDATE_CODE(p->code)) + return (0); + /* + * Check that that jumps are forward, and within + * the code block. + */ + if (USBPF_CLASS(p->code) == USBPF_JMP) { + register u_int 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) + return (0); + continue; + } + /* + * Check that memory operations use valid addresses. + */ + if (p->code == USBPF_ST || p->code == USBPF_STX || + p->code == (USBPF_LD|USBPF_MEM) || + p->code == (USBPF_LDX|USBPF_MEM)) { + if (p->k >= USBPF_MEMWORDS) + return (0); + continue; + } + /* + * Check for constant division by 0. + */ + if (p->code == (USBPF_ALU|USBPF_DIV|USBPF_K) && p->k == 0) + return (0); + } + 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) +{ + u_int32_t A = 0, X = 0; + usbpf_u_int32 k; + u_int32_t mem[USBPF_MEMWORDS]; + + /* + * 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); + + --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); + + case USBPF_RET|USBPF_A: + return ((u_int)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 + 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)); + 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 + return (0); +#endif + } + A = USBPF_EXTRACT_SHORT(&p[k]); + 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 + return (0); +#endif + } + A = p[k]; + continue; + + case USBPF_LD|USBPF_W|USBPF_LEN: + A = wirelen; + continue; + + case USBPF_LDX|USBPF_W|USBPF_LEN: + X = wirelen; + 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 + 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)); + 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 + return (0); +#endif + } + A = USBPF_EXTRACT_SHORT(&p[k]); + 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 + return (0); +#endif + } + A = p[k]; + 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 + return (0); +#endif + } + X = (p[pc->k] & 0xf) << 2; + continue; + + case USBPF_LD|USBPF_IMM: + A = pc->k; + continue; + + case USBPF_LDX|USBPF_IMM: + X = pc->k; + continue; + + case USBPF_LD|USBPF_MEM: + A = mem[pc->k]; + continue; + + case USBPF_LDX|USBPF_MEM: + X = mem[pc->k]; + continue; + + case USBPF_ST: + mem[pc->k] = A; + continue; + + case USBPF_STX: + mem[pc->k] = X; + continue; + + case USBPF_JMP|USBPF_JA: + pc += pc->k; + continue; + + case USBPF_JMP|USBPF_JGT|USBPF_K: + pc += (A > pc->k) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JGE|USBPF_K: + pc += (A >= pc->k) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JEQ|USBPF_K: + pc += (A == pc->k) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JSET|USBPF_K: + pc += (A & pc->k) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JGT|USBPF_X: + pc += (A > X) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JGE|USBPF_X: + pc += (A >= X) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JEQ|USBPF_X: + pc += (A == X) ? pc->jt : pc->jf; + continue; + + case USBPF_JMP|USBPF_JSET|USBPF_X: + pc += (A & X) ? pc->jt : pc->jf; + continue; + + case USBPF_ALU|USBPF_ADD|USBPF_X: + A += X; + continue; + + case USBPF_ALU|USBPF_SUB|USBPF_X: + A -= X; + continue; + + case USBPF_ALU|USBPF_MUL|USBPF_X: + A *= X; + continue; + + case USBPF_ALU|USBPF_DIV|USBPF_X: + if (X == 0) + return (0); + A /= X; + continue; + + case USBPF_ALU|USBPF_AND|USBPF_X: + A &= X; + continue; + + case USBPF_ALU|USBPF_OR|USBPF_X: + A |= X; + continue; + + case USBPF_ALU|USBPF_LSH|USBPF_X: + A <<= X; + continue; + + case USBPF_ALU|USBPF_RSH|USBPF_X: + A >>= X; + continue; + + case USBPF_ALU|USBPF_ADD|USBPF_K: + A += pc->k; + continue; + + case USBPF_ALU|USBPF_SUB|USBPF_K: + A -= pc->k; + continue; + + case USBPF_ALU|USBPF_MUL|USBPF_K: + A *= pc->k; + continue; + + case USBPF_ALU|USBPF_DIV|USBPF_K: + A /= pc->k; + continue; + + case USBPF_ALU|USBPF_AND|USBPF_K: + A &= pc->k; + continue; + + case USBPF_ALU|USBPF_OR|USBPF_K: + A |= pc->k; + continue; + + case USBPF_ALU|USBPF_LSH|USBPF_K: + A <<= pc->k; + continue; + + case USBPF_ALU|USBPF_RSH|USBPF_K: + A >>= pc->k; + continue; + + case USBPF_ALU|USBPF_NEG: + A = -A; + continue; + + case USBPF_MISC|USBPF_TAX: + X = A; + continue; + + case USBPF_MISC|USBPF_TXA: + A = X; + continue; + } + } +} + +static void +usbpf_free(struct usbpf_d *ud) +{ + + switch (ud->ud_bufmode) { + case USBPF_BUFMODE_BUFFER: + return (usbpf_buffer_free(ud)); + default: + panic("usbpf_buf_free"); + } +} + +/* + * Notify the buffer model that a buffer has moved into the hold position. + */ +static void +usbpf_bufheld(struct usbpf_d *ud) +{ + + USBPFD_LOCK_ASSERT(ud); +} + +/* + * Free buffers currently in use by a descriptor. + * Called on close. + */ +static void +usbpf_freed(struct usbpf_d *ud) +{ + + /* + * 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); +} + +/* + * Close the descriptor by detaching it from its interface, + * deallocating its buffers, and marking it free. + */ +static void +usbpf_dtor(void *data) +{ + struct usbpf_d *ud = data; + + 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); + knlist_destroy(&ud->ud_sel.si_note); + callout_drain(&ud->ud_callout); + usbpf_freed(ud); + 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) +{ + struct usbpf_d *ud; + int error; + + ud = malloc(sizeof(*ud), M_USBPF, M_WAITOK | M_ZERO); + error = devfs_set_cdevpriv(ud, usbpf_dtor); + if (error != 0) { + free(ud, M_USBPF); + 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); + + return (0); +} + +static int +usbpf_uiomove(struct usbpf_d *ud, caddr_t buf, u_int len, struct uio *uio) +{ + + if (ud->ud_bufmode != USBPF_BUFMODE_BUFFER) + return (EOPNOTSUPP); + return (usbpf_buffer_uiomove(ud, buf, len, uio)); +} + +/* + * usbpf_read - read next chunk of packets from buffers + */ +static int +usbpf_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct usbpf_d *ud; + int error; + int non_block; + int timed_out; + + 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); + + 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); + 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 (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; + + if (ud->ud_slen == 0) { + USBPFD_UNLOCK(ud); + return (0); + } + USBPF_ROTATE_BUFFERS(ud); + 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); + + USBPFD_LOCK(ud); + ud->ud_fbuf = ud->ud_hbuf; + ud->ud_hbuf = NULL; + ud->ud_hlen = 0; + usbpf_buf_reclaimed(ud); + USBPFD_UNLOCK(ud); + + return (error); +} + +static int +usbpf_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + + /* NOT IMPLEMENTED */ + 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_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; + + theywant = usb_bus_find(ufr->ufr_name); + if (theywant == NULL || theywant->uif == NULL) + return (ENXIO); + + uif = theywant->uif; + + 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; + + 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); + + 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; + + 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); + + 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); +} + +static int +usbpf_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, + struct thread *td) +{ + struct usbpf_d *ud; + int error; + + error = devfs_get_cdevpriv((void **)&ud); + 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()]. + */ + case UIOCGBLEN: + *(u_int *)addr = ud->ud_bufsize; + 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: + { + struct timeval *tv = (struct timeval *)addr; + + /* + * Subtract 1 tick from tvtohz() since this isn't + * a one-shot timer. + */ + if ((error = itimerfix(tv)) == 0) + ud->ud_rtout = tvtohz(tv) - 1; + break; + } + + /* + * Get read timeout. + */ + case UIOCGRTIMEOUT: + { + struct timeval *tv = (struct timeval *)addr; + + tv->tv_sec = ud->ud_rtout / hz; + tv->tv_usec = (ud->ud_rtout % hz) * tick; + break; + } + + /* + * Get packet stats. + */ + case UIOCGSTATS: + { + struct usbpf_stat *us = (struct usbpf_stat *)addr; + + /* XXXCSJP overflow */ + us->us_recv = ud->ud_rcount; + us->us_drop = ud->ud_dcount; + break; + } + + case UIOCVERSION: + { + struct usbpf_version *uv = (struct usbpf_version *)addr; + + uv->uv_major = USBPF_MAJOR_VERSION; + uv->uv_minor = USBPF_MINOR_VERSION; + break; + } + + /* + * Set interface. + */ + case UIOCSETIF: + error = usbpf_setif(ud, (struct usbpf_ifreq *)addr); + break; + + } + return (error); +} + +/* + * Support for select() and poll() system calls + * + * Return true iff the specific operation will not block indefinitely. + * Otherwise, return false but make a note that a selwakeup() must be done. + */ +static int +usbpf_poll(struct cdev *dev, int events, struct thread *td) +{ + + /* NOT IMPLEMENTED */ + return (ENOSYS); +} + +/* + * Support for kevent() system call. Register EVFILT_READ filters and + * reject all others. + */ +int +usbpf_kqfilter(struct cdev *dev, struct knote *kn) +{ + + /* NOT IMPLEMENTED */ + return (ENOSYS); +} + +/* + * Attach file to the usbpf interface, i.e. make d listen on bp. + */ +static void +usbpf_attachd(struct usbpf_d *ud, struct usbpf_if *uif) +{ + + USBPFIF_LOCK(uif); + ud->ud_bif = uif; + LIST_INSERT_HEAD(&uif->uif_dlist, ud, ud_next); + + usbpf_uifd_cnt++; + USBPFIF_UNLOCK(uif); +} + +/* + * 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); +} + +void +usbpf_attach(struct usb_bus *ubus, struct usbpf_if **driverp) +{ + struct usbpf_if *uif; + + 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; + + mtx_lock(&usbpf_mtx); + LIST_INSERT_HEAD(&usbpf_iflist, uif, uif_next); + mtx_unlock(&usbpf_mtx); + + if (bootverbose) + device_printf(ubus->parent, "usbpf attached\n"); +} + +/* + * If there are processes sleeping on this descriptor, wake them up. + */ +static __inline void +usbpf_wakeup(struct usbpf_d *ud) +{ + + USBPFD_LOCK_ASSERT(ud); + if (ud->ud_state == USBPF_WAITING) { + callout_stop(&ud->ud_callout); + ud->ud_state = USBPF_IDLE; + } + 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 */ + return; + } + + LIST_REMOVE(uif, uif_next); + mtx_unlock(&usbpf_mtx); + + while ((ud = LIST_FIRST(&uif->uif_dlist)) != NULL) { + usbpf_detachd(ud); + USBPFD_LOCK(ud); + usbpf_wakeup(ud); + USBPFD_UNLOCK(ud); + } + + mtx_destroy(&uif->uif_mtx); + free(uif, M_USBPF); +} + +/* 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) + +#define USBPF_TSTAMP_NONE 0 +#define USBPF_TSTAMP_FAST 1 +#define USBPF_TSTAMP_NORMAL 2 + +static int +usbpf_ts_quality(int tstype) +{ + + if (tstype == USBPF_T_NONE) + return (USBPF_TSTAMP_NONE); + if ((tstype & USBPF_T_FAST) != 0) + return (USBPF_TSTAMP_FAST); + + return (USBPF_TSTAMP_NORMAL); +} + +static int +usbpf_gettime(struct bintime *bt, int tstype) +{ + int quality; + + quality = usbpf_ts_quality(tstype); + if (quality == USBPF_TSTAMP_NONE) + return (quality); + if (quality == USBPF_TSTAMP_NORMAL) + binuptime(bt); + else + getbinuptime(bt); + + return (quality); +} + +/* + * 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) +{ + + USBPFD_LOCK_ASSERT(ud); + + return (0); +} + +/* + * 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) +{ + + USBPFD_LOCK_ASSERT(ud); + return (1); +} + +/* + * 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) +{ + + USBPFD_LOCK_ASSERT(ud); +} + +/* + * 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"); + } +} + +#define SIZEOF_USBPF_HDR(type) \ + (offsetof(type, uh_hdrlen) + sizeof(((type *)0)->uh_hdrlen)) + +static int +usbpf_hdrlen(struct usbpf_d *ud) +{ + int hdrlen; + + hdrlen = ud->ud_bif->uif_hdrlen; + hdrlen += SIZEOF_USBPF_HDR(struct usbpf_xhdr); + hdrlen = USBPF_WORDALIGN(hdrlen); + + return (hdrlen - ud->ud_bif->uif_hdrlen); +} + +static void +usbpf_bintime2ts(struct bintime *bt, struct usbpf_ts *ts, int tstype) +{ + struct bintime bt2; + struct timeval tsm; + struct timespec tsn; + + if ((tstype & USBPF_T_MONOTONIC) == 0) { + bt2 = *bt; + bintime_add(&bt2, &boottimebin); + bt = &bt2; + } + 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; + + 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. + */ + 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); + } + + /* + * 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; + + /* + * 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; + + /* + * 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)); + + /* + * 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; + + 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); + } + USBPFD_UNLOCK(ud); + } + USBPFIF_UNLOCK(uif); +} + +static uint32_t +usbpf_aggregate_xferflags(struct usb_xfer_flags *flags) +{ + uint32_t val = 0; + + 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); +} + +static uint32_t +usbpf_aggregate_status(struct usb_xfer_flags_int *flags) +{ + uint32_t val = 0; + + 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; + + return (val); +} + +void +usbpf_xfertap(struct usb_xfer *xfer, int type) +{ + struct usb_endpoint *ep = xfer->endpoint; + struct usb_page_search res; + struct usb_xfer_root *info = xfer->xroot; + struct usb_bus *bus = info->bus; + struct usbpf_pkthdr *up; + usb_frlength_t isoc_offset = 0; + int i; + char *buf, *ptr, *end; + + /* + * NB: usbpf_uifd_cnt isn't protected by USBPFIF_LOCK() because it's + * not harmful. + */ + if (usbpf_uifd_cnt == 0) + return; + + /* + * 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); + + 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); + } + + up->up_error = htole32(xfer->error); + up->up_interval = htole32(xfer->interval); + ptr += sizeof(struct usbpf_pkthdr); + + 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); +} + +static void +usbpf_append_bytes(struct usbpf_d *ud, caddr_t buf, u_int offset, void *src, + u_int len) +{ + + USBPFD_LOCK_ASSERT(ud); + + switch (ud->ud_bufmode) { + case USBPF_BUFMODE_BUFFER: + return (usbpf_buffer_append_bytes(ud, buf, offset, src, len)); + default: + panic("usbpf_buf_append_bytes"); + } +} + +static void +usbpf_drvinit(void *unused) +{ + struct cdev *dev; + + mtx_init(&usbpf_mtx, "USB packet filter global lock", NULL, + MTX_DEF); + LIST_INIT(&usbpf_iflist); + + dev = make_dev(&usbpf_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "usbpf"); +} + +SYSINIT(usbpf_dev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, usbpf_drvinit, NULL); diff --git a/sys/dev/usb/usb_pf.h b/sys/dev/usb/usb_pf.h new file mode 100644 index 000000000000..f5ed9a080961 --- /dev/null +++ b/sys/dev/usb/usb_pf.h @@ -0,0 +1,319 @@ +/*- + * 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. + * + * 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. + * 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 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS 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. + * + * $FreeBSD$ + */ + +#ifndef _DEV_USB_PF_H +#define _DEV_USB_PF_H + +#ifdef _KERNEL +#include +#include +#include +#include +#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 usbpf_if; + +/* + * Alignment macros. USBPF_WORDALIGN rounds up to the next + * even multiple of USBPF_ALIGNMENT. + */ +#define USBPF_ALIGNMENT sizeof(long) +#define USBPF_WORDALIGN(x) (((x)+(USBPF_ALIGNMENT-1))&~(USBPF_ALIGNMENT-1)) + +/* + * The instruction encodings. + */ + +/* instruction classes */ +#define USBPF_CLASS(code) ((code) & 0x07) +#define USBPF_LD 0x00 +#define USBPF_LDX 0x01 +#define USBPF_ST 0x02 +#define USBPF_STX 0x03 +#define USBPF_ALU 0x04 +#define USBPF_JMP 0x05 +#define USBPF_RET 0x06 +#define USBPF_MISC 0x07 + +/* ld/ldx fields */ +#define USBPF_SIZE(code) ((code) & 0x18) +#define USBPF_W 0x00 +#define USBPF_H 0x08 +#define USBPF_B 0x10 +#define USBPF_MODE(code) ((code) & 0xe0) +#define USBPF_IMM 0x00 +#define USBPF_ABS 0x20 +#define USBPF_IND 0x40 +#define USBPF_MEM 0x60 +#define USBPF_LEN 0x80 +#define USBPF_MSH 0xa0 + +/* alu/jmp fields */ +#define USBPF_OP(code) ((code) & 0xf0) +#define USBPF_ADD 0x00 +#define USBPF_SUB 0x10 +#define USBPF_MUL 0x20 +#define USBPF_DIV 0x30 +#define USBPF_OR 0x40 +#define USBPF_AND 0x50 +#define USBPF_LSH 0x60 +#define USBPF_RSH 0x70 +#define USBPF_NEG 0x80 +#define USBPF_JA 0x00 +#define USBPF_JEQ 0x10 +#define USBPF_JGT 0x20 +#define USBPF_JGE 0x30 +#define USBPF_JSET 0x40 +#define USBPF_SRC(code) ((code) & 0x08) +#define USBPF_K 0x00 +#define USBPF_X 0x08 + +/* ret - USBPF_K and USBPF_X also apply */ +#define USBPF_RVAL(code) ((code) & 0x18) +#define USBPF_A 0x10 + +/* misc */ +#define USBPF_MISCOP(code) ((code) & 0xf8) +#define USBPF_TAX 0x00 +#define USBPF_TXA 0x80 + +/* + * The instruction data structure. + */ +struct usbpf_insn { + u_short code; + u_char jt; + u_char jf; + usbpf_u_int32 k; +}; + +#ifdef _KERNEL + +/* + * Descriptor associated with each open uff file. + */ + +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 */ + + int ud_bufsize; /* absolute length of buffers */ + + 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 */ + + 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 */ +}; + +#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) + +/* + * Descriptor associated with each attached hardware interface. + */ +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 */ +}; + +#define USBPFIF_LOCK(uif) mtx_lock(&(uif)->uif_mtx) +#define USBPFIF_UNLOCK(uif) mtx_unlock(&(uif)->uif_mtx) + +#endif + +/* + * 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) */ +}; + +#define USBPF_BUFMODE_BUFFER 1 /* Kernel buffers with read(). */ +#define USBPF_BUFMODE_ZBUF 2 /* Zero-copy buffers. */ + +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]; +}; + +struct usbpf_version { + u_short uv_major; + u_short uv_minor; +}; +#define USBPF_MAJOR_VERSION 1 +#define USBPF_MINOR_VERSION 1 + +#define USBPF_IFNAMSIZ 32 +struct usbpf_ifreq { + /* bus name, e.g. "usbus0" */ + char ufr_name[USBPF_IFNAMSIZ]; +}; + +/* + * Structure for UIOCSETF. + */ +struct usbpf_program { + u_int uf_len; + struct usbpf_insn *uf_insns; +}; + +/* + * Struct returned by UIOCGSTATS. + */ +struct usbpf_stat { + u_int us_recv; /* number of packets received */ + u_int us_drop; /* number of packets dropped */ +}; + +#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 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 diff --git a/sys/dev/usb/usb_transfer.c b/sys/dev/usb/usb_transfer.c index e0f5a3bc7cdd..cdaa227c52a6 100644 --- a/sys/dev/usb/usb_transfer.c +++ b/sys/dev/usb/usb_transfer.c @@ -60,6 +60,7 @@ #include #include +#include struct usb_std_packet_size { struct { @@ -2196,6 +2197,9 @@ usbd_callback_wrapper(struct usb_xfer_queue *pq) } } + if (xfer->usb_state != USB_ST_SETUP) + usbpf_xfertap(xfer, USBPF_XFERTAP_DONE); + /* call processing routine */ (xfer->callback) (xfer, xfer->error); @@ -2383,6 +2387,8 @@ usbd_transfer_start_cb(void *arg) DPRINTF("start\n"); + usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT); + /* start the transfer */ (ep->methods->start) (xfer); @@ -2560,6 +2566,8 @@ usbd_pipe_start(struct usb_xfer_queue *pq) } DPRINTF("start\n"); + usbpf_xfertap(xfer, USBPF_XFERTAP_SUBMIT); + /* start USB transfer */ (ep->methods->start) (xfer); diff --git a/sys/modules/usb/usb/Makefile b/sys/modules/usb/usb/Makefile index 32a210750059..5bae119aaae6 100644 --- a/sys/modules/usb/usb/Makefile +++ b/sys/modules/usb/usb/Makefile @@ -32,11 +32,11 @@ S= ${.CURDIR}/../../.. KMOD= usb SRCS= bus_if.h device_if.h usb_if.h usb_if.c vnode_if.h \ opt_usb.h opt_bus.h opt_ddb.h \ - usbdevs.h usbdevs_data.h \ + usb_pf.h usbdevs.h usbdevs_data.h \ usb_busdma.c usb_controller.c usb_compat_linux.c usb_core.c usb_debug.c \ usb_dev.c usb_device.c usb_dynamic.c usb_error.c usb_generic.c \ usb_handle_request.c usb_hid.c usb_hub.c usb_lookup.c usb_mbuf.c \ - usb_msctest.c usb_parse.c usb_process.c usb_request.c \ + usb_msctest.c usb_parse.c usb_pf.c usb_process.c usb_request.c \ usb_transfer.c usb_util.c .include