realtekwifi & net80211: Synchronize with FreeBSD.
As of upstream fcb5e8d0c19ac21515ab3047d39a76b32d835cec.
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
+2
-4
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user