From 7bcc4a30f93cc644383b3ea1e74af03cb6f6db68 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Mon, 15 Jan 2024 14:12:09 -0500 Subject: [PATCH] openbsd_wlan: Synchronize net80211 with OpenBSD. --- .../openbsd_wlan/net80211/ieee80211_node.c | 134 +++++++++++++++++- 1 file changed, 127 insertions(+), 7 deletions(-) diff --git a/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c b/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c index f3bb6dd1ee..e3c5fc207b 100644 --- a/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c +++ b/src/libs/compat/openbsd_wlan/net80211/ieee80211_node.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ieee80211_node.c,v 1.195 2022/03/20 07:50:32 stsp Exp $ */ +/* $OpenBSD: ieee80211_node.c,v 1.198 2023/10/22 12:01:36 stsp Exp $ */ /* $NetBSD: ieee80211_node.c,v 1.14 2004/05/09 09:18:47 dyoung Exp $ */ /*- @@ -1881,7 +1881,7 @@ ieee80211_find_txnode(struct ieee80211com *ic, const u_int8_t *macaddr) /* * Fake up a node; this handles node discovery in * adhoc mode. Note that for the driver's benefit - * we we treat this like an association so the driver + * we treat this like an association so the driver * has an opportunity to setup its private state. * * XXX need better way to handle this; issue probe @@ -2392,6 +2392,81 @@ ieee80211_clear_htcaps(struct ieee80211_node *ni) } #endif +int +ieee80211_40mhz_valid_secondary_above(uint8_t primary_chan) +{ + static const uint8_t valid_secondary_chan[] = { + 5, 6, 7, 8, 9, 10, 11, 12, 13, + 40, 48, 56, 64, 104, 112, 120, 128, 136, 144, 153, 161 + }; + uint8_t secondary_chan; + int i; + + if ((primary_chan >= 1 && primary_chan <= 9) || + (primary_chan >= 36 && primary_chan <= 157)) + secondary_chan = primary_chan + 4; + else + return 0; + + for (i = 0; i < nitems(valid_secondary_chan); i++) { + if (secondary_chan == valid_secondary_chan[i]) + return 1; + } + + return 0; +} + +int +ieee80211_40mhz_valid_secondary_below(uint8_t primary_chan) +{ + static const uint8_t valid_secondary_chan[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, + 36, 44, 52, 60, 100, 108, 116, 124, 132, 140, 149, 157 + }; + int8_t secondary_chan; + int i; + + if ((primary_chan >= 5 && primary_chan <= 13) || + (primary_chan >= 40 && primary_chan <= 161)) + secondary_chan = primary_chan - 4; + else + return 0; + + for (i = 0; i < nitems(valid_secondary_chan); i++) { + if (secondary_chan == valid_secondary_chan[i]) + return 1; + } + + return 0; +} + +/* + * Only accept 40 MHz channel configurations that conform to + * regulatory operating classes as defined by the 802.11ac spec. + * Passing other configurations down to firmware can result in + * regulatory assertions being trigged, such as fatal firmware + * error 14FD in iwm(4). + * + * See 802.11ac 2013, page 380, Tables E-1 to E-5. + */ +int +ieee80211_40mhz_center_freq_valid(uint8_t primary_chan, uint8_t htop0) +{ + uint8_t sco; + + sco = ((htop0 & IEEE80211_HTOP0_SCO_MASK) >> IEEE80211_HTOP0_SCO_SHIFT); + switch (sco) { + case IEEE80211_HTOP0_SCO_SCN: + return 1; + case IEEE80211_HTOP0_SCO_SCA: + return ieee80211_40mhz_valid_secondary_above(primary_chan); + case IEEE80211_HTOP0_SCO_SCB: + return ieee80211_40mhz_valid_secondary_below(primary_chan); + } + + return 0; +} + /* * Install received HT op information in the node's state block. */ @@ -2402,9 +2477,10 @@ ieee80211_setup_htop(struct ieee80211_node *ni, const uint8_t *data, if (len != 22) return 0; - ni->ni_primary_chan = data[0]; /* XXX corresponds to ni_chan */ - + ni->ni_primary_chan = data[0]; /* corresponds to ni_chan */ ni->ni_htop0 = data[1]; + if (!ieee80211_40mhz_center_freq_valid(data[0], data[1])) + ni->ni_htop0 &= ~IEEE80211_HTOP0_SCO_MASK; ni->ni_htop1 = (data[2] | (data[3] << 8)); ni->ni_htop2 = (data[3] | (data[4] << 8)); @@ -2441,6 +2517,31 @@ ieee80211_setup_vhtcaps(struct ieee80211_node *ni, const uint8_t *data, ni->ni_flags |= IEEE80211_NODE_VHTCAP; } +/* + * Only accept 80 MHz channel configurations that conform to + * regulatory operating classes as defined by the 802.11ac spec. + * Passing other configurations down to firmware can result in + * regulatory assertions being trigged, such as fatal firmware + * error 14FD in iwm(4). + * + * See 802.11ac 2013, page 380, Tables E-1 to E-5. + */ +int +ieee80211_80mhz_center_freq_valid(const uint8_t chanidx) +{ + static const uint8_t valid_center_chanidx[] = { + 42, 50, 58, 106, 112, 114, 138, 155 + }; + int i; + + for (i = 0; i < nitems(valid_center_chanidx); i++) { + if (chanidx == valid_center_chanidx[i]) + return 1; + } + + return 0; +} + /* * Install received VHT op information in the node's state block. */ @@ -2448,6 +2549,8 @@ int ieee80211_setup_vhtop(struct ieee80211_node *ni, const uint8_t *data, uint8_t len, int isprobe) { + uint8_t sco; + int have_40mhz; if (len != 5) return 0; @@ -2458,9 +2561,26 @@ ieee80211_setup_vhtop(struct ieee80211_node *ni, const uint8_t *data, data[0] != IEEE80211_VHTOP0_CHAN_WIDTH_8080) return 0; - ni->ni_vht_chan_width = data[0]; - ni->ni_vht_chan_center_freq_idx0 = data[1]; - ni->ni_vht_chan_center_freq_idx1 = data[2]; + sco = ((ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK) >> + IEEE80211_HTOP0_SCO_SHIFT); + have_40mhz = (sco == IEEE80211_HTOP0_SCO_SCA || + sco == IEEE80211_HTOP0_SCO_SCB); + + if (have_40mhz && ieee80211_80mhz_center_freq_valid(data[1])) { + ni->ni_vht_chan_width = data[0]; + ni->ni_vht_chan_center_freq_idx0 = data[1]; + + /* Only used in non-consecutive 80-80 160MHz configs. */ + if (data[2] && ieee80211_80mhz_center_freq_valid(data[2])) + ni->ni_vht_chan_center_freq_idx1 = data[2]; + else + ni->ni_vht_chan_center_freq_idx1 = 0; + } else { + ni->ni_vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_HT; + ni->ni_vht_chan_center_freq_idx0 = 0; + ni->ni_vht_chan_center_freq_idx1 = 0; + } + ni->ni_vht_basic_mcs = (data[3] | data[4] << 8); return 1; }