Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save berkus/bacdd6bdad10ab83c8179a9802998ed3 to your computer and use it in GitHub Desktop.
Save berkus/bacdd6bdad10ab83c8179a9802998ed3 to your computer and use it in GitHub Desktop.
XBox One Wireless Controller Protocol

Physical layer

The dongle itself is sending out data using 802.11a (5 GHz WiFi) with OFDM and 6 Mbit/s data rate:

Radiotap Header v0, Length 38
    Header revision: 0
    Header pad: 0
    Header length: 38
    Present flags
    MAC timestamp: 84378069
    Flags: 0x10
    Data Rate: 6,0 Mb/s
    Channel frequency: 5220 [A 44]
    Channel flags: 0x0140, Orthogonal Frequency-Division Multiplexing (OFDM), 5 GHz spectrum
    SSI Signal: -43 dBm
    RX flags: 0x0000
    SSI Signal: -43 dBm
    Antenna: 0
    SSI Signal: -46 dBm
    Antenna: 1
802.11 radio information
    PHY type: 802.11a (5)
    Turbo type: Non-turbo (0)
    Data rate: 6,0 Mb/s
    Channel: 44
    Frequency: 5220 MHz
    Signal strength (dBm): -46 dBm
    TSF timestamp: 84378069
    [Duration: 104 us]
        [Preamble: 20 us]

The controller seems to respond with 802.11n (also in the 5 GHz band and with OFDM) with an MCS index of 0 and 6.5 Mbit/s data rate:

Radiotap Header v0, Length 33
    Header revision: 0
    Header pad: 0
    Header length: 33
    Present flags
    Flags: 0x10
    Channel frequency: 5220 [A 44]
    Channel flags: 0x0140, Orthogonal Frequency-Division Multiplexing (OFDM), 5 GHz spectrum
    SSI Signal: -50 dBm
    RX flags: 0x0000
    MCS information
        Known MCS information: 0x37, Bandwidth, MCS index, Guard interval, FEC type, STBC streams
        .... ..00 = Bandwidth: 20 MHz (0)
        .... .0.. = Guard interval: long (0)
        ...0 .... = FEC type: BCC (0)
        .00. .... = STBC streams: 0
        MCS index: 0
    [Data Rate: 6,5 Mb/s]
    SSI Signal: -50 dBm
    Antenna: 0
    SSI Signal: -56 dBm
    Antenna: 1
802.11 radio information
    PHY type: 802.11n (7)
    MCS index: 0
    Bandwidth: 20 MHz (0)
    Short GI: False
    FEC: BEC (0)
    Number of STBC streams: 0
    Data rate: 6,5 Mb/s
    Channel: 44
    Frequency: 5220 MHz
    Signal strength (dBm): -56 dBm
    [Duration: 92 us]
        [Expert Info (Warning/Assumption): No plcp type information was available, assuming non greenfield.]
            [No plcp type information was available, assuming non greenfield.]
            [Severity level: Warning]
            [Group: Assumption]
        [Expert Info (Warning/Assumption): No extension stream information was available, assuming no extension streams.]
            [No extension stream information was available, assuming no extension streams.]
            [Severity level: Warning]
            [Group: Assumption]
        [Preamble: 36 us]

Channel 44 was used in above examples, but when I first started the sniffing, I saw traffic on channels 36, 40 and 48 as well. The driver probably chooses the channel randomly or depending on the current traffic situation. The controller seems to scan each channel.

Beacons

The dongle features a standard Access Point, so it is constantly sending out Beacon frames:

IEEE 802.11 Beacon frame, Flags: ........C
    Type/Subtype: Beacon frame (0x0008)
    Frame Control Field: 0x8000
    .000 0000 0000 0000 = Duration: 0 microseconds
    Receiver address: Broadcast (ff:ff:ff:ff:ff:ff)
    Destination address: Broadcast (ff:ff:ff:ff:ff:ff)
    Transmitter address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Source address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    .... .... .... 0000 = Fragment number: 0
    0010 1001 0011 .... = Sequence number: 659
    Frame check sequence: 0xbad38b42 [correct]
    [FCS Status: Good]
IEEE 802.11 wireless LAN management frame
    Fixed parameters (12 bytes)
        Timestamp: 0x0000000003f48332
        Beacon Interval: 0,102400 [Seconds]
        Capabilities Information: 0xc631
    Tagged parameters (20 bytes)
        Tag: SSID parameter set: Broadcast
            Tag Number: SSID parameter set (0)
            Tag length: 0
            SSID: 
        Tag: Vendor Specific: Microsof: Unknown 17
            Tag Number: Vendor Specific (221)
            Tag length: 16
            OUI: 00-50-f2
            Vendor Specific OUI Type: 17
            Type: Unknown (0x11)

Most noticable here is the vendor specific information element (with tag number 221). There is even more data appended to that tag that is not recognized by Wireshark. The whole tag is:

dd10 0050 f211 0110 0024 9d99 0000 0000  ...P.....$......
0000                                     ..

Connecting

Every single frame, starting from here, is immediately followed by a standard ACK frame.

As I had already paired both devices prior to starting the analysis, I didn't manage to capture the actual pairing process and I have no idea how to »unpair« them. Therefore, I will start with the connecting phase. This one is pretty straight forward.

First the controller sends an association request to the dongle:

IEEE 802.11 Association Request, Flags: ........C
    Type/Subtype: Association Request (0x0000)
    Frame Control Field: 0x0000
    .000 0000 1010 0000 = Duration: 160 microseconds
    Receiver address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Destination address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Transmitter address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Source address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    .... .... .... 0000 = Fragment number: 0
    0000 0000 0000 .... = Sequence number: 0
    Frame check sequence: 0xe58e6b71 [correct]
    [FCS Status: Good]
IEEE 802.11 wireless LAN management frame
    Fixed parameters (4 bytes)
        Capabilities Information: 0x0f10
        Listen Interval: 0x0008
    Tagged parameters (10 bytes)
        Tag: SSID parameter set: Broadcast
            Tag Number: SSID parameter set (0)
            Tag length: 0
            SSID: 
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0

The information elements here don't really make sense, it seems like there are just 10 zero bytes appended to the end of the packet.

The dongle responds with a association response:

IEEE 802.11 Association Response, Flags: ........C
    Type/Subtype: Association Response (0x0001)
    Frame Control Field: 0x1000
    .000 0000 0010 1100 = Duration: 44 microseconds
    Receiver address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Destination address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Transmitter address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Source address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    .... .... .... 0000 = Fragment number: 0
    0000 0000 1111 .... = Sequence number: 15
    Frame check sequence: 0xbf57e3f5 [correct]
    [FCS Status: Good]
IEEE 802.11 wireless LAN management frame
    Fixed parameters (6 bytes)
        Capabilities Information: 0x0000
        Status code: Unknown (0x0110)
        ..00 1111 0000 0000 = Association ID: 0x0f00
    Tagged parameters (8 bytes)
        Tag: SSID parameter set: Broadcast
            Tag Number: SSID parameter set (0)
            Tag length: 0
            SSID: 
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0
        Tag: SSID parameter set
            Tag Number: SSID parameter set (0)
            Tag length: 0

The association ID 0x0f00 seems to be constant (at least with the one controller I have available for testing). The information elements are the same as in the request.

Probing

After association, there is a probe request:

IEEE 802.11 Probe Request, Flags: ........C
    Type/Subtype: Probe Request (0x0004)
    Frame Control Field: 0x4000
    .000 0000 1010 0000 = Duration: 160 microseconds
    Receiver address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Destination address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Transmitter address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Source address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    .... .... .... 0000 = Fragment number: 0
    0000 0000 0010 .... = Sequence number: 2
    Frame check sequence: 0x9bee2c85 [correct]
    [FCS Status: Good]
IEEE 802.11 wireless LAN management frame
    Tagged parameters (12 bytes)
        Tag: SSID parameter set: Broadcast
            Tag Number: SSID parameter set (0)
            Tag length: 0
            SSID: 
        Tag: Supported Rates 6, 9, 12, 18, 24, 36, 48, 54, [Mbit/sec]
            Tag Number: Supported Rates (1)
            Tag length: 8
            Supported Rates: 6 (0x0c)
            Supported Rates: 9 (0x12)
            Supported Rates: 12 (0x18)
            Supported Rates: 18 (0x24)
            Supported Rates: 24 (0x30)
            Supported Rates: 36 (0x48)
            Supported Rates: 48 (0x60)
            Supported Rates: 54 (0x6c)

and a probe response:

IEEE 802.11 Probe Response, Flags: ........C
    Type/Subtype: Probe Response (0x0005)
    Frame Control Field: 0x5000
    .000 0000 0010 1100 = Duration: 44 microseconds
    Receiver address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Destination address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Transmitter address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Source address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    .... .... .... 0000 = Fragment number: 0
    0000 0001 0000 .... = Sequence number: 16
    Frame check sequence: 0xe562542c [correct]
    [FCS Status: Good]
IEEE 802.11 wireless LAN management frame
    Fixed parameters (12 bytes)
        Timestamp: 0x0000000003ffe486
        Beacon Interval: 0,102400 [Seconds]
        Capabilities Information: 0xc631
    Tagged parameters (20 bytes)
        Tag: SSID parameter set: Broadcast
            Tag Number: SSID parameter set (0)
            Tag length: 0
            SSID: 
        Tag: Vendor Specific: Microsof: Unknown 17
            Tag Number: Vendor Specific (221)
            Tag length: 16
            OUI: 00-50-f2
            Vendor Specific OUI Type: 17
            Type: Unknown (0x11)

The »management« part of the frame is exactly the same as in the beacon frame.

»Null« data frames

After being connected the controller and the dongle seem to be exchanging »QoS Null function« frames continously with the controller sending the frame first and the dongle responding immediately. After the response, the controller seems to wait for exactly 8 milliseconds before sending the next frame.

Those frame look like the following:

IEEE 802.11 QoS Null function (No data), Flags: ......F.C
    Type/Subtype: QoS Null function (No data) (0x002c)
    Frame Control Field: 0xc802
    .000 0000 0110 0100 = Duration: 100 microseconds
    Receiver address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Destination address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Transmitter address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Source address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    STA address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    .... .... .... 0000 = Fragment number: 0
    0000 0000 0000 .... = Sequence number: 0
    Frame check sequence: 0x5e06d924 [correct]
    [FCS Status: Good]
    Qos Control: 0x0000

The controller, however, has the QoS Control flag set to 0x0001 instead (meaning »background« priority).

About 250 »QoS Null function« frames are exchanged within one second.

Actual controller input data

When you actually do something with the controller (e.g. pressing buttons or moving the joysticks), the controller sends a »QoS Data« frame.

IEEE 802.11 QoS Data, Flags: ...P...T
    Type/Subtype: QoS Data (0x0028)
    Frame Control Field: 0x8811
    .000 0000 1010 0000 = Duration: 160 microseconds
    Receiver address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Destination address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Transmitter address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Source address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    STA address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    .... .... .... 0000 = Fragment number: 0
    0000 0000 0010 .... = Sequence number: 2
    Qos Control: 0x0000

The rest of the frame is interpreted as Logical Link Control and other protocols by Wireshark which doesn't make sense in this case. It actually consist of the button map and analog input values and looks like the following:

20 00 03 0e 00 00 00 00 00 00 4f 03 9c 02 b4 ff 26 ff

Broken down:

  • 20 00: seems like a command / status flag (see below) and is constant for all input data frames; I will call it »command« field
  • 03: kind of a counter as it increases with every action
  • 0e: number of bytes that follow (14 bytes)
  • 00 00: button map (in this case no buttons were being pressed), with the following bit mapping (bit 0 is LSB, bit 15 is MSB)
    • 0: DPAD up
    • 1: DPAD down
    • 2: DPAD left
    • 3: DPAD right
    • 4: LB
    • 5: RB
    • 6: left analog stick pressing
    • 7: right analog stick pressing
    • 8-9: unknown
    • 10: right button
    • 11: left buton
    • 12: A
    • 13: B
    • 14: X
    • 15: Y
  • 00 00: LT position (not pressed at all)
  • 00 00: RT position
  • 4f 03 9c 02: left joystick position (X and Y coordinates)
  • b4 ff 26 ff: right joystick position

Other data frames

About 500 milliseconds after the connection between the controller and the dongle has been established (and after about 125 »QoS Null function« frames have been passed back and forth), there are »QoS Data« frames thate are constructed similar to those that contain the input data. They have other values in the command field (like 20 00 for the input data) and the position of the »number of bytes that follow« field (marked with * below) seems to be varying depending on the command.

Following are the commands that I recognized so far (in the order they appeared):

