On Tue, Feb 20, 2018 at 03:05:33PM +0100, Martin Pieuchot wrote:
> Diff below implements the USBPcap interface for dumping USB isochronous
> frames.  It can be very useful to analyze what the stack is doing.  Note
> that tcpdump(8)'s snaplen default is too small to capture such frames. I
> used the following to analyze uaudio(4) traffic on ehci(4):
> 
>   # tcpdump -s 3303 -w usnd.pcap -i usb0
> 
> The first capture I did was with AUDIODEVICE=snd/0 then I did a second
> one with AUDIODEVICE=rsnd/0.  Like Stefan I hear some crackling noise
> in the first case.
> 
> What I could see after opening the pcap(3) files in wireshark confirmed
> my theory.  When using the raw audio device delay between frames is less
> than 8us.  However in the general case it jumps to 35us.
> 
> It is too early to say what needs to be fixed, but at least I'd like to
> get the USBPcap part in, ok?

Response from the peanut gallery...
This seems like a cool thing to have. I can try to test this later
when I get home from work.

> 
> Index: usb.c
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/usb.c,v
> retrieving revision 1.117
> diff -u -p -r1.117 usb.c
> --- usb.c     19 Feb 2018 09:20:45 -0000      1.117
> +++ usb.c     20 Feb 2018 13:34:43 -0000
> @@ -992,11 +992,17 @@ usb_tap(struct usbd_bus *bus, struct usb
>  #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)
> @@ -1004,13 +1010,34 @@ usb_tap(struct usbd_bus *bus, struct usb
>  
>       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));
> @@ -1034,7 +1061,7 @@ usb_tap(struct usbd_bus *bus, struct usb
>  
>       /* 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);
> @@ -1045,11 +1072,13 @@ usb_tap(struct usbd_bus *bus, struct usb
>               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;
> @@ -1057,11 +1086,13 @@ usb_tap(struct usbd_bus *bus, struct usb
>               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;
>               }
>       }
>  
> @@ -1070,8 +1101,8 @@ usb_tap(struct usbd_bus *bus, struct usb
>  
>       /* 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);
>       }
> Index: usbpcap.h
> ===================================================================
> RCS file: /cvs/src/sys/dev/usb/usbpcap.h,v
> retrieving revision 1.1
> diff -u -p -r1.1 usbpcap.h
> --- usbpcap.h 3 Feb 2018 13:37:37 -0000       1.1
> +++ usbpcap.h 20 Feb 2018 13:33:43 -0000
> @@ -53,4 +53,35 @@ struct usbpcap_ctl_hdr {
>  #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_ */
> 

Reply via email to