@@ -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 */
@@ -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,