Security is becoming more and more important in wireless sensor network, aka Internet of Things, applications. As more devices come online and connect via network, it is important to have the capability to capture packets and study them to debug network issues as well as find vulnerabilities.One of the most powerful tools for debugging networks is a protocol analyzer, and one of the best protocol analyzers is an open source tool called Wireshark. Wireshark, formerly known as Ethereal, captures and displays packets in real time or offline via file dumps known as PCAPs. It has configurable filters, color coding, and many other features that allow you to do deep analysis on network traffic and inspect individual packets. I put together this video tutorial and writeup together to demonstrate how to sniff and capture data packets for IEEE 802.15.4 wireless sensor networks, a common wireless protocol used in Internet of Things applications.

IEEE 802.15.4 is a standardized wireless protocol used in products such as the Nest thermostat, Philips Hue lighting, Kwikset Smart deadbolt locks, and most smart meters in public power grids. The protocol has been around for a while now and has been integrated into many products, especially for home automation and smart grid applications. This makes it a good target for wireless packet capture and traffic analysis.

To capture packets, Wireshark needs a capture device that feeds it data in a specified format. Many years ago, I wrote a blog post on how to use a Freakduino as a wireshark capture device using a software bridge to collect the raw data and feed it into Wireshark. Since then, one of the main applications the Freakduinos were used for was an 802.15.4 packet sniffer. I've also had to field many questions on setting up the Freakduino as a capture device for Wireshark so I decided to put together a video on it. I also put together a writeup of the tutorial below the video for those that just want to skim the text.

Video Tutorial Timing


  • 00:21 - Choosing Sniffer Hardware
  • 02:09 - Setting up the FreakUSB board as a sniffer
  • 04:00 - Getting and Setting up Sensniff

Choosing a Capture Device


One of the main reasons I created the FreakUSB series of devices was so they could be used as a packet sniffer. They're compact, simple, and optimized for interfacing to a PC. There are two MCU variations of the FreakUSB devices, one with an ATMega328P and one with an ATMega1284P. The ATMega328P is the standard MCU that is used in Arduino applications. It's a general purpose MCU that is also low cost which means that it doesn't have much in terms of resources or more specifically, RAM. 

RAM is important in packet capture type applications since the size of the receive buffer determines how much traffic you can handle. The MCU needs RAM to buffer packets that come in since it takes time to process them and dump them to the serial interface. Under heavy traffic loads, the amount of packets coming in is usually greater than going out which means that your ability to weather the load is dependent on how many packets you can buffer until the packet storm ends and you can output the data. The more RAM you have, the more packets you can buffer. I put together a simple stress test to emulate outputting wireless received data to the serial port in high traffic conditions. This is to demonstrate the effect that buffer size has on wireless capture device performance. The following code needs to be run with the chibiArduino wireless stack, v1.06 or above.

