From: Haim Dreyfuss <haim.dreyfuss@xxxxxxxxx> In case the current channel has WMM limitation, take it into account when filling the WMM IE. Also check if the new WMM IE 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 <haim.dreyfuss@xxxxxxxxx> --- src/ap/hostapd.h | 3 +++ src/ap/wmm.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 790d377548..ff4e247e90 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -541,6 +541,9 @@ struct hostapd_iface { unsigned int num_sta_seen; u8 dfs_domain; + + /* previous wmm ie */ + 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 8054c5d2f2..a4a5cab617 100644 --- a/src/ap/wmm.c +++ b/src/ap/wmm.c @@ -20,6 +20,12 @@ #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 +45,60 @@ static inline u8 wmm_ecw(int ecwmin, int ecwmax) } +static void wmm_set_regulatory_limit(struct hostapd_wmm_ac_params *wmm_conf, + struct hostapd_wmm_ac_params *wmm, + 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; + + for (c = 0; 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); + else + os_memcpy(acp, hapd->iconf->wmm_ac_params, + sizeof(hapd->iconf->wmm_ac_params)); + 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 +108,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 +132,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, -- 2.19.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap