The net80211 input routine expects that ic->ic_bss->ni_chan will always
correspond to the channel which is currently being scanned. This dates
back to older devices which are manually tuned to the next channel by the
driver during SCAN->SCAN state transitions. And this must of course be
kept working for these drivers.

However, this approach is very awkward for drivers which scan across a
whole range of channels in firmware. Right now such drivers have an ugly
workaround around in place which changes the ni_chan variable for each
received frame.

This patch introduces a channel number field in the Rx info struct which
can be used to indicate the hardware channel number on which a frame was
received. If this field is set, net80211 will use it instead of using the
current channel of ic_bss.

Works for me on iwm(4).
Additional tests on iwn, iwm, iwx, and bwfm would be good.

ok?

 introduce rxi_chan to communicate Rx channel to net80211
 get rid of saved_bssid hacks in drivers
 
diff 72ccef0dd6ed210ccf409e8bd0918949ccb70238 
20d70a4353a34d2cb2f94d8a15fd7b3b8cdd7158
blob - 15e712c92ee21ac76262d534d58b7f5548341107
blob + ef8ea9876a4f77106aa42033fdff7f8f2bb53d4c
--- sys/dev/ic/bwfm.c
+++ sys/dev/ic/bwfm.c
@@ -2703,8 +2703,6 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
        struct ieee80211_frame *wh;
        struct ieee80211_node *ni;
        struct ieee80211_rxinfo rxi;
-       struct ieee80211_channel *bss_chan;
-       uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
        struct mbuf *m;
        uint32_t pktlen, ieslen;
        uint16_t iesoff;
@@ -2739,28 +2737,14 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_
        /* Finalize mbuf. */
        m->m_pkthdr.len = m->m_len = pktlen;
        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;
-               IEEE80211_ADDR_COPY(&saved_bssid, ni->ni_macaddr);
-       }
        /* Channel mask equals IEEE80211_CHAN_MAX */
        chanidx = bwfm_spec2chan(sc, letoh32(bss->chanspec));
-       ni->ni_chan = &ic->ic_channels[chanidx];
        /* Supply RSSI */
        rxi.rxi_flags = 0;
        rxi.rxi_rssi = (int16_t)letoh16(bss->rssi);
        rxi.rxi_tstamp = 0;
+       rxi.rxi_chan = chanidx;
        ieee80211_input(ifp, m, ni, &rxi);
-       /*
-        * ieee80211_input() might have changed our BSS.
-        * Restore ic_bss's channel if we are still in the same BSS.
-        */
-       if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-               ni->ni_chan = bss_chan;
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
 }
blob - c7115ed57c8f3367983d438ade529d39a8cd2872
blob + 984ac6f8913c3f576a724e13dbaf9371d14b3d9a
--- sys/dev/pci/if_iwm.c
+++ sys/dev/pci/if_iwm.c
@@ -4775,24 +4775,12 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
        struct ifnet *ifp = IC2IFP(ic);
        struct ieee80211_frame *wh;
        struct ieee80211_node *ni;
-       struct ieee80211_channel *bss_chan;
-       uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
 
        if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
                chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
 
        wh = mtod(m, struct ieee80211_frame *);
        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;
-               IEEE80211_ADDR_COPY(&saved_bssid, ni->ni_macaddr);
-       }
-       ni->ni_chan = &ic->ic_channels[chanidx];
-
        if ((rxi->rxi_flags & IEEE80211_RXI_HWDEC) &&
            iwm_ccmp_decap(sc, m, ni, rxi) != 0) {
                ifp->if_ierrors++;
@@ -4856,12 +4844,6 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int
        }
 #endif
        ieee80211_inputm(IC2IFP(ic), m, ni, rxi, ml);
-       /*
-        * ieee80211_inputm() might have changed our BSS.
-        * Restore ic_bss's channel if we are still in the same BSS.
-        */
-       if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-               ni->ni_chan = bss_chan;
        ieee80211_release_node(ic, ni);
 }
 
