From de6aafaa637049b6553320fc607a54c63f915b34 Mon Sep 17 00:00:00 2001 From: Haim Dreyfuss Date: Wed, 3 Apr 2019 19:07:53 +0300 Subject: [PATCH] AP: Consider regulatory limitation when filling WMM element In case the current channel has regulatory WMM limitations, take them into account when filling the WMM element. Also check if the new WMM element is different from the previous one and if so change the parameter_set_count to imply stations to look into it. Signed-off-by: Haim Dreyfuss --- src/ap/hostapd.h | 3 +++ src/ap/wmm.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index f573717d1..52b5dbc69 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -551,6 +551,9 @@ struct hostapd_iface { #ifdef CONFIG_AIRTIME_POLICY unsigned int airtime_quantum; #endif /* CONFIG_AIRTIME_POLICY */ + + /* Previous WMM element information */ + struct hostapd_wmm_ac_params prev_wmm[WMM_AC_NUM]; }; /* hostapd.c */ diff --git a/src/ap/wmm.c b/src/ap/wmm.c index 8054c5d2f..dc7349337 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -20,6 +20,13 @@ #include "ap_drv_ops.h" #include "wmm.h" +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci) { @@ -39,6 +46,62 @@ static inline u8 wmm_ecw(int ecwmin, int ecwmax) } +static void +wmm_set_regulatory_limit(const struct hostapd_wmm_ac_params *wmm_conf, + struct hostapd_wmm_ac_params *wmm, + const struct hostapd_wmm_rule *wmm_reg) +{ + int ac; + + for (ac = 0; ac < WMM_AC_NUM; ac++) { + wmm[ac].cwmin = MAX(wmm_conf[ac].cwmin, wmm_reg[ac].min_cwmin); + wmm[ac].cwmax = MAX(wmm_conf[ac].cwmax, wmm_reg[ac].min_cwmax); + wmm[ac].aifs = MAX(wmm_conf[ac].aifs, wmm_reg[ac].min_aifs); + wmm[ac].txop_limit = + MIN(wmm_conf[ac].txop_limit, wmm_reg[ac].max_txop); + wmm[ac].admission_control_mandatory = + wmm_conf[ac].admission_control_mandatory; + } +} + + +/* + * Calculate WMM regulatory limit if any. + */ +static void wmm_calc_regulatory_limit(struct hostapd_data *hapd, + struct hostapd_wmm_ac_params *acp) +{ + struct hostapd_hw_modes *mode = hapd->iface->current_mode; + int c; + + os_memcpy(acp, hapd->iconf->wmm_ac_params, + sizeof(hapd->iconf->wmm_ac_params)); + + for (c = 0; mode && c < mode->num_channels; c++) { + struct hostapd_channel_data *chan = &mode->channels[c]; + + if (chan->freq != hapd->iface->freq) + continue; + + if (chan->wmm_rules_valid) + wmm_set_regulatory_limit(hapd->iconf->wmm_ac_params, + acp, chan->wmm_rules); + break; + } + + /* + * Check if we need to update set count. Since both were initialized to + * zero we can compare the whole array in one shot. + */ + if (os_memcmp(acp, hapd->iface->prev_wmm, + sizeof(hapd->iconf->wmm_ac_params)) != 0) { + os_memcpy(hapd->iface->prev_wmm, acp, + sizeof(hapd->iconf->wmm_ac_params)); + hapd->parameter_set_count++; + } +} + + /* * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association * Response frames. @@ -48,10 +111,12 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) u8 *pos = eid; struct wmm_parameter_element *wmm = (struct wmm_parameter_element *) (pos + 2); + struct hostapd_wmm_ac_params wmmp[WMM_AC_NUM] = { 0 }; int e; if (!hapd->conf->wmm_enabled) return eid; + wmm_calc_regulatory_limit(hapd, wmmp); eid[0] = WLAN_EID_VENDOR_SPECIFIC; wmm->oui[0] = 0x00; wmm->oui[1] = 0x50; @@ -70,8 +135,7 @@ u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid) /* fill in a parameter set record for each AC */ for (e = 0; e < 4; e++) { struct wmm_ac_parameter *ac = &wmm->ac[e]; - struct hostapd_wmm_ac_params *acp = - &hapd->iconf->wmm_ac_params[e]; + struct hostapd_wmm_ac_params *acp = &wmmp[e]; ac->aci_aifsn = wmm_aci_aifsn(acp->aifs, acp->admission_control_mandatory,