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