-/* $OpenBSD: usb.c,v 1.117 2018/02/19 09:20:45 jsg Exp $ */
+/* $OpenBSD: usb.c,v 1.118 2018/02/26 13:06:49 mpi Exp $ */
/* $NetBSD: usb.c,v 1.77 2003/01/01 00:10:26 thorpej Exp $ */
/*
#if NBPFILTER > 0
struct usb_softc *sc = (struct usb_softc *)bus->usbctl;
usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
- struct usbpcap_ctl_hdr uch;
- struct usbpcap_pkt_hdr *uph = &uch.uch_hdr;
+ union {
+ struct usbpcap_ctl_hdr uch;
+ struct usbpcap_iso_hdr_full uih;
+ } h;
+ struct usbpcap_pkt_hdr *uph = &h.uch.uch_hdr;
+ uint32_t nframes, offset;
unsigned int bpfdir;
void *data = NULL;
+ size_t flen;
caddr_t bpf;
+ int i;
bpf = bus->bpf;
if (bpf == NULL)
switch (UE_GET_XFERTYPE(ed->bmAttributes)) {
case UE_CONTROL:
- /* Control transfer headers include an extra byte. */
- uph->uph_hlen = htole16(sizeof(uch));
+ /* Control transfer headers include an extra byte */
+ uph->uph_hlen = htole16(sizeof(struct usbpcap_ctl_hdr));
uph->uph_xfertype = USBPCAP_TRANSFER_CONTROL;
break;
case UE_ISOCHRONOUS:
- uph->uph_hlen = htole16(sizeof(*uph));
+ offset = 0;
+ nframes = xfer->nframes;
+#ifdef DIAGNOSTIC
+ if (nframes > _USBPCAP_MAX_ISOFRAMES) {
+ printf("%s: too many frames: %d > %d\n", __func__,
+ xfer->nframes, _USBPCAP_MAX_ISOFRAMES);
+ nframes = _USBPCAP_MAX_ISOFRAMES;
+ }
+#endif
+ /* Isochronous transfer headers include space for one frame */
+ flen = (nframes - 1) * sizeof(struct usbpcap_iso_pkt);
+ uph->uph_hlen = htole16(sizeof(struct usbpcap_iso_hdr) + flen);
uph->uph_xfertype = USBPCAP_TRANSFER_ISOCHRONOUS;
+ h.uih.uih_startframe = 0; /* not yet used */
+ h.uih.uih_nframes = nframes;
+ h.uih.uih_errors = 0; /* we don't have per-frame error */
+ for (i = 0; i < nframes; i++) {
+ h.uih.uih_frames[i].uip_offset = offset;
+ h.uih.uih_frames[i].uip_length = xfer->frlengths[i];
+ /* See above, we don't have per-frame error */
+ h.uih.uih_frames[i].uip_status = 0;
+ offset += xfer->frlengths[i];
+ }
break;
case UE_BULK:
uph->uph_hlen = htole16(sizeof(*uph));
/* Outgoing control requests start with a STAGE dump. */
if ((xfer->rqflags & URQ_REQUEST) && (dir == USBTAP_DIR_OUT)) {
- uch.uch_stage = USBPCAP_CONTROL_STAGE_SETUP;
+ h.uch.uch_stage = USBPCAP_CONTROL_STAGE_SETUP;
uph->uph_dlen = sizeof(usb_device_request_t);
bpf_tap_hdr(bpf, uph, uph->uph_hlen, &xfer->request,
uph->uph_dlen, BPF_DIRECTION_OUT);
if (!usbd_xfer_isread(xfer)) {
data = KERNADDR(&xfer->dmabuf, 0);
uph->uph_dlen = xfer->length;
- uch.uch_stage = USBPCAP_CONTROL_STAGE_DATA;
+ if (xfer->rqflags & URQ_REQUEST)
+ h.uch.uch_stage = USBPCAP_CONTROL_STAGE_DATA;
} else {
data = NULL;
uph->uph_dlen = 0;
- uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS;
+ if (xfer->rqflags & URQ_REQUEST)
+ h.uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS;
}
} else { /* USBTAP_DIR_IN */
bpfdir = BPF_DIRECTION_IN;
if (usbd_xfer_isread(xfer)) {
data = KERNADDR(&xfer->dmabuf, 0);
uph->uph_dlen = xfer->actlen;
- uch.uch_stage = USBPCAP_CONTROL_STAGE_DATA;
+ if (xfer->rqflags & URQ_REQUEST)
+ h.uch.uch_stage = USBPCAP_CONTROL_STAGE_DATA;
} else {
data = NULL;
uph->uph_dlen = 0;
- uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS;
+ if (xfer->rqflags & URQ_REQUEST)
+ h.uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS;
}
}
/* Incoming control requests with DATA need a STATUS stage. */
if ((xfer->rqflags & URQ_REQUEST) && (dir == USBTAP_DIR_IN) &&
- (uch.uch_stage == USBPCAP_CONTROL_STAGE_DATA)) {
- uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS;
+ (h.uch.uch_stage == USBPCAP_CONTROL_STAGE_DATA)) {
+ h.uch.uch_stage = USBPCAP_CONTROL_STAGE_STATUS;
uph->uph_dlen = 0;
bpf_tap_hdr(bpf, uph, uph->uph_hlen, NULL, 0, BPF_DIRECTION_IN);
}
-/* $OpenBSD: usbpcap.h,v 1.1 2018/02/03 13:37:37 mpi Exp $ */
+/* $OpenBSD: usbpcap.h,v 1.2 2018/02/26 13:06:49 mpi Exp $ */
/*
* Copyright (c) 2018 Martin Pieuchot
#define USBPCAP_CONTROL_STAGE_STATUS 2
} __attribute__((packed));
+struct usbpcap_iso_pkt {
+ uint32_t uip_offset;
+ uint32_t uip_length;
+ uint32_t uip_status;
+} __attribute__((packed));
+
+/*
+ * Header used when dumping isochronous transfers.
+ */
+struct usbpcap_iso_hdr {
+ struct usbpcap_pkt_hdr uih_hdr;
+ uint32_t uih_startframe;
+ uint32_t uih_nframes; /* number of frame */
+ uint32_t uih_errors; /* error count */
+ struct usbpcap_iso_pkt uih_frames[1];
+} __attribute__((packed));
+
+#ifdef _KERNEL
+/*
+ * OpenBSD specific, maximum number of frames per transfer used across
+ * all USB drivers. This allows us to setup the header on the stack.
+ */
+#define _USBPCAP_MAX_ISOFRAMES 40
+struct usbpcap_iso_hdr_full {
+ struct usbpcap_pkt_hdr uih_hdr;
+ uint32_t uih_startframe;
+ uint32_t uih_nframes;
+ uint32_t uih_errors;
+ struct usbpcap_iso_pkt uih_frames[_USBPCAP_MAX_ISOFRAMES];
+} __attribute__((packed));
+#endif /* _KERNEL */
#endif /* _USBCAP_H_ */