[net80211] Migrate short slot time configuration into per-vap and deferred taskqueue updates.

The 11b/11g ERP and slot time update handling are two things which weren't
migrated into the per-VAP state when Sam did the initial VAP work.
That makes sense for a lot of setups where net80211 is driving radio state
and the radio only cares about the shared state.

However, as noted by a now deleted comment, the ERP and slot time updates
aren't EXACTLY correct/accurate - they only take into account the most
RECENTLY created VAP, and the state updates when one creates/destroys
VAPs isn't exactly great.

So:

* track the short slot logic per VAP;
* whenever the slot time configuration changes, just push it into a deferred
  task queue update so drivers don't have to serialise it themselves;
* if a driver registers a per-VAP slot time handler then it'll just get the
  per VAP one;
* .. if a driver registers a global one then the legacy behaviour is maintained -
  a single slot time is calculated and pushed out.

Note that the calculated slot time is better than the existing logic - if ANY
of the VAPs require long slot then it's disabled for all VAPs rather than
whatever the last configured VAP did.

Now, this isn't entirely complete - the rest of ERP tracking around short/long
slot capable station tracking needs to be converted into per-VAP, as well
as the preamble/barker flags.  Luckily those also can be done in a similar
fashion - keep per-VAP counters/flags and unify them before doing the driver
update.  I'll defer that work until later.

All the existing drivers can keep doing what they're doing with the global
slot time flags as that is maintained. One driver (iwi) used the per-VAP
flags instead of the ic flags, so now that driver will work properly.

This unblocks some ath10k porting work as the firmware takes the slot time
configuration per-VAP rather than globally, and some firmware handles
STA+AP and STA+STA (on same/different channels) configurations where
the firmware will switch slot time as appropriate.

Tested:

* AR9380, STA/AP mode
* AR9880 (ath10k), STA mode
This commit is contained in:
Adrian Chadd 2020-06-05 06:21:23 +00:00
parent 7280f37401
commit d20ff6e680
8 changed files with 145 additions and 30 deletions

View File

@ -645,6 +645,7 @@ ieee80211_vap_setup(struct ieee80211com *ic, struct ieee80211vap *vap,
ieee80211_scan_vattach(vap);
ieee80211_regdomain_vattach(vap);
ieee80211_radiotap_vattach(vap);
ieee80211_vap_reset_erp(vap);
ieee80211_ratectl_set(vap, IEEE80211_RATECTL_NONE);
return 0;
@ -2200,7 +2201,7 @@ ieee80211_setmode(struct ieee80211com *ic, enum ieee80211_phymode mode)
ieee80211_setbasicrates(&ic->ic_sup_rates[mode], mode);
ic->ic_curmode = mode;
ieee80211_reset_erp(ic); /* reset ERP state */
ieee80211_reset_erp(ic); /* reset global ERP state */
return 0;
}

View File

@ -446,7 +446,7 @@ ieee80211_reset_bss(struct ieee80211vap *vap)
ieee80211_node_table_reset(&ic->ic_sta, vap);
/* XXX multi-bss: wrong */
ieee80211_reset_erp(ic);
ieee80211_vap_reset_erp(vap);
ni = ieee80211_alloc_node(&ic->ic_sta, vap, vap->iv_myaddr);
KASSERT(ni != NULL, ("unable to setup initial BSS node"));
@ -682,7 +682,7 @@ ieee80211_ibss_merge(struct ieee80211_node *ni)
"%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",
ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
vap->iv_flags&IEEE80211_F_SHSLOT ? "short" : "long",
ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : ""
);
return ieee80211_sta_join1(ieee80211_ref_node(ni));
@ -881,7 +881,7 @@ ieee80211_sta_join1(struct ieee80211_node *selbs)
* the auto-select case; this should be redundant if the
* mode is locked.
*/
ieee80211_reset_erp(ic);
ieee80211_vap_reset_erp(vap);
ieee80211_wme_initparams(vap);
if (vap->iv_opmode == IEEE80211_M_STA) {
@ -2645,6 +2645,7 @@ static void
ieee80211_node_join_11g(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap;
IEEE80211_LOCK_ASSERT(ic);
@ -2660,14 +2661,13 @@ ieee80211_node_join_11g(struct ieee80211_node *ni)
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ASSOC, ni,
"station needs long slot time, count %d",
ic->ic_longslotsta);
/* XXX vap's w/ conflicting needs won't work */
if (!IEEE80211_IS_CHAN_108G(ic->ic_bsschan)) {
/*
* Don't force slot time when switched to turbo
* mode as non-ERP stations won't be present; this
* need only be done when on the normal G channel.
*/
ieee80211_set_shortslottime(ic, 0);
ieee80211_vap_set_shortslottime(vap, 0);
}
}
/*
@ -2757,7 +2757,7 @@ ieee80211_node_join(struct ieee80211_node *ni, int resp)
"station associated at aid %d: %s preamble, %s slot time%s%s%s%s%s%s%s%s",
IEEE80211_NODE_AID(ni),
ic->ic_flags & IEEE80211_F_SHPREAMBLE ? "short" : "long",
ic->ic_flags & IEEE80211_F_SHSLOT ? "short" : "long",
vap->iv_flags & IEEE80211_F_SHSLOT ? "short" : "long",
ic->ic_flags & IEEE80211_F_USEPROT ? ", protection" : "",
ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
/* XXX update for VHT string */
@ -2810,6 +2810,7 @@ static void
ieee80211_node_leave_11g(struct ieee80211_node *ni)
{
struct ieee80211com *ic = ni->ni_ic;
struct ieee80211vap *vap = ni->ni_vap;
IEEE80211_LOCK_ASSERT(ic);
@ -2838,7 +2839,7 @@ ieee80211_node_leave_11g(struct ieee80211_node *ni)
IEEE80211_MSG_ASSOC,
"%s: re-enable use of short slot time\n",
__func__);
ieee80211_set_shortslottime(ic, 1);
ieee80211_vap_set_shortslottime(vap, 1);
}
}
}

