16

I am trying to reverse engineer an usb (HID) device and cannot really figure out how what I see on wireshark (usbmon + wireshark on linux, or windows) relates to the usb protocol?. I have looked at the usb protocol from www.usb.org.

What does wireshark show?

1)One line per packet? (token, data, handshake)

2)One line per transaction? (token + [data] + handshake) (my guess)

3)One line per control transfer?

The direction of the transaction is very strange as well (to/from fields). At least,it does not match my expectations :-) ... And the data part of the enumeration, hid report etc... seems sometimes to be displayed with the setup data (8 bytes) and sometime not... I don't really know what URB is... there is no mention of that in the usb protocol as far as I could see... It looks to me that wireshark/usbmon trace at a higher stack level and tries to deduce what would be on the wire from that...

An example of what I can see is given below, what to we see here?.

a)I could not even find bmtype=0x20 (of the setup, frame No=599)in the specs.

b)Because I have a HID device, I assumed this could be a report/feature config (the enumeration is passed at this stage). So I could agree with the direction (host->device). but where is the data? Or there no data phase here? What is frame 600 then?

c)what is frame 600? the data?

d)what is frame 601? a status ACK?... but then the data and ACK have the same source?

No.     Time        Source                Destination           Protocol Length Info
    599 67.996889   host                  2.0                   USB      36     URB_CONTROL out

Frame 599: 36 bytes on wire (288 bits), 36 bytes captured (288 bits)
USB URB
    USBPcap pseudoheader length: 28
    IRP ID: 0xfffffa800a1e2610
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CLASS_DEVICE (0x001a)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 1
    Device address: 2
    Endpoint: 0x00, Direction: OUT
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    Control transfer stage: Setup (0)
    [Response in: 601]
    [bInterfaceClass: Unknown (0xffff)]
URB setup
    bmRequestType: 0x20
        0... .... = Direction: Host-to-device
        .01. .... = Type: Class (0x01)
        ...0 0000 = Recipient: Device (0x00)
    bRequest: 0
    wValue: 0x0000
    wIndex: 0
    wLength: 16

0000  1c 00 10 26 1e 0a 80 fa ff ff 00 00 00 00 1a 00   ...&............
0010  00 01 00 02 00 00 02 08 00 00 00 00 20 00 00 00   ............ ...
0020  00 00 10 00                                       ....

No.     Time        Source                Destination           Protocol Length Info
    600 67.997889   2.0                   host                  USB      44     URB_CONTROL out

Frame 600: 44 bytes on wire (352 bits), 44 bytes captured (352 bits)
USB URB
    USBPcap pseudoheader length: 28
    IRP ID: 0xfffffa800a1e2610
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 1
    Device address: 2
    Endpoint: 0x00, Direction: OUT
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 16
    Control transfer stage: Data (1)
    [Request in: 599]
    [Time from request: 0.001000000 seconds]
    [bInterfaceClass: Unknown (0xffff)]
CONTROL response data

0000  1c 00 10 26 1e 0a 80 fa ff ff 00 00 00 00 08 00   ...&............
0010  01 01 00 02 00 00 02 10 00 00 00 01 05 04 0d 56   ...............V
0020  fb 82 c0 1d 10 18 cc 02 00 00 00 01               ............

No.     Time        Source                Destination           Protocol Length Info
    601 67.997889   2.0                   host                  USB      28     GET STATUS Status

Frame 601: 28 bytes on wire (224 bits), 28 bytes captured (224 bits)
USB URB
    USBPcap pseudoheader length: 28
    IRP ID: 0xfffffa800a1e2610
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CONTROL_TRANSFER (0x0008)
    IRP information: 0x01, Direction: PDO -> FDO
    URB bus id: 1
    Device address: 2
    Endpoint: 0x00, Direction: OUT
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 0
    Control transfer stage: Status (2)
    [Request in: 599]
    [Time from request: 0.001000000 seconds]

0000  1c 00 10 26 1e 0a 80 fa ff ff 00 00 00 00 08 00   ...&............
0010  01 01 00 02 00 00 02 00 00 00 00 02               ............

Obviously I am missing something. A general explanation on how the wireshark display relates to the protocol and, (based on it), the meaning of the above trace is welcomed!

I originaly posted this on Stack Overflow, but was told it was not directly a programming question. Hope it fits better here.

2 Answers 2

18

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_address.direction == IN) && !(usb.urb_type == URB_COMPLETE && usb.endpoint_address.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

EDIT: the field endpoint_address was previously endpoint_number

5
  • Thanks for your answer, Gus. Actually this does not answer all my questions, but you gave the best (as unique) answer!. Would you mind commenting the capture I have included as example (taking from a HID device). What is it we see? what fields in the trace tells what? Thanks again!
    – user415772
    Feb 13, 2015 at 9:40
  • Has this changed recently? I'm looking at my HID devices in Wireshark and there are zero URB_SUBMIT and URB_COMPLETE entries - only URB_INTERRUPT.
    – Dai
    Jan 31, 2021 at 9:29
  • @Dai as tannewt clarified in their answer, this USB activity is captured based on the OS's implementation of USB. When I wrote my answer, I did not realize this might vary across different OSs. What operating system are you running? In any case, I might have based my information on a device that was not an HID, and so the transfer type might be different due to that. After reading wiki.osdev.org/USB_Human_Interface_Devices , I wonder if you'll see a different transfer type if you hit any keys that modify the keyboard lights, like Num, Caps, or Scroll Lock. Please report back!
    – Gus
    Feb 1, 2021 at 18:21
  • @Gus Windows 10 2004 - I was looking at the data my Logitech mouse sends to my computer. I didn't see any other types of entries besides URB_INTERRUPT on both my mouse and keyboard, regardless of what keyboard/mouse button I pressed.
    – Dai
    Feb 1, 2021 at 21:57
  • Can i ask a tangentially-related question regarding how the Wireshark USB capture is displayed in relation to writing a driver? I did a USB capture between a device and an application, and the capture looked roughly like this: * URB_INTERRUPT out from host to target * URB_INTERRUPT out from target to host * URB_INTERRUPT out from host to target * URB_INTERRUPT out from target to host If I'm writing a driver for this device, do I need to have 4 calls to libusb_interrupt_transfer, or only 2 -- the ones from host to target?
    – rlittles
    Mar 4, 2022 at 19:31
7

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 */
};

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .