Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Feb 2012 23:18:13 -0800
From:      Adrian Chadd <adrian@freebsd.org>
To:        Bernhard Schmidt <bschmidt@freebsd.org>
Cc:        freebsd-wireless@freebsd.org
Subject:   Re: [net80211] support vendor bitmap entries; teach if_ath to export PHY error code in error frames
Message-ID:  <CAJ-Vmonmk=0maQcJd8iZscZvRxi%2BZcZiwWQyZ1r1Ju4QyhgKXw@mail.gmail.com>
In-Reply-To: <CAJ-Vmo=6xF8pWceBQVb4x3PYbLoGiiiAh9u2ZA8A=bAQdrOFdg@mail.gmail.com>
References:  <CAJ-VmonSrcSQmZeENgH1fagnn6DOMhX6rC-n9=dOtypTabcSLg@mail.gmail.com> <CAAgh0_aAijDoguQCJO8jR=cZ5LrZGLfxpGruZWGsjGf987-zOw@mail.gmail.com> <CAJ-Vmon%2BpQ9U7-YEQ1pYVbHM=5D=cp-z6eoPGJhV_GU3r7hy8A@mail.gmail.com> <201202062059.16816.bschmidt@freebsd.org> <CAJ-Vmo=6xF8pWceBQVb4x3PYbLoGiiiAh9u2ZA8A=bAQdrOFdg@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

