aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorAdrian Chadd <adrian@FreeBSD.org>2020-07-01 00:23:49 +0000
committerAdrian Chadd <adrian@FreeBSD.org>2020-07-01 00:23:49 +0000
commitf1481c8d3b58eacdded319a76413062dac228574 (patch)
treef3afe3458ea712d17fb772ab1e45d6cb3efbe8f1 /sys
parent7290cb47fced28b5d0654cd1de7cc721e214ea32 (diff)
Notes
Diffstat (limited to 'sys')
-rw-r--r--sys/net80211/ieee80211_ddb.c20
-rw-r--r--sys/net80211/ieee80211_hostap.c24
-rw-r--r--sys/net80211/ieee80211_ht.c140
-rw-r--r--sys/net80211/ieee80211_ioctl.c12
-rw-r--r--sys/net80211/ieee80211_node.c142
-rw-r--r--sys/net80211/ieee80211_node.h2
-rw-r--r--sys/net80211/ieee80211_output.c39
-rw-r--r--sys/net80211/ieee80211_power.c2
-rw-r--r--sys/net80211/ieee80211_proto.c425
-rw-r--r--sys/net80211/ieee80211_proto.h3
-rw-r--r--sys/net80211/ieee80211_sta.c25
-rw-r--r--sys/net80211/ieee80211_var.h39
12 files changed, 670 insertions, 203 deletions
diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c
index dbcf589b8a13..272aaf988ba1 100644
--- a/sys/net80211/ieee80211_ddb.c
+++ b/sys/net80211/ieee80211_ddb.c
@@ -483,6 +483,17 @@ _db_show_vap(const struct ieee80211vap *vap, int showmesh, int showprocs)
if (vap->iv_tdma != NULL)
_db_show_tdma("\t", vap->iv_tdma, showprocs);
#endif /* IEEE80211_SUPPORT_TDMA */
+
+ db_printf("\tsta_assoc %u", vap->iv_sta_assoc);
+ db_printf(" ht_sta_assoc %u", vap->iv_ht_sta_assoc);
+ db_printf(" ht40_sta_assoc %u", vap->iv_ht40_sta_assoc);
+ db_printf("\n");
+ db_printf(" nonerpsta %u", vap->iv_nonerpsta);
+ db_printf(" longslotsta %u", vap->iv_longslotsta);
+ db_printf(" lastnonerp %d", vap->iv_lastnonerp);
+ db_printf(" lastnonht %d", vap->iv_lastnonht);
+ db_printf("\n");
+
if (showprocs) {
DB_PRINTSYM("\t", "iv_key_alloc", vap->iv_key_alloc);
DB_PRINTSYM("\t", "iv_key_delete", vap->iv_key_delete);
@@ -608,17 +619,8 @@ _db_show_com(const struct ieee80211com *ic, int showvaps, int showsta,
_db_show_node_table("\t", &ic->ic_sta);
db_printf("\tprotmode %d", ic->ic_protmode);
- db_printf(" nonerpsta %u", ic->ic_nonerpsta);
- db_printf(" longslotsta %u", ic->ic_longslotsta);
- db_printf(" lastnonerp %d", ic->ic_lastnonerp);
- db_printf("\n");
- db_printf("\tsta_assoc %u", ic->ic_sta_assoc);
- db_printf(" ht_sta_assoc %u", ic->ic_ht_sta_assoc);
- db_printf(" ht40_sta_assoc %u", ic->ic_ht40_sta_assoc);
- db_printf("\n");
db_printf("\tcurhtprotmode 0x%x", ic->ic_curhtprotmode);
db_printf(" htprotmode %d", ic->ic_htprotmode);
- db_printf(" lastnonht %d", ic->ic_lastnonht);
db_printf("\n");
db_printf("\tsuperg %p\n", ic->ic_superg);
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index a8a976a035cb..6687276d0181 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -206,8 +206,9 @@ hostap_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
* state and the timeout routines check if the flag
* is set before doing anything so this is sufficient.
*/
- ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
- ic->ic_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
+ vap->iv_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
+ vap->iv_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
+ /* XXX TODO: schedule deferred update? */
/* fall thru... */
case IEEE80211_S_CAC:
/*
@@ -1812,10 +1813,13 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
scan.status == 0 && /* NB: on-channel */
((scan.erp & 0x100) == 0 || /* NB: no ERP, 11b sta*/
(scan.erp & IEEE80211_ERP_NON_ERP_PRESENT))) {
- ic->ic_lastnonerp = ticks;
- ic->ic_flags_ext |= IEEE80211_FEXT_NONERP_PR;
- if (ic->ic_protmode != IEEE80211_PROT_NONE &&
- (ic->ic_flags & IEEE80211_F_USEPROT) == 0) {
+ vap->iv_lastnonerp = ticks;
+ vap->iv_flags_ext |= IEEE80211_FEXT_NONERP_PR;
+ /*
+ * XXX TODO: this may need to check all VAPs?
+ */
+ if (vap->iv_protmode != IEEE80211_PROT_NONE &&
+ (vap->iv_flags & IEEE80211_F_USEPROT) == 0) {
IEEE80211_NOTE_FRAME(vap,
IEEE80211_MSG_ASSOC, wh,
"non-ERP present on channel %d "
@@ -1823,8 +1827,8 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
"enable use of protection",
ic->ic_curchan->ic_ieee,
scan.erp, scan.chan);
- ic->ic_flags |= IEEE80211_F_USEPROT;
- ieee80211_notify_erp(ic);
+ vap->iv_flags |= IEEE80211_F_USEPROT;
+ ieee80211_vap_update_erp_protmode(vap);
}
}
/*
@@ -1844,12 +1848,12 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
break;
}
if (scan.htinfo == NULL) {
- ieee80211_htprot_update(ic,
+ ieee80211_htprot_update(vap,
IEEE80211_HTINFO_OPMODE_PROTOPT |
IEEE80211_HTINFO_NONHT_PRESENT);
} else if (ishtmixed(scan.htinfo)) {
/* XXX? take NONHT_PRESENT from beacon? */
- ieee80211_htprot_update(ic,
+ ieee80211_htprot_update(vap,
IEEE80211_HTINFO_OPMODE_MIXED |
IEEE80211_HTINFO_NONHT_PRESENT);
}
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 1827f012f4e0..9a4c046c2c1b 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -270,6 +270,9 @@ ieee80211_ht_vattach(struct ieee80211vap *vap)
vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
+ vap->iv_htprotmode = IEEE80211_PROT_RTSCTS;
+ vap->iv_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
+
if (vap->iv_htcaps & IEEE80211_HTC_HT) {
/*
* Device is HT capable; enable all HT-related
@@ -1509,38 +1512,36 @@ ieee80211_ht_wds_init(struct ieee80211_node *ni)
}
/*
- * Notify hostap vaps of a change in the HTINFO ie.
+ * Notify a VAP of a change in the HTINFO ie if it's a hostap VAP.
+ *
+ * This is to be called from the deferred HT protection update
+ * task once the flags are updated.
*/
-static void
-htinfo_notify(struct ieee80211com *ic)
+void
+ieee80211_htinfo_notify(struct ieee80211vap *vap)
{
- struct ieee80211vap *vap;
- int first = 1;
- IEEE80211_LOCK_ASSERT(ic);
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
- TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
- if (vap->iv_opmode != IEEE80211_M_HOSTAP)
- continue;
- if (vap->iv_state != IEEE80211_S_RUN ||
- !IEEE80211_IS_CHAN_HT(vap->iv_bss->ni_chan))
- continue;
- if (first) {
- IEEE80211_NOTE(vap,
- IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
- vap->iv_bss,
- "HT bss occupancy change: %d sta, %d ht, "
- "%d ht40%s, HT protmode now 0x%x"
- , ic->ic_sta_assoc
- , ic->ic_ht_sta_assoc
- , ic->ic_ht40_sta_assoc
- , (ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) ?
- ", non-HT sta present" : ""
- , ic->ic_curhtprotmode);
- first = 0;
- }
- ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
- }
+ if (vap->iv_opmode != IEEE80211_M_HOSTAP)
+ return;
+ if (vap->iv_state != IEEE80211_S_RUN ||
+ !IEEE80211_IS_CHAN_HT(vap->iv_bss->ni_chan))
+ return;
+
+ IEEE80211_NOTE(vap,
+ IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
+ vap->iv_bss,
+ "HT bss occupancy change: %d sta, %d ht, "
+ "%d ht40%s, HT protmode now 0x%x"
+ , vap->iv_sta_assoc
+ , vap->iv_ht_sta_assoc
+ , vap->iv_ht40_sta_assoc
+ , (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) ?
+ ", non-HT sta present" : ""
+ , vap->iv_curhtprotmode);
+
+ ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
}
/*
@@ -1548,26 +1549,28 @@ htinfo_notify(struct ieee80211com *ic)
* state and handle updates.
*/
static void
-htinfo_update(struct ieee80211com *ic)
+htinfo_update(struct ieee80211vap *vap)
{
+ struct ieee80211com *ic = vap->iv_ic;
uint8_t protmode;
- if (ic->ic_sta_assoc != ic->ic_ht_sta_assoc) {
+ if (vap->iv_sta_assoc != vap->iv_ht_sta_assoc) {
protmode = IEEE80211_HTINFO_OPMODE_MIXED
| IEEE80211_HTINFO_NONHT_PRESENT;
- } else if (ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) {
+ } else if (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) {
protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
| IEEE80211_HTINFO_NONHT_PRESENT;
} else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) &&
- ic->ic_sta_assoc != ic->ic_ht40_sta_assoc) {
+ vap->iv_sta_assoc != vap->iv_ht40_sta_assoc) {
protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
} else {
protmode = IEEE80211_HTINFO_OPMODE_PURE;
}
- if (protmode != ic->ic_curhtprotmode) {
- ic->ic_curhtprotmode = protmode;
- htinfo_notify(ic);
+ if (protmode != vap->iv_curhtprotmode) {
+ vap->iv_curhtprotmode = protmode;
+ /* Update VAP with new protection mode */
+ ieee80211_vap_update_ht_protmode(vap);
}
}
@@ -1577,16 +1580,16 @@ htinfo_update(struct ieee80211com *ic)
void
ieee80211_ht_node_join(struct ieee80211_node *ni)
{
- struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
- IEEE80211_LOCK_ASSERT(ic);
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
if (ni->ni_flags & IEEE80211_NODE_HT) {
- ic->ic_ht_sta_assoc++;
+ vap->iv_ht_sta_assoc++;
if (ni->ni_chw == 40)
- ic->ic_ht40_sta_assoc++;
+ vap->iv_ht40_sta_assoc++;
}
- htinfo_update(ic);
+ htinfo_update(vap);
}
/*
@@ -1595,16 +1598,16 @@ ieee80211_ht_node_join(struct ieee80211_node *ni)
void
ieee80211_ht_node_leave(struct ieee80211_node *ni)
{
- struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
- IEEE80211_LOCK_ASSERT(ic);
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
if (ni->ni_flags & IEEE80211_NODE_HT) {
- ic->ic_ht_sta_assoc--;
+ vap->iv_ht_sta_assoc--;
if (ni->ni_chw == 40)
- ic->ic_ht40_sta_assoc--;
+ vap->iv_ht40_sta_assoc--;
}
- htinfo_update(ic);
+ htinfo_update(vap);
}
/*
@@ -1618,25 +1621,27 @@ ieee80211_ht_node_leave(struct ieee80211_node *ni)
* a higher precedence than PROTOPT (i.e. we will not change
* change PROTOPT -> MIXED; only MIXED -> PROTOPT). This
* corresponds to how we handle things in htinfo_update.
+ *
*/
void
-ieee80211_htprot_update(struct ieee80211com *ic, int protmode)
+ieee80211_htprot_update(struct ieee80211vap *vap, int protmode)
{
+ struct ieee80211com *ic = vap->iv_ic;
#define OPMODE(x) SM(x, IEEE80211_HTINFO_OPMODE)
IEEE80211_LOCK(ic);
/* track non-HT station presence */
KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
("protmode 0x%x", protmode));
- ic->ic_flags_ht |= IEEE80211_FHT_NONHT_PR;
- ic->ic_lastnonht = ticks;
+ vap->iv_flags_ht |= IEEE80211_FHT_NONHT_PR;
+ vap->iv_lastnonht = ticks;
- if (protmode != ic->ic_curhtprotmode &&
- (OPMODE(ic->ic_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
+ if (protmode != vap->iv_curhtprotmode &&
+ (OPMODE(vap->iv_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
- /* push beacon update */
- ic->ic_curhtprotmode = protmode;
- htinfo_notify(ic);
+ vap->iv_curhtprotmode = protmode;
+ /* Update VAP with new protection mode */
+ ieee80211_vap_update_ht_protmode(vap);
}
IEEE80211_UNLOCK(ic);
#undef OPMODE
@@ -1651,18 +1656,17 @@ ieee80211_htprot_update(struct ieee80211com *ic, int protmode)
* gone we time out this condition.
*/
void
-ieee80211_ht_timeout(struct ieee80211com *ic)
+ieee80211_ht_timeout(struct ieee80211vap *vap)
{
- IEEE80211_LOCK_ASSERT(ic);
- if ((ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR) &&
- ieee80211_time_after(ticks, ic->ic_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
-#if 0
- IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
+
+ if ((vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) &&
+ ieee80211_time_after(ticks, vap->iv_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
"%s", "time out non-HT STA present on channel");
-#endif
- ic->ic_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
- htinfo_update(ic);
+ vap->iv_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
+ htinfo_update(vap);
}
}
@@ -3507,6 +3511,12 @@ ieee80211_ht_update_beacon(struct ieee80211vap *vap,
ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
/* protection mode */
+ /*
+ * XXX TODO: this uses the global flag, not the per-VAP flag.
+ * Eventually (once the protection modes are done per-channel
+ * rather than per-VAP) we can flip this over to be per-VAP but
+ * using the channel protection mode.
+ */
ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
ieee80211_free_node(ni);
@@ -3547,7 +3557,11 @@ ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
- frm[1] = ic->ic_curhtprotmode;
+ /*
+ * Add current protection mode. Unlike for beacons,
+ * this will respect the per-VAP flags.
+ */
+ frm[1] = vap->iv_curhtprotmode;
frm += 5;
diff --git a/sys/net80211/ieee80211_ioctl.c b/sys/net80211/ieee80211_ioctl.c
index d84abc1ae894..0eed8667460e 100644
--- a/sys/net80211/ieee80211_ioctl.c
+++ b/sys/net80211/ieee80211_ioctl.c
@@ -851,7 +851,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
ireq->i_val = vap->iv_rtsthreshold;
break;
case IEEE80211_IOC_PROTMODE:
- ireq->i_val = ic->ic_protmode;
+ ireq->i_val = vap->iv_protmode;
break;
case IEEE80211_IOC_TXPOWER:
/*
@@ -1097,7 +1097,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_long cmd,
error = ieee80211_ioctl_getdevcaps(ic, ireq);
break;
case IEEE80211_IOC_HTPROTMODE:
- ireq->i_val = ic->ic_htprotmode;
+ ireq->i_val = vap->iv_htprotmode;
break;
case IEEE80211_IOC_HTCONF:
if (vap->iv_flags_ht & IEEE80211_FHT_HT) {
@@ -2912,11 +2912,13 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
case IEEE80211_IOC_PROTMODE:
if (ireq->i_val > IEEE80211_PROT_RTSCTS)
return EINVAL;
- ic->ic_protmode = (enum ieee80211_protmode)ireq->i_val;
+ vap->iv_protmode = (enum ieee80211_protmode)ireq->i_val;
/* NB: if not operating in 11g this can wait */
if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
IEEE80211_IS_CHAN_ANYG(ic->ic_bsschan))
error = ERESTART;
+ /* driver callback for protection mode update */
+ ieee80211_vap_update_erp_protmode(vap);
break;
case IEEE80211_IOC_TXPOWER:
if ((ic->ic_caps & IEEE80211_C_TXPMGT) == 0)
@@ -3384,11 +3386,13 @@ ieee80211_ioctl_set80211(struct ieee80211vap *vap, u_long cmd, struct ieee80211r
case IEEE80211_IOC_HTPROTMODE:
if (ireq->i_val > IEEE80211_PROT_RTSCTS)
return EINVAL;
- ic->ic_htprotmode = ireq->i_val ?
+ vap->iv_htprotmode = ireq->i_val ?
IEEE80211_PROT_RTSCTS : IEEE80211_PROT_NONE;
/* NB: if not operating in 11n this can wait */
if (isvapht(vap))
error = ERESTART;
+ /* Notify driver layer of HT protmode changes */
+ ieee80211_vap_update_ht_protmode(vap);
break;
case IEEE80211_IOC_STA_VLAN:
error = ieee80211_ioctl_setstavlan(vap, ireq);
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index 14e1e762aa84..9ee5b1b83cde 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -99,7 +99,7 @@ static void ieee80211_node_table_init(struct ieee80211com *ic,
static void ieee80211_node_table_reset(struct ieee80211_node_table *,
struct ieee80211vap *);
static void ieee80211_node_table_cleanup(struct ieee80211_node_table *nt);
-static void ieee80211_erp_timeout(struct ieee80211com *);
+static void ieee80211_vap_erp_timeout(struct ieee80211vap *);
MALLOC_DEFINE(M_80211_NODE, "80211node", "802.11 node state");
MALLOC_DEFINE(M_80211_NODE_IE, "80211nodeie", "802.11 node ie");
@@ -674,7 +674,6 @@ ieee80211_ibss_merge(struct ieee80211_node *ni)
{
#ifdef IEEE80211_DEBUG
struct ieee80211vap *vap = ni->ni_vap;
- struct ieee80211com *ic = ni->ni_ic;
#endif
if (! ieee80211_ibss_merge_check(ni))
@@ -683,9 +682,9 @@ ieee80211_ibss_merge(struct ieee80211_node *ni)
IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
"%s: new bssid %s: %s preamble, %s slot time%s\n", __func__,
ether_sprintf(ni->ni_bssid),
- ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
+ vap->iv_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
vap->iv_flags&IEEE80211_F_SHSLOT ? "short" : "long",
- ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
+ vap->iv_flags&IEEE80211_F_USEPROT ? ", protection" : ""
);
return ieee80211_sta_join1(ieee80211_ref_node(ni));
}
@@ -2508,12 +2507,27 @@ ieee80211_drain(struct ieee80211com *ic)
}
/*
+ * Per-ieee80211vap inactivity timer callback.
+ */
+static void
+ieee80211_vap_timeout(struct ieee80211vap *vap)
+{
+
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
+
+ ieee80211_vap_erp_timeout(vap);
+ ieee80211_ht_timeout(vap);
+ ieee80211_vht_timeout(vap);
+}
+
+/*
* Per-ieee80211com inactivity timer callback.
*/
void
ieee80211_node_timeout(void *arg)
{
struct ieee80211com *ic = arg;
+ struct ieee80211vap *vap;
/*
* Defer timeout processing if a channel switch is pending.
@@ -2530,9 +2544,8 @@ ieee80211_node_timeout(void *arg)
ieee80211_ageq_age(&ic->ic_stageq, IEEE80211_INACT_WAIT);
IEEE80211_LOCK(ic);
- ieee80211_erp_timeout(ic);
- ieee80211_ht_timeout(ic);
- ieee80211_vht_timeout(ic);
+ TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next)
+ ieee80211_vap_timeout(vap);
IEEE80211_UNLOCK(ic);
}
callout_reset(&ic->ic_inact, IEEE80211_INACT_WAIT*hz,
@@ -2645,7 +2658,12 @@ ieee80211_dump_nodes(struct ieee80211_node_table *nt)
(ieee80211_iter_func *) ieee80211_dump_node, nt);
}
-static void
+/*
+ * Iterate over the VAPs and update their ERP beacon IEs.
+ *
+ * Note this must be called from the deferred ERP update task paths.
+ */
+void
ieee80211_notify_erp_locked(struct ieee80211com *ic)
{
struct ieee80211vap *vap;
@@ -2657,14 +2675,6 @@ ieee80211_notify_erp_locked(struct ieee80211com *ic)
ieee80211_beacon_notify(vap, IEEE80211_BEACON_ERP);
}
-void
-ieee80211_notify_erp(struct ieee80211com *ic)
-{
- IEEE80211_LOCK(ic);
- ieee80211_notify_erp_locked(ic);
- IEEE80211_UNLOCK(ic);
-}
-
/*
* Handle a station joining an 11g network.
*/
@@ -2684,10 +2694,13 @@ ieee80211_node_join_11g(struct ieee80211_node *ni)
* next beacon transmission (per sec. 7.3.1.4 of 11g).
*/
if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
- ic->ic_longslotsta++;
+ vap->iv_longslotsta++;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
"station needs long slot time, count %d",
- ic->ic_longslotsta);
+ vap->iv_longslotsta);
+ /*
+ * XXX TODO: this may need all VAPs checked!
+ */
if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) {
/*
* Don't force slot time when switched to turbo
@@ -2703,10 +2716,10 @@ ieee80211_node_join_11g(struct ieee80211_node *ni)
* if configured.
*/
if (!ieee80211_iserp_rateset(&ni->ni_rates)) {
- ic->ic_nonerpsta++;
+ vap->iv_nonerpsta++;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
"station is !ERP, %d non-ERP stations associated",
- ic->ic_nonerpsta);
+ vap->iv_nonerpsta);
/*
* If station does not support short preamble
* then we must enable use of Barker preamble.
@@ -2714,20 +2727,21 @@ ieee80211_node_join_11g(struct ieee80211_node *ni)
if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE) == 0) {
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
"%s", "station needs long preamble");
- ic->ic_flags |= IEEE80211_F_USEBARKER;
- ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
+ vap->iv_flags |= IEEE80211_F_USEBARKER;
+ vap->iv_flags &= ~IEEE80211_F_SHPREAMBLE;
+ ieee80211_vap_update_preamble(vap);
}
/*
* If protection is configured and this is the first
* indication we should use protection, enable it.
*/
- if (ic->ic_protmode != IEEE80211_PROT_NONE &&
- ic->ic_nonerpsta == 1 &&
- (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
+ if (vap->iv_protmode != IEEE80211_PROT_NONE &&
+ vap->iv_nonerpsta == 1 &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
"%s: enable use of protection\n", __func__);
- ic->ic_flags |= IEEE80211_F_USEPROT;
- ieee80211_notify_erp_locked(ic);
+ vap->iv_flags |= IEEE80211_F_USEPROT;
+ ieee80211_vap_update_erp_protmode(vap);
}
} else
ni->ni_flags |= IEEE80211_NODE_ERP;
@@ -2762,7 +2776,6 @@ ieee80211_node_join(struct ieee80211_node *ni, int resp)
IEEE80211_LOCK(ic);
IEEE80211_AID_SET(vap, ni->ni_associd);
vap->iv_sta_assoc++;
- ic->ic_sta_assoc++;
if (IEEE80211_IS_CHAN_HT(ic->ic_bsschan))
ieee80211_ht_node_join(ni);
@@ -2783,9 +2796,9 @@ ieee80211_node_join(struct ieee80211_node *ni, int resp)
IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, ni,
"station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s%s",
IEEE80211_NODE_AID(ni),
- ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
+ vap->iv_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
vap->iv_flags & IEEE80211_F_SHSLOT ? "short" : "long",
- ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "",
+ vap->iv_flags & IEEE80211_F_USEPROT ? ", protection" : "",
ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
/* XXX update for VHT string */
ni->ni_flags & IEEE80211_NODE_HT ?
@@ -2815,20 +2828,23 @@ ieee80211_node_join(struct ieee80211_node *ni, int resp)
}
static void
-disable_protection(struct ieee80211com *ic)
+disable_protection(struct ieee80211vap *vap)
{
- KASSERT(ic->ic_nonerpsta == 0 &&
- (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0,
- ("%d non ERP stations, flags 0x%x", ic->ic_nonerpsta,
- ic->ic_flags_ext));
+ struct ieee80211com *ic = vap->iv_ic;
- ic->ic_flags &= ~IEEE80211_F_USEPROT;
+ KASSERT(vap->iv_nonerpsta == 0 &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0,
+ ("%d non ERP stations, flags 0x%x", vap->iv_nonerpsta,
+ vap->iv_flags_ext));
+
+ vap->iv_flags &= ~IEEE80211_F_USEPROT;
/* XXX verify mode? */
if (ic->ic_caps & IEEE80211_C_SHPREAMBLE) {
- ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
- ic->ic_flags &= ~IEEE80211_F_USEBARKER;
+ vap->iv_flags |= IEEE80211_F_SHPREAMBLE;
+ vap->iv_flags &= ~IEEE80211_F_USEBARKER;
}
- ieee80211_notify_erp_locked(ic);
+ ieee80211_vap_update_erp_protmode(vap);
+ ieee80211_vap_update_preamble(vap);
}
/*
@@ -2850,13 +2866,16 @@ ieee80211_node_leave_11g(struct ieee80211_node *ni)
* If a long slot station do the slot time bookkeeping.
*/
if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) == 0) {
- KASSERT(ic->ic_longslotsta > 0,
- ("bogus long slot station count %d", ic->ic_longslotsta));
- ic->ic_longslotsta--;
+ KASSERT(vap->iv_longslotsta > 0,
+ ("bogus long slot station count %d", vap->iv_longslotsta));
+ vap->iv_longslotsta--;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
"long slot time station leaves, count now %d",
- ic->ic_longslotsta);
- if (ic->ic_longslotsta == 0) {
+ vap->iv_longslotsta);
+ /*
+ * XXX TODO: this may need all VAPs checked!
+ */
+ if (vap->iv_longslotsta == 0) {
/*
* Re-enable use of short slot time if supported
* and not operating in IBSS mode (per spec).
@@ -2875,18 +2894,18 @@ ieee80211_node_leave_11g(struct ieee80211_node *ni)
* If a non-ERP station do the protection-related bookkeeping.
*/
if ((ni->ni_flags & IEEE80211_NODE_ERP) == 0) {
- KASSERT(ic->ic_nonerpsta > 0,
- ("bogus non-ERP station count %d", ic->ic_nonerpsta));
- ic->ic_nonerpsta--;
+ KASSERT(vap->iv_nonerpsta > 0,
+ ("bogus non-ERP station count %d", vap->iv_nonerpsta));
+ vap->iv_nonerpsta--;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
- "non-ERP station leaves, count now %d%s", ic->ic_nonerpsta,
- (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) ?
+ "non-ERP station leaves, count now %d%s", vap->iv_nonerpsta,
+ (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) ?
" (non-ERP sta present)" : "");
- if (ic->ic_nonerpsta == 0 &&
- (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
+ if (vap->iv_nonerpsta == 0 &&
+ (vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) == 0) {
IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_ASSOC,
"%s: disable use of protection\n", __func__);
- disable_protection(ic);
+ disable_protection(vap);
}
}
}
@@ -2900,20 +2919,18 @@ ieee80211_node_leave_11g(struct ieee80211_node *ni)
* condition.
*/
static void
-ieee80211_erp_timeout(struct ieee80211com *ic)
+ieee80211_vap_erp_timeout(struct ieee80211vap *vap)
{
- IEEE80211_LOCK_ASSERT(ic);
+ IEEE80211_LOCK_ASSERT(vap->iv_ic);
- if ((ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) &&
- ieee80211_time_after(ticks, ic->ic_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
-#if 0
- IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni,
+ if ((vap->iv_flags_ext & IEEE80211_FEXT_NONERP_PR) &&
+ ieee80211_time_after(ticks, vap->iv_lastnonerp + IEEE80211_NONERP_PRESENT_AGE)) {
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_ASSOC,
"%s", "age out non-ERP sta present on channel");
-#endif
- ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
- if (ic->ic_nonerpsta == 0)
- disable_protection(ic);
+ vap->iv_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
+ if (vap->iv_nonerpsta == 0)
+ disable_protection(vap);
}
}
@@ -2952,7 +2969,6 @@ ieee80211_node_leave(struct ieee80211_node *ni)
IEEE80211_LOCK(ic);
IEEE80211_AID_CLR(vap, ni->ni_associd);
vap->iv_sta_assoc--;
- ic->ic_sta_assoc--;
if (IEEE80211_IS_CHAN_VHT(ic->ic_bsschan))
ieee80211_vht_node_leave(ni);
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index 6e9fa5f168ae..ff826d30ca72 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -479,7 +479,7 @@ int ieee80211_iterate_nodes_vap(struct ieee80211_node_table *,
void ieee80211_iterate_nodes(struct ieee80211_node_table *,
ieee80211_iter_func *, void *);
-void ieee80211_notify_erp(struct ieee80211com *);
+void ieee80211_notify_erp_locked(struct ieee80211com *);
void ieee80211_dump_node(struct ieee80211_node_table *,
struct ieee80211_node *);
void ieee80211_dump_nodes(struct ieee80211_node_table *);
diff --git a/sys/net80211/ieee80211_output.c b/sys/net80211/ieee80211_output.c
index c53911604efa..a753c8c8faed 100644
--- a/sys/net80211/ieee80211_output.c
+++ b/sys/net80211/ieee80211_output.c
@@ -2100,15 +2100,34 @@ ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len)
* Add an erp element to a frame.
*/
static uint8_t *
-ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic)
+ieee80211_add_erp(uint8_t *frm, struct ieee80211vap *vap)
{
+ struct ieee80211com *ic = vap->iv_ic;
uint8_t erp;
*frm++ = IEEE80211_ELEMID_ERP;
*frm++ = 1;
erp = 0;
- if (ic->ic_nonerpsta != 0)
+
+ /*
+ * TODO: This uses the global flags for now because
+ * the per-VAP flags are fine for per-VAP, but don't
+ * take into account which VAPs share the same channel
+ * and which are on different channels.
+ *
+ * ERP and HT/VHT protection mode is a function of
+ * how many stations are on a channel, not specifically
+ * the VAP or global. But, until we grow that status,
+ * the global flag will have to do.
+ */
+ if (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR)
erp |= IEEE80211_ERP_NON_ERP_PRESENT;
+
+ /*
+ * TODO: same as above; these should be based not
+ * on the vap or ic flags, but instead on a combination
+ * of per-VAP and channels.
+ */
if (ic->ic_flags & IEEE80211_F_USEPROT)
erp |= IEEE80211_ERP_USE_PROTECTION;
if (ic->ic_flags & IEEE80211_F_USEBARKER)
@@ -2569,7 +2588,6 @@ ieee80211_send_probereq(struct ieee80211_node *ni,
uint16_t
ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
{
- struct ieee80211com *ic = vap->iv_ic;
uint16_t capinfo;
KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode"));
@@ -2582,7 +2600,7 @@ ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
capinfo = 0;
if (vap->iv_flags & IEEE80211_F_PRIVACY)
capinfo |= IEEE80211_CAPINFO_PRIVACY;
- if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) &&
IEEE80211_IS_CHAN_2GHZ(chan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if (vap->iv_flags & IEEE80211_F_SHSLOT)
@@ -2761,7 +2779,7 @@ ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg)
* NB: Some 11a AP's reject the request when
* short preamble is set.
*/
- if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
+ if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) &&
IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
@@ -3098,7 +3116,7 @@ ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy)
}
}
if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan))
- frm = ieee80211_add_erp(frm, ic);
+ frm = ieee80211_add_erp(frm, vap);
frm = ieee80211_add_xrates(frm, rs);
frm = ieee80211_add_rsn(frm, vap);
/*
@@ -3268,6 +3286,7 @@ ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m,
uint8_t rate, int prot)
{
struct ieee80211com *ic = ni->ni_ic;
+ struct ieee80211vap *vap = ni->ni_vap;
const struct ieee80211_frame *wh;
struct mbuf *mprot;
uint16_t dur;
@@ -3279,7 +3298,7 @@ ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m,
wh = mtod(m, const struct ieee80211_frame *);
pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN;
- isshort = (ic->ic_flags & IEEE80211_F_SHPREAMBLE) != 0;
+ isshort = (vap->iv_flags & IEEE80211_F_SHPREAMBLE) != 0;
dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort)
+ ieee80211_ack_duration(ic->ic_rt, rate, isshort);
@@ -3288,7 +3307,7 @@ ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m,
dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort);
mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur);
} else
- mprot = ieee80211_alloc_cts(ic, ni->ni_vap->iv_myaddr, dur);
+ mprot = ieee80211_alloc_cts(ic, vap->iv_myaddr, dur);
return (mprot);
}
@@ -3496,7 +3515,7 @@ ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm,
if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) {
bo->bo_erp = frm;
- frm = ieee80211_add_erp(frm, ic);
+ frm = ieee80211_add_erp(frm, vap);
}
frm = ieee80211_add_xrates(frm, rs);
frm = ieee80211_add_rsn(frm, vap);
@@ -3981,7 +4000,7 @@ ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast)
/*
* ERP element needs updating.
*/
- (void) ieee80211_add_erp(bo->bo_erp, ic);
+ (void) ieee80211_add_erp(bo->bo_erp, vap);
clrbit(bo->bo_flags, IEEE80211_BEACON_ERP);
}
#ifdef IEEE80211_SUPPORT_SUPERG
diff --git a/sys/net80211/ieee80211_power.c b/sys/net80211/ieee80211_power.c
index f38a5148fef2..75d2dbea92ce 100644
--- a/sys/net80211/ieee80211_power.c
+++ b/sys/net80211/ieee80211_power.c
@@ -335,7 +335,7 @@ ieee80211_pwrsave(struct ieee80211_node *ni, struct mbuf *m)
if (psq->psq_len >= psq->psq_maxlen) {
psq->psq_drops++;
IEEE80211_PSQ_UNLOCK(psq);
- IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni,
+ IEEE80211_NOTE(vap, IEEE80211_MSG_POWER, ni,
"pwr save q overflow, drops %d (size %d)",
psq->psq_drops, psq->psq_len);
#ifdef IEEE80211_DEBUG
diff --git a/sys/net80211/ieee80211_proto.c b/sys/net80211/ieee80211_proto.c
index be7bb1430c02..2f98deea88d9 100644
--- a/sys/net80211/ieee80211_proto.c
+++ b/sys/net80211/ieee80211_proto.c
@@ -246,6 +246,9 @@ static void update_chw(void *, int);
static void vap_update_wme(void *, int);
static void vap_update_slot(void *, int);
static void restart_vaps(void *, int);
+static void vap_update_erp_protmode(void *, int);
+static void vap_update_preamble(void *, int);
+static void vap_update_ht_protmode(void *, int);
static void ieee80211_newstate_cb(void *, int);
static int
@@ -275,7 +278,7 @@ ieee80211_proto_attach(struct ieee80211com *ic)
max_hdr = max_linkhdr + max_protohdr;
max_datalen = MHLEN - max_hdr;
}
- ic->ic_protmode = IEEE80211_PROT_CTSONLY;
+ //ic->ic_protmode = IEEE80211_PROT_CTSONLY;
TASK_INIT(&ic->ic_parent_task, 0, parent_updown, ic);
TASK_INIT(&ic->ic_mcast_task, 0, update_mcast, ic);
@@ -342,6 +345,9 @@ ieee80211_proto_vattach(struct ieee80211vap *vap)
TASK_INIT(&vap->iv_swbmiss_task, 0, beacon_swmiss, vap);
TASK_INIT(&vap->iv_wme_task, 0, vap_update_wme, vap);
TASK_INIT(&vap->iv_slot_task, 0, vap_update_slot, vap);
+ TASK_INIT(&vap->iv_erp_protmode_task, 0, vap_update_erp_protmode, vap);
+ TASK_INIT(&vap->iv_ht_protmode_task, 0, vap_update_ht_protmode, vap);
+ TASK_INIT(&vap->iv_preamble_task, 0, vap_update_preamble, vap);
/*
* Install default tx rate handling: no fixed rate, lowest
* supported rate for mgmt and multicast frames. Default
@@ -388,6 +394,7 @@ ieee80211_proto_vattach(struct ieee80211vap *vap)
vap->iv_update_beacon = null_update_beacon;
vap->iv_deliver_data = ieee80211_deliver_data;
+ vap->iv_protmode = IEEE80211_PROT_CTSONLY;
/* attach support for operating mode */
ic->ic_vattach[vap->iv_opmode](vap);
@@ -763,6 +770,22 @@ ieee80211_vap_reset_erp(struct ieee80211vap *vap)
{
struct ieee80211com *ic = vap->iv_ic;
+ vap->iv_nonerpsta = 0;
+ vap->iv_longslotsta = 0;
+
+ vap->iv_flags &= ~IEEE80211_F_USEPROT;
+ /*
+ * Set short preamble and ERP barker-preamble flags.
+ */
+ if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
+ (vap->iv_caps & IEEE80211_C_SHPREAMBLE)) {
+ vap->iv_flags |= IEEE80211_F_SHPREAMBLE;
+ vap->iv_flags &= ~IEEE80211_F_USEBARKER;
+ } else {
+ vap->iv_flags &= ~IEEE80211_F_SHPREAMBLE;
+ vap->iv_flags |= IEEE80211_F_USEBARKER;
+ }
+
/*
* Short slot time is enabled only when operating in 11g
* and not in an IBSS. We must also honor whether or not
@@ -778,13 +801,15 @@ ieee80211_vap_reset_erp(struct ieee80211vap *vap)
/*
* Reset 11g-related state.
+ *
+ * Note this resets the global state and a caller should schedule
+ * a re-check of all the VAPs after setup to update said state.
*/
void
ieee80211_reset_erp(struct ieee80211com *ic)
{
+#if 0
ic->ic_flags &= ~IEEE80211_F_USEPROT;
- ic->ic_nonerpsta = 0;
- ic->ic_longslotsta = 0;
/*
* Set short preamble and ERP barker-preamble flags.
*/
@@ -796,6 +821,8 @@ ieee80211_reset_erp(struct ieee80211com *ic)
ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
ic->ic_flags |= IEEE80211_F_USEBARKER;
}
+#endif
+ /* XXX TODO: schedule a new per-VAP ERP calculation */
}
/*
@@ -812,6 +839,9 @@ ieee80211_reset_erp(struct ieee80211com *ic)
* If the per-VAP method is not called then the global flags will be
* flipped into sync with the VAPs; ic_flags IEEE80211_F_SHSLOT will
* be set only if all of the vaps will have it set.
+ *
+ * Look at the comments for vap_update_erp_protmode() for more
+ * background; this assumes all VAPs are on the same channel.
*/
static void
vap_update_slot(void *arg, int npending)
@@ -848,7 +878,6 @@ vap_update_slot(void *arg, int npending)
else
num_lgslot++;
}
- IEEE80211_UNLOCK(ic);
/*
* It looks backwards but - if the number of short slot VAPs
@@ -860,6 +889,7 @@ vap_update_slot(void *arg, int npending)
ic->ic_flags &= ~IEEE80211_F_SHSLOT;
else if (num_lgslot == 0)
ic->ic_flags |= IEEE80211_F_SHSLOT;
+ IEEE80211_UNLOCK(ic);
/*
* Call the driver with our new global slot time flags.
@@ -869,6 +899,293 @@ vap_update_slot(void *arg, int npending)
}
/*
+ * Deferred ERP protmode update.
+ *
+ * This currently calculates the global ERP protection mode flag
+ * based on each of the VAPs. Any VAP with it enabled is enough
+ * for the global flag to be enabled. All VAPs with it disabled
+ * is enough for it to be disabled.
+ *
+ * This may make sense right now for the supported hardware where
+ * net80211 is controlling the single channel configuration, but
+ * offload firmware that's doing channel changes (eg off-channel
+ * TDLS, off-channel STA, off-channel P2P STA/AP) may get some
+ * silly looking flag updates.
+ *
+ * Ideally the protection mode calculation is done based on the
+ * channel, and all VAPs using that channel will inherit it.
+ * But until that's what net80211 does, this wil have to do.
+ */
+static void
+vap_update_erp_protmode(void *arg, int npending)
+{
+ struct ieee80211vap *vap = arg;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211vap *iv;
+ int enable_protmode = 0;
+ int non_erp_present = 0;
+
+ /*
+ * Iterate over all of the VAPs to calculate the overlapping
+ * ERP protection mode configuration and ERP present math.
+ *
+ * For now we assume that if a driver can handle this per-VAP
+ * then it'll ignore the ic->ic_protmode variant and instead
+ * will look at the vap related flags.
+ */
+ IEEE80211_LOCK(ic);
+ TAILQ_FOREACH(iv, &ic->ic_vaps, iv_next) {
+ if (iv->iv_flags & IEEE80211_F_USEPROT)
+ enable_protmode = 1;
+ if (iv->iv_flags_ext & IEEE80211_FEXT_NONERP_PR)
+ non_erp_present = 1;
+ }
+
+ if (enable_protmode)
+ ic->ic_flags |= IEEE80211_F_USEPROT;
+ else
+ ic->ic_flags &= ~IEEE80211_F_USEPROT;
+
+ if (non_erp_present)
+ ic->ic_flags_ext |= IEEE80211_FEXT_NONERP_PR;
+ else
+ ic->ic_flags_ext &= ~IEEE80211_FEXT_NONERP_PR;
+
+ /* Beacon update on all VAPs */
+ ieee80211_notify_erp_locked(ic);
+
+ IEEE80211_UNLOCK(ic);
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: called; enable_protmode=%d, non_erp_present=%d\n",
+ __func__, enable_protmode, non_erp_present);
+
+ /*
+ * Now that the global configuration flags are calculated,
+ * notify the VAP about its configuration.
+ *
+ * The global flags will be used when assembling ERP IEs
+ * for multi-VAP operation, even if it's on a different
+ * channel. Yes, that's going to need fixing in the
+ * future.
+ */
+ if (vap->iv_erp_protmode_update != NULL)
+ vap->iv_erp_protmode_update(vap);
+}
+
+/*
+ * Deferred ERP short preamble/barker update.
+ *
+ * All VAPs need to use short preamble for it to be globally
+ * enabled or not.
+ *
+ * Look at the comments for vap_update_erp_protmode() for more
+ * background; this assumes all VAPs are on the same channel.
+ */
+static void
+vap_update_preamble(void *arg, int npending)
+{
+ struct ieee80211vap *vap = arg;
+ struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211vap *iv;
+ int barker_count = 0, short_preamble_count = 0, count = 0;
+
+ /*
+ * Iterate over all of the VAPs to calculate the overlapping
+ * short or long preamble configuration.
+ *
+ * For now we assume that if a driver can handle this per-VAP
+ * then it'll ignore the ic->ic_flags variant and instead
+ * will look at the vap related flags.
+ */
+ IEEE80211_LOCK(ic);
+ TAILQ_FOREACH(iv, &ic->ic_vaps, iv_next) {
+ if (iv->iv_flags & IEEE80211_F_USEBARKER)
+ barker_count++;
+ if (iv->iv_flags & IEEE80211_F_SHPREAMBLE)
+ short_preamble_count++;
+ count++;
+ }
+
+ /*
+ * As with vap_update_erp_protmode(), the global flags are
+ * currently used for beacon IEs.
+ */
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: called; barker_count=%d, short_preamble_count=%d\n",
+ __func__, barker_count, short_preamble_count);
+
+ /*
+ * Only flip on short preamble if all of the VAPs support
+ * it.
+ */
+ if (barker_count == 0 && short_preamble_count == count) {
+ ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
+ ic->ic_flags &= ~IEEE80211_F_USEBARKER;
+ } else {
+ ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
+ ic->ic_flags |= IEEE80211_F_USEBARKER;
+ }
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: global barker=%d preamble=%d\n",
+ __func__,
+ !! (ic->ic_flags & IEEE80211_F_USEBARKER),
+ !! (ic->ic_flags & IEEE80211_F_SHPREAMBLE));
+
+ /* Beacon update on all VAPs */
+ ieee80211_notify_erp_locked(ic);
+
+ IEEE80211_UNLOCK(ic);
+
+ /* Driver notification */
+ if (vap->iv_erp_protmode_update != NULL)
+ vap->iv_preamble_update(vap);
+}
+
+/*
+ * Deferred HT protmode update and beacon update.
+ *
+ * Look at the comments for vap_update_erp_protmode() for more
+ * background; this assumes all VAPs are on the same channel.
+ */
+static void
+vap_update_ht_protmode(void *arg, int npending)
+{
+ struct ieee80211vap *vap = arg;
+ struct ieee80211vap *iv;
+ struct ieee80211com *ic = vap->iv_ic;
+ int num_vaps = 0, num_pure = 0, num_mixed = 0;
+ int num_optional = 0, num_ht2040 = 0, num_nonht = 0;
+ int num_ht_sta = 0, num_ht40_sta = 0, num_sta = 0;
+ int num_nonhtpr = 0;
+
+ /*
+ * Iterate over all of the VAPs to calculate everything.
+ *
+ * There are a few different flags to calculate:
+ *
+ * + whether there's HT only or HT+legacy stations;
+ * + whether there's HT20, HT40, or HT20+HT40 stations;
+ * + whether the desired protection mode is mixed, pure or
+ * one of the two above.
+ *
+ * For now we assume that if a driver can handle this per-VAP
+ * then it'll ignore the ic->ic_htprotmode / ic->ic_curhtprotmode
+ * variant and instead will look at the vap related variables.
+ *
+ * XXX TODO: non-greenfield STAs present (IEEE80211_HTINFO_NONGF_PRESENT) !
+ */
+
+ IEEE80211_LOCK(ic);
+ TAILQ_FOREACH(iv, &ic->ic_vaps, iv_next) {
+ num_vaps++;
+ /* overlapping BSSes advertising non-HT status present */
+ if (iv->iv_flags_ht & IEEE80211_FHT_NONHT_PR)
+ num_nonht++;
+ /* Operating mode flags */
+ if (iv->iv_curhtprotmode & IEEE80211_HTINFO_NONHT_PRESENT)
+ num_nonhtpr++;
+ switch (iv->iv_curhtprotmode & IEEE80211_HTINFO_OPMODE) {
+ case IEEE80211_HTINFO_OPMODE_PURE:
+ num_pure++;
+ break;
+ case IEEE80211_HTINFO_OPMODE_PROTOPT:
+ num_optional++;
+ break;
+ case IEEE80211_HTINFO_OPMODE_HT20PR:
+ num_ht2040++;
+ break;
+ case IEEE80211_HTINFO_OPMODE_MIXED:
+ num_mixed++;
+ break;
+ }
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
+ "%s: vap %s: nonht_pr=%d, curhtprotmode=0x%02x\n",
+ __func__,
+ ieee80211_get_vap_ifname(iv),
+ !! (iv->iv_flags_ht & IEEE80211_FHT_NONHT_PR),
+ iv->iv_curhtprotmode);
+
+ num_ht_sta += iv->iv_ht_sta_assoc;
+ num_ht40_sta += iv->iv_ht40_sta_assoc;
+ num_sta += iv->iv_sta_assoc;
+ }
+
+ /*
+ * Step 1 - if any VAPs indicate NONHT_PR set (overlapping BSS
+ * non-HT present), set it here. This shouldn't be used by
+ * anything but the old overlapping BSS logic so if any drivers
+ * consume it, it's up to date.
+ */
+ if (num_nonht > 0)
+ ic->ic_flags_ht |= IEEE80211_FHT_NONHT_PR;
+ else
+ ic->ic_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
+
+ /*
+ * Step 2 - default HT protection mode to MIXED (802.11-2016 10.26.3.1.)
+ *
+ * + If all VAPs are PURE, we can stay PURE.
+ * + If all VAPs are PROTOPT, we can go to PROTOPT.
+ * + If any VAP has HT20PR then it sees at least a HT40+HT20 station.
+ * Note that we may have a VAP with one HT20 and a VAP with one HT40;
+ * So we look at the sum ht and sum ht40 sta counts; if we have a
+ * HT station and the HT20 != HT40 count, we have to do HT20PR here.
+ * Note all stations need to be HT for this to be an option.
+ * + The fall-through is MIXED, because it means we have some odd
+ * non HT40-involved combination of opmode and this is the most
+ * sensible default.
+ */
+ ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_MIXED;
+
+ if (num_pure == num_vaps)
+ ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
+
+ if (num_optional == num_vaps)
+ ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PROTOPT;
+
+ /*
+ * Note: we need /a/ HT40 station somewhere for this to
+ * be a possibility.
+ */
+ if ((num_ht2040 > 0) ||
+ ((num_ht_sta > 0) && (num_ht40_sta > 0) &&
+ (num_ht_sta != num_ht40_sta)))
+ ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_HT20PR;
+
+ /*
+ * Step 3 - if any of the stations across the VAPs are
+ * non-HT then this needs to be flipped back to MIXED.
+ */
+ if (num_ht_sta != num_sta)
+ ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_MIXED;
+
+ /*
+ * Step 4 - If we see any overlapping BSS non-HT stations
+ * via beacons then flip on NONHT_PRESENT.
+ */
+ if (num_nonhtpr > 0)
+ ic->ic_curhtprotmode |= IEEE80211_HTINFO_NONHT_PRESENT;
+
+ /* Notify all VAPs to potentially update their beacons */
+ TAILQ_FOREACH(iv, &ic->ic_vaps, iv_next)
+ ieee80211_htinfo_notify(iv);
+
+ IEEE80211_UNLOCK(ic);
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
+ "%s: global: nonht_pr=%d ht_opmode=0x%02x\n",
+ __func__,
+ !! (ic->ic_flags_ht & IEEE80211_FHT_NONHT_PR),
+ ic->ic_curhtprotmode);
+
+ /* Driver update */
+ if (vap->iv_erp_protmode_update != NULL)
+ vap->iv_ht_protmode_update(vap);
+}
+
+/*
* Set the short slot time state and notify the driver.
*
* This is the per-VAP slot time state.
@@ -878,6 +1195,8 @@ ieee80211_vap_set_shortslottime(struct ieee80211vap *vap, int onoff)
{
struct ieee80211com *ic = vap->iv_ic;
+ /* XXX lock? */
+
/*
* Only modify the per-VAP slot time.
*/
@@ -886,11 +1205,69 @@ ieee80211_vap_set_shortslottime(struct ieee80211vap *vap, int onoff)
else
vap->iv_flags &= ~IEEE80211_F_SHSLOT;
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: called; onoff=%d\n", __func__, onoff);
/* schedule the deferred slot flag update and update */
ieee80211_runtask(ic, &vap->iv_slot_task);
}
/*
+ * Update the VAP short /long / barker preamble state and
+ * update beacon state if needed.
+ *
+ * For now it simply copies the global flags into the per-vap
+ * flags and schedules the callback. Later this will support
+ * both global and per-VAP flags, especially useful for
+ * and STA+STA multi-channel operation (eg p2p).
+ */
+void
+ieee80211_vap_update_preamble(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ /* XXX lock? */
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: called\n", __func__);
+ /* schedule the deferred slot flag update and update */
+ ieee80211_runtask(ic, &vap->iv_preamble_task);
+}
+
+/*
+ * Update the VAP 11g protection mode and update beacon state
+ * if needed.
+ */
+void
+ieee80211_vap_update_erp_protmode(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ /* XXX lock? */
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: called\n", __func__);
+ /* schedule the deferred slot flag update and update */
+ ieee80211_runtask(ic, &vap->iv_erp_protmode_task);
+}
+
+/*
+ * Update the VAP 11n protection mode and update beacon state
+ * if needed.
+ */
+void
+ieee80211_vap_update_ht_protmode(struct ieee80211vap *vap)
+{
+ struct ieee80211com *ic = vap->iv_ic;
+
+ /* XXX lock? */
+
+ IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG,
+ "%s: called\n", __func__);
+ /* schedule the deferred protmode update */
+ ieee80211_runtask(ic, &vap->iv_ht_protmode_task);
+}
+
+/*
* Check if the specified rate set supports ERP.
* NB: the rate set is assumed to be sorted.
*/
@@ -1344,7 +1721,7 @@ ieee80211_wme_updateparams_locked(struct ieee80211vap *vap)
* further.
*/
if (vap->iv_opmode == IEEE80211_M_HOSTAP &&
- ic->ic_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) {
+ vap->iv_sta_assoc < 2 && (wme->wme_flags & WME_F_AGGRMODE) != 0) {
static const uint8_t logCwMin[IEEE80211_MODE_MAX] = {
[IEEE80211_MODE_AUTO] = 3,
[IEEE80211_MODE_11A] = 3,
@@ -1370,22 +1747,6 @@ ieee80211_wme_updateparams_locked(struct ieee80211vap *vap)
ieee80211_wme_acnames[WME_AC_BE], chanp->wmep_logcwmin);
}
- /*
- * Arrange for the beacon update.
- *
- * XXX what about MBSS, WDS?
- */
- if (vap->iv_opmode == IEEE80211_M_HOSTAP
- || vap->iv_opmode == IEEE80211_M_IBSS) {
- /*
- * Arrange for a beacon update and bump the parameter
- * set number so associated stations load the new values.
- */
- wme->wme_bssChanParams.cap_info =
- (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT;
- ieee80211_beacon_notify(vap, IEEE80211_BEACON_WME);
- }
-
/* schedule the deferred WME update */
ieee80211_runtask(ic, &vap->iv_wme_task);
@@ -1499,7 +1860,7 @@ update_chw(void *arg, int npending)
}
/*
- * Deferred WME update.
+ * Deferred WME parameter and beacon update.
*
* In preparation for per-VAP WME configuration, call the VAP
* method if the VAP requires it. Otherwise, just call the
@@ -1511,12 +1872,32 @@ vap_update_wme(void *arg, int npending)
{
struct ieee80211vap *vap = arg;
struct ieee80211com *ic = vap->iv_ic;
+ struct ieee80211_wme_state *wme = &ic->ic_wme;
+ /* Driver update */
if (vap->iv_wme_update != NULL)
vap->iv_wme_update(vap,
ic->ic_wme.wme_chanParams.cap_wmeParams);
else
ic->ic_wme.wme_update(ic);
+
+ IEEE80211_LOCK(ic);
+ /*
+ * Arrange for the beacon update.
+ *
+ * XXX what about MBSS, WDS?
+ */
+ if (vap->iv_opmode == IEEE80211_M_HOSTAP
+ || vap->iv_opmode == IEEE80211_M_IBSS) {
+ /*
+ * Arrange for a beacon update and bump the parameter
+ * set number so associated stations load the new values.
+ */
+ wme->wme_bssChanParams.cap_info =
+ (wme->wme_bssChanParams.cap_info+1) & WME_QOSINFO_COUNT;
+ ieee80211_beacon_notify(vap, IEEE80211_BEACON_WME);
+ }
+ IEEE80211_UNLOCK(ic);
}
static void
diff --git a/sys/net80211/ieee80211_proto.h b/sys/net80211/ieee80211_proto.h
index f445da39b257..1f255f4c736a 100644
--- a/sys/net80211/ieee80211_proto.h
+++ b/sys/net80211/ieee80211_proto.h
@@ -303,6 +303,9 @@ void ieee80211_wme_vap_getparams(struct ieee80211vap *vap,
void ieee80211_wme_ic_getparams(struct ieee80211com *ic,
struct chanAccParams *);
int ieee80211_wme_vap_ac_is_noack(struct ieee80211vap *vap, int ac);
+void ieee80211_vap_update_preamble(struct ieee80211vap *vap);
+void ieee80211_vap_update_erp_protmode(struct ieee80211vap *vap);
+void ieee80211_vap_update_ht_protmode(struct ieee80211vap *vap);
/*
* Return pointer to the QoS field from a Qos frame.
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index ab446d94b081..f852c4b88b58 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -1460,12 +1460,13 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
ni->ni_erp, scan.erp);
if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
(ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
- ic->ic_flags |= IEEE80211_F_USEPROT;
+ vap->iv_flags |= IEEE80211_F_USEPROT;
else
- ic->ic_flags &= ~IEEE80211_F_USEPROT;
+ vap->iv_flags &= ~IEEE80211_F_USEPROT;
ni->ni_erp = scan.erp;
/* XXX statistic */
- /* XXX driver notification */
+ /* driver notification */
+ ieee80211_vap_update_erp_protmode(vap);
}
if ((ni->ni_capinfo ^ scan.capinfo) & IEEE80211_CAPINFO_SHORT_SLOTTIME) {
IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_ASSOC,
@@ -1891,15 +1892,16 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
*/
if (IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
- ic->ic_flags |= IEEE80211_F_SHPREAMBLE;
- ic->ic_flags &= ~IEEE80211_F_USEBARKER;
+ vap->iv_flags |= IEEE80211_F_SHPREAMBLE;
+ vap->iv_flags &= ~IEEE80211_F_USEBARKER;
} else {
- ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
- ic->ic_flags |= IEEE80211_F_USEBARKER;
+ vap->iv_flags &= ~IEEE80211_F_SHPREAMBLE;
+ vap->iv_flags |= IEEE80211_F_USEBARKER;
}
ieee80211_vap_set_shortslottime(vap,
IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
+ ieee80211_vap_update_preamble(vap);
/*
* Honor ERP protection.
*
@@ -1907,17 +1909,18 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
*/
if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
(ni->ni_erp & IEEE80211_ERP_USE_PROTECTION))
- ic->ic_flags |= IEEE80211_F_USEPROT;
+ vap->iv_flags |= IEEE80211_F_USEPROT;
else
- ic->ic_flags &= ~IEEE80211_F_USEPROT;
+ vap->iv_flags &= ~IEEE80211_F_USEPROT;
+ ieee80211_vap_update_erp_protmode(vap);
IEEE80211_NOTE_MAC(vap,
IEEE80211_MSG_ASSOC | IEEE80211_MSG_DEBUG, wh->i_addr2,
"%sassoc success at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s%s",
ISREASSOC(subtype) ? "re" : "",
IEEE80211_NODE_AID(ni),
- ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
+ vap->iv_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
vap->iv_flags&IEEE80211_F_SHSLOT ? "short" : "long",
- ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
+ vap->iv_flags&IEEE80211_F_USEPROT ? ", protection" : "",
ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
ni->ni_flags & IEEE80211_NODE_HT ?
(ni->ni_chw == 40 ? ", HT40" : ", HT20") : "",
diff --git a/sys/net80211/ieee80211_var.h b/sys/net80211/ieee80211_var.h
index 84b69da7ec2b..fba82cc3d28e 100644
--- a/sys/net80211/ieee80211_var.h
+++ b/sys/net80211/ieee80211_var.h
@@ -233,17 +233,11 @@ struct ieee80211com {
/* XXX multi-bss: split out common/vap parts */
struct ieee80211_wme_state ic_wme; /* WME/WMM state */
- /* XXX multi-bss: can per-vap be done/make sense? */
+ /* Protection mode for net80211 driven channel NICs */
enum ieee80211_protmode ic_protmode; /* 802.11g protection mode */
- uint16_t ic_nonerpsta; /* # non-ERP stations */
- uint16_t ic_longslotsta; /* # long slot time stations */
- uint16_t ic_sta_assoc; /* stations associated */
- uint16_t ic_ht_sta_assoc;/* HT stations associated */
- uint16_t ic_ht40_sta_assoc;/* HT40 stations associated */
- uint8_t ic_curhtprotmode;/* HTINFO bss state */
enum ieee80211_protmode ic_htprotmode; /* HT protection mode */
- int ic_lastnonerp; /* last time non-ERP sta noted*/
- int ic_lastnonht; /* last time non-HT sta noted */
+ uint8_t ic_curhtprotmode;/* HTINFO bss state */
+
uint8_t ic_rxstream; /* # RX streams */
uint8_t ic_txstream; /* # TX streams */
@@ -391,6 +385,8 @@ struct ieee80211_aclator;
struct ieee80211_tdma_state;
struct ieee80211_mesh_state;
struct ieee80211_hwmp_state;
+struct ieee80211_rx_histogram;
+struct ieee80211_tx_histogram;
struct ieee80211vap {
struct ifmedia iv_media; /* interface media config */
@@ -577,13 +573,38 @@ struct ieee80211vap {
const struct wmeParams *wme_params);
struct task iv_wme_task; /* deferred VAP WME update */
+ /* associated state; protection mode */
+ enum ieee80211_protmode iv_protmode; /* 802.11g protection mode */
+ enum ieee80211_protmode iv_htprotmode; /* HT protection mode */
+ uint8_t iv_curhtprotmode;/* HTINFO bss state */
+
+ uint16_t iv_nonerpsta; /* # non-ERP stations */
+ uint16_t iv_longslotsta; /* # long slot time stations */
+ uint16_t iv_ht_sta_assoc;/* HT stations associated */
+ uint16_t iv_ht40_sta_assoc;/* HT40 stations associated */
+ int iv_lastnonerp; /* last time non-ERP sta noted*/
+ int iv_lastnonht; /* last time non-HT sta noted */
+
/* update device state for 802.11 slot time change */
void (*iv_updateslot)(struct ieee80211vap *);
struct task iv_slot_task; /* deferred slot time update */
+ struct task iv_erp_protmode_task; /* deferred ERP protmode update */
+ void (*iv_erp_protmode_update)(struct ieee80211vap *);
+
+ struct task iv_preamble_task; /* deferred short/barker preamble update */
+ void (*iv_preamble_update)(struct ieee80211vap *);
+
+ struct task iv_ht_protmode_task; /* deferred HT protmode update */
+ void (*iv_ht_protmode_update)(struct ieee80211vap *);
+
/* per-vap U-APSD state */
uint8_t iv_uapsdinfo; /* sta mode QoS Info flags */
+ /* Optional transmit/receive histogram statistics */
+ struct ieee80211_rx_histogram *rx_histogram;
+ struct ieee80211_tx_histogram *tx_histogram;
+
uint64_t iv_spare[6];
};
MALLOC_DECLARE(M_80211_VAP);