Nexmon CSI in practice: 80 MHz / 256 subcarriers on Raspberry Pi, Pi 5 compatibility and safe rollback

By Wu Jun · Updated 2026-10-29 · 7 min read

Nexmon CSI is maintained by SEEMOO Lab at TU Darmstadt [1]. It is not an ordinary userspace packet sniffer: it patches Broadcom Wi-Fi firmware so the radio emits per-frame CSI to a UDP socket. A peer-reviewed paper describes the platform and its extraction model [2].

That gives useful high-bandwidth measurements, with an equally clear cost: the chip, firmware and OS must match; the patch changes the network interface; and a failed installation can temporarily remove Wi-Fi. Use a dedicated experiment SD card and test machine, not the only Raspberry Pi that carries your home network.

0. Bottom line

Need Is Nexmon a fit?
Fixed-channel, 80 MHz, 256 complex CSI values Yes, after checking the exact chip and OS path
Research across channels, bandwidths, frame types and transmitters Yes; more flexible than a consumer router UI
Use the same radio for daily Wi-Fi and 24/7 CSI capture No; capture takes the interface away from NetworkManager
Operate only over the Pi's own Wi-Fi, with no backup image Do not start; a failure can remove remote access
You already own an MT6000 and need long-running home coverage Prefer this project's tested mt76 router route

1. Supported chips and Raspberry Pi models

The official matrix lists four primary chips [1]:

Chip Firmware directory Typical device Bandwidth
bcm43455c0 7_45_189 Raspberry Pi 3B+ / 4B / 5 20 / 40 / 80 MHz
bcm4339 6_37_34_43 Nexus 5 20 / 40 / 80 MHz
bcm4358 7_112_300_14_sta Nexus 6P 20 / 40 / 80 MHz
bcm4366c0 10_10_122_20 Some ASUS RT-AC86U devices 20 / 40 / 80 MHz

"Raspberry Pi 5" does not mean "any Raspberry Pi OS image compiles unchanged." The maintainer's recent guide says:

Record these before touching the system:

cat /proc/device-tree/model
uname -a
getconf PAGESIZE
iw dev
sudo dmesg | grep -i -E 'brcmfmac|cyfmac|firmware'

If getconf PAGESIZE returns 16384 on a Pi 5, switch to kernel=kernel8.img as required by the upstream guide. Do not make that change on the only card without understanding how to recover it.

2. Prerequisites

  1. A dedicated SD card: image the whole card first and keep a second bootable card;
  2. Ethernet or a serial console: Makefile.rpi unmanage disconnects wlan0 from NetworkManager;
  3. Stable power: compilation and long captures need a reliable supply;
  4. A transmitter on the same channel: a phone, ESP32 or second Wi-Fi interface;
  5. A pinned 5 GHz channel: disable automatic selection and avoid DFS/congested primary channels;
  6. A local experiment log: chip, firmware directory, OS, kernel, page size, channel, bandwidth, spatial streams and capture time.

The upstream Pi 5 path installs historical compatibility packages and may temporarily use an archived Debian source [3]. That is not a hardened production-server recipe. Treat the card as a short-lived experiment: do not keep SSH private keys, password stores, family photos or the only copy of any data on it. Restore the official firmware after the experiment.

3. Two installation paths

Path A: older Raspberry Pi OS / legacy upstream flow

The official README documents modified brcmfmac drivers and patch builds for Pi 3B+/4B on kernels 4.19, 5.4 and 5.10. It depends heavily on those kernel versions. Do not copy those commands onto a Pi 5 or a current OS.

Path B: current Raspberry Pi OS / Pi 5

For current Raspberry Pi OS and Pi 5, use the maintainer's Makefile.rpi guide [3]. The core sequence is below. Do not treat the block as a complete one-command installer: Pi 5 armhf compatibility packages and the Python 2.7 build dependency must be installed according to the linked guide.

