Introduce an optional ath(4) radiotap vendor extension.

This includes a few new fields in each RXed frame:

* per chain RX RSSI (ctl and ext);
* current RX chainmask;
* EVM information;
* PHY error code;
* basic RX status bits (CRC error, PHY error, etc).

This is primarily to allow me to do some userland PHY error processing
for radar and spectral scan data.  However since EVM and per-chain RSSI
is provided, others may find it useful for a variety of tasks.

The default is to not compile in the radiotap vendor extensions, primarily
because tcpdump doesn't seem to handle the particular vendor extension
layout I'm using, and I'd rather not break existing code out there that
may be (badly) parsing the radiotap data.

Instead, add the option 'ATH_ENABLE_RADIOTAP_VENDOR_EXT' to your kernel
configuration file to enable these options.
This commit is contained in:
Adrian Chadd 2012-06-24 07:01:49 +00:00
parent a183985e6f
commit e1b5ab97e8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=237522
4 changed files with 166 additions and 2 deletions

View File

@ -783,6 +783,7 @@ ATH_TX99_DIAG opt_ath.h
ATH_ENABLE_11N opt_ath.h
ATH_ENABLE_DFS opt_ath.h
ATH_EEPROM_FIRMWARE opt_ath.h
ATH_ENABLE_RADIOTAP_VENDOR_EXT opt_ath.h
# options for the Atheros hal
AH_SUPPORT_AR5416 opt_ah.h

View File

