1215649Sweongyo/*- 2215649Sweongyo * Copyright (c) 1990, 1991, 1993 3215649Sweongyo * The Regents of the University of California. All rights reserved. 4215649Sweongyo * 5215649Sweongyo * This code is derived from the Stanford/CMU enet packet filter, 6215649Sweongyo * (net/enet.c) distributed as part of 4.3BSD, and code contributed 7215649Sweongyo * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence 8215649Sweongyo * Berkeley Laboratory. 9215649Sweongyo * 10215649Sweongyo * Redistribution and use in source and binary forms, with or without 11215649Sweongyo * modification, are permitted provided that the following conditions 12215649Sweongyo * are met: 13215649Sweongyo * 1. Redistributions of source code must retain the above copyright 14215649Sweongyo * notice, this list of conditions and the following disclaimer. 15215649Sweongyo * 2. Redistributions in binary form must reproduce the above copyright 16215649Sweongyo * notice, this list of conditions and the following disclaimer in the 17215649Sweongyo * documentation and/or other materials provided with the distribution. 18215649Sweongyo * 4. Neither the name of the University nor the names of its contributors 19215649Sweongyo * may be used to endorse or promote products derived from this software 20215649Sweongyo * without specific prior written permission. 21215649Sweongyo * 22215649Sweongyo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23215649Sweongyo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24215649Sweongyo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25215649Sweongyo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26215649Sweongyo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27215649Sweongyo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28215649Sweongyo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29215649Sweongyo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30215649Sweongyo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31215649Sweongyo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32215649Sweongyo * SUCH DAMAGE. 33215649Sweongyo */ 34215649Sweongyo 35215649Sweongyo#include <sys/cdefs.h> 36215649Sweongyo__FBSDID("$FreeBSD$"); 37215649Sweongyo#include <sys/param.h> 38215649Sweongyo#include <sys/kernel.h> 39215649Sweongyo#include <sys/bus.h> 40215649Sweongyo#include <sys/fcntl.h> 41215649Sweongyo#include <sys/malloc.h> 42215649Sweongyo#include <sys/proc.h> 43215649Sweongyo#include <sys/socket.h> 44215649Sweongyo#include <sys/sockio.h> 45215649Sweongyo#include <net/if.h> 46215802Sweongyo#include <net/if_types.h> 47215802Sweongyo#include <net/bpf.h> 48220301Shselasky#include <sys/sysctl.h> 49215649Sweongyo 50215649Sweongyo#include <dev/usb/usb.h> 51215649Sweongyo#include <dev/usb/usbdi.h> 52215649Sweongyo#include <dev/usb/usb_busdma.h> 53215649Sweongyo#include <dev/usb/usb_controller.h> 54215649Sweongyo#include <dev/usb/usb_core.h> 55215649Sweongyo#include <dev/usb/usb_process.h> 56215649Sweongyo#include <dev/usb/usb_device.h> 57215649Sweongyo#include <dev/usb/usb_bus.h> 58215649Sweongyo#include <dev/usb/usb_pf.h> 59215649Sweongyo#include <dev/usb/usb_transfer.h> 60215649Sweongyo 61220301Shselaskystatic int usb_no_pf; 62220301Shselasky 63220301ShselaskySYSCTL_INT(_hw_usb, OID_AUTO, no_pf, CTLFLAG_RW, 64220301Shselasky &usb_no_pf, 0, "Set to disable USB packet filtering"); 65220301Shselasky 66220301ShselaskyTUNABLE_INT("hw.usb.no_pf", &usb_no_pf); 67220301Shselasky 68215802Sweongyovoid 69215802Sweongyousbpf_attach(struct usb_bus *ubus) 70215649Sweongyo{ 71215802Sweongyo struct ifnet *ifp; 72215649Sweongyo 73220301Shselasky if (usb_no_pf != 0) { 74220301Shselasky ubus->ifp = NULL; 75220301Shselasky return; 76220301Shselasky } 77220301Shselasky 78215802Sweongyo ifp = ubus->ifp = if_alloc(IFT_USB); 79220301Shselasky if (ifp == NULL) { 80220301Shselasky device_printf(ubus->parent, "usbpf: Could not allocate " 81220301Shselasky "instance\n"); 82220301Shselasky return; 83220301Shselasky } 84220301Shselasky 85215812Sweongyo if_initname(ifp, "usbus", device_get_unit(ubus->bdev)); 86216267Sweongyo ifp->if_flags = IFF_CANTCONFIG; 87215802Sweongyo if_attach(ifp); 88216091Sweongyo if_up(ifp); 89215649Sweongyo 90215649Sweongyo /* 91220301Shselasky * XXX According to the specification of DLT_USB, it indicates 92220301Shselasky * packets beginning with USB setup header. But not sure all 93220301Shselasky * packets would be. 94215649Sweongyo */ 95215802Sweongyo bpfattach(ifp, DLT_USB, USBPF_HDR_LEN); 96215649Sweongyo 97215649Sweongyo if (bootverbose) 98220301Shselasky device_printf(ubus->parent, "usbpf: Attached\n"); 99215649Sweongyo} 100215649Sweongyo 101215649Sweongyovoid 102215649Sweongyousbpf_detach(struct usb_bus *ubus) 103215649Sweongyo{ 104215802Sweongyo struct ifnet *ifp = ubus->ifp; 105215649Sweongyo 106215802Sweongyo if (ifp != NULL) { 107215802Sweongyo bpfdetach(ifp); 108216091Sweongyo if_down(ifp); 109215802Sweongyo if_detach(ifp); 110215802Sweongyo if_free(ifp); 111215649Sweongyo } 112215802Sweongyo ubus->ifp = NULL; 113215649Sweongyo} 114215649Sweongyo 115215649Sweongyostatic uint32_t 116215649Sweongyousbpf_aggregate_xferflags(struct usb_xfer_flags *flags) 117215649Sweongyo{ 118215649Sweongyo uint32_t val = 0; 119215649Sweongyo 120215649Sweongyo if (flags->force_short_xfer == 1) 121215649Sweongyo val |= USBPF_FLAG_FORCE_SHORT_XFER; 122215649Sweongyo if (flags->short_xfer_ok == 1) 123215649Sweongyo val |= USBPF_FLAG_SHORT_XFER_OK; 124215649Sweongyo if (flags->short_frames_ok == 1) 125215649Sweongyo val |= USBPF_FLAG_SHORT_FRAMES_OK; 126215649Sweongyo if (flags->pipe_bof == 1) 127215649Sweongyo val |= USBPF_FLAG_PIPE_BOF; 128215649Sweongyo if (flags->proxy_buffer == 1) 129215649Sweongyo val |= USBPF_FLAG_PROXY_BUFFER; 130215649Sweongyo if (flags->ext_buffer == 1) 131215649Sweongyo val |= USBPF_FLAG_EXT_BUFFER; 132215649Sweongyo if (flags->manual_status == 1) 133215649Sweongyo val |= USBPF_FLAG_MANUAL_STATUS; 134215649Sweongyo if (flags->no_pipe_ok == 1) 135215649Sweongyo val |= USBPF_FLAG_NO_PIPE_OK; 136215649Sweongyo if (flags->stall_pipe == 1) 137215649Sweongyo val |= USBPF_FLAG_STALL_PIPE; 138215649Sweongyo return (val); 139215649Sweongyo} 140215649Sweongyo 141215649Sweongyostatic uint32_t 142215649Sweongyousbpf_aggregate_status(struct usb_xfer_flags_int *flags) 143215649Sweongyo{ 144215649Sweongyo uint32_t val = 0; 145215649Sweongyo 146215649Sweongyo if (flags->open == 1) 147215649Sweongyo val |= USBPF_STATUS_OPEN; 148215649Sweongyo if (flags->transferring == 1) 149215649Sweongyo val |= USBPF_STATUS_TRANSFERRING; 150215649Sweongyo if (flags->did_dma_delay == 1) 151215649Sweongyo val |= USBPF_STATUS_DID_DMA_DELAY; 152215649Sweongyo if (flags->did_close == 1) 153215649Sweongyo val |= USBPF_STATUS_DID_CLOSE; 154215649Sweongyo if (flags->draining == 1) 155215649Sweongyo val |= USBPF_STATUS_DRAINING; 156215649Sweongyo if (flags->started == 1) 157215649Sweongyo val |= USBPF_STATUS_STARTED; 158215649Sweongyo if (flags->bandwidth_reclaimed == 1) 159215649Sweongyo val |= USBPF_STATUS_BW_RECLAIMED; 160215649Sweongyo if (flags->control_xfr == 1) 161215649Sweongyo val |= USBPF_STATUS_CONTROL_XFR; 162215649Sweongyo if (flags->control_hdr == 1) 163215649Sweongyo val |= USBPF_STATUS_CONTROL_HDR; 164215649Sweongyo if (flags->control_act == 1) 165215649Sweongyo val |= USBPF_STATUS_CONTROL_ACT; 166215649Sweongyo if (flags->control_stall == 1) 167215649Sweongyo val |= USBPF_STATUS_CONTROL_STALL; 168215649Sweongyo if (flags->short_frames_ok == 1) 169215649Sweongyo val |= USBPF_STATUS_SHORT_FRAMES_OK; 170215649Sweongyo if (flags->short_xfer_ok == 1) 171215649Sweongyo val |= USBPF_STATUS_SHORT_XFER_OK; 172215649Sweongyo#if USB_HAVE_BUSDMA 173215649Sweongyo if (flags->bdma_enable == 1) 174215649Sweongyo val |= USBPF_STATUS_BDMA_ENABLE; 175215649Sweongyo if (flags->bdma_no_post_sync == 1) 176215649Sweongyo val |= USBPF_STATUS_BDMA_NO_POST_SYNC; 177215649Sweongyo if (flags->bdma_setup == 1) 178215649Sweongyo val |= USBPF_STATUS_BDMA_SETUP; 179215649Sweongyo#endif 180215649Sweongyo if (flags->isochronous_xfr == 1) 181215649Sweongyo val |= USBPF_STATUS_ISOCHRONOUS_XFR; 182215649Sweongyo if (flags->curr_dma_set == 1) 183215649Sweongyo val |= USBPF_STATUS_CURR_DMA_SET; 184215649Sweongyo if (flags->can_cancel_immed == 1) 185215649Sweongyo val |= USBPF_STATUS_CAN_CANCEL_IMMED; 186215649Sweongyo if (flags->doing_callback == 1) 187215649Sweongyo val |= USBPF_STATUS_DOING_CALLBACK; 188215649Sweongyo 189215649Sweongyo return (val); 190215649Sweongyo} 191215649Sweongyo 192220301Shselaskystatic int 193220301Shselaskyusbpf_xfer_frame_is_read(struct usb_xfer *xfer, uint32_t frame) 194220301Shselasky{ 195220301Shselasky int isread; 196220301Shselasky 197220301Shselasky if ((frame == 0) && (xfer->flags_int.control_xfr != 0) && 198220301Shselasky (xfer->flags_int.control_hdr != 0)) { 199220301Shselasky /* special case */ 200220301Shselasky if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 201220301Shselasky /* The device controller writes to memory */ 202220301Shselasky isread = 1; 203220301Shselasky } else { 204220301Shselasky /* The host controller reads from memory */ 205220301Shselasky isread = 0; 206220301Shselasky } 207220301Shselasky } else { 208220301Shselasky isread = USB_GET_DATA_ISREAD(xfer); 209220301Shselasky } 210220301Shselasky return (isread); 211220301Shselasky} 212220301Shselasky 213220301Shselaskystatic uint32_t 214220301Shselaskyusbpf_xfer_precompute_size(struct usb_xfer *xfer, int type) 215220301Shselasky{ 216220301Shselasky uint32_t totlen; 217220301Shselasky uint32_t x; 218220301Shselasky uint32_t nframes; 219220301Shselasky 220220301Shselasky if (type == USBPF_XFERTAP_SUBMIT) 221220301Shselasky nframes = xfer->nframes; 222220301Shselasky else 223220301Shselasky nframes = xfer->aframes; 224220301Shselasky 225220301Shselasky totlen = USBPF_HDR_LEN + (USBPF_FRAME_HDR_LEN * nframes); 226220301Shselasky 227220301Shselasky /* precompute all trace lengths */ 228220301Shselasky for (x = 0; x != nframes; x++) { 229220301Shselasky if (usbpf_xfer_frame_is_read(xfer, x)) { 230220301Shselasky if (type != USBPF_XFERTAP_SUBMIT) { 231220301Shselasky totlen += USBPF_FRAME_ALIGN( 232220301Shselasky xfer->frlengths[x]); 233220301Shselasky } 234220301Shselasky } else { 235220301Shselasky if (type == USBPF_XFERTAP_SUBMIT) { 236220301Shselasky totlen += USBPF_FRAME_ALIGN( 237220301Shselasky xfer->frlengths[x]); 238220301Shselasky } 239220301Shselasky } 240220301Shselasky } 241220301Shselasky return (totlen); 242220301Shselasky} 243220301Shselasky 244215649Sweongyovoid 245215649Sweongyousbpf_xfertap(struct usb_xfer *xfer, int type) 246215649Sweongyo{ 247220301Shselasky struct usb_bus *bus; 248215649Sweongyo struct usbpf_pkthdr *up; 249220301Shselasky struct usbpf_framehdr *uf; 250220301Shselasky usb_frlength_t offset; 251220301Shselasky uint32_t totlen; 252220301Shselasky uint32_t frame; 253220301Shselasky uint32_t temp; 254220301Shselasky uint32_t nframes; 255220301Shselasky uint32_t x; 256220301Shselasky uint8_t *buf; 257220301Shselasky uint8_t *ptr; 258215649Sweongyo 259220301Shselasky bus = xfer->xroot->bus; 260220301Shselasky 261220301Shselasky /* sanity checks */ 262220301Shselasky if (usb_no_pf != 0) 263220301Shselasky return; 264266258Shselasky if (bus->ifp == NULL || bus->ifp->if_bpf == NULL) 265220301Shselasky return; 266215802Sweongyo if (!bpf_peers_present(bus->ifp->if_bpf)) 267215649Sweongyo return; 268215649Sweongyo 269220301Shselasky totlen = usbpf_xfer_precompute_size(xfer, type); 270220301Shselasky 271220301Shselasky if (type == USBPF_XFERTAP_SUBMIT) 272220301Shselasky nframes = xfer->nframes; 273220301Shselasky else 274220301Shselasky nframes = xfer->aframes; 275220301Shselasky 276215649Sweongyo /* 277220301Shselasky * XXX TODO XXX 278220301Shselasky * 279220301Shselasky * When BPF supports it we could pass a fragmented array of 280220301Shselasky * buffers avoiding the data copy operation here. 281215649Sweongyo */ 282220301Shselasky buf = ptr = malloc(totlen, M_TEMP, M_NOWAIT); 283215649Sweongyo if (buf == NULL) { 284220301Shselasky device_printf(bus->parent, "usbpf: Out of memory\n"); 285215649Sweongyo return; 286215649Sweongyo } 287215649Sweongyo 288215649Sweongyo up = (struct usbpf_pkthdr *)ptr; 289220301Shselasky ptr += USBPF_HDR_LEN; 290220301Shselasky 291220301Shselasky /* fill out header */ 292220301Shselasky temp = device_get_unit(bus->bdev); 293220301Shselasky up->up_totlen = htole32(totlen); 294220301Shselasky up->up_busunit = htole32(temp); 295220301Shselasky up->up_address = xfer->xroot->udev->device_index; 296220301Shselasky if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) 297220301Shselasky up->up_mode = USBPF_MODE_DEVICE; 298220301Shselasky else 299220301Shselasky up->up_mode = USBPF_MODE_HOST; 300215649Sweongyo up->up_type = type; 301220301Shselasky up->up_xfertype = xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE; 302220301Shselasky temp = usbpf_aggregate_xferflags(&xfer->flags); 303220301Shselasky up->up_flags = htole32(temp); 304220301Shselasky temp = usbpf_aggregate_status(&xfer->flags_int); 305220301Shselasky up->up_status = htole32(temp); 306220301Shselasky temp = xfer->error; 307220301Shselasky up->up_error = htole32(temp); 308220301Shselasky temp = xfer->interval; 309220301Shselasky up->up_interval = htole32(temp); 310220301Shselasky up->up_frames = htole32(nframes); 311220301Shselasky temp = xfer->max_packet_size; 312220301Shselasky up->up_packet_size = htole32(temp); 313220301Shselasky temp = xfer->max_packet_count; 314220301Shselasky up->up_packet_count = htole32(temp); 315220301Shselasky temp = xfer->endpointno; 316220301Shselasky up->up_endpoint = htole32(temp); 317220301Shselasky up->up_speed = xfer->xroot->udev->speed; 318215649Sweongyo 319220301Shselasky /* clear reserved area */ 320220301Shselasky memset(up->up_reserved, 0, sizeof(up->up_reserved)); 321215649Sweongyo 322220301Shselasky /* init offset and frame */ 323220301Shselasky offset = 0; 324220301Shselasky frame = 0; 325215649Sweongyo 326220301Shselasky /* iterate all the USB frames and copy data, if any */ 327220301Shselasky for (x = 0; x != nframes; x++) { 328220301Shselasky uint32_t length; 329220301Shselasky int isread; 330220301Shselasky 331220301Shselasky /* get length */ 332220301Shselasky length = xfer->frlengths[x]; 333220301Shselasky 334220301Shselasky /* get frame header pointer */ 335220301Shselasky uf = (struct usbpf_framehdr *)ptr; 336220301Shselasky ptr += USBPF_FRAME_HDR_LEN; 337220301Shselasky 338220301Shselasky /* fill out packet header */ 339220301Shselasky uf->length = htole32(length); 340220301Shselasky uf->flags = 0; 341220301Shselasky 342220301Shselasky /* get information about data read/write */ 343220301Shselasky isread = usbpf_xfer_frame_is_read(xfer, x); 344220301Shselasky 345220301Shselasky /* check if we need to copy any data */ 346220301Shselasky if (isread) { 347220301Shselasky if (type == USBPF_XFERTAP_SUBMIT) 348220301Shselasky length = 0; 349220301Shselasky else { 350220301Shselasky uf->flags |= htole32( 351220301Shselasky USBPF_FRAMEFLAG_DATA_FOLLOWS); 352220301Shselasky } 353220301Shselasky } else { 354220301Shselasky if (type != USBPF_XFERTAP_SUBMIT) 355220301Shselasky length = 0; 356220301Shselasky else { 357220301Shselasky uf->flags |= htole32( 358220301Shselasky USBPF_FRAMEFLAG_DATA_FOLLOWS); 359220301Shselasky } 360220301Shselasky } 361220301Shselasky 362220301Shselasky /* check if data is read direction */ 363220301Shselasky if (isread) 364220301Shselasky uf->flags |= htole32(USBPF_FRAMEFLAG_READ); 365220301Shselasky 366220301Shselasky /* copy USB data, if any */ 367220301Shselasky if (length != 0) { 368220301Shselasky /* copy data */ 369220301Shselasky usbd_copy_out(&xfer->frbuffers[frame], 370220301Shselasky offset, ptr, length); 371220301Shselasky 372220301Shselasky /* align length */ 373220301Shselasky temp = USBPF_FRAME_ALIGN(length); 374220301Shselasky 375220301Shselasky /* zero pad */ 376220301Shselasky if (temp != length) 377220301Shselasky memset(ptr + length, 0, temp - length); 378220301Shselasky 379220301Shselasky ptr += temp; 380220301Shselasky } 381220301Shselasky 382220301Shselasky if (xfer->flags_int.isochronous_xfr) { 383220301Shselasky offset += usbd_xfer_old_frame_length(xfer, x); 384220301Shselasky } else { 385220301Shselasky frame ++; 386220301Shselasky } 387215649Sweongyo } 388215649Sweongyo 389220301Shselasky bpf_tap(bus->ifp->if_bpf, buf, totlen); 390220301Shselasky 391215802Sweongyo free(buf, M_TEMP); 392215649Sweongyo} 393