May 22, 2013

USB Packet Sniffing on Linux

Amazingly, sniffing USB traffic is dog easy under linux. It turns out that everything you need is already there!!

I didn't have to do the following mount and modprobe, but on some systems this might be needed:

mount -t debugfs none_debugs /sys/kernel/debug
modprobe usbmon
After this you have a choice of usb buses to examine:
ls /sys/kernel/debug/usb/usbmon/
cat /sys/kernel/debug/usb/usbmon/2u
On my system, when I look at "2u" I would see traffic on the cable I had connected to my atmega32u4 device. On "1u" I would see traffic generated by my mouse. This is because there are several independent USB buses and you have to choose which one you want to study.

The output directly from these kernel monitoring interfaces, while ascii text, are not convenient to study (to put it mildly).

Wireshark to the rescue

Amazingly, good old wireshark is able to sniff USB traffic as well as network traffic, and does a nice job of displaying the packets. Nothing special seems to be necessary, just start wireshark and select 1u or 2u from a menu, start the capture and there you go. A filter like the following will select only traffic to a specific advice and elminate short packets:
usb.device_address == 33 and usb.data_len > 2
I have this blog to thank for getting me started on this:

Traffic from my USB mouse

As soon as I get wireshark going and move my mouse I see lots of traffic. My mouse is device 3 on bus 1 (use lsusb to determine this).

There are lots of packets going back and forth between the host and device 3.1 (device 3 on bus 1). The mouse sends a 69 byte packet about every .02 seconds. The host answers each of these packets with a 64 byte reponse.

The Transfer type is all URB_INTERRUPT to endpoint 0x81 with direction IN. There is actually only 5 bytes of payload in the packets from the mouse (hence the packet size of 64 + 5 = 69 bytes).

Traffic from my atmega32u4

I have an atmega32u4 on an Adafruit Breakout board. I burned the LUFA HID low level demo on it, with a few modifications. I find a port on my machine where I can plug this in on a different bus from my mouse (bus 2). This port also has an embedded hub, so I see a little traffic from that. I could use a wireshark filter to see only the traffic from my device. To get rid of the hub traffic, I would have to use a filter that excludes it since the atmega gets a new address assigned each time I replug it.
usb.device_address != 2

The first thing I see is a GET_DESCRIPTOR for DEVICE on endpoint 0x80 (IN). The device answers with an 82 byte packet (18 bytes payload) giving the vendor ID, product ID, and specifying an 8 byte max packet size - among other things.

Next we see a GET_DESCRIPTOR for CONFIGURATION on endpoint 0x80 (IN). The device answers with an 73 byte packet (9 bytes payload) which includes (among other things) the fact that it is internally powered and draws at most 50 mA.

Next we see another GET_DESCRIPTOR for CONFIGURATION on endpoint 0x80 (IN). The device answers with an 105 byte packet. Here we have interface and endpoint description. We find out that this is an HID device with two endpoints. The endpoints are 0x81 in and 0x02 out.

Next we get 3 strings (language, device name, and "manufacturer").

Now we get a SET_CONFIGURATION on endpoint 0x0 (OUT) followed by a SET_IDLE on endpoint 0x0 (OUT). followed by a GET_DESCRIPTOR for RPIPE.

Lastly there is a GET_REPORT request on endpoing 0x80 (IN), which gets an 72 byte response (8 bytes of payload), and the 8 bytes are the values I coded in the HID demo!

Now the device is idle, and just sits there. After 25 seconds there is a burst of activity with the host chatting with both the hub and my atmega32u4.


Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org