View File

@ -2522,7 +2522,7 @@ ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan)
if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
IEEE80211_IS_CHAN_2GHZ(chan))
capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
if (ic->ic_flags & IEEE80211_F_SHSLOT)
if (vap->iv_flags & IEEE80211_F_SHSLOT)
capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH))
capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT;

View File

@ -55,10 +55,25 @@
#define IEEE80211_DUR_SHSLOT 9 /* ERP short slottime */
#define IEEE80211_DUR_OFDM_SLOT 9 /* OFDM slottime */
/*
* For drivers that don't implement per-VAP slot time
* (ie, they rely on net80211 figuring out the union
* between VAPs to program a single radio) - return
* the current radio configured slot time.
*/
#define IEEE80211_GET_SLOTTIME(ic) \
((ic->ic_flags & IEEE80211_F_SHSLOT) ? \
IEEE80211_DUR_SHSLOT : IEEE80211_DUR_SLOT)
/*
* For drivers that implement per-VAP slot time; look
* at the per-VAP flags to determine whether this VAP
* is in short or long slot time.
*/
#define IEEE80211_VAP_GET_SLOTTIME(vap) \
((vap->iv_flags & IEEE80211_F_SHSLOT) ? \
IEEE80211_DUR_SHSLOT : IEEE80211_DUR_SLOT)
/*
* DIFS (microseconds).
*/

View File

