Introduce an alternative mechanism for wifi drivers to communicate
authorstsp <stsp@openbsd.org>
Sun, 20 Mar 2022 12:01:58 +0000 (12:01 +0000)
committerstsp <stsp@openbsd.org>
Sun, 20 Mar 2022 12:01:58 +0000 (12:01 +0000)
the channel on which a frame was received.

ieee80211_inputm() was expecting that ic->ic_bss->ni_chan would 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.

However, this approach is very awkward for drivers which scan across a
whole range of channels in firmware. Such drivers had an ugly workaround
in place which tweaked ni_chan for each received frame.

Introduce a channel number field in the Rx info struct which drivers
can use to indicate the channel on which a frame was received.
If this field is set, net80211 will use it instead of using the current
channel of ic_bss. Use this new mechanism in all affected drivers.

Tested by jmc@, sthen@, and myself on iwm(4) and iwx(4).
Changes to iwn(4) and bwfm(4) are the same mechanical changes to get rid
of the ni_chan tweak, and are therefore expected to work.

ok sthen@ dlg@

sys/dev/ic/bwfm.c
sys/dev/pci/if_iwm.c
sys/dev/pci/if_iwn.c
sys/dev/pci/if_iwx.c
sys/net80211/ieee80211_input.c
sys/net80211/ieee80211_node.h

index 15e712c..c245bcd 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: bwfm.c,v 1.101 2022/03/06 18:52:47 kettenis Exp $ */
+/* $OpenBSD: bwfm.c,v 1.102 2022/03/20 12:01:58 stsp Exp $ */
 /*
  * Copyright (c) 2010-2016 Broadcom Corporation
  * Copyright (c) 2016,2017 Patrick Wildt <patrick@blueri.se>
@@ -2703,8 +2703,6 @@ bwfm_scan_node(struct bwfm_softc *sc, struct bwfm_bss_info *bss, size_t len)
        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_info *bss, size_t len)
        /* 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);
 }
index 582a4c7..d7abfc1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwm.c,v 1.398 2022/03/20 11:59:39 stsp Exp $       */
+/*     $OpenBSD: if_iwm.c,v 1.399 2022/03/20 12:01:58 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -4775,24 +4775,12 @@ iwm_rx_frame(struct iwm_softc *sc, struct mbuf *m, int chanidx,
        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 chanidx,
        }
 #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 *pktdata,
 
        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, void *pktdata,
 
        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),
index dd62922..e940010 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwn.c,v 1.256 2022/03/11 18:00:45 mpi Exp $        */
+/*     $OpenBSD: if_iwn.c,v 1.257 2022/03/20 12:01:58 stsp Exp $       */
 
 /*-
  * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr>
@@ -2004,8 +2004,6 @@ iwn_rx_done(struct iwn_softc *sc, struct iwn_rx_desc *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 *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 *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);
 }
index a000c69..2e96219 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_iwx.c,v 1.139 2022/03/20 11:59:39 stsp Exp $       */
+/*     $OpenBSD: if_iwx.c,v 1.140 2022/03/20 12:01:58 stsp Exp $       */
 
 /*
  * Copyright (c) 2014, 2016 genua gmbh <info@genua.de>
@@ -3992,24 +3992,12 @@ iwx_rx_frame(struct iwx_softc *sc, struct mbuf *m, int chanidx,
        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 chanidx,
        }
 #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, void *pktdata,
 
        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),
index 5b06079..212209f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_input.c,v 1.246 2022/03/20 07:50:32 stsp Exp $      */
+/*     $OpenBSD: ieee80211_input.c,v 1.247 2022/03/20 12:01:58 stsp Exp $      */
 
 /*-
  * Copyright (c) 2001 Atsushi Onoe
@@ -1648,7 +1648,10 @@ ieee80211_recv_probe_resp(struct ieee80211com *ic, struct mbuf *m,
 
        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, struct mbuf *m,
                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, struct mbuf *m,
        } 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, struct mbuf *m,
                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, struct mbuf *m,
                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 */
index d03d256..6a9fd5f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ieee80211_node.h,v 1.93 2022/03/19 10:25:09 stsp Exp $        */
+/*     $OpenBSD: ieee80211_node.h,v 1.94 2022/03/20 12:01:58 stsp Exp $        */
 /*     $NetBSD: ieee80211_node.h,v 1.9 2004/04/30 22:57:32 dyoung Exp $        */
 
 /*-
@@ -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