# Raspberry Pi 5 only: switch to a non-16K-page kernel, then reboot
grep -qxF 'kernel=kernel8.img' /boot/firmware/config.txt || \
  echo 'kernel=kernel8.img' | sudo tee -a /boot/firmware/config.txt
sudo reboot

sudo apt update
sudo apt full-upgrade
sudo apt install git libgmp3-dev gawk qpdf bison flex make \
  autoconf libtool texinfo xxd libnl-3-dev libnl-genl-3-dev \
  bc libssl-dev tcpdump

git clone --depth=1 https://github.com/seemoo-lab/nexmon.git
cd nexmon
source setup_env.sh
make

# The modern driver path requires vendor commands
cd "$NEXMON_ROOT/utilities/nexutil"
sudo -E make install USE_VENDOR_CMD=1
sudo setcap cap_net_admin+ep /usr/bin/nexutil

cd "$NEXMON_ROOT/patches/bcm43455c0/7_45_189"
git clone --depth=1 https://github.com/seemoo-lab/nexmon_csi.git
cd nexmon_csi
make -f Makefile.rpi install-firmware
make -f Makefile.rpi unmanage
make -f Makefile.rpi reload-full

After unmanage, do not expect wlan0 to keep SSH alive. Generate extractor parameters with the upstream makecsiparams, then configure CSI and monitor mode:

# The fields are illustrative; replace MAC, frame type and channel for your test
SENDER_MAC="${SENDER_MAC:?set the test transmitter MAC first}"
CSI_PARAMS="$(makecsiparams -c 44/80 -C 1 -N 1 -m "$SENDER_MAC" -b 0x88)"
sudo nexutil -Iwlan0 -s500 -b -l34 -v"$CSI_PARAMS"
sudo nexutil -m1
sudo tcpdump -i wlan0 dst port 5500 -w csi-10s.pcap

The command has no built-in example MAC; it fails immediately unless SENDER_MAC is set. Always copy the current parameter syntax from the upstream README. The repository has introduced backward-incompatible changes; magic values and configuration strings in old blog posts can be stale.

4. UDP packet and CSI format

The current README says each matching Wi-Fi frame produces one UDP packet per configured core/spatial stream, normally on port 5500. The payload layout is:

uint16  magic = 0x1111
uint8   source_mac[6]
uint16  wifi_sequence
uint16  core_and_spatial_stream
uint16  chanspec
uint16  chip_version
...     CSI samples

For bcm43455c0 and bcm4339, CSI is interleaved int16 I / int16 Q. The bcm4358 and bcm4366c0 use different packed floating-point formats. A 20 / 40 / 80 MHz extraction contains 64 / 128 / 256 complex slots respectively, at four bytes per slot. Those slots include guard, null and pilot positions; do not treat all 256 as useful information subcarriers.

An 80 MHz receiver can also receive a frame transmitted in a 20 MHz-wide portion of the channel. Most of the CSI slots being empty does not necessarily mean capture is broken; check the transmitter's actual bandwidth and frame type. Remove guard/null positions and report the ratio of usable subcarriers.

5. Capture settings and data budget

A rough budget: at about 100 matching frames/s, one 80 MHz stream carries about 100 × 256 × 4 = 102.4 KB/s of CSI before Ethernet/IP/UDP and pcapng overhead. Actual size depends on matched frame rate, cores and spatial streams. This project's MT6000 capture is 58 MB for 10 minutes and eight-chain records, which is a useful order-of-magnitude reference.

6. Parsing and quality checks

Tool Best use
CSIKit [4] multi-format parsing, plots and CSV/JSON export
csiread [5] Cython parsing with faster batch and live-capture examples

After a capture, verify:

Check Pass condition
UDP traffic port 5500 receives a sustained stream
pcap readability tcpdump -r csi-10s.pcap returns packets
magic / chip format matches current Nexmon release and chip
bandwidth 80 MHz configuration exposes the expected 256 slots
usable subcarriers frame bandwidth and zero-slot ratio are recorded
timeline report inter-packet p95 and maximum gap
filtering transmitter MAC and frame type match the configuration

