wireshark usb traces explanations

A USB URB is like an IP packet and a USB endpoint is like an IP port. USB endpoints 0x00-0x7F are on the host, and the endpoints 0x80-0xFF are on the device (I think). Therefore, the endpoint encodes the direction of the transfer. lsusb will show you what endpoints and which transfer types a device supports.

I'll use "packets" in quotes to mean the unit of activity that wireshark captures. These aren't literally what is being send on the wire. For example, the "packets" will have timestamps for when transfers were initiated, even though this isn't transmitted over the USB bus.

I think the most confusing aspect of sniffing the USB protocol is that you see two Wireshark "packets" for each USB URB. When the host initiates some transfer, that is a URB_SUBMIT (Wireshark display filter usb.urb_type == URB_SUBMIT) . When the transfer completes, that is a URB_COMPLETE (Wireshark display filter usb.urb_type == URB_COMPLETE)

From what I can tell, when there is a transfer from host to device, the SUBMIT "packet" contains the actual USB data transmitted. When there is a transfer from device to host (initiated by the host, as always), the COMPLETE "packet" contains the actual USB data transmitted.

From the point of view of analyzing a protocol, all other "packets" are a distraction OR a URB error. To filter out the distractions, I use the following display filter !(usb.urb_type == URB_SUBMIT && usb.endpoint_number.direction == IN) && !(usb.urb_type == URB_COMPLETE && usb.endpoint_number.direction == OUT)

I believe the USB protocol does involve some handshaking and ACKs and retransmissions, but this is all handled by the host controller, and the OS is not involved. I don't think, for example, the OS keeps track of the acknowledgements or retransmissions.

By the way, I am using the following command to analyze a protocol. In addition to doing the filtering above, it only displays the endpoint number (in decimal) and the USB data. This is on a GNU/Linux machine using the usbmon1 device to sniff, and assuming that the USB device I want to monitor is on bus 1 and has address 11.

tshark -i usbmon1 -Y "usb.device_address == 11 && !(usb.urb_type == URB_SUBMIT && usb.endpoint_address.direction == IN) && !(usb.urb_type == URB_COMPLETE && usb.endpoint_address.direction == OUT)" -Tfields -e usb.endpoint_address -e usb.capdata


WireShark USB logs are done at the OS level. With Linux its based on the data that usbmon generates which is based on Linux's internal URB structure described here. So, looking at kernel and WireShark comments and docs provides the best insight into what it is.

What I've found from the kernel docs is that the packets are usbmon structs followed by the data sent and received. This is the struct (copied from here):

struct usbmon_packet {
    u64 id;         /*  0: URB ID - from submission to callback */
    unsigned char type; /*  8: Same as text; extensible. */
    unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
    unsigned char epnum;    /*     Endpoint number and transfer direction */
    unsigned char devnum;   /*     Device address */
    u16 busnum;     /* 12: Bus number */
    char flag_setup;    /* 14: Same as text */
    char flag_data;     /* 15: Same as text; Binary zero is OK. */
    s64 ts_sec;     /* 16: gettimeofday */
    s32 ts_usec;        /* 24: gettimeofday */
    int status;     /* 28: */
    unsigned int length;    /* 32: Length of data (submitted or actual) */
    unsigned int len_cap;   /* 36: Delivered length */
    union {         /* 40: */
        unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
        struct iso_rec {        /* Only for ISO */
            int error_count;
            int numdesc;
        } iso;
    } s;
    int interval;       /* 48: Only for Interrupt and ISO */
    int start_frame;    /* 52: For ISO */
    unsigned int xfer_flags; /* 56: copy of URB's transfer_flags */
    unsigned int ndesc; /* 60: Actual number of ISO descriptors */
};

Tags:

Usb

Wireshark