@ -244,6 +244,7 @@ static void update_promisc(void *, int);
static void update_channel(void *, int);
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 ieee80211_newstate_cb(void *, int);
@ -340,6 +341,7 @@ ieee80211_proto_vattach(struct ieee80211vap *vap)
TASK_INIT(&vap->iv_nstate_task, 0, ieee80211_newstate_cb, 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);
/*
* Install default tx rate handling: no fixed rate, lowest
* supported rate for mgmt and multicast frames. Default
@ -748,6 +750,32 @@ ieee80211_fix_rate(struct ieee80211_node *ni,
return IEEE80211_RV(okrate);
}
/*
* Reset 11g-related state.
*
* This is for per-VAP ERP/11g state.
*
* Eventually everything in ieee80211_reset_erp() will be
* per-VAP and in here.
*/
void
ieee80211_vap_reset_erp(struct ieee80211vap *vap)
{
struct ieee80211com *ic = vap->iv_ic;
/*
* 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.
*/
ieee80211_vap_set_shortslottime(vap,
IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
IEEE80211_IS_CHAN_HT(ic->ic_curchan) ||
(IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
vap->iv_opmode == IEEE80211_M_HOSTAP &&
(ic->ic_caps & IEEE80211_C_SHSLOT)));
}
/*
* Reset 11g-related state.
*/
@ -757,17 +785,6 @@ ieee80211_reset_erp(struct ieee80211com *ic)
ic->ic_flags &= ~IEEE80211_F_USEPROT;
ic->ic_nonerpsta = 0;
ic->ic_longslotsta = 0;
/*
* 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.
*/
ieee80211_set_shortslottime(ic,
IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
IEEE80211_IS_CHAN_HT(ic->ic_curchan) ||
(IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) &&
ic->ic_opmode == IEEE80211_M_HOSTAP &&
(ic->ic_caps & IEEE80211_C_SHSLOT)));
/*
* Set short preamble and ERP barker-preamble flags.
*/
@ -781,19 +798,95 @@ ieee80211_reset_erp(struct ieee80211com *ic)
}
}
/*
* Deferred slot time update.
*
* For per-VAP slot time configuration, call the VAP
* method if the VAP requires it. Otherwise, just call the
* older global method.
*
* If the per-VAP method is called then it's expected that
* the driver/firmware will take care of turning the per-VAP
* flags into slot time configuration.
*
* 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.
*/
static void
vap_update_slot(void *arg, int npending)
{
struct ieee80211vap *vap = arg;
struct ieee80211com *ic = vap->iv_ic;
struct ieee80211vap *iv;
int num_shslot = 0, num_lgslot = 0;
/*
* Per-VAP path - we've already had the flags updated;
* so just notify the driver and move on.
*/
if (vap->iv_updateslot != NULL) {
vap->iv_updateslot(vap);
return;
}
/*
* Iterate over all of the VAP flags to update the
* global flag.
*
* If all vaps have short slot enabled then flip on
* short slot. If any vap has it disabled then
* we leave it globally disabled. This should provide
* correct behaviour in a multi-BSS scenario where
* at least one VAP has short slot disabled for some
* reason.
*/
IEEE80211_LOCK(ic);
TAILQ_FOREACH(iv, &ic->ic_vaps, iv_next) {
if (iv->iv_flags & IEEE80211_F_SHSLOT)
num_shslot++;
else
num_lgslot++;
}
IEEE80211_UNLOCK(ic);
/*
* It looks backwards but - if the number of short slot VAPs
* is zero then we're not short slot. Else, we have one
* or more short slot VAPs and we're checking to see if ANY
* of them have short slot disabled.
*/
if (num_shslot == 0)
ic->ic_flags &= ~IEEE80211_F_SHSLOT;
else if (num_lgslot == 0)
ic->ic_flags |= IEEE80211_F_SHSLOT;
/*
* Call the driver with our new global slot time flags.
*/
ic->ic_updateslot(ic);
}
/*
* Set the short slot time state and notify the driver.
*
* This is the per-VAP slot time state.
*/
void
ieee80211_set_shortslottime(struct ieee80211com *ic, int onoff)
ieee80211_vap_set_shortslottime(struct ieee80211vap *vap, int onoff)
{
struct ieee80211com *ic = vap->iv_ic;
/*
* Only modify the per-VAP slot time.
*/
if (onoff)
ic->ic_flags |= IEEE80211_F_SHSLOT;
vap->iv_flags |= IEEE80211_F_SHSLOT;
else
ic->ic_flags &= ~IEEE80211_F_SHSLOT;
/* notify driver */
if (ic->ic_updateslot != NULL)
ic->ic_updateslot(ic);
vap->iv_flags &= ~IEEE80211_F_SHSLOT;
/* schedule the deferred slot flag update and update */
ieee80211_runtask(ic, &vap->iv_slot_task);
}
/*

View File

@ -154,8 +154,9 @@ uint16_t ieee80211_getcapinfo(struct ieee80211vap *,
struct ieee80211_wme_state;
uint8_t * ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme);
void ieee80211_vap_reset_erp(struct ieee80211vap *);
void ieee80211_reset_erp(struct ieee80211com *);
void ieee80211_set_shortslottime(struct ieee80211com *, int onoff);
void ieee80211_vap_set_shortslottime(struct ieee80211vap *, int onoff);
int ieee80211_iserp_rateset(const struct ieee80211_rateset *);
void ieee80211_setbasicrates(struct ieee80211_rateset *,
enum ieee80211_phymode);

View File

@ -1435,7 +1435,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
* NB: we assume short preamble doesn't
* change dynamically
*/
ieee80211_set_shortslottime(ic,
ieee80211_vap_set_shortslottime(vap,
IEEE80211_IS_CHAN_A(ic->ic_bsschan) ||
(scan.capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
ni->ni_capinfo = (ni->ni_capinfo &~ IEEE80211_CAPINFO_SHORT_SLOTTIME)
@ -1847,7 +1847,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
ic->ic_flags &= ~IEEE80211_F_SHPREAMBLE;
ic->ic_flags |= IEEE80211_F_USEBARKER;
}
ieee80211_set_shortslottime(ic,
ieee80211_vap_set_shortslottime(vap,
IEEE80211_IS_CHAN_A(ic->ic_curchan) ||
(ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME));
/*
@ -1866,7 +1866,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
ISREASSOC(subtype) ? "re" : "",
IEEE80211_NODE_AID(ni),
ic->ic_flags&IEEE80211_F_SHPREAMBLE ? "short" : "long",
ic->ic_flags&IEEE80211_F_SHSLOT ? "short" : "long",
vap->iv_flags&IEEE80211_F_SHSLOT ? "short" : "long",
ic->ic_flags&IEEE80211_F_USEPROT ? ", protection" : "",
ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
ni->ni_flags & IEEE80211_NODE_HT ?

View File

@ -563,6 +563,10 @@ struct ieee80211vap {
const struct wmeParams *wme_params);
struct task iv_wme_task; /* deferred VAP WME update */
/* update device state for 802.11 slot time change */
void (*iv_updateslot)(struct ieee80211vap *);
struct task iv_slot_task; /* deferred slot time update */
uint64_t iv_spare[6];
};
MALLOC_DECLARE(M_80211_VAP);