IEEE80211_RADIOTAP(9)
π ieee80211_radiotap β 802.11 device packet capture support π
okay so bestie, welcome to IEEE80211_RADIOTAP(9) from the Kernel Developer's Manual π«Ά this is the whole entire lore on how the net80211 layer does radiotap packet capture, and ngl it's kind of iconic. grab a strawberry drink π and let's get into it.
πΈ NAME πΈ
ieee80211_radiotap β 802.11 device packet capture support β¨
β¨ SYNOPSIS β¨
#include <net80211/ieee80211_var.h>
void
ieee80211_radiotap_attach(struct ieee80211com *,
struct ieee80211_radiotap_header *th, int tlen,
uint32_t tx_radiotap, struct ieee80211_radiotap_header *rh,
int rlen, uint32_t rx_radiotap);
int
ieee80211_radiotap_active_vap(struct ieee80211vap *);
int
ieee80211_radiotap_active(struct ieee80211com *);
void
ieee80211_radiotap_tx(struct ieee80211vap *, struct mbuf *);
π¦ DESCRIPTION π¦
so the net80211 layer that all the 802.11 drivers use ships with support for a device-independent packet capture format called radiotap, and tools like tcpdump(1) justβ¦ understand it. no cap. it's built specifically for capturing 802.11 traffic, including the info that is not part of the normal 802.11 frame structure. the way that it catches stuff the regular frames don't even carry? obsessed. π
radiotap was designed to balance two things at once: wanting a hardware-independent, extensible capture format, versus needing to conserve CPU and memory bandwidth on embedded systems. iconic tension, honestly. those considerations are what led to a format that's a standard preamble followed by an extensible bitmap that says which optional capture fields are present. π
a net80211 device driver that supports radiotap defines two packed structures that it shares with net80211. these structures embed an instance of a ieee80211_radiotap_header structure at the beginning, with subsequent fields in the appropriate order, plus macros to set the bits of the it_present bitmap to indicate which fields exist and are filled in by the driver. then all of that info gets supplied through the ieee80211_radiotap_attach() call β but only after a successful ieee80211_ifattach() request, okay? order matters, bestie. π
once radiotap is set up, drivers just have to fill in per-packet capture state for frames sent/received, and dispatch capture state in the transmit path (since control is not returned to the net80211 layer before the packet is handed to the device). and to minimize overhead, this work should only be done when one or more processes are actively capturing data β which you check with either ieee80211_radiotap_active_vap() or ieee80211_radiotap_active(). efficient queen behavior. π
in the transmit path, the capture work looks like this:
if (ieee80211_radiotap_active_vap(vap)) {
... /* record transmit state */
ieee80211_radiotap_tx(vap, m); /* capture transmit event */
}
while in the receive path, capture is handled in net80211, but state must be captured before dispatching a frame:
if (ieee80211_radiotap_active(ic)) {
... /* record receive state */
}
...
ieee80211_input(...); /* packet capture handled in net80211 */
the following fields are defined for radiotap, in the order in which they should appear in the buffer supplied to net80211. bestie, the order is not a vibe suggestion, it's the vibe. β¨
IEEE80211_RADIOTAP_TSFT
this field contains the unsigned 64-bit value, in microseconds, of the MAC's 802.11 Time Synchronization Function (TSF). in theory, for each received frame, this value is recorded when the first bit of the MPDU arrived at the MAC. in practice though? hardware snapshots the TSF otherwise, so you cannot assume this data is accurate without driver adjustment. π
IEEE80211_RADIOTAP_FLAGS
this field contains a single unsigned 8-bit value, holding one or more of these bit flags:
IEEE80211_RADIOTAP_F_CFPβ frame was sent/received during the Contention Free Period (CFP).IEEE80211_RADIOTAP_F_SHORTPREβ frame was sent/received with short preamble.IEEE80211_RADIOTAP_F_WEPβ frame was encrypted. πIEEE80211_RADIOTAP_F_FRAGβ frame was an 802.11 fragment.IEEE80211_RADIOTAP_F_FCSβ frame contents includes the FCS.IEEE80211_RADIOTAP_F_DATAPADβ frame contents potentially has padding between the 802.11 header and the data payload to align the payload to a 32-bit boundary.IEEE80211_RADIOTAP_F_BADFCSβ frame was received with an invalid FCS. πIEEE80211_RADIOTAP_F_SHORTGIβ frame was sent/received with Short Guard Interval.
IEEE80211_RADIOTAP_RATE
this field contains a single unsigned 8-bit value that is the data rate. legacy rates are in units of 500Kbps. MCS rates (used on 802.11n/HT channels) have the high bit set and the MCS in the low 7 bits. π
IEEE80211_RADIOTAP_CHANNEL
this field contains two unsigned 16-bit values. the first value is the center frequency for the channel the frame was sent/received on. the second value is a bitmap containing flags that specify channel properties.
this field is deprecated in favor of IEEE80211_RADIOTAP_XCHANNEL but may be used to save space in the capture file for legacy devices.
IEEE80211_RADIOTAP_DBM_ANTSIGNAL
this field contains a single signed 8-bit value that indicates the RF signal power at the antenna, in decibels difference from 1mW. πΆ
IEEE80211_RADIOTAP_DBM_ANTNOISE
this field contains a single signed 8-bit value that indicates the RF noise power at the antenna, in decibels difference from 1mW.
IEEE80211_RADIOTAP_DBM_TX_POWER
transmit power expressed as decibels from a 1mW reference. this field is a single signed 8-bit value. this is the absolute power level measured at the antenna port.
IEEE80211_RADIOTAP_ANTENNA
this field contains a single unsigned 8-bit value that specifies which antenna was used to transmit or receive the frame. antenna numbering is device-specific but typically the primary antenna has the lowest number. on transmit a value of zero may be seen which typically means antenna selection is left to the device. π‘
IEEE80211_RADIOTAP_DB_ANTSIGNAL
this field contains a single unsigned 8-bit value that indicates the RF signal power at the antenna, in decibels difference from an arbitrary, fixed reference.
IEEE80211_RADIOTAP_DB_ANTNOISE
this field contains a single unsigned 8-bit value that indicates the RF noise power at the antenna, in decibels difference from an arbitrary, fixed reference.
IEEE80211_RADIOTAP_XCHANNEL
this field contains four values: a 32-bit unsigned bitmap of flags that describe the channel attributes, a 16-bit unsigned frequency in MHz (typically the channel center), an 8-bit unsigned IEEE channel number, and a signed 8-bit value that holds the maximum regulatory transmit power cap in .5 dBm (8 bytes total). channel flags are defined in <net80211/_ieee80211.h> (only a subset are found in <net80211/ieee80211_radiotap.h>). this property supersedes IEEE80211_RADIOTAP_CHANNEL and is the only way to completely express all channel attributes and the mapping between channel frequency and IEEE channel number. periodt. π
π EXAMPLES π
radiotap receive definitions for the Intersil Prism driver:
#define WI_RX_RADIOTAP_PRESENT \
((1 << IEEE80211_RADIOTAP_TSFT) \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_CHANNEL) | \
(1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) | \
(1 << IEEE80211_RADIOTAP_DB_ANTNOISE))
struct wi_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
uint64_t wr_tsf;
uint8_t wr_flags;
uint8_t wr_rate;
uint16_t wr_chan_freq;
uint16_t wr_chan_flags;
uint8_t wr_antsignal;
uint8_t wr_antnoise;
} __packed __aligned(8);
and transmit definitions for the Atheros driver:
#define ATH_TX_RADIOTAP_PRESENT ( \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
(1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \
(1 << IEEE80211_RADIOTAP_ANTENNA) | \
(1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct ath_tx_radiotap_header {
struct ieee80211_radiotap_header wt_ihdr;
uint8_t wt_flags;
uint8_t wt_rate;
uint8_t wt_txpower;
uint8_t wt_antenna;
uint32_t wt_chan_flags;
uint16_t wt_chan_freq;
uint8_t wt_chan_ieee;
int8_t wt_chan_maxpow;
} __packed;
π SEE ALSO π
tcpdump(1), bpf(4), ieee80211(9)
π HISTORY π
the ieee80211_radiotap definitions first appeared in NetBSD 1.5. throwback era fr fr. π°οΈ
π AUTHORS π
the original version of this manual page was written by Bruce M. Simpson <bms@FreeBSD.org> and Darron Broad <darron@kewl.org>. legends, honestly, we thank them for their service. π«Ά
and that's the whole page bestie!! this was the Debian build of IEEE80211_RADIOTAP(9), dated March 11, 2019 β go forth and capture those packets, you absolute main character π¦β¨π
π¦ where this page comes from
- debian bookworm: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- debian trixie: freebsd-manpages 12.2-2 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu jammy: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu noble: freebsd-manpages 12.2-1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu questing: freebsd-manpages 12.2-2
- ubuntu resolute: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- ubuntu stonking: freebsd-manpages 12.2-2build1 Β· BSD-2-Clause-FreeBSD AND BSD-4-Clause
- Copyright (c) 2004 Bruce M. Simpson <bms@spc.org>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms