svn commit: r362815 - head/sys/net80211
Adrian Chadd
adrian at FreeBSD.org
Wed Jul 1 00:23:51 UTC 2020
Author: adrian
Date: Wed Jul 1 00:23:49 2020
New Revision: 362815
URL: https://svnweb.freebsd.org/changeset/base/362815
Log:
[net80211] Migrate HT/legacy protection mode and preamble calculation to per-VAP flags
The later firmware devices (including iwn!) support multiple configuration
contexts for a lot of things, leaving it up to the firmware to decide
which channel and vap is active. This allows for things like off-channel
p2p sta/ap operation and other weird things.
However, net80211 is still focused on a "net80211 drives all" when it comes to driving
the NIC, and as part of this history a lot of these options are global and not per-VAP.
This is fine when net80211 drives things and all VAPs share a single channel - these
parameters importantly really reflect the state of the channel! - but it will increasingly
be not fine when we start supporting more weird configurations and more recent NICs.
Yeah, recent like iwn/iwm.
Anyway - so, migrate all of the HT protection, legacy protection and preamble
stuff to be per-VAP. The global flags are still there; they're now calculated
in a deferred taskqueue that mirrors the old behaviour. Firmware based drivers
which have per-VAP configuration of these parameters can now just listen to the
per-VAP options.
What do I mean by per-channel? Well, the above configuration parameters really
are about interoperation with other devices on the same channel. Eg, HT protection
mode will flip to legacy/mixed if it hears ANY BSS that supports non-HT stations or
indicates it has non-HT stations associated. So, these flags really should be
per-channel rather than per-VAP, and then for things like "do i need short preamble
or long preamble?" turn into a "do I need it for this current operating channel".
Then any VAP using it can query the channel that it's on, reflecting the real
required state.
This patch does none of the above paragraph just yet.
I'm also cheating a bit - I'm currently not using separate taskqueues for
the beacon updates and the per-VAP configuration updates. I can always further
split it later if I need to but I didn't think it was SUPER important here.
So:
* Create vap taskqueue entries for ERP/protection, HT protection and short/long
preamble;
* Migrate the HT station count, short/long slot station count, etc - into per-VAP
variables rather than global;
* Fix a bug with my WME work from a while ago which made it per-VAP - do the WME
beacon update /after/ the WME update taskqueue runs, not before;
* Any time the HT protmode configuration changes or the ERP protection mode
config changes - schedule the task, which will call the driver without the
net80211 lock held and all correctly serialised;
* Use the global flags for beacon IEs and VAP flags for probe responses and
other IE situations.
The primary consumer of this is ath10k. iwn could use it when sending RXON,
but we don't support IBSS or AP modes on it yet, and I'm not yet sure whether
it's required in STA mode (ie whether the firmware parses beacons to change
protection mode or whether we need to.)
Tested:
* AR9280, STA/AP
* AR9380, DWDS STA+STA/AP
* ath10k work, STA/AP
* Intel 6235, STA
* Various rtwn / run NICs, DWDS STA and STA configurations
Modified:
head/sys/net80211/ieee80211_ddb.c
head/sys/net80211/ieee80211_hostap.c
head/sys/net80211/ieee80211_ht.c
head/sys/net80211/ieee80211_ioctl.c
head/sys/net80211/ieee80211_node.c
head/sys/net80211/ieee80211_node.h
head/sys/net80211/ieee80211_output.c
head/sys/net80211/ieee80211_power.c
head/sys/net80211/ieee80211_proto.c
head/sys/net80211/ieee80211_proto.h
head/sys/net80211/ieee80211_sta.c
head/sys/net80211/ieee80211_var.h
Modified: head/sys/net80211/ieee80211_ddb.c
==============================================================================
--- head/sys/net80211/ieee80211_ddb.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_ddb.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -483,6 +483,17 @@ _db_show_vap(const struct ieee80211vap *vap, int showm
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 showva
_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);
Modified: head/sys/net80211/ieee80211_hostap.c
==============================================================================
--- head/sys/net80211/ieee80211_hostap.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_hostap.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -206,8 +206,9 @@ hostap_newstate(struct ieee80211vap *vap, enum ieee802
* 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 mbu
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 mbu
"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 mbu
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);
}
Modified: head/sys/net80211/ieee80211_ht.c
==============================================================================
--- head/sys/net80211/ieee80211_ht.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_ht.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -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 p
* 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 ieee802
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;
Modified: head/sys/net80211/ieee80211_ioctl.c
==============================================================================
--- head/sys/net80211/ieee80211_ioctl.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_ioctl.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -851,7 +851,7 @@ ieee80211_ioctl_get80211(struct ieee80211vap *vap, u_l
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_l
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_l
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_l
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);
Modified: head/sys/net80211/ieee80211_node.c
==============================================================================
--- head/sys/net80211/ieee80211_node.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_node.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -99,7 +99,7 @@ static void ieee80211_node_table_init(struct ieee80211
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 res
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 res
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 res
}
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);
Modified: head/sys/net80211/ieee80211_node.h
==============================================================================
--- head/sys/net80211/ieee80211_node.h Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_node.h Wed Jul 1 00:23:49 2020 (r362815)
@@ -479,7 +479,7 @@ int ieee80211_iterate_nodes_vap(struct ieee80211_node_
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 *);
Modified: head/sys/net80211/ieee80211_output.c
==============================================================================
--- head/sys/net80211/ieee80211_output.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_output.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -2100,15 +2100,34 @@ ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid,
* 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
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 typ
* 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,
}
}
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
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
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
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 *fr
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, str
/*
* 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
Modified: head/sys/net80211/ieee80211_power.c
==============================================================================
--- head/sys/net80211/ieee80211_power.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_power.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -335,7 +335,7 @@ ieee80211_pwrsave(struct ieee80211_node *ni, struct mb
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
Modified: head/sys/net80211/ieee80211_proto.c
==============================================================================
--- head/sys/net80211/ieee80211_proto.c Tue Jun 30 22:01:21 2020 (r362814)
+++ head/sys/net80211/ieee80211_proto.c Wed Jul 1 00:23:49 2020 (r362815)
@@ -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,7 +770,23 @@ 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
* the driver is capable of doing it.
@@ -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;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list