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);
 }
 

Reply via email to