November 17, 2023

Let's learn USB! -- using Wireshark

I will be giving you sort of a play by play as I figure out how to do this. I am working on a linux system. Fedora 38 on my x86 desktop.

It turns out that nothing special is needed other than running wireshark as root and pulling down the hidden usbmon interfaces from the menu. Wireshark seems to remember that you did that and shows them to you on future startups.

First investigations

I have found wireshark very useful for ethernet traffic, and am hoping it will be just as helpful for USB.

This document states that usbmon should be compiled into the fedora kernel. I type the following and see:
grep USB_MON config-6.4.10-200.fc38.x86_64
CONFIG_USB_MON=y
I type "modprobe usbmon" and I get no errors. This is not needed. The Fedora gang compiles this driver into the static kernel as per the config setting above (thanks!).
Probing further I type:
ls /sys/kernel/debug/usb/usbmon/
0s  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u  5s  5t  5u  6s  6t  6u
ls -l /dev/usbmon*
crw-r----- 1 root usbmon 243, 0 Nov  6 11:27 /dev/usbmon0
crw-r----- 1 root usbmon 243, 1 Nov  6 11:27 /dev/usbmon1
crw-r----- 1 root usbmon 243, 2 Nov  6 11:27 /dev/usbmon2
crw-r----- 1 root usbmon 243, 3 Nov  6 11:27 /dev/usbmon3
crw-r----- 1 root usbmon 243, 4 Nov  6 11:27 /dev/usbmon4
crw-r----- 1 root usbmon 243, 5 Nov  6 11:27 /dev/usbmon5
crw-r----- 1 root usbmon 243, 6 Nov  6 11:27 /dev/usbmon6
I have been trying to run wireshark as root, but they say I can run it as "tom" by belonging to the right groups, so I do this, but it yields no benefits
su
usermod -a -G usbmon tom
usermod -a -G wireshark tom

Aha!

Wireshark hides the USB interfaces by default. Never mind running as "tom", that is another thing entirely and I don't really care about making it work if I can run wireshark as root. A pulldown menu in Wireshark (it tells me there are 14 "hidden" interfaces). I pull down the menu and click the box to show USB and now I have 7 interfaces: usbmon0 to usbmon6

Why 7? And which one do I use? Using "lsusb" is the ticket here:

lsusb
Bus 002 Device 010: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
Bus 002 Device 012: ID 0483:3748 STMicroelectronics ST-LINK/V2
Bus 004 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub
Bus 004 Device 010: ID 0483:5740 STMicroelectronics Virtual COM Port
The above is just part of the output, but I can see the F103 (currently running papoon and enumerating as the STMicro Virtual Com Port) on USB Bus 4.

A further help is looking at the linux log (/var/log/messages) where I see:

Nov 16 09:21:56 trona kernel: usb 4-1.2: new full-speed USB device number 123 using ehci-pci
Nov 16 09:22:02 trona kernel: usb 4-1.2: New USB device found, idVendor=0483, idProduct=5740, bcdDevice= 2.00
Nov 16 09:22:02 trona kernel: usb 4-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
Nov 16 09:22:02 trona kernel: usb 4-1.2: Product: STM32 Virtual COM Port
Nov 16 09:22:02 trona kernel: usb 4-1.2: Manufacturer: STMicroelectronics
Nov 16 09:22:02 trona kernel: usb 4-1.2: SerialNumber: 8717472853518850066fff48
Nov 16 09:22:02 trona kernel: cdc_acm 4-1.2:1.0: ttyACM0: USB ACM device
So, at least when this enumeration succeeded, the F103 device was "usb 4-1.2".

When I actually start a capture on bus 4 (usbmon4) I see lots of distracting chatter from the hub between the host and my device. The trick then is to set a filter. Something like this:

usb.dst == "4.13.0"
But rather than typing something like that, you can select a line that you are interested in, right click to get a menu, and type "select as filter" and let Wireshark generate something like the above and stick it into the bar at the top of the windows (which is a display filter). Wireshark has both capture and display filters. Don't get me started. They have different syntax and this leads to endless confusion, misery, and anger. But if you just use the menu to get wireshark to do it for you, life is good.

What is this syntax? Clearly "4" is the bus. The "13" is the device. Maybe "0" is the endpoint? Nobody seems sure.

To see both sides, you may want to edit the expression to be something like:

usb.dst == "4.13.0" or usb.src == "4.13.0"
Once you get it all going, Wireshark allows you to click on a packet and takes it apart and displays it for you. It looks pretty nice.

Note -- after a reboot the USB bus numbers can change. Before booting I was plugging into the same port and getting bus 4, after a reboot I get bus 2. Just use lsusb to check and/or keep an eye on the messages in /var/log/messages

Test fly it

