Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Jun 2011 10:55:38 +0800
From:      Adrian Chadd <adrian@freebsd.org>
To:        freebsd-wireless@freebsd.org
Subject:   [PATCH] ath: enforce beacon expect when going CAC -> RUN
Message-ID:  <BANLkTi=0qkdy9yG46DT2U5ez=Ww=ScMkcw@mail.gmail.com>

index | next in thread | raw e-mail

[-- Attachment #1 --]
Hi,

Here's an initial patch for ath(4) to work around one of the DFS / CAC
issues in my previous post.

It enforces a 60 (+ 1) second "beacon expect" timer when the station
goes from CSA -> RUN.
This forces the beacon configuration to be re-written if a beacon
hasn't been heard by then.

If a beacon is received, it clears the callback.

What I don't like about it:

* CAC is hard-coded to 60 seconds here. It should yank the config from
net80211, but the net80211 NOL/CAC configuration values are static.
* 'stamode' doesn't include MBSS (mesh) and needs some testing. I'll
likely add a comment to that effect so it gets revisited when
IBSS/MBSS DFS support is written/tested.
* I think this belongs in net80211 rather than ath(4) so it can work
for any wireless NIC which participates in a DFS BSS. (The NIC doesn't
have to radar detection, it just has to receive/process a CSA and
change channel.) I'll revisit that at a later date once all the kinks
are worked out with ath(4).

Thanks,


Adrian

[-- Attachment #2 --]
Index: if_athvar.h
===================================================================
--- if_athvar.h	(revision 223525)
+++ if_athvar.h	(working copy)
@@ -254,7 +254,8 @@
 				sc_tdma	    : 1,/* TDMA in use */
 				sc_setcca   : 1,/* set/clr CCA with TDMA */
 				sc_resetcal : 1,/* reset cal state next trip */
-				sc_rxslink  : 1;/* do self-linked final descriptor */
+				sc_rxslink  : 1,/* do self-linked final descriptor */
+				sc_bexpect  : 1;/* expecting becaons to be RXed */
 	uint32_t		sc_eerd;	/* regdomain from EEPROM */
 	uint32_t		sc_eecc;	/* country code from EEPROM */
 						/* rate tables */
@@ -358,6 +359,8 @@
 	int			sc_txchainmask;	/* currently configured TX chainmask */
 	int			sc_rxchainmask;	/* currently configured RX chainmask */
 
+	struct callout		sc_bexpect_ch;	/* beacon expect callout */
+
 	/* DFS related state */
 	void			*sc_dfs;	/* Used by an optional DFS module */
 	int			sc_dodfs;	/* Whether to enable DFS rx filter bits */
Index: if_ath.c
===================================================================
--- if_ath.c	(revision 223568)
+++ if_ath.c	(working copy)
@@ -184,6 +184,8 @@
 static void	ath_scan_start(struct ieee80211com *);
 static void	ath_scan_end(struct ieee80211com *);
 static void	ath_set_channel(struct ieee80211com *);
+static void	ath_beacon_expect_reset(struct ath_softc *sc);
+static void	ath_beacon_expect_schedule(struct ath_softc *sc, int when);
 static void	ath_calibrate(void *);
 static int	ath_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void	ath_setup_stationkey(struct ieee80211_node *);
@@ -387,6 +389,7 @@
 	}
 	callout_init_mtx(&sc->sc_cal_ch, &sc->sc_mtx, 0);
 	callout_init_mtx(&sc->sc_wd_ch, &sc->sc_mtx, 0);
+	callout_init_mtx(&sc->sc_bexpect_ch, &sc->sc_mtx, 0);
 
 	ATH_TXBUF_LOCK_INIT(sc);
 
@@ -2746,6 +2749,9 @@
 	u_int32_t nexttbtt, intval, tsftu;
 	u_int64_t tsf;
 
+	/* Clear any pending beacon expect timer */
+	ath_beacon_expect_reset(sc);
+
 	if (vap == NULL)
 		vap = TAILQ_FIRST(&ic->ic_vaps);	/* XXX */
 	ni = vap->iv_bss;
@@ -4666,6 +4672,58 @@
 }
 
 /*
+ * A beacon hasn't been heard in the given timeframe;
+ * write the last known beacon config to the hardware
+ * so beacon miss events begin occuring again.
+ */
+static void
+ath_beacon_expect(void *arg)
+{
+	struct ath_softc *sc = (struct ath_softc *) arg;
+	sc->sc_bexpect = 0;
+	DPRINTF(sc, ATH_DEBUG_BEACON, "%s: beacons not seen, kick!\n", __func__);
+	ath_beacon_config(sc, NULL);
+}
+
+/*
+ * Clear the beacon expect callout.
+ */
+static void
+ath_beacon_expect_reset(struct ath_softc *sc)
+{
+	if (! sc->sc_bexpect)
+		return;
+	sc->sc_bexpect = 0;
+	DPRINTF(sc, ATH_DEBUG_BEACON, "%s: clearing beacon expect\n", __func__);
+	callout_drain(&sc->sc_bexpect_ch);
+}
+
+/*
+ * Expect beacons in 'when' seconds.
+ *
+ * If they don't occur, begin the process of signalling
+ * the upper levels that beacons are being missed.
+ *
+ * This is done for now by simply writing the beacon config
+ * and letting the bmiss timer/interrupt handle things.
+ */
+static void
+ath_beacon_expect_schedule(struct ath_softc *sc, int when)
+{
+	sc->sc_bexpect = 1;
+	DPRINTF(sc, ATH_DEBUG_BEACON,
+	    "%s: scheduling beacon config in %d seconds\n",
+	    __func__, when);
+	callout_drain(&sc->sc_bexpect_ch);
+	/*
+	 * Add 1 second to 'when' to ensure the hostap actually
+	 * starts transmitting.
+	 */
+	callout_reset(&sc->sc_bexpect_ch, (when + 1) * hz,
+	    ath_beacon_expect, sc);
+}
+
+/*
  * Walk the vap list and check if there any vap's in RUN state.
  */
 static int
@@ -4748,6 +4806,28 @@
 	}
 
 	/*
+	 * If there's been a state transition from CSA -> RUN,
+	 * start a task to force reset the beacon timers
+	 * after CAC (default to 60 seconds.) Do this for non-
+	 * hostap modes.
+	 *
+	 * If we don't begin hearing beacons by then, we need
+	 * start registering beacon misses with net80211 or
+	 * rescanning won't occur and the interface will sit
+	 * here forever.
+	 *
+	 * XXX this requires that an association actually
+	 * XXX   occured sometime in the past!
+	 */
+	if (stamode && vap->iv_state == IEEE80211_S_CSA &&
+	    nstate == IEEE80211_S_RUN) {
+		DPRINTF(sc, ATH_DEBUG_STATE | ATH_DEBUG_BEACON,
+		    "%s: CSA->RUN detected; expecting beacons to appear"
+		    " in 60 seconds\n", __func__);
+		ath_beacon_expect_schedule(sc, 60);	/* XXX hard-coded CAC */
+	}
+
+	/*
 	 * Invoke the parent method to do net80211 work.
 	 */
 	error = avp->av_newstate(vap, nstate, arg);
help

Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?BANLkTi=0qkdy9yG46DT2U5ez=Ww=ScMkcw>