From: Peter Hessler Subject: Re: sys/iwx: support of 160Mhz window at 5Ghz To: tech@openbsd.org Date: Tue, 24 Mar 2026 18:49:18 +0100 On 2026 Mar 23 (Mon) at 03:22:11 +0100 (+0100), Kirill A. Korinsky wrote: :On Sun, 22 Mar 2026 22:00:50 +0100, :Stefan Sperling wrote: :> :> On Sun, Mar 22, 2026 at 09:56:18PM +0100, Stefan Sperling wrote: :> > On Sun, Mar 22, 2026 at 09:07:37PM +0100, Kirill A. Korinsky wrote: :> > > And in beacon I see: Channel Width: 80 MHz, 160 MHz or 80+80 MHz BSS :> > > Bandwidth (1). :> > :> > I checked our net80211 headers first, which still list value 2 as 160 MHz. :> > :> > Turns out the 802.11 spec has since deprecated values 2 and 3. Wireshark is :> > correct that this value by itself doesn't mean anything and can be set to 1 :> > in all cases. We need to check the two bytes following this value specify :> > the center frequency of two 80 MHz portions of a 160 MHz channel. :> :> And in case it wasn't clear, this means that the function :> ieee80211_node_supports_vht_chan160() will always return false at present :> because it checks for the deprecated value 2 here: :> :> return (op_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160); :> :> Which would explain why 160 MHz is not actually being used for transmit :> with your patch. :> : :Thanks for direction, it allows to cook a better diff. : :With it my unifi network says that this laptop is connected to network with :Rx Rate 1.56 Gbps and Tx Rate 1.30 Gbps. : :I had added instruments to decode PHY width/NSS/MCS/SGI and let say on my :iperf tests like 95% of frames were with 160Mhz window. : :But I still limited for ~400 Mbits/sec (without this diff it is ~350). : :My main thought that we have hardcoded MPDU as 3895, when Linux driver uses :11454. Plus it may need a bit more bits to set inside vhtcaps. I only :touched antenna patterns and TX/RX STBC with following Linux logic. : :Frankly, I think that optimization of speed should be the next diff, and :keep this one is focused on 160Mhz window. : I still like this. OK : :Index: sys/dev/pci/if_iwx.c :=================================================================== :RCS file: /home/cvs/src/sys/dev/pci/if_iwx.c,v :diff -u -p -r1.223 if_iwx.c :--- sys/dev/pci/if_iwx.c 14 Mar 2026 15:37:44 -0000 1.223 :+++ sys/dev/pci/if_iwx.c 23 Mar 2026 00:32:20 -0000 :@@ -3207,6 +3207,8 @@ iwx_init_channel_map(struct iwx_softc *s : IEEE80211_CHAN_A; : } : channel->ic_freq = ieee80211_ieee2mhz(hw_value, flags); :+ channel->ic_xflags &= ~(IEEE80211_CHANX_80MHZ | :+ IEEE80211_CHANX_160MHZ); : : if (!(ch_flags & IWX_NVM_CHANNEL_ACTIVE)) : channel->ic_flags |= IEEE80211_CHAN_PASSIVE; :@@ -3221,6 +3223,8 @@ iwx_init_channel_map(struct iwx_softc *s : channel->ic_flags |= IEEE80211_CHAN_VHT; : if (ch_flags & IWX_NVM_CHANNEL_80MHZ) : channel->ic_xflags |= IEEE80211_CHANX_80MHZ; :+ if (ch_flags & IWX_NVM_CHANNEL_160MHZ) :+ channel->ic_xflags |= IEEE80211_CHANX_160MHZ; : } : } : } :@@ -3259,8 +3263,28 @@ void : iwx_setup_vht_rates(struct iwx_softc *sc) : { : struct ieee80211com *ic = &sc->sc_ic; :+ uint8_t tx_ant = iwx_fw_valid_tx_ant(sc); : uint8_t rx_ant = iwx_fw_valid_rx_ant(sc); : int n; :+ int num_tx_ant, num_rx_ant; :+ :+ ic->ic_vht_rx_max_lgi_mbit_s = 0; :+ ic->ic_vht_tx_max_lgi_mbit_s = 0; :+ :+ num_tx_ant = !!(tx_ant & IWX_ANT_A) + !!(tx_ant & IWX_ANT_B) + :+ !!(tx_ant & IWX_ANT_C); :+ num_rx_ant = !!(rx_ant & IWX_ANT_A) + !!(rx_ant & IWX_ANT_B) + :+ !!(rx_ant & IWX_ANT_C); :+ :+ ic->ic_vhtcaps &= ~(IEEE80211_VHTCAP_TX_STBC | :+ IEEE80211_VHTCAP_RX_ANT_PATTERN | :+ IEEE80211_VHTCAP_TX_ANT_PATTERN); :+ if (num_tx_ant > 1) :+ ic->ic_vhtcaps |= IEEE80211_VHTCAP_TX_STBC; :+ else :+ ic->ic_vhtcaps |= IEEE80211_VHTCAP_TX_ANT_PATTERN; :+ if (num_rx_ant == 1) :+ ic->ic_vhtcaps |= IEEE80211_VHTCAP_RX_ANT_PATTERN; : : ic->ic_vht_rxmcs = (IEEE80211_VHT_MCS_0_9 << : IEEE80211_VHT_MCS_FOR_SS_SHIFT(1)); :@@ -3620,6 +3644,10 @@ iwx_phy_ctxt_task(void *arg) : else : sco = IEEE80211_HTOP0_SCO_SCN; : if ((ni->ni_flags & IEEE80211_NODE_VHT) && :+ IEEE80211_CHAN_160MHZ_ALLOWED(in->in_ni.ni_chan) && :+ ieee80211_node_supports_vht_chan160(ni)) :+ vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_160; :+ else if ((ni->ni_flags & IEEE80211_NODE_VHT) && : IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) && : ieee80211_node_supports_vht_chan80(ni)) : vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80; :@@ -5573,6 +5601,12 @@ iwx_get_vht_ctrl_pos(struct ieee80211com : uint8_t pos = IWX_PHY_VHT_CTRL_POS_1_BELOW; : : switch (primary_idx - center_idx) { :+ case -14: :+ pos = IWX_PHY_VHT_CTRL_POS_4_BELOW; :+ break; :+ case -10: :+ pos = IWX_PHY_VHT_CTRL_POS_3_BELOW; :+ break; : case -6: : pos = IWX_PHY_VHT_CTRL_POS_2_BELOW; : break; :@@ -5585,6 +5619,12 @@ iwx_get_vht_ctrl_pos(struct ieee80211com : case 6: : pos = IWX_PHY_VHT_CTRL_POS_2_ABOVE; : break; :+ case 10: :+ pos = IWX_PHY_VHT_CTRL_POS_3_ABOVE; :+ break; :+ case 14: :+ pos = IWX_PHY_VHT_CTRL_POS_4_ABOVE; :+ break; : default: : break; : } :@@ -5616,7 +5656,10 @@ iwx_phy_ctxt_cmd_uhb_v3_v4(struct iwx_so : cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? : IWX_PHY_BAND_24 : IWX_PHY_BAND_5; : cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan)); :- if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) { :+ if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160) { :+ cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan); :+ cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE160; :+ } else if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) { : cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan); : cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE80; : } else if (chan->ic_flags & IEEE80211_CHAN_40MHZ) { :@@ -5676,7 +5719,10 @@ iwx_phy_ctxt_cmd_v3_v4(struct iwx_softc : cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ? : IWX_PHY_BAND_24 : IWX_PHY_BAND_5; : cmd.ci.channel = ieee80211_chan2ieee(ic, chan); :- if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) { :+ if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160) { :+ cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan); :+ cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE160; :+ } else if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) { : cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan); : cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE80; : } else if (chan->ic_flags & IEEE80211_CHAN_40MHZ) { :@@ -6731,7 +6777,11 @@ iwx_add_sta_cmd(struct iwx_softc *sc, st : } : : if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) { :- if (IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) && :+ if (IEEE80211_CHAN_160MHZ_ALLOWED(in->in_ni.ni_chan) && :+ ieee80211_node_supports_vht_chan160(&in->in_ni)) { :+ add_sta_cmd.station_flags |= htole32( :+ IWX_STA_FLG_FAT_EN_160MHZ); :+ } else if (IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) && : ieee80211_node_supports_vht_chan80(&in->in_ni)) { : add_sta_cmd.station_flags |= htole32( : IWX_STA_FLG_FAT_EN_80MHZ); :@@ -8433,6 +8483,13 @@ iwx_rs_init_v3(struct iwx_softc *sc, str : htole16(iwx_rs_vht_rates(sc, ni, 1)); : cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] = : htole16(iwx_rs_vht_rates(sc, ni, 2)); :+ if (in->in_phyctxt->vht_chan_width == :+ IEEE80211_VHTOP0_CHAN_WIDTH_160) { :+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_160] = :+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80]; :+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_160] = :+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80]; :+ } : } else if (ni->ni_flags & IEEE80211_NODE_HT) { : cfg_cmd.mode = IWX_TLC_MNG_MODE_HT; : cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] = :@@ -8446,6 +8503,9 @@ iwx_rs_init_v3(struct iwx_softc *sc, str : : cfg_cmd.sta_id = IWX_STATION_ID; : if ((ni->ni_flags & IEEE80211_NODE_VHT) && :+ in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160) :+ cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_160MHZ; :+ else if ((ni->ni_flags & IEEE80211_NODE_VHT) && : in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) : cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ; : else if ((ni->ni_flags & IEEE80211_NODE_HT) && :@@ -8477,6 +8537,10 @@ iwx_rs_init_v3(struct iwx_softc *sc, str : if ((ni->ni_flags & IEEE80211_NODE_VHT) && : ieee80211_node_supports_vht_sgi80(ni)) : cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ); :+ if ((ni->ni_flags & IEEE80211_NODE_VHT) && :+ in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160 && :+ ieee80211_node_supports_vht_sgi160(ni)) :+ cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_160MHZ); : : cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0); : return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd); :@@ -8508,6 +8572,13 @@ iwx_rs_init_v4(struct iwx_softc *sc, str : htole16(iwx_rs_vht_rates(sc, ni, 1)); : cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] = : htole16(iwx_rs_vht_rates(sc, ni, 2)); :+ if (in->in_phyctxt->vht_chan_width == :+ IEEE80211_VHTOP0_CHAN_WIDTH_160) { :+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_160] = :+ cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80]; :+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_160] = :+ cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80]; :+ } : } else if (ni->ni_flags & IEEE80211_NODE_HT) { : cfg_cmd.mode = IWX_TLC_MNG_MODE_HT; : cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] = :@@ -8521,6 +8592,9 @@ iwx_rs_init_v4(struct iwx_softc *sc, str : : cfg_cmd.sta_id = IWX_STATION_ID; : if ((ni->ni_flags & IEEE80211_NODE_VHT) && :+ in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160) :+ cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_160MHZ; :+ else if ((ni->ni_flags & IEEE80211_NODE_VHT) && : in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) : cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ; : else if ((ni->ni_flags & IEEE80211_NODE_HT) && :@@ -8552,6 +8626,10 @@ iwx_rs_init_v4(struct iwx_softc *sc, str : if ((ni->ni_flags & IEEE80211_NODE_VHT) && : ieee80211_node_supports_vht_sgi80(ni)) : cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ); :+ if ((ni->ni_flags & IEEE80211_NODE_VHT) && :+ in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160 && :+ ieee80211_node_supports_vht_sgi160(ni)) :+ cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_160MHZ); : : cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0); : return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd); :@@ -8936,6 +9014,10 @@ iwx_run(struct iwx_softc *sc) : else : sco = IEEE80211_HTOP0_SCO_SCN; : if ((ni->ni_flags & IEEE80211_NODE_VHT) && :+ IEEE80211_CHAN_160MHZ_ALLOWED(in->in_ni.ni_chan) && :+ ieee80211_node_supports_vht_chan160(ni)) :+ vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_160; :+ else if ((ni->ni_flags & IEEE80211_NODE_VHT) && : IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) && : ieee80211_node_supports_vht_chan80(ni)) : vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80; :@@ -12378,11 +12460,16 @@ iwx_attach(struct device *parent, struct : ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_4 | 0x3 /* 64k */); : : ic->ic_vhtcaps = IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895 | :- (IEEE80211_VHTCAP_MAX_AMPDU_LEN_64K << :+ (IEEE80211_VHTCAP_MAX_AMPDU_LEN_1024K << : IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT) | :- (IEEE80211_VHTCAP_CHAN_WIDTH_80 << :- IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) | IEEE80211_VHTCAP_SGI80 | :- IEEE80211_VHTCAP_RX_ANT_PATTERN | IEEE80211_VHTCAP_TX_ANT_PATTERN; :+ (IEEE80211_VHTCAP_CHAN_WIDTH_160 << :+ IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) | :+ IEEE80211_VHTCAP_RX_LDPC | :+ (1 << IEEE80211_VHTCAP_RX_STBC_SS_SHIFT) | :+ IEEE80211_VHTCAP_SGI80 | IEEE80211_VHTCAP_SGI160 | :+ IEEE80211_VHTCAP_SU_BEAMFORMEE | :+ (3 << IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT) | :+ IEEE80211_VHTCAP_MU_BEAMFORMEE; : : ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a; : ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b; :Index: sys/net80211/ieee80211.h :=================================================================== :RCS file: /home/cvs/src/sys/net80211/ieee80211.h,v :diff -u -p -r1.65 ieee80211.h :--- sys/net80211/ieee80211.h 19 Mar 2026 16:50:32 -0000 1.65 :+++ sys/net80211/ieee80211.h 22 Mar 2026 21:57:37 -0000 :@@ -720,7 +720,8 @@ enum { : #define IEEE80211_HTOP1_NONGF_STA 0x0004 : /* Bit 3 is reserved. */ : #define IEEE80211_HTOP1_OBSS_NONHT_STA 0x0010 :-/* Bits 5-15 are reserved. */ :+#define IEEE80211_HTOP1_CCFS2_SHIFT 5 :+#define IEEE80211_HTOP1_CCFS2_MASK 0x1fe0 : /* Bytes 4-5. */ : /* Bits 0-5 are reserved. */ : #define IEEE80211_HTOP2_DUALBEACON 0x0040 :@@ -776,6 +777,8 @@ enum { : #define IEEE80211_VHTCAP_LINK_ADAPT_MRQ_MFB 3 : #define IEEE80211_VHTCAP_RX_ANT_PATTERN 0x10000000 : #define IEEE80211_VHTCAP_TX_ANT_PATTERN 0x20000000 :+#define IEEE80211_VHTCAP_EXT_NSS_BW_SHIFT 30 :+#define IEEE80211_VHTCAP_EXT_NSS_BW_MASK 0xc0000000 : : /* : * VHT-MCS and NSS map (see 802.11ac-2013 8.4.2.160.3, Figure 8-401bs). :@@ -792,6 +795,7 @@ enum { : : #define IEEE80211_VHT_MAX_LGI_MBIT_S_MASK 0x1fff : #define IEEE80211_VHT_MAX_LGI_MBIT_S_SHIFT 0 :+#define IEEE80211_VHT_EXT_NSS_BW_CAPABLE (1 << 13) : : /* The highest number of spatial streams supported by VHT. */ : #define IEEE80211_VHT_NUM_SS 8 :Index: sys/net80211/ieee80211_node.c :=================================================================== :RCS file: /home/cvs/src/sys/net80211/ieee80211_node.c,v :diff -u -p -r1.211 ieee80211_node.c :--- sys/net80211/ieee80211_node.c 19 Mar 2026 16:50:32 -0000 1.211 :+++ sys/net80211/ieee80211_node.c 22 Mar 2026 21:57:37 -0000 :@@ -2534,7 +2534,7 @@ ieee80211_setup_htop(struct ieee80211_no : 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)); :+ ni->ni_htop2 = (data[4] | (data[5] << 8)); : : /* : * According to 802.11-2012 Table 8-130 the Basic MCS set is :@@ -2563,8 +2563,7 @@ ieee80211_setup_vhtcaps(struct ieee80211 : ni->ni_vht_rx_max_lgi_mbit_s = ((data[6] | (data[7] << 8)) & : IEEE80211_VHT_MAX_LGI_MBIT_S_MASK); : ni->ni_vht_txmcs = (data[8] | (data[9] << 8)); :- ni->ni_vht_tx_max_lgi_mbit_s = ((data[10] | (data[11] << 8)) & :- IEEE80211_VHT_MAX_LGI_MBIT_S_MASK); :+ ni->ni_vht_tx_max_lgi_mbit_s = (data[10] | (data[11] << 8)); : : ni->ni_flags |= IEEE80211_NODE_VHTCAP; : } :@@ -2601,8 +2600,8 @@ int : ieee80211_setup_vhtop(struct ieee80211_node *ni, const uint8_t *data, : uint8_t len, int isprobe) : { :- uint8_t sco; :- int have_40mhz; :+ uint8_t sco, ccfs0, ccfs1, ccfs2, supp_chwidth, ext_nss_bw_supp; :+ int have_40mhz, width, ccf1; : : if (len != 5) : return 0; :@@ -2619,14 +2618,66 @@ ieee80211_setup_vhtop(struct ieee80211_n : 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. */ :+ width = data[0]; :+ ccfs0 = data[1]; : if (data[2] && ieee80211_80mhz_center_freq_valid(data[2])) :- ni->ni_vht_chan_center_freq_idx1 = data[2]; :+ ccfs1 = data[2]; : else :+ ccfs1 = 0; :+ ccfs2 = (ni->ni_htop1 & IEEE80211_HTOP1_CCFS2_MASK) >> :+ IEEE80211_HTOP1_CCFS2_SHIFT; :+ if (!ieee80211_80mhz_center_freq_valid(ccfs2)) :+ ccfs2 = 0; :+ :+ supp_chwidth = (ni->ni_vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK) >> :+ IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT; :+ ext_nss_bw_supp = :+ (ni->ni_vhtcaps & IEEE80211_VHTCAP_EXT_NSS_BW_MASK) >> :+ IEEE80211_VHTCAP_EXT_NSS_BW_SHIFT; :+ :+ switch ((supp_chwidth << 4) | ext_nss_bw_supp) { :+ case 0x01: :+ case 0x02: :+ case 0x03: :+ ccf1 = ccfs2; :+ break; :+ case 0x10: :+ ccf1 = ccfs1; :+ break; :+ case 0x11: :+ case 0x12: :+ if (ccfs1 != 0) :+ ccf1 = ccfs1; :+ else :+ ccf1 = ccfs2; :+ break; :+ case 0x13: :+ case 0x20: :+ case 0x23: :+ ccf1 = ccfs1; :+ break; :+ default: :+ ccf1 = 0; :+ break; :+ } :+ :+ ni->ni_vht_chan_center_freq_idx0 = ccfs0; :+ ni->ni_vht_chan_center_freq_idx1 = ccfs1; :+ :+ if (width == IEEE80211_VHTOP0_CHAN_WIDTH_80 && ccf1 != 0) { :+ int diff; :+ :+ diff = abs(ccf1 - ccfs0); :+ if (diff == 8) { :+ ni->ni_vht_chan_center_freq_idx0 = ccf1; :+ ni->ni_vht_chan_center_freq_idx1 = 0; :+ width = IEEE80211_VHTOP0_CHAN_WIDTH_160; :+ } :+ } else if (width == IEEE80211_VHTOP0_CHAN_WIDTH_160) { : ni->ni_vht_chan_center_freq_idx1 = 0; :+ } :+ :+ ni->ni_vht_chan_width = width; : } else { : ni->ni_vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_HT; : ni->ni_vht_chan_center_freq_idx0 = 0; :Index: sys/net80211/ieee80211_node.h :=================================================================== :RCS file: /home/cvs/src/sys/net80211/ieee80211_node.h,v :diff -u -p -r1.99 ieee80211_node.h :--- sys/net80211/ieee80211_node.h 19 Mar 2026 16:50:32 -0000 1.99 :+++ sys/net80211/ieee80211_node.h 22 Mar 2026 21:43:09 -0000 :@@ -607,7 +607,11 @@ ieee80211_node_supports_vht_chan160(stru : : cap_chan_width = (ni->ni_vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK) >> : IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT; :- if (cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160) :+ if (cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160 && :+ cap_chan_width != IEEE80211_VHTCAP_CHAN_WIDTH_160_8080 && :+ ((ni->ni_vhtcaps & IEEE80211_VHTCAP_EXT_NSS_BW_MASK) == 0 || :+ (ni->ni_vht_tx_max_lgi_mbit_s & :+ IEEE80211_VHT_EXT_NSS_BW_CAPABLE) == 0)) : return 0; : : op_chan_width = (ni->ni_vht_chan_width & : : :-- :wbr, Kirill : -- Ray's Rule of Precision: Measure with a micrometer. Mark with chalk. Cut with an axe.