diff options
| author | Adrian Chadd <adrian@FreeBSD.org> | 2020-07-01 00:23:49 +0000 |
|---|---|---|
| committer | Adrian Chadd <adrian@FreeBSD.org> | 2020-07-01 00:23:49 +0000 |
| commit | f1481c8d3b58eacdded319a76413062dac228574 (patch) | |
| tree | f3afe3458ea712d17fb772ab1e45d6cb3efbe8f1 /sys | |
| parent | 7290cb47fced28b5d0654cd1de7cc721e214ea32 (diff) | |
Notes
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/net80211/ieee80211_ddb.c | 20 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_hostap.c | 24 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_ht.c | 140 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_ioctl.c | 12 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_node.c | 142 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_node.h | 2 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_output.c | 39 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_power.c | 2 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_proto.c | 425 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_proto.h | 3 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_sta.c | 25 | ||||
| -rw-r--r-- | sys/net80211/ieee80211_var.h | 39 |
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); |