Controller Dongle Payload
02 20 01 1c* 7e ed 80 1f 6d 53 00 00 5e 04 dd 02 02 00 03 00
37 09 06 00 02 01 01 00 01 00 01 00
04 20 01 00*
04 f0 01 3a* d6 01 10 00 01 00 00 00 00 00 00 00 00 00 00 00 d6 00
97 00 16 00 37 00 38 00 41 00 49 00 66 00 00 00
00 00 00 00 00 00 08 01 00 00 00 01 00 01 00 01
00 02 00 01 00 03 00 02 00 00
01 20 01 09* 00 04 20 3a 00 00 00 9c 00
04 a0 01 ba 00 3a* 02 00 01 00 02 00 02 00 02 00 03 00 00 08 01 02
03 04 06 07 0c 1e 07 01 04 05 06 0a 0c 1e 01 1a
00 57 69 6e 64 6f 77 73 2e 58 62 6f 78 2e 2e 49
6e 70 75 74 2e 47 61 6d 65 70 1
04 a0 01 ba 00 74* 2 61 64 03 56 ff 76 97 fd 9b 81 45 ad 45 b6 45 bb
a5 26 d6 2c 40 2e 08 df 07 e1 45 a5 ab a3 12 7a
f1 97 b5 e7 1f f3 b8 86 73 e9 40 a9 f8 2f 21 26
3a cf b7 02 17 00 20 0e 00 01
04 a0 01 28* ae 01 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 17 00 09 3c 00 01 00 08 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
04 20 01 09* 00 04 20 d6 00 00 00 00 00
04 20 01 00* d6 01
05 20 02 01* 00
0a 20 03 03* 00 01 14
20 00 01 0e* 00 00 00 00 00 00 c5 01 45 fd bc 02 50 02 3
03 20 01 04* 87 01 00 00
1e 30 04 01* 00
1e 20 01 22* 00 00 17 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00
01 20 04 09* 4 00 1e 30 00 00 00 00 00 00
1e 30 05 01* 01
1e f0 02 3a* 8a 02 01 00 01 00 12 00 00 00 02 00 00 00 00 00 03 00
00 00 00 00 04 00 00 00 00 00 10 00 01 00 00 00
11 00 00 00 00 00 20 00 00 00 00 00 21 00 00 00
00 00 22 00 00 00 00 00 23 00
01 20 05 09* 00 1e 30 00 00 00 00 00 00
01 20 02 09* 00 1e 20 3a 00 00 00 d0 00
1e a0 02 ba 00 3a* 00 00 00 00 24 00 00 00 00 00 25 00 00 00 00 00
26 00 00 00 00 00 27 00 00 00 00 00 28 00 01 00
00 00 29 00 00 00 00 00 2a 00 00 00 00 00 2b 00
03 00 00 00 2c 00 03 00 00 00
1e a0 02 ba 00 74* 2 2d 00 03 00 00 00 2e 00 00 00 00 00 2f 00 01 00
00 00 40 00 00 00 00 00 41 00 00 00 00 00 42 00
00 00 00 00 43 00 00 00 00 00 50 00 d9 06 00 00
51 00 01 00 00 00 52 00 01 00
1e a0 02 3a* ae 01 00 00 53 00 06 00 00 00 54 00 03 00 00 00 55 00
0c 00 00 00 56 00 03 00 00 00 57 00 07 00 00 00
58 00 07 00 00 00 59 00 04 00 00 00 60 00 00 00
00 00 64 00 00 00 00 00 61 00
1e b0 02 22* e8 01 01 00 00 00 65 00 2a 01 00 00 62 00 00 00 00 00
66 00 00 00 00 00 63 00 00 00 00 00 67 00 00 00
00 00
1e a0 02 00* 8a 02
1e 30 06 01* 04
1e 20 03 10* 04 00 30 32 39 38 30 30 38 31 31 38 35 36 32 35 5
01 20 06 09* 00 1e 30 00 00 00 00 00 00
06 20 01 02* 01 00
09 00 07 09* 00 0f 00 00 00 00 ff 00 00
{:.widetable}

1 has »Windows.Xbox.Input.Gamep« (24 bytes) as ASCII in payload

2 7416 = 3416 / 2

3 actual input data

4 MAC address of destination has bit 1 cleared

5 has the serial number of the controller as ASCII in payload

Overall, this seems to be something like a status protocol. The dongle can request certain status flags from the controller or send commands and the controller respons accordingly. Status messages are also sent without prior request.

Reserved frames

Apart from those undecipherable data frames, the devices sometimes exchange frames with frame control field set to 0x7000:

IEEE 802.11 Unrecognized (Reserved frame), Flags: ........C
    Type/Subtype: Unknown (0x0007)
    Frame Control Field: 0x7000
    .000 0000 1010 0000 = Duration: 160 microseconds
    Receiver address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Destination address: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    Transmitter address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    Source address: 7e:ed:80:1f:6d:53 (7e:ed:80:1f:6d:53)
    BSS Id: 62:45:b4:f4:41:51 (62:45:b4:f4:41:51)
    .... .... .... 0000 = Fragment number: 0
    0000 0101 0110 .... = Sequence number: 86
    Frame check sequence: 0x51b474e5 [correct]
    [FCS Status: Good]
IEEE 802.11 wireless LAN management frame

Example payload of such a frame: 70 05. All payloads start with 07 and have something like a 1-byte command field directy after where odd numbers seem to be request commands from the dongle to controller and even numbers are responses from the controller to the dongle; in this case 07 05 is a request from dongle to controller and the controller responds with 07 06 (command field + 1) and further payload.

Following are the commands I have recognized so far:

  • 70 05
    70 06 13 00 00 00 01 00 00 00 00 00 00 00 12 00
    00 00 00 00 00 00 00 00 00 00 ba 00 00 00 04 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 01 00 00 00 0c 00 00 00 00 00
    00 00 0c 00 00 00 00 00 00 00 00 00 00 00 bd 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 cb ff ff ff 16 00 00 00 04 00
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 (some bytes vary)
  • 07 07 01 0070 08 00 01 03 03 0a
  • ? → 70 10 00 00 (without request)

Some of the responses are sent without prior request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment