Saturday 15 May 2010

Device vs hub emulation

There are 2 main alternatives to implement the USB sniffer:
  • Device emulation: Emulate the sniffed device itself: That is, pretend that we are the device itself, and forward packets back and forth between the device and the host.
  • Hub emulation: Emulate a USB hub. That is, act as if we were a USB hub, with several ports. One (or more) of these ports would be connected to the device to be analysed. Other ports would still be available for other USB gadgets (e.g., Ethernet, serial gadgets).
For the hub emulation, I should first try to explain how a USB hub works (or at least, how I understand it works, skipping details):
An USB hub is a simple repeater: that is, each packet coming from the host is broadcasted to all the devices connected to it. An USB token packet contains, among other things, an address field. As each device is assigned an unique address, it can safely ignore transfers that are not meant for it. Packets coming from the device are not broadcasted (it would not make any sense), and are simply forwarded back to the host.

When a new device is connected to a hub, the hub informs the host. The new device, by default, takes address 0, and the host can then initiate basic communication with it using that address. One of the first thing the host does it to send a SET_ADDRESS command to the device, the new device will then answer on that new address (and not on address 0 anymore).

Now, the question is, can we implement this on the BeagleBoard, with the MUSB controller? For this, the MUSB controller needs to be able to listen on all possible USB addresses (similar to a promiscuous mode on an Ethernet controller). Depending on the address, we could then forward the packet to the sniffed device, or on any other virtual gadget device (since we have more processing power than a normal USB hub, we can be more clever and avoid broadcasting the data to every device).

From what I see in the code of the MUSB controller driver, there seems to be only one register containing the USB address to listen on. This register (F_ADDR) is updated at line 706, after a SET_ADDRESS command is received from the host:
 if (musb->set_address) {
musb->set_address = false;
musb_writeb(mbase, MUSB_FADDR, musb->address);
}
Therefore, it seems like the MUSB controller is only able to listen on a single address, so it looks like it may not be possible to implement a USB hub.