realtekwifi & net80211: Synchronize with FreeBSD.

As of upstream fcb5e8d0c19ac21515ab3047d39a76b32d835cec.
This commit is contained in:
Augustin Cavalier
2024-12-05 23:18:45 -05:00
parent cd730cbd7c
commit 6193a477b8
21 changed files with 321 additions and 78 deletions
@@ -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,
@@ -16,7 +16,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -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;
@@ -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;
@@ -18,7 +18,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/lock.h>
@@ -18,7 +18,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -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);
@@ -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;
@@ -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
@@ -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);
@@ -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 */
@@ -18,7 +18,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/lock.h>
@@ -18,7 +18,6 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -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);
@@ -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
@@ -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);
@@ -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));
}
@@ -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_ */
@@ -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;
@@ -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 */
@@ -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);