@ -799,11 +799,26 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
ic->ic_update_chw = ath_update_chw;
#endif /* ATH_ENABLE_11N */
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
/*
* There's one vendor bitmap entry in the RX radiotap
* header; make sure that's taken into account.
*/
ieee80211_radiotap_attachv(ic,
&sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th), 0,
ATH_TX_RADIOTAP_PRESENT,
&sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), 1,
ATH_RX_RADIOTAP_PRESENT);
#else
/*
* No vendor bitmap/extensions are present.
*/
ieee80211_radiotap_attach(ic,
&sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
ATH_TX_RADIOTAP_PRESENT,
&sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th),
ATH_RX_RADIOTAP_PRESENT);
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
/*
* Setup dynamic sysctl's now that country code and

View File

@ -354,6 +354,55 @@ ath_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m,
}
}
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
static void
ath_rx_tap_vendor(struct ifnet *ifp, struct mbuf *m,
const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
{
struct ath_softc *sc = ifp->if_softc;
/* Fill in the extension bitmap */
sc->sc_rx_th.wr_ext_bitmap = htole32(1 << ATH_RADIOTAP_VENDOR_HEADER);
/* Fill in the vendor header */
sc->sc_rx_th.wr_vh.vh_oui[0] = 0x7f;
sc->sc_rx_th.wr_vh.vh_oui[1] = 0x03;
sc->sc_rx_th.wr_vh.vh_oui[2] = 0x00;
/* XXX what should this be? */
sc->sc_rx_th.wr_vh.vh_sub_ns = 0;
sc->sc_rx_th.wr_vh.vh_skip_len =
htole16(sizeof(struct ath_radiotap_vendor_hdr));
/* General version info */
sc->sc_rx_th.wr_v.vh_version = 1;
sc->sc_rx_th.wr_v.vh_rx_chainmask = sc->sc_rxchainmask;
/* rssi */
sc->sc_rx_th.wr_v.rssi_ctl[0] = rs->rs_rssi_ctl[0];
sc->sc_rx_th.wr_v.rssi_ctl[1] = rs->rs_rssi_ctl[1];
sc->sc_rx_th.wr_v.rssi_ctl[2] = rs->rs_rssi_ctl[2];
sc->sc_rx_th.wr_v.rssi_ext[0] = rs->rs_rssi_ext[0];
sc->sc_rx_th.wr_v.rssi_ext[1] = rs->rs_rssi_ext[1];
sc->sc_rx_th.wr_v.rssi_ext[2] = rs->rs_rssi_ext[2];
/* evm */
sc->sc_rx_th.wr_v.evm[0] = rs->rs_evm0;
sc->sc_rx_th.wr_v.evm[1] = rs->rs_evm1;
sc->sc_rx_th.wr_v.evm[2] = rs->rs_evm2;
/* XXX TODO: extend this to include 3-stream EVM */
/* phyerr info */
if (rs->rs_status & HAL_RXERR_PHY)
sc->sc_rx_th.wr_v.vh_phyerr_code = rs->rs_phyerr;
else
sc->sc_rx_th.wr_v.vh_phyerr_code = 0xff;
sc->sc_rx_th.wr_v.vh_rs_status = rs->rs_status;
sc->sc_rx_th.wr_v.vh_rssi = rs->rs_rssi;
}
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
static void
ath_rx_tap(struct ifnet *ifp, struct mbuf *m,
const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
@ -552,6 +601,9 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status,
m->m_pkthdr.len = m->m_len = len;
bf->bf_m = NULL;
ath_rx_tap(ifp, m, rs, rstamp, nf);
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
ath_rx_tap_vendor(ifp, m, rs, rstamp, nf);
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
ieee80211_radiotap_rx_all(ic, m);
m_freem(m);
}
@ -646,8 +698,12 @@ ath_rx_pkt(struct ath_softc *sc, struct ath_rx_status *rs, HAL_STATUS status,
* material required by ieee80211_input. Note that
* noise setting is filled in above.
*/
if (ieee80211_radiotap_active(ic))
if (ieee80211_radiotap_active(ic)) {
ath_rx_tap(ifp, m, rs, rstamp, nf);
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
ath_rx_tap_vendor(ifp, m, rs, rstamp, nf);
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
}
/*
* From this point on we assume the frame is at least

View File

@ -187,7 +187,7 @@ struct ath_diag {
/*
* Radio capture format.
*/
#define ATH_RX_RADIOTAP_PRESENT ( \
#define ATH_RX_RADIOTAP_PRESENT_BASE ( \
(1 << IEEE80211_RADIOTAP_TSFT) | \
(1 << IEEE80211_RADIOTAP_FLAGS) | \
(1 << IEEE80211_RADIOTAP_RATE) | \
@ -197,8 +197,80 @@ struct ath_diag {
(1 << IEEE80211_RADIOTAP_XCHANNEL) | \
0)
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
#define ATH_RX_RADIOTAP_PRESENT \
(ATH_RX_RADIOTAP_PRESENT_BASE | \
(1 << IEEE80211_RADIOTAP_VENDOREXT) | \
(1 << IEEE80211_RADIOTAP_EXT) | \
0)
#else
#define ATH_RX_RADIOTAP_PRESENT ATH_RX_RADIOTAP_PRESENT_BASE
#endif /* ATH_ENABLE_RADIOTAP_PRESENT */
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
/*
* This is higher than the vendor bitmap used inside
* the Atheros reference codebase.
*/
/* Bit 8 */
#define ATH_RADIOTAP_VENDOR_HEADER 8
/*
* Using four chains makes all the fields in the
* per-chain info header be 4-byte aligned.
*/
#define ATH_RADIOTAP_MAX_CHAINS 4
/*
* The vendor radiotap header data needs to be:
*
* + Aligned to a 4 byte address
* + .. so all internal fields are 4 bytes aligned;
* + .. and no 64 bit fields are allowed.
*
* So padding is required to ensure this is the case.
*
* Note that because of the lack of alignment with the
* vendor header (6 bytes), the first field must be
* two bytes so it can be accessed by alignment-strict
* platform (eg MIPS.)
*/
struct ath_radiotap_vendor_hdr { /* 30 bytes */
uint8_t vh_version; /* 1 */
uint8_t vh_rx_chainmask; /* 1 */
/* At this point it should be 4 byte aligned */
uint32_t evm[ATH_RADIOTAP_MAX_CHAINS]; /* 4 * 4 = 16 */
uint8_t rssi_ctl[ATH_RADIOTAP_MAX_CHAINS]; /* 4 */
uint8_t rssi_ext[ATH_RADIOTAP_MAX_CHAINS]; /* 4 */
uint8_t vh_phyerr_code; /* Phy error code, or 0xff */
uint8_t vh_rs_status; /* RX status */
uint8_t vh_rssi; /* Raw RSSI */
uint8_t vh_pad1[1]; /* Pad to 4 byte boundary */
} __packed;
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
struct ath_rx_radiotap_header {
struct ieee80211_radiotap_header wr_ihdr;
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
/* Vendor extension header bitmap */
uint32_t wr_ext_bitmap; /* 4 */
/*
* This padding is needed because:
* + the radiotap header is 8 bytes;
* + the extension bitmap is 4 bytes;
* + the tsf is 8 bytes, so it must start on an 8 byte
* boundary.
*/
uint32_t wr_pad1;
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
/* Normal radiotap fields */
u_int64_t wr_tsf;
u_int8_t wr_flags;
u_int8_t wr_rate;
@ -210,6 +282,26 @@ struct ath_rx_radiotap_header {
u_int16_t wr_chan_freq;
u_int8_t wr_chan_ieee;
int8_t wr_chan_maxpow;
#ifdef ATH_ENABLE_RADIOTAP_VENDOR_EXT
/*
* Vendor header section, as required by the
* presence of the vendor extension bit and bitmap
* entry.
*
* XXX This must be aligned to a 4 byte address?
* XXX or 8 byte address?
*/
struct ieee80211_radiotap_vendor_header wr_vh; /* 6 bytes */
/*
* Because of the lack of alignment enforced by the above
* header, this vendor section won't be aligned in any
* useful way. So, this will include a two-byte version
* value which will force the structure to be 4-byte aligned.
*/
struct ath_radiotap_vendor_hdr wr_v;
#endif /* ATH_ENABLE_RADIOTAP_VENDOR_EXT */
} __packed;
#define ATH_TX_RADIOTAP_PRESENT ( \