Saturday, July 26, 2014

nRF24L01+ sniffer - part 1

When working with wireless networks, or any network in general, it can be very helpfull to inspect the raw message data. Networking chips only accept messages directly addressed to them (or when broadcasteded), but most also support a so-called promiscuous mode. This mode allows the networking chip to capture all network traffic on air/on the wire and is used to monitor all network traffic, not just the traffic addressed to our node.
As a picture is worth a thousand words, a moving picture is probably worth a million words!

nRF24 sniffing

The wireless 2.4GHz Nordic Semiconductor nRF24L01+ chip (or nRF24 for short), which I'm experimenting with for wireless domotica applications, does however not support promiscuous mode, which in theory makes it impossible to capture network traffic between different nodes on a network.
Some time ago I stumbled upon a blogpost by Travis Goodspeed, in which he explains how reducing the wireless network address length of an nRF24 (together with some other tricks) allows capturing traffic not directly addressed to this chip.
After reading his blog and some more google'ing around I started thinking of building a 'simple' network sniffer for nRF24 traffic. I faced following requirements & challenges:
  • Based on commodity, cheap hardware
  • Traffic capturing for network with known parameters (channel, baudrate, base address)
  • Analysis using Wireshark network protocol analyzer
  • Possibility to analyze protocols which use the nRF24 for transport in their network

Packet formats