7. Failure guide

Symptom Cause Check first
build fails on Pi 5 still using a 16K-page kernel getconf PAGESIZE, kernel=kernel8.img
nexutil commands are rejected built without vendor-command support rebuild with USE_VENDOR_CMD=1
no UDP packets no traffic or wrong MAC/frame filter ping/iperf, tcpdump, extractor parameters
bad chanspec / interface down radio down or another service changed the channel nexutil -k, stop wpa_supplicant
most 80 MHz slots are empty a 20 MHz frame or transmitter not using full width inspect transmitter bandwidth and frame type
Wi-Fi remains missing after rollback firmware alternative or driver not restored sudo update-alternatives --config cyfmac43455-sdio.bin
capture stops after a few minutes power, heat, distance or interference stable supply, temperature, pinned channel

8. Safe rollback

Restore the normal firmware when the experiment ends:

make -f Makefile.rpi restore-wifi

If rollback fails, boot from the spare SD card or restore the card image with a reader. Never combine experiment, remote administration and the only copy of important data on one card.

9. Nexmon vs ESP32 vs MT6000

Item Nexmon + Pi ESP32 CSI MT6000 + mt76 CSI
Typical bandwidth 20–80 MHz 20 MHz, some 40 MHz HE80 in this project
Typical slots/subcarriers 64 / 128 / 256 slots 30–64 measured subcarriers 256 complex slots
Channel/bandwidth flexibility high medium medium
Long-running deployment needs a maintained experiment host low power, single room natural fit for an existing router
Main risk firmware, kernel and network changes sampling rate and interference driver patch and router performance tuning

Continue with the Raspberry Pi role guide, ESP32 CSI introduction, MT6000 reproduction guide or the project's 10-minute dataset.

References and data sources

Every external claim carries a source and an evidence grade (grading scheme). Grade E marks first-party, reproducible measurements from this project.

  1. Grade C · official docs seemoo-lab/nexmon_csi — CSI extraction on various Broadcom Wi-Fi chips
    SEEMOO Lab, TU Darmstadt
    github.com/seemoo-lab/nexmon_csi · verified: GitHub API 2026-10-29 (stars 479, last push 2026-09-30; README lists bcm43455c0 on Raspberry Pi 3B+/4B/5)
  2. Grade B · peer-reviewed Free Your CSI: A Channel State Information Extraction Platform For Modern Wi-Fi Chipsets
    F. Gringoli, M. Schulz, J. Link, M. Hollick · Proceedings of the 13th ACM Workshop on Wireless Network Testbeds, Experimental Evaluation & Characterization · 2019
    doi:10.1145/3349623.3355477 · citations 334 · verified: Crossref API 2026-10-29 (334 citations; DOI and venue resolved) · Peer-reviewed description of the Nexmon CSI platform, its firmware patch and per-frame CSI extraction.
  3. Grade C · official docs Raspberry Pi 5 and recent Raspberry Pi OS kernel versions — Makefile.rpi guide
    SEEMOO Lab, TU Darmstadt · 2026
    github.com/seemoo-lab/nexmon_csi/discussions/395 · verified: Official maintainer discussion fetched 2026-10-29; documents Pi 5 kernel=kernel8.img, USE_VENDOR_CMD=1, capture and restore-wifi · The maintainer's current Raspberry Pi route; use a dedicated experiment SD card because it changes firmware, drivers and system packages.
  4. Grade C · official docs Gi-z/CSIKit — Python CSI parsing and visualisation
    G. Zhang
    github.com/Gi-z/CSIKit · verified: GitHub API 2026-10-11 (stars 307, MIT, last push 2025-02-19) · Parses many formats: Atheros / Intel / Nexmon / ESP32 / FeitCSI / PicoScenes.
  5. Grade C · official docs citysu/csiread — fast Cython CSI parser
    S. Zhu
    github.com/citysu/csiread · verified: GitHub API 2026-10-11 (stars 142, MIT, last push 2024-10-12)