WNM: AP configuration to allow BSS max idle period requests
Add a new hostapd configuration parameter max_acceptable_idle_period to allow the AP to accept per-STA requested BSS max idle periods. Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
parent
6594ea9ef1
commit
58ac46baf7
9 changed files with 54 additions and 11 deletions
|
@ -2558,6 +2558,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
bss->bss_max_idle = val;
|
bss->bss_max_idle = val;
|
||||||
|
} else if (os_strcmp(buf, "max_acceptable_idle_period") == 0) {
|
||||||
|
bss->max_acceptable_idle_period = atoi(pos);
|
||||||
} else if (os_strcmp(buf, "no_disconnect_on_group_keyerror") == 0) {
|
} else if (os_strcmp(buf, "no_disconnect_on_group_keyerror") == 0) {
|
||||||
int val = atoi(pos);
|
int val = atoi(pos);
|
||||||
|
|
||||||
|
|
|
@ -530,6 +530,11 @@ wmm_ac_vo_acm=0
|
||||||
# period and require STAs to use protected keep-alive frames)
|
# period and require STAs to use protected keep-alive frames)
|
||||||
#bss_max_idle=1
|
#bss_max_idle=1
|
||||||
#
|
#
|
||||||
|
# Maximum acceptable BSS maximum idle period
|
||||||
|
# If this is set to a nonzero value, the AP allows STAs to request different
|
||||||
|
# maximum idle period values. This is in the units to 1000 TUs (1.024 s)
|
||||||
|
#max_acceptable_idle_period=600
|
||||||
|
#
|
||||||
# Allow STA to skip group key handshake without getting disconnection when
|
# Allow STA to skip group key handshake without getting disconnection when
|
||||||
# BSS max idle period management is enabled.
|
# BSS max idle period management is enabled.
|
||||||
# 0 = disconnect STA if it does not reply to group key handshake (default)
|
# 0 = disconnect STA if it does not reply to group key handshake (default)
|
||||||
|
|
|
@ -466,6 +466,7 @@ struct hostapd_bss_config {
|
||||||
|
|
||||||
int ap_max_inactivity;
|
int ap_max_inactivity;
|
||||||
int bss_max_idle;
|
int bss_max_idle;
|
||||||
|
int max_acceptable_idle_period;
|
||||||
bool no_disconnect_on_group_keyerror;
|
bool no_disconnect_on_group_keyerror;
|
||||||
int ignore_broadcast_ssid;
|
int ignore_broadcast_ssid;
|
||||||
int no_probe_resp_if_max_sta;
|
int no_probe_resp_if_max_sta;
|
||||||
|
|
|
@ -277,6 +277,14 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
|
||||||
return len;
|
return len;
|
||||||
len += ret;
|
len += ret;
|
||||||
|
|
||||||
|
if (sta->max_idle_period) {
|
||||||
|
ret = os_snprintf(buf + len, buflen - len,
|
||||||
|
"max_idle_period=%d\n", sta->max_idle_period);
|
||||||
|
if (os_snprintf_error(buflen - len, ret))
|
||||||
|
return len;
|
||||||
|
len += ret;
|
||||||
|
}
|
||||||
|
|
||||||
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
|
||||||
if (res >= 0)
|
if (res >= 0)
|
||||||
len += res;
|
len += res;
|
||||||
|
|
|
@ -4328,6 +4328,19 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
sta->power_capab = 0;
|
sta->power_capab = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (elems->bss_max_idle_period &&
|
||||||
|
hapd->conf->max_acceptable_idle_period) {
|
||||||
|
u16 req;
|
||||||
|
|
||||||
|
req = WPA_GET_LE16(elems->bss_max_idle_period);
|
||||||
|
if (req <= hapd->conf->max_acceptable_idle_period)
|
||||||
|
sta->max_idle_period = req;
|
||||||
|
else if (hapd->conf->max_acceptable_idle_period >
|
||||||
|
hapd->conf->ap_max_inactivity)
|
||||||
|
sta->max_idle_period =
|
||||||
|
hapd->conf->max_acceptable_idle_period;
|
||||||
|
}
|
||||||
|
|
||||||
return WLAN_STATUS_SUCCESS;
|
return WLAN_STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4902,7 +4915,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
|
||||||
#endif /* CONFIG_IEEE80211AX */
|
#endif /* CONFIG_IEEE80211AX */
|
||||||
|
|
||||||
p = hostapd_eid_ext_capab(hapd, p, false);
|
p = hostapd_eid_ext_capab(hapd, p, false);
|
||||||
p = hostapd_eid_bss_max_idle_period(hapd, p);
|
p = hostapd_eid_bss_max_idle_period(hapd, p, sta->max_idle_period);
|
||||||
if (sta && sta->qos_map_enabled)
|
if (sta && sta->qos_map_enabled)
|
||||||
p = hostapd_eid_qos_map_set(hapd, p);
|
p = hostapd_eid_qos_map_set(hapd, p);
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,8 @@ u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
|
||||||
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
|
u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
|
||||||
int hostapd_update_time_adv(struct hostapd_data *hapd);
|
int hostapd_update_time_adv(struct hostapd_data *hapd);
|
||||||
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
|
void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
|
||||||
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
|
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
|
||||||
|
u16 value);
|
||||||
|
|
||||||
int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
|
int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
|
||||||
#ifdef CONFIG_SAE
|
#ifdef CONFIG_SAE
|
||||||
|
|
|
@ -737,7 +737,8 @@ int hostapd_update_time_adv(struct hostapd_data *hapd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid,
|
||||||
|
u16 value)
|
||||||
{
|
{
|
||||||
u8 *pos = eid;
|
u8 *pos = eid;
|
||||||
|
|
||||||
|
@ -756,6 +757,8 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
|
||||||
val = 1;
|
val = 1;
|
||||||
if (val > 65535)
|
if (val > 65535)
|
||||||
val = 65535;
|
val = 65535;
|
||||||
|
if (value)
|
||||||
|
val = value;
|
||||||
WPA_PUT_LE16(pos, val);
|
WPA_PUT_LE16(pos, val);
|
||||||
pos += 2;
|
pos += 2;
|
||||||
/* Set the Protected Keep-Alive Required bit based on
|
/* Set the Protected Keep-Alive Required bit based on
|
||||||
|
|
|
@ -532,6 +532,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
struct sta_info *sta = timeout_ctx;
|
struct sta_info *sta = timeout_ctx;
|
||||||
unsigned long next_time = 0;
|
unsigned long next_time = 0;
|
||||||
int reason;
|
int reason;
|
||||||
|
int max_inactivity = hapd->conf->ap_max_inactivity;
|
||||||
|
|
||||||
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
|
wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
|
||||||
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
|
hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
|
||||||
|
@ -544,6 +545,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sta->max_idle_period)
|
||||||
|
max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
|
||||||
|
|
||||||
if ((sta->flags & WLAN_STA_ASSOC) &&
|
if ((sta->flags & WLAN_STA_ASSOC) &&
|
||||||
(sta->timeout_next == STA_NULLFUNC ||
|
(sta->timeout_next == STA_NULLFUNC ||
|
||||||
sta->timeout_next == STA_DISASSOC)) {
|
sta->timeout_next == STA_DISASSOC)) {
|
||||||
|
@ -565,7 +569,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
* Anyway, try again after the next inactivity timeout,
|
* Anyway, try again after the next inactivity timeout,
|
||||||
* but do not disconnect the station now.
|
* but do not disconnect the station now.
|
||||||
*/
|
*/
|
||||||
next_time = hapd->conf->ap_max_inactivity + fuzz;
|
next_time = max_inactivity + fuzz;
|
||||||
} else if (inactive_sec == -ENOENT) {
|
} else if (inactive_sec == -ENOENT) {
|
||||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||||
"Station " MACSTR " has lost its driver entry",
|
"Station " MACSTR " has lost its driver entry",
|
||||||
|
@ -574,20 +578,19 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
/* Avoid sending client probe on removed client */
|
/* Avoid sending client probe on removed client */
|
||||||
sta->timeout_next = STA_DISASSOC;
|
sta->timeout_next = STA_DISASSOC;
|
||||||
goto skip_poll;
|
goto skip_poll;
|
||||||
} else if (inactive_sec < hapd->conf->ap_max_inactivity) {
|
} else if (inactive_sec < max_inactivity) {
|
||||||
/* station activity detected; reset timeout state */
|
/* station activity detected; reset timeout state */
|
||||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||||
"Station " MACSTR " has been active %is ago",
|
"Station " MACSTR " has been active %is ago",
|
||||||
MAC2STR(sta->addr), inactive_sec);
|
MAC2STR(sta->addr), inactive_sec);
|
||||||
sta->timeout_next = STA_NULLFUNC;
|
sta->timeout_next = STA_NULLFUNC;
|
||||||
next_time = hapd->conf->ap_max_inactivity + fuzz -
|
next_time = max_inactivity + fuzz - inactive_sec;
|
||||||
inactive_sec;
|
|
||||||
} else {
|
} else {
|
||||||
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
wpa_msg(hapd->msg_ctx, MSG_DEBUG,
|
||||||
"Station " MACSTR " has been "
|
"Station " MACSTR " has been "
|
||||||
"inactive too long: %d sec, max allowed: %d",
|
"inactive too long: %d sec, max allowed: %d",
|
||||||
MAC2STR(sta->addr), inactive_sec,
|
MAC2STR(sta->addr), inactive_sec,
|
||||||
hapd->conf->ap_max_inactivity);
|
max_inactivity);
|
||||||
|
|
||||||
if (hapd->conf->skip_inactivity_poll)
|
if (hapd->conf->skip_inactivity_poll)
|
||||||
sta->timeout_next = STA_DISASSOC;
|
sta->timeout_next = STA_DISASSOC;
|
||||||
|
@ -603,7 +606,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
/* data nullfunc frame poll did not produce TX errors; assume
|
/* data nullfunc frame poll did not produce TX errors; assume
|
||||||
* station ACKed it */
|
* station ACKed it */
|
||||||
sta->timeout_next = STA_NULLFUNC;
|
sta->timeout_next = STA_NULLFUNC;
|
||||||
next_time = hapd->conf->ap_max_inactivity;
|
next_time = max_inactivity;
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_poll:
|
skip_poll:
|
||||||
|
@ -791,6 +794,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||||
{
|
{
|
||||||
struct sta_info *sta;
|
struct sta_info *sta;
|
||||||
int i;
|
int i;
|
||||||
|
int max_inactivity = hapd->conf->ap_max_inactivity;
|
||||||
|
|
||||||
sta = ap_get_sta(hapd, addr);
|
sta = ap_get_sta(hapd, addr);
|
||||||
if (sta)
|
if (sta)
|
||||||
|
@ -824,12 +828,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
|
||||||
}
|
}
|
||||||
sta->supported_rates_len = i;
|
sta->supported_rates_len = i;
|
||||||
|
|
||||||
|
if (sta->max_idle_period)
|
||||||
|
max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
|
||||||
|
|
||||||
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)) {
|
||||||
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
|
||||||
"for " MACSTR " (%d seconds - ap_max_inactivity)",
|
"for " MACSTR " (%d seconds - ap_max_inactivity)",
|
||||||
__func__, MAC2STR(addr),
|
__func__, MAC2STR(addr),
|
||||||
hapd->conf->ap_max_inactivity);
|
max_inactivity);
|
||||||
eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
|
eloop_register_timeout(max_inactivity, 0,
|
||||||
ap_handle_timer, hapd, sta);
|
ap_handle_timer, hapd, sta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -332,6 +332,9 @@ struct sta_info {
|
||||||
struct mld_info mld_info;
|
struct mld_info mld_info;
|
||||||
u8 mld_assoc_link_id;
|
u8 mld_assoc_link_id;
|
||||||
#endif /* CONFIG_IEEE80211BE */
|
#endif /* CONFIG_IEEE80211BE */
|
||||||
|
|
||||||
|
u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
|
||||||
|
* units of 1000 TUs */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue