Taking a deep dive into MTP
I've done a 5-part series on using MTP on MacOS with Node.js in 2018. I also did a 3-part series on using MTP on Windows with Node.js just last month. The learnings from all these posts have been incorporated into my node-mtp Node.js library.
The node-mtp library is essentially a wrapper around the libmtp library, which means it doesn't work in the browser. Given that I eventually want this to work in the browser, and that I'm struggling to get libmtp built on 32-bit Windows, I decided to write a subset of the MTP protocol myself on top of WebUSB.
The MTP protocol spec itself can be downloaded for free from the USB Implementer's Forum. It's a 282-page document, but doesn't itself describe what the packet structure looks like. For that, you need the earlier PTP protocol that it builds on, which has been standardized as ISO 15740. Luckily the USB Implementer's Forum also has the PTP over USB spec, so you don't have to buy the ISO spec to be able to implement it. Before I discovered the PTP over USB spec, this USB device fuzzing code was pretty helpful to start decoding what's going on.
When you connect to an MTP device over USB, you should look for an interface with three endpoints, one of which will be a bulk transfer endpoint. I captured some packets in Wireshark while running Android File Transfer on Linux, which has a nice CLI tool called aft-mtp-cli
.
The first bulk transfer packet sent to the device from the computer looks like this:
10000000010002100000000001000000
According to the PTP over USB spec, the structure is as follows:
- Container Length (4 bytes)
- Container Type (2 bytes)
- Code (2 bytes)
- Transaction ID (4 bytes)
- Payload
Now we can see that10000000010002100000000001000000
can be broken down into:
- Length:
0x10000000
– 16 (in little-endian format) - Type:
0x0100
– Command Block 0x0210
, or0x1002
in big-endian – operation codeOpenSession
0x00000000
– Transaction ID0x01000000
– Payload, parameter 1: Session ID
Next up, actually using WebUSB to start a new MTP session on the device and read some data!
I’m publishing this as part of 100 Days To Offload. You can join in yourself by visiting https://100daystooffload.com.