[-- Attachment #1 --]
Hi,

Please find the second pass of this attached.

Fixes:

* I was missing a call to ath_rx_tap_vendor() when processing normal frames
* I've extended the data stored in the radiotap vendor header to
include the EVM and per-chain RSSI.
* I'm also storing the _raw_ combined RSSI in the radiotap header.
* The rs_status and rs_phyerr_code fields are also stored.

The EVM isn't strictly needed for radar work and the only RSSI
required for radar is rssi_ctl[0] and rssi_ext[0] (with the combined
RSSI used in some instances.)

What's left:

* I have a need for some continuous feedback about how busy the
primary/extension channels are. I may add some method of encoding this
in the radiotap header as a vendor extension; I'm not sure yet.

I don't like the idea of doing this via radiotap but I need a way to
encode this live as part of the stream so it can be played back with
the rest of the radar error frames.

I'm not sure if I really _want_ this to be part of the default FreeBSD
build but honestly, having these as vendor extensions will make
debugging a few things a lot easier moving forward. For example, users
could begin writing live traffic sniffing applications that track
per-RX-rate EVM in userland and provide graphical feedback.

Bernhard: what do you think?



Adrian

[-- Attachment #2 --]
Index: sys/net80211/ieee80211_node.c
===================================================================
--- sys/net80211/ieee80211_node.c	(revision 230855)
+++ sys/net80211/ieee80211_node.c	(working copy)
@@ -34,6 +34,8 @@
 #include <sys/mbuf.h>   
 #include <sys/malloc.h>
 #include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/proc.h>
 
 #include <sys/socket.h>
  
@@ -431,6 +433,9 @@
 	ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
 	KASSERT(ni != NULL, ("unable to setup initial BSS node"));
 	obss = vap->iv_bss;
+	printf("[%lld]: %s: iv_bss=%p, new iv_bss=%p\n",
+	    (long long int) curthread->td_tid,
+	    __func__,vap->iv_bss, ni);
 	vap->iv_bss = ieee80211_ref_node(ni);
 	if (obss != NULL) {
 		copy_bss(ni, obss);
@@ -700,6 +705,9 @@
 	/*
 	 * Committed to selbs, setup state.
 	 */
+	printf("[%lld]: %s: selbs=%p, obss=%p\n",
+	    (long long int) curthread->td_tid,
+	    __func__, selbs, vap->iv_bss);
 	obss = vap->iv_bss;
 	/*
 	 * Check if old+new node have the same address in which
Index: sys/net80211/ieee80211_wds.c
===================================================================
--- sys/net80211/ieee80211_wds.c	(revision 230855)
+++ sys/net80211/ieee80211_wds.c	(working copy)
@@ -46,6 +46,8 @@
 #include <sys/errno.h>
 #include <sys/proc.h>
 #include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/proc.h>
 
 #include <net/if.h>
 #include <net/if_media.h>
@@ -175,6 +177,9 @@
 			/*
 			 * Committed to new node, setup state.
 			 */
+			printf("[%lld]: %s: iv_bss=%p, new iv_bss=%p\n",
+			    (long long int) (curthread->td_tid),
+			    __func__, vap->iv_bss, ni);
 			obss = vap->iv_bss;
 			vap->iv_bss = ni;
 			ni->ni_wdsvap = vap;
@@ -197,6 +202,9 @@
 		 */
 		ni = ieee80211_node_create_wds(vap, vap->iv_des_bssid, chan);
 		if (ni != NULL) {
+			printf("[%lld]: %s: iv_bss=%p, new iv_bss=%p\n",
+			    (long long int) (curthread->td_tid),
+			    __func__, vap->iv_bss, ni);
 			obss = vap->iv_bss;
 			vap->iv_bss = ieee80211_ref_node(ni);
 			ni->ni_flags |= IEEE80211_NODE_AREF;
Index: sys/net80211/ieee80211_var.h
===================================================================
--- sys/net80211/ieee80211_var.h	(revision 230855)
+++ sys/net80211/ieee80211_var.h	(working copy)
@@ -700,6 +700,11 @@
 		uint32_t tx_radiotap,
 	    struct ieee80211_radiotap_header *rh, int rlen,
 		uint32_t rx_radiotap);
+void	ieee80211_radiotap_attachv(struct ieee80211com *,
+	    struct ieee80211_radiotap_header *th,
+	    int tlen, int n_tx_v, uint32_t tx_radiotap,
+	    struct ieee80211_radiotap_header *rh,
+	    int rlen, int n_rx_v, uint32_t rx_radiotap);
 void	ieee80211_radiotap_detach(struct ieee80211com *);
 void	ieee80211_radiotap_vattach(struct ieee80211vap *);
 void	ieee80211_radiotap_vdetach(struct ieee80211vap *);
Index: sys/net80211/ieee80211_radiotap.c
===================================================================
--- sys/net80211/ieee80211_radiotap.c	(revision 230855)
+++ sys/net80211/ieee80211_radiotap.c	(working copy)
@@ -47,13 +47,24 @@
 
 #include <net80211/ieee80211_var.h>
 
-static int radiotap_offset(struct ieee80211_radiotap_header *, int);
+static int radiotap_offset(struct ieee80211_radiotap_header *, int, int);
 
 void
 ieee80211_radiotap_attach(struct ieee80211com *ic,
 	struct ieee80211_radiotap_header *th, int tlen, uint32_t tx_radiotap,
 	struct ieee80211_radiotap_header *rh, int rlen, uint32_t rx_radiotap)
 {
+	ieee80211_radiotap_attachv(ic, th, tlen, 0, tx_radiotap,
+	    rh, rlen, 0, rx_radiotap);
+}
+
+void
+ieee80211_radiotap_attachv(struct ieee80211com *ic,
+	struct ieee80211_radiotap_header *th,
+	int tlen, int n_tx_v, uint32_t tx_radiotap,
+	struct ieee80211_radiotap_header *rh,
+	int rlen, int n_rx_v, uint32_t rx_radiotap)
+{
 #define	B(_v)	(1<<(_v))
 	int off;
 
@@ -63,9 +74,9 @@
 	/* calculate offset to channel data */
 	off = -1;
 	if (tx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
-		off = radiotap_offset(th, IEEE80211_RADIOTAP_CHANNEL);
+		off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_CHANNEL);
 	else if (tx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
-		off = radiotap_offset(th, IEEE80211_RADIOTAP_XCHANNEL);
+		off = radiotap_offset(th, n_tx_v, IEEE80211_RADIOTAP_XCHANNEL);
 	if (off == -1) {
 		if_printf(ic->ic_ifp, "%s: no tx channel, radiotap 0x%x",
 		    __func__, tx_radiotap);
@@ -79,9 +90,9 @@
 	/* calculate offset to channel data */
 	off = -1;
 	if (rx_radiotap & B(IEEE80211_RADIOTAP_CHANNEL))
-		off = radiotap_offset(rh, IEEE80211_RADIOTAP_CHANNEL);
+		off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_CHANNEL);
 	else if (rx_radiotap & B(IEEE80211_RADIOTAP_XCHANNEL))
-		off = radiotap_offset(rh, IEEE80211_RADIOTAP_XCHANNEL);
+		off = radiotap_offset(rh, n_rx_v, IEEE80211_RADIOTAP_XCHANNEL);
 	if (off == -1) {
 		if_printf(ic->ic_ifp, "%s: no rx channel, radiotap 0x%x",
 		    __func__, rx_radiotap);
@@ -260,7 +271,8 @@
  * known -1 is returned.
  */
 static int
-radiotap_offset(struct ieee80211_radiotap_header *rh, int item)
+radiotap_offset(struct ieee80211_radiotap_header *rh,
+    int n_vendor_attributes, int item)
 {
 	static const struct {
 		size_t	align, width;
@@ -334,6 +346,8 @@
 	int off, i;
 
 	off = sizeof(struct ieee80211_radiotap_header);
+	off += n_vendor_attributes * (sizeof(uint32_t));
+
 	for (i = 0; i < IEEE80211_RADIOTAP_EXT; i++) {
 		if ((present & (1<<i)) == 0)
 			continue;
Index: sys/net80211/ieee80211_radiotap.h
===================================================================
--- sys/net80211/ieee80211_radiotap.h	(revision 230855)
+++ sys/net80211/ieee80211_radiotap.h	(working copy)
@@ -54,6 +54,12 @@
 
 #define	IEEE80211_RADIOTAP_HDRLEN	64	/* XXX deprecated */
 
+struct ieee80211_radiotap_vendor_header {
+	uint8_t		vh_oui[3];	/* 3 byte vendor OUI */
+	uint8_t		vh_sub_ns;	/* Sub namespace of this section */
+	uint16_t	vh_skip_len;	/* Length of this vendor section */
+} __packed;
+
 /*
  * The radio capture header precedes the 802.11 header.
  *
Index: sys/dev/ath/ath_hal/ar5416/ar5416_misc.c
===================================================================
--- sys/dev/ath/ath_hal/ar5416/ar5416_misc.c	(revision 230855)
+++ sys/dev/ath/ath_hal/ar5416/ar5416_misc.c	(working copy)
@@ -714,13 +714,11 @@
 	pe->pe_relpwr = MS(val, AR_PHY_RADAR_1_RELPWR_THRESH);
 	if (temp)
 		pe->pe_relpwr |= HAL_PHYERR_PARAM_ENABLE;
-	temp = val & AR_PHY_RADAR_1_RELSTEP_CHECK;
 	pe->pe_relstep = MS(val, AR_PHY_RADAR_1_RELSTEP_THRESH);
-	if (temp)
-		pe->pe_enabled = 1;
-	else
-		pe->pe_enabled = 0;
 
+	pe->pe_enabled = !!
+	    (OS_REG_READ(ah, AR_PHY_RADAR_0) & AR_PHY_RADAR_0_ENA);
+
 	pe->pe_maxlen = MS(val, AR_PHY_RADAR_1_MAXLEN);
 	pe->pe_extchannel = !! (OS_REG_READ(ah, AR_PHY_RADAR_EXT) &
 	    AR_PHY_RADAR_EXT_ENA);
@@ -767,9 +765,15 @@
 
 	/*Enable FFT data*/
 	val |= AR_PHY_RADAR_0_FFT_ENA;
+	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val);
 
-	OS_REG_WRITE(ah, AR_PHY_RADAR_0, val | AR_PHY_RADAR_0_ENA);
+	/* Implicitly enable */
+	if (pe->pe_enabled == 1)
+		OS_REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
+	else if (pe->pe_enabled == 0)
+		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_ENA);
 
+	/* XXX is this around the correct way?! */
 	if (pe->pe_usefir128 == 1)
 		OS_REG_CLR_BIT(ah, AR_PHY_RADAR_1, AR_PHY_RADAR_1_USE_FIR128);
 	else if (pe->pe_usefir128 == 0)
Index: sys/dev/ath/if_athioctl.h
===================================================================
--- sys/dev/ath/if_athioctl.h	(revision 230855)
+++ sys/dev/ath/if_athioctl.h	(working copy)
@@ -188,10 +188,70 @@
 	(1 << IEEE80211_RADIOTAP_DBM_ANTSIGNAL)	| \
 	(1 << IEEE80211_RADIOTAP_DBM_ANTNOISE)	| \
 	(1 << IEEE80211_RADIOTAP_XCHANNEL)	| \
+	(1 << IEEE80211_RADIOTAP_VENDOREXT)	| \
+	(1 << IEEE80211_RADIOTAP_EXT)		| \
 	0)
 
+/*
+ * 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 */
+	u_int8_t	vh_version;		/* 1 */
+	u_int8_t	vh_rx_chainmask;	/* 1 */
+
+	/* At this point it should be 4 byte aligned */
+	u_int32_t	evm[ATH_RADIOTAP_MAX_CHAINS];	/* 4 * 4 = 16 */
+
+	u_int8_t	rssi_ctl[ATH_RADIOTAP_MAX_CHAINS];	/* 4 */
+	u_int8_t	rssi_ext[ATH_RADIOTAP_MAX_CHAINS];	/* 4 */
+
+	u_int8_t	vh_phyerr_code;	/* Phy error code, or 0xff */
+	u_int8_t	vh_rs_status;	/* RX status */
+	u_int8_t	vh_rssi;	/* Raw RSSI */
+	u_int8_t	vh_pad1[1];	/* Pad to 4 byte boundary */
+} __packed;
+
 struct ath_rx_radiotap_header {
-	struct ieee80211_radiotap_header wr_ihdr;
+	struct ieee80211_radiotap_header wr_ihdr;	/* 8 */
+	/* Vendor extension header bitmap */
+	u_int32_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.
+	 */
+	u_int32_t	wr_pad1;
+
+	/* Normal radiotap fields */
 	u_int64_t	wr_tsf;
 	u_int8_t	wr_flags;
 	u_int8_t	wr_rate;
@@ -203,6 +263,24 @@
 	u_int16_t	wr_chan_freq;
 	u_int8_t	wr_chan_ieee;
 	int8_t		wr_chan_maxpow;
+
+	/*
+	 * 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;
 } __packed;
 
 #define ATH_TX_RADIOTAP_PRESENT (		\
Index: sys/dev/ath/ath_dfs/null/dfs_null.c
===================================================================
--- sys/dev/ath/ath_dfs/null/dfs_null.c	(revision 231099)
+++ sys/dev/ath/ath_dfs/null/dfs_null.c	(working copy)
@@ -120,7 +120,7 @@
 int
 ath_dfs_radar_enable(struct ath_softc *sc, struct ieee80211_channel *chan)
 {
-#if 0
+#if 1
 	HAL_PHYERR_PARAM pe;
 
 	/* Check if the current channel is radar-enabled */
Index: sys/dev/ath/if_ath.c
===================================================================
--- sys/dev/ath/if_ath.c	(revision 230855)
+++ sys/dev/ath/if_ath.c	(working copy)
@@ -766,10 +766,14 @@
 	ic->ic_addba_stop = ath_addba_stop;
 	ic->ic_bar_response = ath_bar_response;
 
-	ieee80211_radiotap_attach(ic,
-	    &sc->sc_tx_th.wt_ihdr, sizeof(sc->sc_tx_th),
+	/*
+	 * 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),
+	    &sc->sc_rx_th.wr_ihdr, sizeof(sc->sc_rx_th), 1,
 		ATH_RX_RADIOTAP_PRESENT);
 
 	/*
@@ -3884,6 +3888,53 @@
 }
 
 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;
+}
+
+static void
 ath_rx_tap(struct ifnet *ifp, struct mbuf *m,
 	const struct ath_rx_status *rs, u_int64_t tsf, int16_t nf)
 {
@@ -3915,7 +3966,7 @@
 			sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_SHORTGI;
 	}
 #endif
-	sc->sc_rx_th.wr_tsf = htole64(ath_extend_tsf(sc, rs->rs_tstamp, tsf));
+	sc->sc_rx_th.wr_tsf = tsf;
 	if (rs->rs_status & HAL_RXERR_CRC)
 		sc->sc_rx_th.wr_flags |= IEEE80211_RADIOTAP_F_BADFCS;
 	/* XXX propagate other error flags from descriptor */
@@ -4156,6 +4207,7 @@
 				m->m_pkthdr.len = m->m_len = len;
 				bf->bf_m = NULL;
 				ath_rx_tap(ifp, m, rs, rstamp, nf);
+				ath_rx_tap_vendor(ifp, m, rs, rstamp, nf);
 				ieee80211_radiotap_rx_all(ic, m);
 				m_freem(m);
 			}
@@ -4251,8 +4303,10 @@
 		 * 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);
+			ath_rx_tap_vendor(ifp, m, rs, rstamp, nf);
+		}
 
 		/*
 		 * From this point on we assume the frame is at least

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-Vmonmk=0maQcJd8iZscZvRxi%2BZcZiwWQyZ1r1Ju4QyhgKXw>