Sunday, July 22, 2018

802.11n monitoring

Today I learned that from the perspective of monitoring wireless networks, 802.11n differs from 802.11b/g in a couple of important ways:

First, there's an option to use 40 MHz channels, where, if I understand correcty, 802.11b/g are limited to 20 MHz.

Second, there's the option to use multiple data streams to increase performance.

Why am I talking about this?

I'm talking about these differences because if you want to monitor 802.11n communications, you need to match the negotiated capabilities between the AP and client you intend to monitor. I've been doing some work involving monitoring a wireless network, and I spent longer than I'd like to admit trying to understand why my AWUS036NH/airmon-ng/wireshark monitoring setup was failing to capture all of the packets. Eventually I came across this question on Superuser about a similar topic. Some smart person responded with a wonderful enumeration of some reasons why I may not see all of the traffic, which made me remember that I used a different client for my initial work.

Specifically, using my AWUS036NH I'm able to capture all wireless traffic from the AP to/from a Samsung Galaxy Tab A (SM-T280), but almost none of the traffic (except some TCP retransmits once in a while) to/from a Motorola Z. My guess is that the Moto Z has more advanced capabilities than the AWUS036NH has, which means the AWUS036NH can't see all of the traffic. As soon as I switched back to the Tab A, I was able to see all of the traffic again.

I'd like to dig up the details of these devices to try to confirm my suspicion, but a quick googling didn't turn up the specifications I was looking for.

Thursday, July 19, 2018

Phantom 3 telemetry post 2

In my last post I documented my progress with decoding the DJI Phantom 3 telemetry protocol between the controller, aircraft, and DJI Go app. This post picks up where I left off, attempting to reverse engineer the Phantom 3 protocol, focusing on data stream from the controller. Unfortunately the controller data is minimally useful for my goal of writing a ground station program, but it's interesting and it helps me further understand the protocol.


A fellow named David was kind enough to leave a comment on my previous post, linking his own protocol reverse engineering work with the DJI Phantom 3. He seems to have discovered some additional details about the protocol through reverse engineering the DJI Go Android app, which I've used to accelerate my work.

Message Header

In my preliminary analysis, I observed that byte 3 seems to correlate with message length. This made me think it may have been a message ID field, but apparently it's an 8-bit CRC of the first three bytes of the message. This makes sense, since the only field in the header that varies is message length! This also explains my observation that byte 2 never changes; It's mostly a version number and the most significant bits of the message length (which are usually zero, since I haven't observed any messages with lengths greater than 255).

Here's the structure of the four-byte DJI message header, thanks to David:
| Bit   | 00000000 | 0111111111 | 122222 | 22222233 |
|       | 01234567 | 8901234567 | 890123 | 45678901 |
| Field | magic    | length     | ver    | CRC      |

Message Source/Target

The first two bytes of the payload describe the source and target systems for this message.

Source/Destination fields:
| Bit   | 00000000 | 011111111 |
|       | 01234567 | 890123456 |
| Field | msg src  | msg tgt   |

The source/target bytes contain two fields: system and subsystem. The system field is 7 bits wide and the subsystem field is 3 bits wide. The system field describes a major component in the system. This includes things like the hand controller, flight controller, camera, mobile app, etc. I'm not really sure what the subsystem field means yet.

Sequence Number

The next field in the payload is a 16-bit counter that seems to increment independently for different types of messages. For example, I've observed that each source/target combination has a distinct counter. In some cases, this counter seems to be used as an acknowledgement.


The next field contains 8 bits of flags. Two of these seem to have somewhat clear meanings, but the rest I'm not sure about. The flag in bit 0 seems to indicate that the message is an acknowledgement to a previous message, and the flag in bit 1 seems to indicate that this message requires an acknowledgement.

I'm guessing about these meanings because of observations like the following:
Message N:
Source(sub-source): 3(3)
Target(sub-target): 2(0)
Sequence Number: 429
Flags: 0100 0000

Message N+1:
Source(sub-source): 2(0)
Target(sub-target): 3(3)
Sequence Number: 429
Flags: 1000 0000

Command Set/Command

Following the Flags byte, there are two bytes that represent a Command Set and Command, respectively. It seems reasonable that a system/subsystem may have more than one type of message to send (or receive), but I haven't tried to make sense of this field yet. So far the messages that I've looked closely at are defined well-enough by the source, target, and length.


The payload field is a variable length string of bytes whose meaning changes depending on the context. I've only been able to fully decode one of these, which I'll talk about shortly.


Finally there's the CRC. I had the right idea initially with the 16-bit CRC field following the payload field, but I couldn't seem to find a match for a CRC algorithm and initialization value. I tried using some online CRC calculators (this one, and this one) by manually entering the byte sequences for some small packets that I had observed, but I couldn't find a match. It turns out that DJI actually has the code for their CRC algorithm on Github.

Discovering Field Boundaries - The Controller

I've never really attempted protocol reverse engineering before this project, but in my fumbling around in the dark I learned something: My assumption that decoding static data would be easier than dynamic data was wrong. The problem with static data (e.g. things like switch positions, camera mode, and other status information that doesn't often change) is that it's very hard to see the field boundaries in the data, particularly in the case of fields that cross byte boundaries.

In order to find field boundaries in the data streams, I need to make the data change. Ideally, I need to make it change one field at a time so that I can see the field boundaries and begin decoding the data. Where should I start? I need some data that I can control. Aircraft position and attitude are really the targets that I want to go after, but I think those are going to be changing pretty much constantly. The buttons and joysticks on the controller are an obvious choice, since these won't change unless I move them, and I can make them change one at a time.

By playing with the controller one axis at a time, I was able to determine the following payload layout for messages with source 6(1) and a length of 26 bytes:
| Bytes  | Field                         |
| 12, 13 | right stick - left/right axis |
| 14, 15 | right stick - up/down axis    |
| 16, 17 | left stick - up/down axis     |
| 18, 19 | left stick - left/right axis  |
| 20, 21 | camera elevation              |

Next Steps

Now that I have a technique for discovering field boundaries for fields that I can control, I'd like to try to find the aircraft attitude fields next. I should be able to control pitch, roll, and compass heading fairly easily.