A regular packet is sent on air by the nRF24 in the following format (supposedly; it's not in the datasheet):
Regular nRF24 packet
Every message starts with a preamble, which the radio uses to identify incoming packets. The target node address follows and can be specified as 3 to 5 bytes (according to Travis Goodspeed a length of 2 is also accepted by the radio, though defined as invalid in the datasheet). Then comes the fixed-size payload, followed by an optional CRC to check the integrity of the message after reception. The CRC is calculated over the whole message, excluding the preamble and the CRC itself. The radio must be told upfront what the length of the payload will be, as a regular packet contains no indication of the length.
When a message received matches the receiver address of the radio and the CRC is found valid or disabled, the radio will store the payload in an internal FIFO for reception by the host (microcontroller or whatever connected to the nRF24 using SPI).

The nRF24L01+ modules support a mode called 'Enhanced Shockburst' which has a number of advantages over regular usage (incomplete):
  • Payload lengths can be set dynamically and are part of the message
  • The receiving node can automatically send an acknowledge to the sender to indicate that the message has been received correctly. The sender will automatically retry transmission a number of times when the acknowledge is not received within a configurable timeout (Nordic calls this "Automatic packet transaction handling")
Enhanced shockburst messages are sent over the air in the following format (from the datasheet):
Enhanced Shockburst nRF24 packet
As you can see a 9 bit packet control field has been added which stores the payload length (in bytes), a packet identifier (PID) to detect retransmissions and a flag to suppress sending acknowledge packets on a per-packet basis. The CRC is no longer optional.
As with the regular packets, a message received must match the receiver address of the radio and the CRC must be valid to have the payload stored in the internal FIFO, otherwise the message will be discarded.

Many (all?) wireless sensor applications based on the nRF24L01+ I've seen so far run the radio in Enhanced Shockburst mode.

Promiscuous reception

When building a wireless network of many nodes you choose a single RF channel which all nodes will operate on. Furthermore each node shall have a unique address within the network (unless you're only broadcasting). Each node can have an arbitrary address, but normally you choose a base address which is identical for all nodes, and a node address which is unique for each node. Combined these form the address:

Address consisting of 4 byte base address and single byte node address
This example addressing scheme (4+1) is used by the MySensors library and allows 255 unique nodes to be addressed (node 255 is used for broadcast addressing).

Should the nRF24 support promiscuous addressing, then the base address would have to be configured in the chip and it should be instructed that the node addressing consists of 1 byte. The nRF24 would then start listening for messages. All messages with matching base address and valid CRC would then be stored...

But the nRF24 does not support promiscuous listening. With some trickery we can however instruct it to capture all messages for a certain base address, including the ones with invalid CRC's !

The following configuration of the nRF24 sniffing radio is required:

  • Set the nRF24 receiver address to just the base address
  • Disable Enhanced Shockburst
  • Disable CRC checking
  • Configure a fixed payload size
The first 3 items will cause the nRF24 to capture anything that matches the base address of the network we're sniffing. As Enhanced Shockburst is disabled, the radio will not determine the payload size from the message anymore and we just have to store a fixed amount of data starting from the Node address. We just fake the message received is a regular packet, while in fact it is an Enhanced Shockburst packet!
CRC checking has to be disabled of course, as the nRF24 doesn't know the payload length anymore and CRC calculation would fail, rejecting all messages.
The process is illustrated by the image below (again, taking the 4+1 addressing scheme as an example):

Capture Enhanced Shockburst packet as regular packet
The payload received will start with the node address the packet was transmitted to, so effectively we've created a promiscuous listening nRF24!
As the nRF24 will no longer dissect the packet for us, we'll have to do it ourselves (actually let Wireshark do it for us). The original length of the payload should be extracted (the 6 bit payload length), the full address recreated and CRC calculated over the data received. When the CRC is invalid the message can be marked, which gives us a nice indication of the link quality. As the nRF24 header is not a multiple of 8 bits, all payload & CRC bytes will be bit-shifted directly adjacent to the packet control field. This is inconvenient when inspecting the raw bytes in a packet, but Wireshark will solve this nicely for us.


Limitations

There are however some limitations to this method which you should be aware of:

  • The maximum length of a payload is limited by the nRF24 to 32 bytes. As we 'shift' the reception of the payload towards the start of the packet and also want to include the CRC in the payload, the effective size of payloads captured will go down by a number of bytes. The amount depends on the number of bytes in the node address, the fixed packet control field and the length of the CRC.
  • When fixed payload size of the sniffer is set to a value (much) larger than the actual payload size in the packet, then subsequent packets might be missed. When the nRF24 is still capturing the fixed size payload and a new packet arrives, this will not be detected. A good example for this are the auto-acknowledge packets which can be enabled in Enhanced Shockburst mode. After the target node receives the packet (and it will know the real size of the payload a lot faster than the sniffer will) it switches its radio from receiving to transmitting mode in only 130us. Then it sends out the acknowledge packet. Reception of 32 bytes at 1Mb/s takes 32*8us = 256us, so acknowledge of a short message will definately be missed. For acknowledge packets this isn't much of a problem as the transmitter will retry to send the identical message when no acknowledge was received and we will know it missed the acknowldge.
  • This method works well for Enhanced Shockburst packages, as they have the payload size embedded in the message. For regular messages the length will have to be known or can be determined by testing different lengths until the CRC matches. With CRC disabled the payload size can only be guessed.
  • The addressing scheme must use a base address in the high address byte(s), and node address in the low byte(s), as explained.

What's next

In the next parts of this series I will dive deeper in the hardware and software required to create the sniffer and give some nice usage examples. Furthermore a Wireshark dissector for the MySensors protocol will be presented.

Updates
July 27 - added youtube video
August 20 - updated Wireshark dissector for MySensors 1.4b to state of Aug. 18, 2014.

20 comments:

  1. Hi,

    i don't know whether i use the nrf24l01 as scanner or not. Can i use the nrf24l01 as scanner in order to dedect the other wireless system for example bluetooth, beacons etc. ? Could you help me for this ? How i can use it for scanner ? And another my question is that if i can use your code can i see the other wireless on WIRESHARK ? My aim is to scan everything that is wireless and then to send command them.

    Thank you in advance.

    ReplyDelete
    Replies
    1. Hi Hakan,

      The scanner presented here is only fit for scanning network based on the Nordic nRF24L01+. Any other 2.4GHz networks (e.g. Bluetooth & WiFi) cannot be sniffed.
      I'm not sure if I understand your question correctly, but Wireshark can be used for sniffing WiFi networks. You don't need this sniffer for that.

      Ciao!

      Delete
  2. hey,
    I have been trying to connect the adafruit esp8266 chip and nrf24l01, although there is a library on github for this I have been trying to work it out for like a week now. can u please help me out on how to send my nrf data to cloud?

    Thank you.

    ReplyDelete
    Replies
    1. I suggest you visit www.mysensors.org. It contains all the info you need on ESP8266 and connecting nRF24L01+!

      Delete
  3. I'm interested in listening to the transmission made by a Disney Magicband device. The magicband is a wearable that includes 2 rfid chips and one long range 2.4ghz RF transmitter. The radio is made by nordic semiconductor and seems to be a special formfactor of their nRF24LE1 device. The nRF24LE1 is described as:

    The nRF24LE1 integrates an nRF24L01+ 2.4GHz RF transceiver core, enhanced 16MHz 8-bit 8051 compatible CPU, 1kB + 256B RAM, 16kB embedded Flash, and a wide range of system peripherals including a hardware AES accelerator, 16MHz and 32kHz RC oscillators, ultra low power 32kHz crystal oscillator, 12-bit ADC and SPI, 2-wire and UART serial interfaces.

    Which is a lot of tech. The device is supposed to send out its serial number every so often to allow Disney infrastructure to determine individual location within the parks.

    Is it likely your method will let me receive the broadcast from the magicband?

    ReplyDelete
    Replies
    1. As I understand the nRF24LE1 radio packet format is identical to the nRF24L01+. This means that, in theory, you should be able to capture data from the magicband with this sniffer.

      Delete
  4. Very helpful sniffer - if it works. Mine don't receive my RF-Packages. I'm sending with the help of the "TMRh20 2014 - Optimized Fork of NRF24L01+" - Library. Could this be the reason?

    Channel, Baudrate, Adresses I have already double-checked, but my sniffer receives only sometimes a packet with crc-error. Any hint?

    ReplyDelete
    Replies
    1. I doubt if the library makes a difference; the sniffer should be agnostic to the library used.
      Do you have communication working between multiple nodes?
      What nRF24 modules are you using? There have been reports of clones using a different packet format.
      When a packet with CRC error is received, does it somewhat resemble a correct packet, or is it completely wrong?

      Delete
  5. Hi Yveaux, thank you for your quick reaction, I've seen it only now.
    In the meantime I've used the Arduino version 1.5.6-r2 as you described and the libs from your zip-file. But it makes no difference.
    My communication is between 2 nodes, one nRF24 standard module and one NRF24 Mini SMD module. The communication itself is working, but no sniffer result.
    At the rare cases of receiving something, it is completely wrong.
    At the sniffer I use the nRF24 standard module and I have tested with changed RF module and Arduino Board.

    ReplyDelete
  6. Hi

    If I used 3 bytes address for NRF24, can I used remaining 2 byte in my payload.. my payload size is 34 byte

    ReplyDelete
    Replies
    1. Hey iRF! In theory that should work, but I haven't tried it myself.

      Delete
    2. Hi, Unfortunately, the payload buffer is only 32 byte wide.

      Delete
  7. Hey!
    Before a month ago i bought cheap Chinese drone which uses SM-217-BKT remote control and 2.4GCOB-1A transmitter.
    I google it many hours to see if i can receive, save and transmit commands for driving the drone to make it with "memory" control, can you give me an advice, what should i do?
    (if something is unclear ask me, my mother's language is not English )

    ReplyDelete
  8. If the payload of TX is short, the 32 byte payload of the sniffer contains also the ACK payload of the RX.
    Just shift the the remaining bytes bitwise until the the address of RX appears. Tested with 250kbs.

    ReplyDelete
  9. How can I sniff this remote http://travisgoodspeed.blogspot.com/2010/07/reversing-rf-clicker.html ?

    ReplyDelete
  10. I got the sniffer working with various keyboard/mouse combos I have laying around. I could not seem to get the dissector (nrf24.dll) to load though. Great work and thanks!

    ReplyDelete
    Replies
    1. Hi
      I had same issue, it looks like wireshark newer versions are not caompatible with nrf24.dll.

      Delete
  11. nrf24.dll not a valid Win32 Application (I'm on a Windows 10 64 bit system, but tried both versions)

    ReplyDelete
    Replies
    1. Hi,
      Will depend on the Wireshark bit, also the nrf24 is not compatible with newer version of wireshark. Not sure until what version is compatible but to be sure try 1.10.8

      Delete
  12. Hi, I want to analyze the packet transmission from NRF24L01 and evaluate it. Do you have any idea or knowledge about it? Because I want to analyze how good the transmission from NRF24L01. Furthermore, it can be a great things if I can get a PCAP file from NRF24L01

    ReplyDelete