From 6193a477b83296d0cca1e1a8d2a4af8cd47f75df Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Thu, 5 Dec 2024 23:18:45 -0500 Subject: [PATCH] realtekwifi & net80211: Synchronize with FreeBSD. As of upstream fcb5e8d0c19ac21515ab3047d39a76b32d835cec. --- .../wlan/realtekwifi/dev/rtwn/if_rtwn.c | 8 +- .../realtekwifi/dev/rtwn/if_rtwn_beacon.c | 1 - .../wlan/realtekwifi/dev/rtwn/if_rtwn_rx.c | 29 +++- .../wlan/realtekwifi/dev/rtwn/if_rtwnvar.h | 3 +- .../dev/rtwn/pci/rtwn_pci_attach.c | 1 - .../realtekwifi/dev/rtwn/pci/rtwn_pci_reg.c | 1 - .../realtekwifi/dev/rtwn/rtl8192c/r92c_tx.c | 49 ++++-- .../realtekwifi/dev/rtwn/rtl8812a/r12a_fw.c | 6 +- .../realtekwifi/dev/rtwn/rtl8812a/r12a_reg.h | 4 +- .../realtekwifi/dev/rtwn/rtl8812a/r12a_tx.c | 61 ++++++-- .../dev/rtwn/rtl8812a/r12a_tx_desc.h | 6 +- .../dev/rtwn/usb/rtwn_usb_attach.c | 1 - .../realtekwifi/dev/rtwn/usb/rtwn_usb_reg.c | 1 - .../compat/freebsd_wlan/net80211/ieee80211.c | 4 + .../compat/freebsd_wlan/net80211/ieee80211.h | 3 +- .../freebsd_wlan/net80211/ieee80211_amrr.c | 37 ++--- .../freebsd_wlan/net80211/ieee80211_ht.c | 140 ++++++++++++++++++ .../freebsd_wlan/net80211/ieee80211_ht.h | 6 + .../freebsd_wlan/net80211/ieee80211_ioctl.c | 20 +++ .../freebsd_wlan/net80211/ieee80211_var.h | 12 +- .../freebsd_wlan/net80211/ieee80211_vht.c | 6 +- 21 files changed, 321 insertions(+), 78 deletions(-) diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn.c index 4334d5700e..3d0dce516f 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn.c @@ -247,6 +247,7 @@ rtwn_attach(struct rtwn_softc *sc) | IEEE80211_HTCAP_SMPS_OFF /* SM PS mode disabled */ /* s/w capabilities */ | IEEE80211_HTC_HT /* HT operation */ + | IEEE80211_HTC_RX_AMSDU_AMPDU /* A-MSDU in A-MPDU */ | IEEE80211_HTC_AMPDU /* A-MPDU tx */ | IEEE80211_HTC_AMSDU /* A-MSDU tx */ ; @@ -325,12 +326,15 @@ rtwn_sysctlattach(struct rtwn_softc *sc) struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev); struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev); -#if 1 sc->sc_ht40 = 0; SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "ht40", CTLFLAG_RDTUN, &sc->sc_ht40, sc->sc_ht40, "Enable 40 MHz mode support"); -#endif + + sc->sc_ena_tsf64 = 0; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "ena_tsf64", CTLFLAG_RWTUN, &sc->sc_ena_tsf64, + sc->sc_ena_tsf64, "Enable/disable per-packet TSF64 reporting"); #ifdef RTWN_DEBUG SYSCTL_ADD_U32(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_beacon.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_beacon.c index eee3499fba..f26a8ed44b 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_beacon.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_beacon.c @@ -16,7 +16,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_rx.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_rx.c index 762472eca4..58cd53b01e 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_rx.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwn_rx.c @@ -285,8 +285,18 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc) rxs.c_pktflags |= IEEE80211_RX_F_FAIL_FCSCRC; rxs.r_flags |= IEEE80211_R_TSF_START; /* XXX undocumented */ - rxs.r_flags |= IEEE80211_R_TSF64; - rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat); + + /* + * Doing the TSF64 extension on USB is expensive, especially + * if it's being done on every MPDU in an AMPDU burst. + */ + if (sc->sc_ena_tsf64) { + rxs.r_flags |= IEEE80211_R_TSF64; + rxs.c_rx_tsf = rtwn_extend_rx_tsf(sc, stat); + } else { + rxs.r_flags |= IEEE80211_R_TSF32; + rxs.c_rx_tsf = le32toh(stat->tsf_low); + } /* Get RSSI from PHY status descriptor. */ is_cck = (rxs.c_pktflags & IEEE80211_RX_F_CCK) != 0; @@ -318,6 +328,10 @@ rtwn_rx_common(struct rtwn_softc *sc, struct mbuf *m, void *desc) /* Drop PHY descriptor. */ m_adj(m, infosz + shift); + /* If APPFCS, drop FCS */ + if (sc->rcr & R92C_RCR_APPFCS) + m_adj(m, -IEEE80211_CRC_LEN); + return (ni); } @@ -456,6 +470,15 @@ rtwn_rxfilter_init(struct rtwn_softc *sc) R92C_RCR_HTC_LOC_CTRL | R92C_RCR_APP_PHYSTS | R92C_RCR_APP_ICV | R92C_RCR_APP_MIC; + /* + * Add FCS, to work around occasional 4 byte truncation + * with some frames. This is more problematic on RTL8812/ + * RTL8821 because they're also doing L3/L4 checksum offload + * and hardware encryption, so both are tagged as "passed" + * before the frame is truncated. + */ + sc->rcr |= R92C_RCR_APPFCS; + /* Update dynamic Rx filter parts. */ rtwn_rxfilter_update(sc); } @@ -487,7 +510,7 @@ rtwn_set_promisc(struct rtwn_softc *sc) RTWN_ASSERT_LOCKED(sc); mask_all = R92C_RCR_ACF | R92C_RCR_ADF | R92C_RCR_AMF | R92C_RCR_AAP; - mask_min = R92C_RCR_APM; + mask_min = R92C_RCR_APM | R92C_RCR_APPFCS; if (sc->bcn_vaps == 0) mask_min |= R92C_RCR_CBSSID_BCN; diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwnvar.h b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwnvar.h index f4c6d7ee64..d4458384db 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwnvar.h +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/if_rtwnvar.h @@ -171,9 +171,8 @@ struct rtwn_softc { struct mbufq sc_snd; device_t sc_dev; -#if 1 int sc_ht40; -#endif + int sc_ena_tsf64; uint32_t sc_debug; int sc_hwcrypto; int sc_ratectl_sysctl; diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_attach.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_attach.c index c359d1c33a..3d8f8bdb83 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_attach.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_attach.c @@ -18,7 +18,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_reg.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_reg.c index 5e383735a8..a0021f1849 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_reg.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/pci/rtwn_pci_reg.c @@ -18,7 +18,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8192c/r92c_tx.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8192c/r92c_tx.c index 15beca776b..a3e92e1b7e 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8192c/r92c_tx.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8192c/r92c_tx.c @@ -171,16 +171,21 @@ static void r92c_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r92c_tx_desc *txd = (struct r92c_tx_desc *)buf; - struct ieee80211vap *vap = ni->ni_vap; - if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ - (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) - txd->txdw5 |= htole32(R92C_TXDW5_SGI); - else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ - IEEE80211_IS_CHAN_HT40(ni->ni_chan) && - (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && - (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) - txd->txdw5 |= htole32(R92C_TXDW5_SGI); + /* + * Only enable short-GI if we're transmitting in that + * width to that node. + * + * Specifically, do not enable shortgi for 20MHz if + * we're attempting to transmit at 40MHz. + */ + if (ieee80211_ht_check_tx_ht40(ni)) { + if (ieee80211_ht_check_tx_shortgi_40(ni)) + txd->txdw5 |= htole32(R92C_TXDW5_SGI); + } else if (ieee80211_ht_check_tx_ht(ni)) { + if (ieee80211_ht_check_tx_shortgi_20(ni)) + txd->txdw5 |= htole32(R92C_TXDW5_SGI); + } } void @@ -216,6 +221,28 @@ r92c_tx_setup_macid(void *buf, int id) txd->txdw4 &= ~htole32(R92C_TXDW4_RTS_SHORT); } +static int +r92c_calculate_tx_agg_window(struct rtwn_softc *sc, + const struct ieee80211_node *ni, int tid) +{ + const struct ieee80211_tx_ampdu *tap; + int wnd; + + tap = &ni->ni_tx_ampdu[tid]; + + /* + * BAW is (MAX_AGG * 2) + 1, hence the /2 here. + * Ensure we don't send 0 or more than 64. + */ + wnd = tap->txa_wnd / 2; + if (wnd == 0) + wnd = 1; + else if (wnd > 0x1f) + wnd = 0x1f; + + return (wnd); +} + void r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, uint8_t ridx, int maxretry) @@ -271,9 +298,9 @@ r92c_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, (m->m_flags & M_AMPDU_MPDU) != 0); if (m->m_flags & M_AMPDU_MPDU) { txd->txdw2 |= htole32(SM(R92C_TXDW2_AMPDU_DEN, - vap->iv_ampdu_density)); + ieee80211_ht_get_node_ampdu_density(ni))); txd->txdw6 |= htole32(SM(R92C_TXDW6_MAX_AGG, - 0x1f)); /* XXX */ + r92c_calculate_tx_agg_window(sc, ni, tid))); } if (sc->sc_ratectl == RTWN_RATECTL_NET80211) { txd->txdw2 |= htole32(R92C_TXDW2_CCX_RPT); diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_fw.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_fw.c index 6d383fe2f5..c2c12c2a2e 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_fw.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_fw.c @@ -171,8 +171,10 @@ r12a_iq_calib_fw(struct rtwn_softc *sc) else cmd.band_bw = RTWN_CMD_IQ_BAND_2GHZ; - /* TODO: 80/160 MHz. */ - if (IEEE80211_IS_CHAN_HT40(c)) + /* TODO: 160MHz */ + if (IEEE80211_IS_CHAN_VHT80(c)) + cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_80; + else if (IEEE80211_IS_CHAN_HT40(c) || IEEE80211_IS_CHAN_VHT40(c)) cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_40; else cmd.band_bw |= RTWN_CMD_IQ_CHAN_WIDTH_20; diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_reg.h b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_reg.h index f9acc20474..4e9892ce25 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_reg.h +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_reg.h @@ -75,8 +75,8 @@ #define R12A_DATA_SEC_PRIM_DOWN_20 0x02 #define R12A_DATA_SEC_PRIM_UPPER_20 0x03 #define R12A_DATA_SEC_PRIM_LOWER_20 0x04 -#define R12A_DATA_SEC_PRIM_UP_40 0x90 -#define R12A_DATA_SEC_PRIM_DOWN_40 0xa0 +#define R12A_DATA_SEC_PRIM_UP_40 0x09 +#define R12A_DATA_SEC_PRIM_DOWN_40 0x0a /* Bits for R12A_HT_SINGLE_AMPDU. */ #define R12A_HT_SINGLE_AMPDU_PKT_ENA 0x80 diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx.c index 9e0d8e85c0..e6b5111063 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx.c @@ -147,6 +147,9 @@ r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd, case IEEE80211_MODE_11NG: mode = IEEE80211_MODE_11G; break; + case IEEE80211_MODE_VHT_5GHZ: + mode = IEEE80211_MODE_VHT_5GHZ; + break; default: device_printf(sc->sc_dev, "unknown mode(1) %d!\n", ic->ic_curmode); @@ -186,8 +189,13 @@ r12a_tx_raid(struct rtwn_softc *sc, struct r12a_tx_desc *txd, raid = R12A_RAID_11BGN_2; } break; + case IEEE80211_MODE_VHT_5GHZ: + if (sc->ntxchains == 1) + raid = R12A_RAID_11AC_1; + else + raid = R12A_RAID_11AC_2; + break; default: - /* TODO: 80 MHz / 11ac */ device_printf(sc->sc_dev, "unknown mode(2) %d!\n", mode); return; } @@ -199,16 +207,23 @@ static void r12a_tx_set_sgi(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni) { struct r12a_tx_desc *txd = (struct r12a_tx_desc *)buf; - struct ieee80211vap *vap = ni->ni_vap; - if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) && /* HT20 */ - (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20)) - txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); - else if (ni->ni_chan != IEEE80211_CHAN_ANYC && /* HT40 */ - IEEE80211_IS_CHAN_HT40(ni->ni_chan) && - (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && - (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)) - txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + /* TODO: VHT 20/40/80 checks */ + + /* + * Only enable short-GI if we're transmitting in that + * width to that node. + * + * Specifically, do not enable shortgi for 20MHz if + * we're attempting to transmit at 40MHz. + */ + if (ieee80211_ht_check_tx_ht40(ni)) { + if (ieee80211_ht_check_tx_shortgi_40(ni)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + } else if (ieee80211_ht_check_tx_ht(ni)) { + if (ieee80211_ht_check_tx_shortgi_20(ni)) + txd->txdw5 |= htole32(R12A_TXDW5_DATA_SHORT); + } } static void @@ -222,6 +237,28 @@ r12a_tx_set_ldpc(struct rtwn_softc *sc, struct r12a_tx_desc *txd, txd->txdw5 |= htole32(R12A_TXDW5_DATA_LDPC); } +static int +r12a_calculate_tx_agg_window(struct rtwn_softc *sc, + const struct ieee80211_node *ni, int tid) +{ + const struct ieee80211_tx_ampdu *tap; + int wnd; + + tap = &ni->ni_tx_ampdu[tid]; + + /* + * BAW is (MAX_AGG * 2) + 1, hence the /2 here. + * Ensure we don't send 0 or more than 64. + */ + wnd = tap->txa_wnd / 2; + if (wnd == 0) + wnd = 1; + else if (wnd > 0x1f) + wnd = 0x1f; + + return (wnd); +} + void r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, struct mbuf *m, void *buf, uint8_t ridx, int maxretry) @@ -273,9 +310,9 @@ r12a_fill_tx_desc(struct rtwn_softc *sc, struct ieee80211_node *ni, if (m->m_flags & M_AMPDU_MPDU) { txd->txdw2 |= htole32(R12A_TXDW2_AGGEN); txd->txdw2 |= htole32(SM(R12A_TXDW2_AMPDU_DEN, - vap->iv_ampdu_density)); + ieee80211_ht_get_node_ampdu_density(ni))); txd->txdw3 |= htole32(SM(R12A_TXDW3_MAX_AGG, - 0x1f)); /* XXX */ + r12a_calculate_tx_agg_window(sc, ni, tid))); } else txd->txdw2 |= htole32(R12A_TXDW2_AGGBK); diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx_desc.h b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx_desc.h index 93cc9b8674..7d0793a0fe 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx_desc.h +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/rtl8812a/r12a_tx_desc.h @@ -138,9 +138,7 @@ struct r12a_tx_desc { #define R12A_RAID_11BG 6 #define R12A_RAID_11G 7 /* "pure" 11g */ #define R12A_RAID_11B 8 -#define R12A_RAID_11AC_2_80 9 -#define R12A_RAID_11AC_1_80 10 -#define R12A_RAID_11AC_1 11 -#define R12A_RAID_11AC_2 12 +#define R12A_RAID_11AC_2 9 +#define R12A_RAID_11AC_1 10 #endif /* R12A_TX_DESC_H */ diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_attach.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_attach.c index df2a8ea955..4958939a76 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_attach.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_attach.c @@ -18,7 +18,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include diff --git a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_reg.c b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_reg.c index b39f1c77aa..5a992379e2 100644 --- a/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_reg.c +++ b/src/add-ons/kernel/drivers/network/wlan/realtekwifi/dev/rtwn/usb/rtwn_usb_reg.c @@ -18,7 +18,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include #include #include #include diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211.c index b10c4a3d44..1651c1e6af 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211.c @@ -752,6 +752,8 @@ ieee80211_vap_attach(struct ieee80211vap *vap, ifm_change_cb_t media_change, ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT160); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80P80); + ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_STBC_TX); + ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_STBC_RX); IEEE80211_UNLOCK(ic); return 1; @@ -809,6 +811,8 @@ ieee80211_vap_detach(struct ieee80211vap *vap) ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT160); ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_USEVHT80P80); + ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_STBC_TX); + ieee80211_syncflag_vht_locked(ic, IEEE80211_FVHT_STBC_RX); /* NB: this handles the bpfdetach done below */ ieee80211_syncflag_ext_locked(ic, IEEE80211_FEXT_BPF); diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211.h index e62b8c16d6..b0bb024501 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211.h @@ -931,6 +931,7 @@ enum ieee80211_vht_mcs_support { IEEE80211_VHT_MCS_NOT_SUPPORTED = 3 /* not supported */ }; +/* 802.11ac-2013, 8.4.2.160.3 Supported VHT-MCS and NSS Set field */ struct ieee80211_vht_mcs_info { uint16_t rx_mcs_map; uint16_t rx_highest; @@ -973,7 +974,7 @@ struct ieee80211_vht_operation { #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK 0x0000000C #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK_S 2 -#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_NONE 0 +#define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_NO160 0 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160MHZ 1 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_160_80P80MHZ 2 #define IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_RESERVED 3 diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c index 461554d75e..386a3de92a 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_amrr.c @@ -138,25 +138,6 @@ amrr_deinit(struct ieee80211vap *vap) nrefs--; /* XXX locking */ } -/* - * Return whether 11n rates are possible. - * - * Some 11n devices may return HT information but no HT rates. - * Thus, we shouldn't treat them as an 11n node. - */ -static int -amrr_node_is_11n(struct ieee80211_node *ni) -{ - - if (ni->ni_chan == NULL) - return (0); - if (ni->ni_chan == IEEE80211_CHAN_ANYC) - return (0); - if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && ni->ni_htrates.rs_nrates == 0) - return (0); - return (IEEE80211_IS_CHAN_HT(ni->ni_chan)); -} - static void amrr_node_init(struct ieee80211_node *ni) { @@ -189,7 +170,7 @@ amrr_node_init(struct ieee80211_node *ni) amn->amn_success_threshold = amrr->amrr_min_success_threshold; /* 11n or not? Pick the right rateset */ - if (amrr_node_is_11n(ni)) { + if (ieee80211_ht_check_tx_ht(ni)) { /* XXX ew */ IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "%s: 11n node", __func__); @@ -204,7 +185,7 @@ amrr_node_init(struct ieee80211_node *ni) rate = rs->rs_rates[0]; /* XXX clear the basic rate flag if it's not 11n */ - if (! amrr_node_is_11n(ni)) + if (! ieee80211_ht_check_tx_ht(ni)) rate &= IEEE80211_RATE_VAL; /* pick initial rate from the rateset - HT or otherwise */ @@ -213,7 +194,7 @@ amrr_node_init(struct ieee80211_node *ni) amn->amn_rix--) { /* legacy - anything < 36mbit, stop searching */ /* 11n - stop at MCS4 */ - if (amrr_node_is_11n(ni)) { + if (ieee80211_ht_check_tx_ht(ni)) { if ((rs->rs_rates[amn->amn_rix] & 0x1f) < 4) break; } else if ((rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL) <= 72) @@ -222,7 +203,7 @@ amrr_node_init(struct ieee80211_node *ni) rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; /* if the rate is an 11n rate, ensure the MCS bit is set */ - if (amrr_node_is_11n(ni)) + if (ieee80211_ht_check_tx_ht(ni)) rate |= IEEE80211_RATE_MCS; /* Assign initial rate from the rateset */ @@ -234,7 +215,7 @@ amrr_node_init(struct ieee80211_node *ni) IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_RATECTL, ni, "AMRR: nrates=%d, initial rate %s%d", rs->rs_nrates, - amrr_node_is_11n(ni) ? "MCS " : "", + ieee80211_ht_check_tx_ht(ni) ? "MCS " : "", rate & IEEE80211_RATE_VAL); } @@ -254,7 +235,7 @@ amrr_update(struct ieee80211_amrr *amrr, struct ieee80211_amrr_node *amn, KASSERT(is_enough(amn), ("txcnt %d", amn->amn_txcnt)); /* 11n or not? Pick the right rateset */ - if (amrr_node_is_11n(ni)) { + if (ieee80211_ht_check_tx_ht(ni)) { /* XXX ew */ rs = (struct ieee80211_rateset *) &ni->ni_htrates; } else { @@ -347,7 +328,7 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) amrr = amn->amn_amrr; /* 11n or not? Pick the right rateset */ - if (amrr_node_is_11n(ni)) { + if (ieee80211_ht_check_tx_ht(ni)) { /* XXX ew */ rs = (struct ieee80211_rateset *) &ni->ni_htrates; } else { @@ -360,7 +341,7 @@ amrr_rate(struct ieee80211_node *ni, void *arg __unused, uint32_t iarg __unused) /* update public rate */ ni->ni_txrate = rs->rs_rates[rix]; /* XXX strip basic rate flag from txrate, if non-11n */ - if (amrr_node_is_11n(ni)) + if (ieee80211_ht_check_tx_ht(ni)) ni->ni_txrate |= IEEE80211_RATE_MCS; else ni->ni_txrate &= IEEE80211_RATE_VAL; @@ -482,7 +463,7 @@ amrr_print_node_rate(struct ieee80211_amrr_node *amn, int rate; struct ieee80211_rateset *rs; - if (amrr_node_is_11n(ni)) { + if (ieee80211_ht_check_tx_ht(ni)) { rs = (struct ieee80211_rateset *) &ni->ni_htrates; rate = rs->rs_rates[amn->amn_rix] & IEEE80211_RATE_VAL; sbuf_printf(s, "rate: MCS %d\n", rate); diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c index 28c329ce3d..1f97b7b992 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.c @@ -3604,3 +3604,143 @@ ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni) frm[5] = BCM_OUI_HTINFO; return ieee80211_add_htinfo_body(frm + 6, ni); } + +/* + * Get the HT density for the given 802.11n node. + * + * Take into account the density advertised from the peer. + * Larger values are longer A-MPDU density spacing values, and + * we want to obey them per station if we get them. + */ +int +ieee80211_ht_get_node_ampdu_density(const struct ieee80211_node *ni) +{ + struct ieee80211vap *vap; + int peer_mpdudensity; + + vap = ni->ni_vap; + peer_mpdudensity = + _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MPDUDENSITY); + if (vap->iv_ampdu_density > peer_mpdudensity) + peer_mpdudensity = vap->iv_ampdu_density; + return (peer_mpdudensity); +} + +/* + * Get the transmit A-MPDU limit for the given 802.11n node. + * + * Take into account the limit advertised from the peer. + * Smaller values indicate smaller maximum A-MPDU sizes, and + * should be used when forming an A-MPDU to the given peer. + */ +int +ieee80211_ht_get_node_ampdu_limit(const struct ieee80211_node *ni) +{ + struct ieee80211vap *vap; + int peer_mpdulimit; + + vap = ni->ni_vap; + peer_mpdulimit = + _IEEE80211_MASKSHIFT(ni->ni_htparam, IEEE80211_HTCAP_MAXRXAMPDU); + + return (MIN(vap->iv_ampdu_limit, peer_mpdulimit)); +} + +/* + * Return true if short-GI is available when transmitting to + * the given node at 20MHz. + * + * Ensure it's configured and available in the VAP / driver as + * well as the node. + */ +bool +ieee80211_ht_check_tx_shortgi_20(const struct ieee80211_node *ni) +{ + const struct ieee80211vap *vap; + const struct ieee80211com *ic; + + if (! ieee80211_ht_check_tx_ht(ni)) + return (false); + + vap = ni->ni_vap; + ic = ni->ni_ic; + + return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) && + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) && + (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)); +} + +/* + * Return true if short-GI is available when transmitting to + * the given node at 40MHz. + * + * Ensure it's configured and available in the VAP / driver as + * well as the node and BSS. + */ +bool +ieee80211_ht_check_tx_shortgi_40(const struct ieee80211_node *ni) +{ + const struct ieee80211vap *vap; + const struct ieee80211com *ic; + + if (! ieee80211_ht_check_tx_ht40(ni)) + return (false); + + vap = ni->ni_vap; + ic = ni->ni_ic; + + return ((ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40) && + (ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) && + (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)); +} + +/* + * Return true if HT rates can be used for the given node. + * + * There are some situations seen in the wild, wild past where + * HT APs would announce HT but no HT rates. + */ +bool +ieee80211_ht_check_tx_ht(const struct ieee80211_node *ni) +{ + const struct ieee80211vap *vap; + const struct ieee80211_channel *bss_chan; + + if (ni == NULL || ni->ni_chan == IEEE80211_CHAN_ANYC || + ni->ni_vap == NULL || ni->ni_vap->iv_bss == NULL) + return (false); + + vap = ni->ni_vap; + bss_chan = vap->iv_bss->ni_chan; + + if (bss_chan == IEEE80211_CHAN_ANYC) + return (false); + + if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && + ni->ni_htrates.rs_nrates == 0) + return (false); + return (IEEE80211_IS_CHAN_HT(ni->ni_chan)); +} + +/* + * Return true if HT40 rates can be transmitted to the given node. + * + * This verifies that the BSS is HT40 capable and the current + * node channel width is 40MHz. + */ +bool +ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni) +{ + struct ieee80211vap *vap; + struct ieee80211_channel *bss_chan; + + if (! ieee80211_ht_check_tx_ht(ni)) + return (false); + + vap = ni->ni_vap; + bss_chan = vap->iv_bss->ni_chan; + + return (IEEE80211_IS_CHAN_HT40(bss_chan) && + IEEE80211_IS_CHAN_HT40(ni->ni_chan) && + (ni->ni_chw == 40)); +} diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h index 6ba791065d..0f4c102569 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ht.h @@ -240,5 +240,11 @@ int ieee80211_ampdu_tx_request_ext(struct ieee80211_node *ni, int tid); int ieee80211_ampdu_tx_request_active_ext(struct ieee80211_node *ni, int tid, int status); void ieee80211_htinfo_notify(struct ieee80211vap *vap); +int ieee80211_ht_get_node_ampdu_density(const struct ieee80211_node *ni); +int ieee80211_ht_get_node_ampdu_limit(const struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_shortgi_20(const struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_shortgi_40(const struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni); +bool ieee80211_ht_check_tx_ht(const struct ieee80211_node *ht); #endif /* _NET80211_IEEE80211_HT_H_ */ diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c index 7ba257b0d1..d536ed2e47 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_ioctl.c @@ -3524,6 +3524,26 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r else ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_USEVHT80P80); + /* Check if we can do STBC TX/RX before changing the setting. */ + if ((ireq->i_val & IEEE80211_FVHT_STBC_TX) && + ((vap->iv_vht_cap.vht_cap_info & IEEE80211_VHTCAP_TXSTBC) == 0)) + return EOPNOTSUPP; + if ((ireq->i_val & IEEE80211_FVHT_STBC_RX) && + ((vap->iv_vht_cap.vht_cap_info & IEEE80211_VHTCAP_RXSTBC_MASK) == 0)) + return EOPNOTSUPP; + + /* TX */ + if (ireq->i_val & IEEE80211_FVHT_STBC_TX) + ieee80211_syncflag_vht(vap, IEEE80211_FVHT_STBC_TX); + else + ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_STBC_TX); + + /* RX */ + if (ireq->i_val & IEEE80211_FVHT_STBC_RX) + ieee80211_syncflag_vht(vap, IEEE80211_FVHT_STBC_RX); + else + ieee80211_syncflag_vht(vap, -IEEE80211_FVHT_STBC_RX); + error = ENETRESET; break; diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h b/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h index db4813bd39..846947df92 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_var.h @@ -739,12 +739,20 @@ MALLOC_DECLARE(M_80211_VAP); #define IEEE80211_FVHT_USEVHT80 0x000000004 /* CONF: Use VHT80 */ #define IEEE80211_FVHT_USEVHT160 0x000000008 /* CONF: Use VHT160 */ #define IEEE80211_FVHT_USEVHT80P80 0x000000010 /* CONF: Use VHT 80+80 */ -#define IEEE80211_FVHT_MASK \ +#define IEEE80211_FVHT_STBC_TX 0x00000020 /* CONF: STBC tx enabled */ +#define IEEE80211_FVHT_STBC_RX 0x00000040 /* CONF: STBC rx enabled */ + +#define IEEE80211_FVHT_CHANWIDTH_MASK \ (IEEE80211_FVHT_VHT | IEEE80211_FVHT_USEVHT40 | \ IEEE80211_FVHT_USEVHT80 | IEEE80211_FVHT_USEVHT160 | \ IEEE80211_FVHT_USEVHT80P80) + +#define IEEE80211_FVHT_MASK \ + (IEEE80211_FVHT_CHANWIDTH_MASK | \ + IEEE80211_FVHT_STBC_TX | IEEE80211_FVHT_STBC_RX) + #define IEEE80211_VFHT_BITS \ - "\20\1VHT\2VHT40\3VHT80\4VHT160\5VHT80P80" + "\20\1VHT\2VHT40\3VHT80\4VHT160\5VHT80P80\6STBC_TX\7STBC_RX" #define IEEE80211_COM_DETACHED 0x00000001 /* ieee80211_ifdetach called */ #define IEEE80211_COM_REF_ADD 0x00000002 /* add / remove reference */ diff --git a/src/libs/compat/freebsd_wlan/net80211/ieee80211_vht.c b/src/libs/compat/freebsd_wlan/net80211/ieee80211_vht.c index 0839f426e0..a05beb9121 100644 --- a/src/libs/compat/freebsd_wlan/net80211/ieee80211_vht.c +++ b/src/libs/compat/freebsd_wlan/net80211/ieee80211_vht.c @@ -439,8 +439,7 @@ ieee80211_vht_get_vhtcap_ie(struct ieee80211_node *ni, IEEE80211_VHTCAP_RXSTBC_MASK); } val = MIN(val1, val2); - /* XXX For now, use the 11n config flag */ - if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_TX) == 0) + if ((vap->iv_vht_flags & IEEE80211_FVHT_STBC_TX) == 0) val = 0; new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_TXSTBC); @@ -453,8 +452,7 @@ ieee80211_vht_get_vhtcap_ie(struct ieee80211_node *ni, IEEE80211_VHTCAP_TXSTBC); } val = MIN(val1, val2); - /* XXX For now, use the 11n config flag */ - if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_RX) == 0) + if ((vap->iv_vht_flags & IEEE80211_FVHT_STBC_RX) == 0) val = 0; new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_RXSTBC_MASK);