Date: Sun, 24 Jun 2012 07:01:49 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r237522 - in head/sys: conf dev/ath Message-ID: <201206240701.q5O71nu1093561@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Sun Jun 24 07:01:49 2012 New Revision: 237522 URL: http://svn.freebsd.org/changeset/base/237522 Log: 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. Modified: head/sys/conf/options head/sys/dev/ath/if_ath.c head/sys/dev/ath/if_ath_rx.c head/sys/dev/ath/if_athioctl.h Modified: head/sys/conf/options ============================================================================== --- head/sys/conf/options Sun Jun 24 06:37:28 2012 (r237521) +++ head/sys/conf/options Sun Jun 24 07:01:49 2012 (r237522) @@ -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 Modified: head/sys/dev/ath/if_ath.c ============================================================================== --- head/sys/dev/ath/if_ath.c Sun Jun 24 06:37:28 2012 (r237521) +++ head/sys/dev/ath/if_ath.c Sun Jun 24 07:01:49 2012 (r237522) @@ -799,11 +799,26 @@ ath_attach(u_int16_t devid, struct ath_s 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 Modified: head/sys/dev/ath/if_ath_rx.c ============================================================================== --- head/sys/dev/ath/if_ath_rx.c Sun Jun 24 06:37:28 2012 (r237521) +++ head/sys/dev/ath/if_ath_rx.c Sun Jun 24 07:01:49 2012 (r237522) @@ -354,6 +354,55 @@ ath_recv_mgmt(struct ieee80211_node *ni, } } +#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 @@ rx_error: 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 @@ rx_accept: * 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 Modified: head/sys/dev/ath/if_athioctl.h ============================================================================== --- head/sys/dev/ath/if_athioctl.h Sun Jun 24 06:37:28 2012 (r237521) +++ head/sys/dev/ath/if_athioctl.h Sun Jun 24 07:01:49 2012 (r237522) @@ -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 ( \
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206240701.q5O71nu1093561>