git: 93c6906e36a4 - main - wtap(4): implement monitor mode and handle radiotap
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 16 Jun 2026 14:58:22 UTC
The branch main has been updated by adrian:
URL: https://cgit.FreeBSD.org/src/commit/?id=93c6906e36a4e60e59279b6b6e18403ea23d56e1
commit 93c6906e36a4e60e59279b6b6e18403ea23d56e1
Author: EN-WEU WU <enweiwu@FreeBSD.org>
AuthorDate: 2026-06-16 14:54:05 +0000
Commit: Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2026-06-16 14:54:55 +0000
wtap(4): implement monitor mode and handle radiotap
Implement monitor mode by simply adding IEEE80211_C_MONITOR to ic->ic_cap.
To get additional informations when capturing 802.11 frames, radiotap is
inserted by wtap_tx_tap() when TX and wtap_rx_tap() when RX.
There are some type faults in struct wtap_rx_radiotap_header which are
mainly mistakenly store unsigned values into signed integers.
I have fixed them (wtap(4)) by complying with the types defined
in https://www.radiotap.org/fields/defined.
Becuase the struct wtap_rx_radiotap_header comes from ath(4),
there may be another patch to fix the type faults in ath(4).
Differential Review: https://reviews.freebsd.org/D36469
---
sys/dev/wtap/if_wtap.c | 59 ++++++++++++++++++++++++++++++++++++++++++---
sys/dev/wtap/if_wtapioctl.h | 31 ++++++++++++------------
2 files changed, 71 insertions(+), 19 deletions(-)
diff --git a/sys/dev/wtap/if_wtap.c b/sys/dev/wtap/if_wtap.c
index d22b79a20dc4..d23036575d7a 100644
--- a/sys/dev/wtap/if_wtap.c
+++ b/sys/dev/wtap/if_wtap.c
@@ -229,6 +229,43 @@ wtap_beacon_config(struct wtap_softc *sc, struct ieee80211vap *vap)
DWTAP_PRINTF("%s\n", __func__);
}
+static void
+wtap_rx_tap(struct wtap_softc *sc, uint64_t tsf)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ const struct ieee80211_rate_table *rt = ic->ic_rt;
+ struct wtap_rx_radiotap_header *rh = &sc->sc_rx_th;
+
+ rh->wr_tsf = tsf;
+ rh->wr_flags = 0;
+ if (rt->rateCount) {
+ /* choose the fastest rate */
+ rh->wr_rate = IEEE80211_RV(rt->info[rt->rateCount - 1].dot11Rate);
+ }
+ rh->wr_chan_flags = IEEE80211_CHAN_2GHZ;
+ rh->wr_chan_freq = ic->ic_curchan->ic_freq;
+ rh->wr_chan_ieee = ic->ic_curchan->ic_ieee;
+ rh->wr_chan_maxpow = 0;
+}
+
+static void
+wtap_tx_tap(struct wtap_softc *sc)
+{
+ struct ieee80211com *ic = &sc->sc_ic;
+ const struct ieee80211_rate_table *rt = ic->ic_rt;
+ struct wtap_tx_radiotap_header *th = &sc->sc_tx_th;
+
+ th->wt_flags = 0;
+ if (rt->rateCount) {
+ /* choose the fastest rate */
+ th->wt_rate = IEEE80211_RV(rt->info[rt->rateCount - 1].dot11Rate);
+ }
+ th->wt_chan_flags = IEEE80211_CHAN_2GHZ;
+ th->wt_chan_freq = ic->ic_curchan->ic_freq;
+ th->wt_chan_ieee = ic->ic_curchan->ic_ieee;
+ th->wt_chan_maxpow = 0;
+}
+
static void
wtap_beacon_intrp(void *arg)
{
@@ -261,8 +298,10 @@ wtap_beacon_intrp(void *arg)
wh = mtod(m, struct ieee80211_frame *);
memcpy(&wh[1], &tsf, sizeof(tsf));
- if (ieee80211_radiotap_active_vap(vap))
- ieee80211_radiotap_tx(vap, m);
+ if (ieee80211_radiotap_active_vap(vap)) {
+ wtap_tx_tap(sc);
+ ieee80211_radiotap_tx(vap, m);
+ }
#if 0
medium_transmit(avp->av_md, avp->id, m);
@@ -459,6 +498,8 @@ static int
wtap_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
const struct ieee80211_bpf_params *params)
{
+ struct ieee80211com *ic = ni->ni_ic;
+ struct wtap_softc *sc = ic->ic_softc;
#if 0
DWTAP_PRINTF("%s, %p\n", __func__, m);
#endif
@@ -466,6 +507,7 @@ wtap_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
struct wtap_vap *avp = WTAP_VAP(vap);
if (ieee80211_radiotap_active_vap(vap)) {
+ wtap_tx_tap(sc);
ieee80211_radiotap_tx(vap, m);
}
if (m->m_flags & M_TXCB)
@@ -529,6 +571,10 @@ wtap_rx_proc(void *arg, int npending)
#if 0
ieee80211_dump_pkt(ic, mtod(m, caddr_t), 0,0,0);
#endif
+ if (ieee80211_radiotap_active(ic)) {
+ uint64_t tsf = wtap_hal_get_tsf(sc->hal);
+ wtap_rx_tap(sc, tsf);
+ }
/*
* Use arbitrary but sane values, and do the correct conversion
@@ -600,6 +646,7 @@ wtap_transmit(struct ieee80211com *ic, struct mbuf *m)
struct ieee80211_node *ni =
(struct ieee80211_node *) m->m_pkthdr.rcvif;
struct ieee80211vap *vap = ni->ni_vap;
+ struct wtap_softc *sc = ic->ic_softc;
struct wtap_vap *avp = WTAP_VAP(vap);
struct ieee80211_key *k;
struct ieee80211_frame *wh;
@@ -612,8 +659,10 @@ wtap_transmit(struct ieee80211com *ic, struct mbuf *m)
return (ENOBUFS);
}
- if (ieee80211_radiotap_active_vap(vap))
+ if (ieee80211_radiotap_active_vap(vap)) {
+ wtap_tx_tap(sc);
ieee80211_radiotap_tx(vap, m);
+ }
if (m->m_flags & M_TXCB)
ieee80211_process_callback(ni, m, 0);
ieee80211_free_node(ni);
@@ -668,7 +717,9 @@ wtap_attach(struct wtap_softc *sc, const uint8_t *macaddr)
| IEEE80211_C_IBSS /* ibss, nee adhoc, mode */
| IEEE80211_C_STA /* station mode */
| IEEE80211_C_HOSTAP /* hostap mode */
- | IEEE80211_C_WPA; /* capable of WPA1+WPA2 */
+ | IEEE80211_C_WPA /* capable of WPA1+WPA2 */
+ | IEEE80211_C_MONITOR /* Enable monitor mode */
+ ;
ic->ic_cryptocaps =
IEEE80211_CRYPTO_WEP
diff --git a/sys/dev/wtap/if_wtapioctl.h b/sys/dev/wtap/if_wtapioctl.h
index 05f88a5dcb81..f9fe35813576 100644
--- a/sys/dev/wtap/if_wtapioctl.h
+++ b/sys/dev/wtap/if_wtapioctl.h
@@ -139,41 +139,42 @@ struct wtap_stats {
/*
* Radio capture format.
*/
-#define WTAP_RX_RADIOTAP_PRESENT ( \
+#define WTAP_RX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_TSFT) | \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct wtap_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
-#if 0
+
u_int64_t wr_tsf;
u_int8_t wr_flags;
u_int8_t wr_rate;
- int8_t wr_antsignal;
- int8_t wr_antnoise;
- u_int8_t wr_antenna;
- u_int8_t wr_pad[3];
+ u_int8_t wr_pad[2];
u_int32_t wr_chan_flags;
u_int16_t wr_chan_freq;
u_int8_t wr_chan_ieee;
- int8_t wr_chan_maxpow;
-#endif
+ u_int8_t wr_chan_maxpow;
} __packed __aligned(8);
-#define WTAP_TX_RADIOTAP_PRESENT ( \
+#define WTAP_TX_RADIOTAP_PRESENT ( \
+ (1 << IEEE80211_RADIOTAP_FLAGS) | \
+ (1 << IEEE80211_RADIOTAP_RATE) | \
+ (1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
struct wtap_tx_radiotap_header {
struct ieee80211_radiotap_header wt_ihdr;
-#if 0
+
u_int8_t wt_flags;
u_int8_t wt_rate;
- u_int8_t wt_txpower;
- u_int8_t wt_antenna;
+ u_int8_t wr_pad[2];
u_int32_t wt_chan_flags;
u_int16_t wt_chan_freq;
u_int8_t wt_chan_ieee;
- int8_t wt_chan_maxpow;
-#endif
-} __packed;
+ u_int8_t wt_chan_maxpow;
+} __packed __aligned(8);
#endif