Fix a corner case in STA beacon processing when a CSA is received but

the AP doesn't transmit beacons.

If the AP requests a CSA (ie, a channel switch) and then enters CAC
(channel availability check) for 60 seconds, it doesn't send beacons
and it just listens for radar events (and other things which we don't
do yet.)

Now, ath_newstate() was not resetting the beacon timer config on
a transition to the RUN state when in STA mode - it was setting
sc_syncbeacon, which simply updates the beacon config from the
contents of the next received beacon.

This means the STA never generates beacon miss events.

If the AP goes into CAC for 60 seconds and recovers, the STA will
happily receive the first beacon and reconfigure timers.
But if it gets a radar event after that, it'll change channel
again, not notify the station that it's changed channel..
and since the station is happily waiting for the first beacon
to configure the beacon timer details from, it won't ever
generate a beacon miss interrupt and it'll sit there forever
(or until the AP appears on that channel once again.)

This change forces the last known beacon timer config to be
written to hardware on a transition from CSA->RUN in STA mode.
This forces bmiss events to occur and the STA will eventually
(after a handful of beacon miss events) begin scanning for
another access point.
This commit is contained in:
Adrian Chadd 2011-06-29 13:21:52 +00:00
parent 70d5775697
commit f52efb6d38

View File

@ -4693,6 +4693,7 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
struct ieee80211_node *ni = NULL;
int i, error, stamode;
u_int32_t rfilt;
int csa_run_transition = 0;
static const HAL_LED_STATE leds[] = {
HAL_LED_INIT, /* IEEE80211_S_INIT */
HAL_LED_SCAN, /* IEEE80211_S_SCAN */
@ -4708,6 +4709,9 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
ieee80211_state_name[vap->iv_state],
ieee80211_state_name[nstate]);
if (vap->iv_state == IEEE80211_S_CSA && nstate == IEEE80211_S_RUN)
csa_run_transition = 1;
callout_drain(&sc->sc_cal_ch);
ath_hal_setledstate(ah, leds[nstate]); /* set LED */
@ -4814,8 +4818,14 @@ ath_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* Defer beacon timer configuration to the next
* beacon frame so we have a current TSF to use
* (any TSF collected when scanning is likely old).
* However if it's due to a CSA -> RUN transition,
* force a beacon update so we pick up a lack of
* beacons from an AP in CAC and thus force a
* scan.
*/
sc->sc_syncbeacon = 1;
if (csa_run_transition)
ath_beacon_config(sc, vap);
break;
case IEEE80211_M_MONITOR:
/*