From: stsp Date: Sun, 20 Mar 2022 12:01:58 +0000 (+0000) Subject: Introduce an alternative mechanism for wifi drivers to communicate X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=7307575a63bf568353aa79af59698a85b8e02d6b;p=openbsd Introduce an alternative mechanism for wifi drivers to communicate 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@ --- diff --git a/sys/dev/ic/bwfm.c b/sys/dev/ic/bwfm.c index 15e712c92ee..c245bcdac69 100644 --- a/sys/dev/ic/bwfm.c +++ b/sys/dev/ic/bwfm.c @@ -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 @@ -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); } diff --git a/sys/dev/pci/if_iwm.c b/sys/dev/pci/if_iwm.c index 582a4c76874..d7abfc149bd 100644 --- a/sys/dev/pci/if_iwm.c +++ b/sys/dev/pci/if_iwm.c @@ -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 @@ -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), diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index dd629227807..e940010efa0 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -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 @@ -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); } diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c index a000c692eba..2e96219c0dc 100644 --- a/sys/dev/pci/if_iwx.c +++ b/sys/dev/pci/if_iwx.c @@ -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 @@ -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), diff --git a/sys/net80211/ieee80211_input.c b/sys/net80211/ieee80211_input.c index 5b060797db5..212209fb7e3 100644 --- a/sys/net80211/ieee80211_input.c +++ b/sys/net80211/ieee80211_input.c @@ -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 */ diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h index d03d25669b6..6a9fd5f3d51 100644 --- a/sys/net80211/ieee80211_node.h +++ b/sys/net80211/ieee80211_node.h @@ -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