@@ -4935,6 +4917,7 @@ iwm_rx_mpdu(struct iwm_softc *sc, struct mbuf *m, void
 
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = device_timestamp;
+       rxi.rxi_chan = chanidx;
 
        iwm_rx_frame(sc, m, chanidx, rx_pkt_status,
            (phy_flags & IWM_PHY_INFO_FLAG_SHPREAMBLE),
@@ -5465,6 +5448,7 @@ iwm_rx_mpdu_mq(struct iwm_softc *sc, struct mbuf *m, v
 
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = le64toh(desc->v1.tsf_on_air_rise);
+       rxi.rxi_chan = chanidx;
 
        if (iwm_rx_reorder(sc, m, chanidx, desc,
            (phy_info & IWM_RX_MPDU_PHY_SHORT_PREAMBLE),
blob - dd629227807ce8697b1a9da6374a3be68279a6e7
blob + c284dc7d27a91d3b05972122edd37f7f8f58910b
--- sys/dev/pci/if_iwn.c
+++ sys/dev/pci/if_iwn.c
@@ -2004,8 +2004,6 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
        struct ieee80211_frame *wh;
        struct ieee80211_rxinfo rxi;
        struct ieee80211_node *ni;
-       struct ieee80211_channel *bss_chan = NULL;
-       uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
        struct mbuf *m, *m1;
        struct iwn_rx_stat *stat;
        caddr_t head;
@@ -2174,17 +2172,6 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
        if (chan > IEEE80211_CHAN_MAX)
                chan = IEEE80211_CHAN_MAX;
 
-       /* Fix current channel. */
-       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;
-               IEEE80211_ADDR_COPY(&saved_bssid, ni->ni_macaddr);
-       }
-       ni->ni_chan = &ic->ic_channels[chan];
-
 #if NBPFILTER > 0
        if (sc->sc_drvbpf != NULL) {
                struct iwn_rx_radiotap_header *tap = &sc->sc_rxtap;
@@ -2232,15 +2219,9 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *
        /* Send the frame to the 802.11 layer. */
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = 0;     /* unused */
+       rxi.rxi_chan = chan;
        ieee80211_inputm(ifp, m, ni, &rxi, ml);
 
-       /*
-        * ieee80211_inputm() might have changed our BSS.
-        * Restore ic_bss's channel if we are still in the same BSS.
-        */
-       if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-               ni->ni_chan = bss_chan;
-
        /* Node is no longer needed. */
        ieee80211_release_node(ic, ni);
 }
blob - ba54430a5bbe62eea3749d62d72ee14d97ffb11e
blob + d63c8ed78396db023402012a22f12635e51fbcb6
--- sys/dev/pci/if_iwx.c
+++ sys/dev/pci/if_iwx.c
@@ -3992,24 +3992,12 @@ iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int
        struct ifnet *ifp = IC2IFP(ic);
        struct ieee80211_frame *wh;
        struct ieee80211_node *ni;
-       struct ieee80211_channel *bss_chan;
-       uint8_t saved_bssid[IEEE80211_ADDR_LEN] = { 0 };
 
        if (chanidx < 0 || chanidx >= nitems(ic->ic_channels))  
                chanidx = ieee80211_chan2ieee(ic, ic->ic_ibss_chan);
 
        wh = mtod(m, struct ieee80211_frame *);
        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;
-               IEEE80211_ADDR_COPY(&saved_bssid, ni->ni_macaddr);
-       }
-       ni->ni_chan = &ic->ic_channels[chanidx];
-
        if ((rxi->rxi_flags & IEEE80211_RXI_HWDEC) &&
            iwx_ccmp_decap(sc, m, ni, rxi) != 0) {
                ifp->if_ierrors++;
@@ -4073,12 +4061,6 @@ iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int
        }
 #endif
        ieee80211_inputm(IC2IFP(ic), m, ni, rxi, ml);
-       /*
-        * ieee80211_inputm() might have changed our BSS.
-        * Restore ic_bss's channel if we are still in the same BSS.
-        */
-       if (ni == ic->ic_bss && IEEE80211_ADDR_EQ(saved_bssid, ni->ni_macaddr))
-               ni->ni_chan = bss_chan;
        ieee80211_release_node(ic, ni);
 }
 
@@ -4593,6 +4575,7 @@ iwx_rx_mpdu_mq(struct iwx_softc *sc, struct mbuf *m, v
 
        rxi.rxi_rssi = rssi;
        rxi.rxi_tstamp = le64toh(desc->v1.tsf_on_air_rise);
+       rxi.rxi_chan = chanidx;
 
        if (iwx_rx_reorder(sc, m, chanidx, desc,
            (phy_info & IWX_RX_MPDU_PHY_SHORT_PREAMBLE),
blob - 29e79454bd5f94785ab0c1f39a0e8e61b997aae2
blob + 76a6c7870a154bfd1c724fe37d76c3ee2d411814
--- sys/net80211/ieee80211_input.c
+++ sys/net80211/ieee80211_input.c
@@ -1648,7 +1648,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
 
        ssid = rates = xrates = edcaie = wmmie = rsnie = wpaie = tim = NULL;
        htcaps = htop = vhtcaps = vhtop = NULL;
-       bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
+       if (rxi->rxi_chan)
+               bchan = rxi->rxi_chan;
+       else
+               bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
        chan = bchan;
        erp = 0;
        while (frm + 2 <= efrm) {
@@ -1744,9 +1747,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
                ic->ic_stats.is_rx_badchan++;
                return;
        }
-       if ((ic->ic_state != IEEE80211_S_SCAN ||
+       if ((rxi->rxi_chan != 0 && chan != rxi->rxi_chan) ||
+           ((ic->ic_state != IEEE80211_S_SCAN ||
             !(ic->ic_caps & IEEE80211_C_SCANALL)) &&
-           chan != bchan) {
+           chan != bchan)) {
                /*
                 * Frame was received on a channel different from the
                 * one indicated in the DS params element id;
@@ -1984,7 +1988,6 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
                memcpy(ni->ni_essid, &ssid[2], ssid[1]);
        }
        IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
-       /* XXX validate channel # */
        ni->ni_chan = &ic->ic_channels[chan];
        if (ic->ic_state == IEEE80211_S_SCAN &&
            IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) {
blob - d03d25669b60a63ffd168bb9884b80883c480e49
blob + a520f65f6904627038b8237518a16aaef64b6563
--- sys/net80211/ieee80211_node.h
+++ sys/net80211/ieee80211_node.h
@@ -192,6 +192,7 @@ struct ieee80211_rxinfo {
        u_int32_t               rxi_flags;
        u_int32_t               rxi_tstamp;
        int                     rxi_rssi;
+       uint8_t                 rxi_chan;
 };
 #define IEEE80211_RXI_HWDEC            0x00000001
 #define IEEE80211_RXI_AMPDU_DONE       0x00000002

Reply via email to