/* chibiArduino Sensniff Stress Test 
This sketch emulates dumping sensniff packets and is used to check buffer
usage under high traffic conditions.
Before using this sketch, please go into the chibiUsrCfg.h file and 
enable promiscuous mode. To do this, change the definition:


When not using promiscuous mode, please disable this setting by changing
it back to 0.

#include <chibi.h>

int cnt = 0;

// dummy magic number
uint16_t magic[] = {0x00, 0x00, 0x00, 0x00};

static FILE uartout = {0};     

// Initialize
void setup()

  // fill in the UART file descriptor with pointer to writer.
  fdev_setup_stream (&amp;uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);
  // The uart is the standard output device STDOUT.
  stdout = &uartout ;
  // Init the chibi stack
  // Open the serial port at specified speed. For sniffing, we want to send data
  // out the serial port as quickly as possible. On windows, 250kbps can be used.
  // On linux, it only seems to like standard speeds up to 115200. To make things
  // compatible on both platforms, I'm keeping the speed at 115200. If you want
  // to boost the speed on a Windows system, use 250000 rather than 115200. 
  // Ex: Serial.begin(250000);
  // Remember: If you change the speed here, make sure you change it on the application
  // program as well. 
  Serial.begin(921600); // use this speed for freakusb 1284p
  //Serial.begin(1000000); // use this speed for freakusb 328p

// Loop
void loop()
  uint16_t rem;
  // Check if any data was received from the radio. If so, then handle it.
  if (chibiDataRcvd() == true)
    int len;
    byte buf[CHB_MAX_PAYLOAD]; 
    // send the raw data out the serial port in binary format
    len = chibiGetData(buf);
    //Serial.write(buf, len);

    for (int i=0; i<4; i++)
      printf("%02x ", magic[i]);
    for (int i=0; i<len; i++)
      printf("%02x ", buf[i]);
    rem = chibiBufGetRemaining();
    if (rem < len)
      printf("%04d, %04d, *** BUFFER FULL ****\r\n", rem, cnt);
      printf("%04d, %04d\r\n", rem, cnt);

// This is to implement the printf function from within arduino
static int uart_putchar (char c, FILE *stream)
    return 0;

In this test, the receive device is set to promiscuous mode. In the chibiArduino library, a standard ATMega328P based device is set to the default 768 bytes of receive buffer. That's near the maximum amount you can safely allocate since the device has 2 kB of RAM and you need approximately 500 bytes for the chibiArduino stack and 500 bytes for the Arduino subsystem. For the ATMega1284P, it has 16 kB of RAM so the chibiArduino stack will set the receive buffer at 10 kB, a 10x increase.


Here is the packet capture dump for the ATMega328P based FreakUSB based device. You can clearly see the packet count at which the buffer indicates its full. After this point, it will start dropping packets if it receives frames that it can't fit inside the buffer.

capture3 - Copy  

The final packet count indicates how many packets it captured out of the 1000 that were transmitted. Each packet was approximately 16 bytes long which means it had a 2 byte payload. It's a pretty gruesome case for a stress test since they're a bunch of minimum sized packets sent back to back with no delay in between sending. In the ATMega328P case, it could capture 628 packets out of the 1000. The same test and same software were run with the ATMega1284P based FreakUSB:



For the FreakUSB 1284P, it was able to handle 1000 packets back to back but with an initial receive buffer size of 10 kB, it went all the way down to about 2.5 kB of free space in the buffer before the packet storm let up. Once the free space in the receive buffer goes to zero, then there is a chance that packets will be dropped.

The stress test is not very realistic in terms of emulating actual traffic but it does provide an indication of performance. RAM, MCU speed, and hardware acceleration like DMA would also affect the performance numbers.

In summary, for packet capture devices, it really depends on what level of performance you need. For general purpose sniffing in light traffic, I'd recommend the FreakUSB standard while if you have RAM heavy applications or will be capturing in heavy traffic, I'd recommend the FreakUSB 1284P.

Setting up the FreakUSB boards


To set up the FreakUSB boards, you need to open the Arduino IDE. In this case, I'm using the Arduino IDE v1.6.7 downloaded from You also need to have the chibiArduino library installed (v1.06 or higher) as well as the hardware board support files. If you haven't done this yet, please check the FreakUSB user manuals on how to install these.


Once that's all out of the way, go to Files/Examples/chibiArduino and open chibi_ex10_sensniff. It's a new example that's been added to interface to the sensniff python application and act as the front end capture device. In the introductory comment in the sketch, I remind the user that promiscuous mode needs to be enabled when used in conjunction with this sketch. Promiscuous mode allows the device to capture all packets and removes any automatic hardware filtering that might be enabled. It also indicates to the stack that the device will be used in a packet capture type application and will increase the amounts of RAM in the receive buffer to accommodate this. To enable promiscuous mode, open the chibiUsrCfg.h file and scroll down to where it says


and change it to



Next, configure the board by going into Tools/Board and selecting the corresponding board and model you'll be uploading the code into. Then select the corresponding serial port that board is using. Once this is all configured, you can simply click on the upload icon to compile and upload the code to the device. Once this is all done, don't forget to set CHIBI_PROMISCUOUS back to 0 for normal operation.


We'll also be setting up another device that can be used as traffic generator for sniffing data. In this case, I'm using another FreakUSB dongle and loading the chibi_ex04_cmdline sketch into it. To do this, you follow the same sequence of steps but don't set the device to promiscuous mode.


Setting up Sensniff

Now we're going to set up the Sensniff software. You can pick it up from the original source here, but I'd recommend picking up the sensniff-freaklabs fork of the software. You can find it at the freaklabs github account here or can just download the zip file here. Sensniff-freaklabs is just the sensniff software but with the defaults already modified to match the example code. It saves you a few steps but either version should work.


Once you have the software unzipped or cloned into your directory, plug in the FreakUSB board, go into the directory and type "python host/sensniff". Alternatively, you can just change into the /host directory and type python sensniff. If everything works, the sensniff application should come up and look like this:


You can change channels by typing in the channel number you want to change to. Otherwise, you can also print the current channel . If you dig into the software, you can also add specific commands that you might want to control from the interactive shell.

Sensniff is a wonderful piece of open source software written in python by George Oikonomou who maintains the Contiki open source project and is a lecturer in IoT at the University of Bristol. Sensniff acts as a bridge between a packet capture device and wireshark and is used by the Contiki project as well as Texas Instruments to capture data for IEEE 802.15.4 traffic. It not only captures data in real time, but can also capture data and store it as a pcap file for offline browsing. This comes in handy to just leave the sniffer on for a few days when intermittent network bugs appear. Then, the packets can be filtered and analyzed in wireshark offline. Sensniff also supports a bunch of other features and is exensible with an interactive command interface. It's quite a nice tool to use in conjunction with the FreakUSB boards.

When starting up, Sensniff will open the serial port and capture device and then create or open a named pipe in the host operating system. When you start wireshark, you give it the path to the named pipe as an interface and then it becomes possible to feed wireshark data through the named pipe. To do this, open a new terminal window and type

wireshark -k -i /tmp/sensniff

This assumes you are using the default pipe name and path in sensniff.


Once wireshark is open, it will listen on the named pipe (/tmp/sensniff) for data that comes in. Any data that comes in via the hardware packet capture device will get sent over serial to sensniff which then formats the packet. It then sends the formatted data into the named pipe to wireshark. Once wireshark sees the data, it will display it in the capture window.

As an example, let's open up a terminal window to the device we're using as a traffic generator. This is the one with the chibi_ex04_cmdline sketch loaded into it. Opening up the terminal window should bring up a command line that we can use to send data over the air. To do this, we use the chibiArduino "send" command:

send 3 hello world


That will send the text string "hello world" to a destination node address of 3. There is no node 3 at the moment, but that's not important. The main thing is to capture the data and view it on wireshark.


Once it's captured, wireshark will decode the data as 802.15.4 data. Then we can click in the various packet fields and wireshark will highlight which field it is as well as bring up the decoded name.


Here's another example where I send a text string to wireshark. Then I click on the destination address field and it will automatically highlight the bytes in the packet where the destination address is.



You can not only decode the raw 802.15.4 packets but any protocol that sits on top of it. So if you have a Zigbee or 6LoWPAN device, you can also decode those packets as well.




When you start doing packet captures often, it gets a bit cumbersome to juggle separate terminal windows for sensniff and wireshark. A handy little trick is to use the following command to open them both at once. Then it also becomes scriptable so you can just have a shell script to automatically start up a packet capture:

wireshark -k -i /tmp/sensniff &amp; python && fg

Offline Packet Capture Using Sensniff

An extremely handy feature of sensniff is the abiliity to log packet capture data to a file in pcap format. It's then possible to capture packets over long periods to a file and then view the file later in wireshark for analysis. Wireshark's filtering capabilities allow for in-depth analysis of the packet dumps. To open sensniff for packet captures you can use the following:

python -p tmp.pcap

In this case, sensniff is opened with both the named pipe into wireshark for real time packet capture and will also log the data to a pcap file named tmp.pcap. You can also open sensniff in offline mode so that there is no real time monitoring. In that case, it will just dump the data to the pcap file:

python -O -p tmp.pcap

Once the data is captured into the pcap file, you can then have wireshark open it to read and decode the packet capture with the following command.

wireshark -r tmp.pcap


I hope you enjoyed this tutorial about how to sniff wireless sensor data using Wireshark, Sensniff, and FreakLabs. The combination creates an amazingly powerful tool for troubleshooting network issues, hardware issues, or IoT security. If you liked this article, please support me by buying my products. All the hardware in this tutorial can be found at my webshop at Thanks!


0 #1 Sudar Muthu 2016-02-13 03:23
Thanks for the great tutorial. Can we use Freakduino to do the sniffing?

I already own a couple of Freakduino and was wondering whether I can use it or I should buy the new FreakUSB to do this.
+1 #2 cjwang 2016-02-14 06:12
Yes! You can use the freakduino for sniffing. In fact, the FreakUSB is just a freakduino optimized for PC tethered applications. Otherwise, is internally identical to a freakduino :)
0 #3 Sudar Muthu 2016-02-14 06:17
Thanks for the confirmation. Time to fire up Wireshark :)

(Sorry, one more question)

Are there any major difference between 900 MHz and 2.4 GHz versions apart from the frequency in which they operate?

Would love an article from you that talks about the difference between them and a guide to choose one over the other.

+1 #4 cjwang 2016-02-14 13:48
900 MHz is generally preferable because it has longer range, passes through obstacles better, and is less crowded. 2.4 GHz is a global license free band though so more products are using it. That makes it more desirable from a compatibility point of view. Unfortunately, WiFi is a major traffic source in this band so you have to be careful where you position 2.4 GHz devices to make sure they can coexist with it.

Thanks for the tip on the article. I'll look into putting something together.
0 #5 Sudar Muthu 2016-02-14 13:57
Thanks again.

Add comment

Security code