wireshark usb traces explanations
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.
Solution 1:
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
Solution 2:
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 */
};