svn commit: r237522 - in head/sys: conf dev/ath

Adrian Chadd adrian at FreeBSD.org
Sun Jun 24 07:01:50 UTC 2012


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 (		\


More information about the svn-src-all mailing list