I have my F103 running papoon and doing an echo demo. A single character shows up as 65 bytes "on the wire" and URB BULK. Is "URB" a typo? Traffic is shown as 2.16.3 for out and 2.16.1 for in. This is bus 2, device 16, endpoint 3 or 1. URB is not a typo, it is "USB request block" and you can read about it here: A URB is an entity in the Linux kernel, and USB transactions are handled by setting up a URB and submitting them to the USB subsystem. The actual payload is what Wireshark calls "leftover capture data".

Examine enumeration data

I press reset on my F103 and then unplug/replug the cable. This leads to lots of activity captured by wireshark. Most of it is chatter between the host and the hub I am using. I might benefit (for purposes of using Wireshark to study a device) by eliminating the hub, but for now we will press forward.

I see what looks like part of enumeration traffic now on 2.17.0 A new device, and endpoint 0, as you would expect for enumeration. I stop the capture and try fiddling with the capture filter. I find a packet I like, right click and use the menu to set a capture filter and I end up with:

usb.dst=="2.17.0" or usb.src=="2.17.0"
This works like a charm and I am left with 20 lines in my display. However we are now confronted with the greatest liability using wireshark. It is a pain to copy and paste out of the wireshark GUI.

They have addressed this in a limited way. You can right click to get the menu, then select "Copy" and various options are available. Once you select one, you wonder where the copy went. Well, it went into your "clipboard" or whatever you call the magic place that mouse copying goes to. You can then go to your text document and use "Paste" to dump whatever you copied into your document.

Another option might be a screen capture which you then crop. Let's try that. I had some trouble using shotwell to crop an image that filled the screen. Doing it in two steps solved the problem and allowed me to access the crop dialog (that got shoved off screen into oblivion) the second time.

So, above you have the top portion of a wireshark window showing the enumeration capture.
And here is what we get when we "copy" all visible items for the big 131 byte descriptor. I am happy to report that "all visible items" is the entire packet, not just what first in the scrolling area on my screen.

Frame 47467: 131 bytes on wire (1048 bits), 131 bytes captured (1048 bits) on interface usbmon2, id 0
USB URB
CONFIGURATION DESCRIPTOR
    bLength: 9
    bDescriptorType: 0x02 (CONFIGURATION)
    wTotalLength: 67
    bNumInterfaces: 2
    bConfigurationValue: 1
    iConfiguration: 0
    Configuration bmAttributes: 0xc0  SELF-POWERED  NO REMOTE-WAKEUP
    bMaxPower: 50  (100mA)
INTERFACE DESCRIPTOR (0.0): class Communications and CDC Control
    bLength: 9
    bDescriptorType: 0x04 (INTERFACE)
    bInterfaceNumber: 0
    bAlternateSetting: 0
    bNumEndpoints: 1
    bInterfaceClass: Communications and CDC Control (0x02)
    bInterfaceSubClass: Abstract Control Model (0x02)
    bInterfaceProtocol: AT Commands: V.250 etc (0x01)
    iInterface: 0
COMMUNICATIONS DESCRIPTOR
    bLength: 5
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Header Functional Descriptor (0x00)
    CDC: 0x0110
COMMUNICATIONS DESCRIPTOR
    bLength: 5
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Call Management Functional Descriptor (0x01)
    bmCapabilities: 0x00
    Data Interface: 0x01
COMMUNICATIONS DESCRIPTOR
    bLength: 4
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Abstract Control Management Functional Descriptor (0x02)
    bmCapabilities: 0x02
COMMUNICATIONS DESCRIPTOR
    bLength: 5
    bDescriptorType: 0x24 (CS_INTERFACE)
    Descriptor Subtype: Union Functional Descriptor (0x06)
    Control Interface: 0x00
    Subordinate Interface: 0x01
ENDPOINT DESCRIPTOR
    bLength: 7
    bDescriptorType: 0x05 (ENDPOINT)
    bEndpointAddress: 0x82  IN  Endpoint:2
    bmAttributes: 0x03
    wMaxPacketSize: 8
    bInterval: 255
INTERFACE DESCRIPTOR (1.0): class CDC-Data
    bLength: 9
    bDescriptorType: 0x04 (INTERFACE)
    bInterfaceNumber: 1
    bAlternateSetting: 0
    bNumEndpoints: 2
    bInterfaceClass: CDC-Data (0x0a)
    bInterfaceSubClass: 0x00
    bInterfaceProtocol: No class specific protocol required (0x00)
    iInterface: 0
ENDPOINT DESCRIPTOR
    bLength: 7
    bDescriptorType: 0x05 (ENDPOINT)
    bEndpointAddress: 0x03  OUT  Endpoint:3
    bmAttributes: 0x02
    wMaxPacketSize: 64
    bInterval: 0
ENDPOINT DESCRIPTOR
    bLength: 7
    bDescriptorType: 0x05 (ENDPOINT)
    bEndpointAddress: 0x81  IN  Endpoint:1
    bmAttributes: 0x02
    wMaxPacketSize: 64
    bInterval: 0
I will stop here. This should give you a nice taste of how handy wireshark can be.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org