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