]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
WNM: AP configuration to allow BSS max idle period requests
authorJouni Malinen <quic_jouni@quicinc.com>
Wed, 29 May 2024 16:41:59 +0000 (19:41 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 29 May 2024 20:40:22 +0000 (23:40 +0300)
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>
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.h
src/ap/ctrl_iface_ap.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_shared.c
src/ap/sta_info.c
src/ap/sta_info.h

index 5c091fcd22dd446cac6fa7a3008aac4004a40757..d728be888bcff3a85aa94b1ddd928ec8d44d6f93 100644 (file)
@@ -2558,6 +2558,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                        return 1;
                }
                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) {
                int val = atoi(pos);
 
index be92db7a3c8bb09e17539df7f62713bcd21425b4..bc9099bc821611a8830cca009173b664bbcf03bf 100644 (file)
@@ -530,6 +530,11 @@ wmm_ac_vo_acm=0
 #     period and require STAs to use protected keep-alive frames)
 #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
 # BSS max idle period management is enabled.
 # 0 = disconnect STA if it does not reply to group key handshake (default)
index 8daea416d0b555c64fd1fd170042720ca877e376..0008583225a4a705cad5d45331653285612de145 100644 (file)
@@ -466,6 +466,7 @@ struct hostapd_bss_config {
 
        int ap_max_inactivity;
        int bss_max_idle;
+       int max_acceptable_idle_period;
        bool no_disconnect_on_group_keyerror;
        int ignore_broadcast_ssid;
        int no_probe_resp_if_max_sta;
index 1acb97f9b5361c260d166a95038cfdc9d3a93c1a..d4d73de19d192938d9e65be214e25649102f4f5e 100644 (file)
@@ -277,6 +277,14 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
                return len;
        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);
        if (res >= 0)
                len += res;
index 54cff1038c2cc4714b40f85f5c8858ba33da7380..80e54b267ac8e075575375325d9d90cad3846517 100644 (file)
@@ -4328,6 +4328,19 @@ static int __check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                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;
 }
 
@@ -4902,7 +4915,7 @@ static u16 send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211AX */
 
        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)
                p = hostapd_eid_qos_map_set(hapd, p);
 
index a389a2ce097c357224a80d3724372fc9f9e3ef3d..dd4995f3f31a66d285657b46f7a716458eaad202 100644 (file)
@@ -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);
 int hostapd_update_time_adv(struct hostapd_data *hapd);
 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);
 #ifdef CONFIG_SAE
index b98b3ecc740bbe36842467cbf4187e17dbd9a0a0..fd8ec6004ab836c8269fcb1bd1850966c7aabc9b 100644 (file)
@@ -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;
 
@@ -756,6 +757,8 @@ u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
                        val = 1;
                if (val > 65535)
                        val = 65535;
+               if (value)
+                       val = value;
                WPA_PUT_LE16(pos, val);
                pos += 2;
                /* Set the Protected Keep-Alive Required bit based on
index 87d63e1883cb5330d6eeda42804c83b695abb82d..24ba86b11b7c6fd1207513c943838049c0f8230b 100644 (file)
@@ -532,6 +532,7 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
        struct sta_info *sta = timeout_ctx;
        unsigned long next_time = 0;
        int reason;
+       int max_inactivity = hapd->conf->ap_max_inactivity;
 
        wpa_printf(MSG_DEBUG, "%s: %s: " MACSTR " flags=0x%x timeout_next=%d",
                   hapd->conf->iface, __func__, MAC2STR(sta->addr), sta->flags,
@@ -544,6 +545,9 @@ void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
                return;
        }
 
+       if (sta->max_idle_period)
+               max_inactivity = (sta->max_idle_period * 1024 + 999) / 1000;
+
        if ((sta->flags & WLAN_STA_ASSOC) &&
            (sta->timeout_next == STA_NULLFUNC ||
             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,
                         * 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) {
                        wpa_msg(hapd->msg_ctx, MSG_DEBUG,
                                "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 */
                        sta->timeout_next = STA_DISASSOC;
                        goto skip_poll;
-               } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
+               } else if (inactive_sec < max_inactivity) {
                        /* station activity detected; reset timeout state */
                        wpa_msg(hapd->msg_ctx, MSG_DEBUG,
                                "Station " MACSTR " has been active %is ago",
                                MAC2STR(sta->addr), inactive_sec);
                        sta->timeout_next = STA_NULLFUNC;
-                       next_time = hapd->conf->ap_max_inactivity + fuzz -
-                               inactive_sec;
+                       next_time = max_inactivity + fuzz - inactive_sec;
                } else {
                        wpa_msg(hapd->msg_ctx, MSG_DEBUG,
                                "Station " MACSTR " has been "
                                "inactive too long: %d sec, max allowed: %d",
                                MAC2STR(sta->addr), inactive_sec,
-                               hapd->conf->ap_max_inactivity);
+                               max_inactivity);
 
                        if (hapd->conf->skip_inactivity_poll)
                                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
                 * station ACKed it */
                sta->timeout_next = STA_NULLFUNC;
-               next_time = hapd->conf->ap_max_inactivity;
+               next_time = max_inactivity;
        }
 
 skip_poll:
@@ -791,6 +794,7 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
 {
        struct sta_info *sta;
        int i;
+       int max_inactivity = hapd->conf->ap_max_inactivity;
 
        sta = ap_get_sta(hapd, addr);
        if (sta)
@@ -824,12 +828,15 @@ struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
        }
        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)) {
                wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
                           "for " MACSTR " (%d seconds - ap_max_inactivity)",
                           __func__, MAC2STR(addr),
-                          hapd->conf->ap_max_inactivity);
-               eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+                          max_inactivity);
+               eloop_register_timeout(max_inactivity, 0,
                                       ap_handle_timer, hapd, sta);
        }
 
index 14bf84b4eb0eac7b4a5983cb2020f22aff1c554d..84629358cc223f8d3bf7684cbf81e6c0560312cc 100644 (file)
@@ -332,6 +332,9 @@ struct sta_info {
        struct mld_info mld_info;
        u8 mld_assoc_link_id;
 #endif /* CONFIG_IEEE80211BE */
+
+       u16 max_idle_period; /* if nonzero, the granted BSS max idle period in
+                             * units of 1000 TUs */
 };