This closes a race where the current BSS channel is set
to whichever channel the most recent frame was received on.
For instance, after a background scan, we might receive a few
more frames from the AP we are going to leave, even after we
have recorded our new AP's channel in ic_bss. Any such frames
would switch the channel back to the old one.
Index: if_iwm.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_iwm.c,v
retrieving revision 1.219
diff -u -p -r1.219 if_iwm.c
--- if_iwm.c 7 Dec 2017 14:13:05 -0000 1.219
+++ if_iwm.c 8 Dec 2017 19:13:17 -0000
@@ -3431,6 +3431,7 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str
struct ieee80211_frame *wh;
struct ieee80211_node *ni;
struct ieee80211_rxinfo rxi;
+ struct ieee80211_channel *bss_chan;
struct mbuf *m;
struct iwm_rx_phy_info *phy_info;
struct iwm_rx_mpdu_res_start *rx_res;
@@ -3485,7 +3486,15 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str
chanidx = letoh32(phy_info->channel);
if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))
chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
+
ni = ieee80211_find_rxnode(ic, wh);
+ if (ni == ic->ic_bss) {
+ /*
+ * We may switch ic_bss's channel during scans.
+ * Record the current channel so we can restore it later.
+ */
+ bss_chan = ni->ni_chan;
+ }
ni->ni_chan = &ic->ic_channels[chanidx];
memset(&rxi, 0, sizeof(rxi));
@@ -3549,6 +3558,8 @@ iwm_rx_rx_mpdu(struct iwm_softc *sc, str
}
#endif
ieee80211_input(IC2IFP(ic), m, ni, &rxi);
+ if (ni == ic->ic_bss)
+ ni->ni_chan = bss_chan;
ieee80211_release_node(ic, ni);
}