A lightweight IEEE 802.15.4 packet sniffer based on the ESP32-C6, streaming captured frames over USB/serial and decoding them live in Wireshark using the official IEEE 802.15.4 TAP PCAP format.
This setup allows you to inspect RSSI, LQI and channel information directly in Wireshark without custom dissectors.
- Captures raw IEEE 802.15.4 MAC frames using the ESP32-C6 radio
- Runs the radio in promiscuous mode
- Attaches metadata per frame:
- RSSI (dBm)
- LQI
- Channel number
- Streams frames over USB serial
- Converts the stream to PCAP (LINKTYPE_IEEE802_15_4_TAP)
- Displays frames live in Wireshark
This sniffer captures raw IEEE 802.15.4 traffic, so it works for all protocols built on top of 802.15.4, including:
- Zigbee
- Thread
- 6LoWPAN
- Matter (over Thread)
- Proprietary / custom 802.15.4 protocols
The sniffer does not decrypt traffic. If encryption is enabled, frames will be visible but payloads remain encrypted unless keys are provided in Wireshark.
- ESP32-C6 (required – includes IEEE 802.15.4 radio)
- Tested with:
- ESP32-C6-DevKitC-1
- USB cable for flashing + serial capture
ESP32, ESP32-S3, ESP32-C3 etc. will NOT work – they do not include an 802.15.4 radio.
- ESP-IDF v5.x
- Target:
esp32c6
- Python 3.9+ (tested with Anaconda)
- Wireshark (recent version)
Required Python modules:
pip install pyserial- ESP32-C6 radio runs in 802.15.4 promiscuous mode
- Each received frame is queued from ISR context
- Metadata (RSSI, LQI, channel) is prepended
- Frames are sent over USB serial using a simple sync protocol
- Python script:
- Parses the serial stream
- Builds IEEE 802.15.4 TAP headers
- Outputs a valid PCAP stream
- Wireshark decodes everything natively
idf.py set-target esp32c6
idf.py build
idf.py flashOptional:
idf.py monitorLogging is disabled by default to keep the PCAP stream clean.
python serial_to_pcap.py | wireshark -k -i -python serial_to_pcap.py > capture.pcapThen open capture.pcap in Wireshark.
- The sniffer starts on channel 15 by default (configured in the firmware), which is often one of the busier Zigbee/Thread channels in 2.4 GHz environments.
- Channel 11 is also a very commonly used 802.15.4 channel (many Zigbee networks start there).
- Press the BOOT button on the DevKit to cycle through the configured channel range (typically 11–26).
If you want a different default channel or range, adjust the current_channel and channel min/max defines in the firmware.
- Link-type: IEEE 802.15.4 TAP
- Useful columns:
wpan-tap.rsswpan-tap.lqiwpan-tap.ch_num
- Enable Zigbee / Thread dissectors in:
Preferences → Protocols
.
├── main/
│ └── main.c
├── serial_to_pcap.py
├── img/
│ └── wireshark.png
├── CMakeLists.txt
├── sdkconfig
└── README.md
- No decryption (keys must be configured in Wireshark)
- USB-serial throughput limits very high frame rates
- Single channel at a time
- Multi-channel hopping
- Timestamp synchronization (PC ↔ ESP)
- USB CDC / native Wireshark extcap
- Optional FCS capture
MIT (or choose your own)
