From owner-svn-src-head@freebsd.org Wed Jul 1 00:23:51 2020 Return-Path: Delivered-To: svn-src-head@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 979DA3595AE; Wed, 1 Jul 2020 00:23:51 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 49xMQv3sMdz47Th; Wed, 1 Jul 2020 00:23:51 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 68B592064F; Wed, 1 Jul 2020 00:23:51 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 0610Npqm031545; Wed, 1 Jul 2020 00:23:51 GMT (envelope-from adrian@FreeBSD.org) Received: (from adrian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 0610Nn4w031533; Wed, 1 Jul 2020 00:23:49 GMT (envelope-from adrian@FreeBSD.org) Message-Id: <202007010023.0610Nn4w031533@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: adrian set sender to adrian@FreeBSD.org using -f From: Adrian Chadd Date: Wed, 1 Jul 2020 00:23:49 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r362815 - head/sys/net80211 X-SVN-Group: head X-SVN-Commit-Author: adrian X-SVN-Commit-Paths: head/sys/net80211 X-SVN-Commit-Revision: 362815 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.33 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Jul 2020 00:23:51 -0000 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 ***