On Sat, Mar 19, 2022 at 05:32:48PM +0100, Stefan Sperling wrote:
> 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.
jmc@ managed to trigger a bug where the interface ended up in 11ac
mode on a 2GHz channel. Should be fixed in this version of the diff.
diff 72ccef0dd6ed210ccf409e8bd0918949ccb70238
2b44274faa697c674c40e5a1ba5ca818cdf5caf4
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 + f9064eaba21945f89a07b33857cde41c004d6dfe
--- 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;
@@ -1783,11 +1787,13 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, str
} else
is_new = 0;
+ ni->ni_chan = &ic->ic_channels[chan];
+
if (htcaps)
ieee80211_setup_htcaps(ni, htcaps + 2, htcaps[1]);
if (htop && !ieee80211_setup_htop(ni, htop + 2, htop[1], 1))
htop = NULL; /* invalid HTOP */
- if (htcaps && vhtcaps && IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
+ if (htcaps && vhtcaps && IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) {
ieee80211_setup_vhtcaps(ni, vhtcaps + 2, vhtcaps[1]);
if (vhtop && !ieee80211_setup_vhtop(ni, vhtop + 2, vhtop[1], 1))
vhtop = NULL; /* invalid VHTOP */
@@ -1984,8 +1990,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)) {
/*
@@ -2645,7 +2649,7 @@ ieee80211_recv_assoc_resp(struct ieee80211com *ic, str
ieee80211_setup_htop(ni, htop + 2, htop[1], 0);
ieee80211_ht_negotiate(ic, ni);
- if (htcaps && vhtcaps && IEEE80211_IS_CHAN_5GHZ(ic->ic_bss->ni_chan)) {
+ if (htcaps && vhtcaps && IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) {
ieee80211_setup_vhtcaps(ni, vhtcaps + 2, vhtcaps[1]);
if (vhtop && !ieee80211_setup_vhtop(ni, vhtop + 2, vhtop[1], 1))
vhtop = NULL; /* invalid VHTOP */
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