]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Use eloop timeout for post-EAP-Failure wait before disconnection
authorJouni Malinen <j@w1.fi>
Tue, 6 Dec 2016 16:12:11 +0000 (18:12 +0200)
committerJouni Malinen <j@w1.fi>
Thu, 8 Dec 2016 16:56:02 +0000 (18:56 +0200)
Previously, os_sleep() was used to block the hostapd (or wpa_supplicant
AP/P2P GO mode) processing between sending out EAP-Failure and
disconnecting the STA. This is not ideal for couple of reasons: it
blocks all other parallel operations in the process and it leaves a
window during which the station might deauthenticate and the AP would
have no option for reacting to that before forcing out its own
Deauthentication frame which could go out after the STA has already
started new connection attempt.

Improve this design by scheduling an eloop timeout of 10 ms instead of
the os_sleep() call and perform the delayed operations from the eloop
callback function. This eloop timeout is cancelled if the STA
disconnects or initiates a new connection attempt before the 10 ms time
is reached. This gets rid of the confusing extra Deauthentication frame
in cases where the STA reacts to EAP-Failure by an immediate
deauthentication.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/ap/ieee802_1x.c
src/ap/sta_info.c
src/ap/sta_info.h

index 7ac337d0deea588e8a58d31029ec37ca85e68cc2..0313cb17c0d6fe9db22fbd2f4efa4cd57cfd7a9c 100644 (file)
@@ -2364,6 +2364,16 @@ int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
                   MAC2STR(sta->addr), xhdr->version, xhdr->type,
                   be_to_host16(xhdr->length), ack);
 
+#ifdef CONFIG_WPS
+       if (xhdr->type == IEEE802_1X_TYPE_EAP_PACKET && ack &&
+           (sta->flags & WLAN_STA_WPS) &&
+           ap_sta_pending_delayed_1x_auth_fail_disconnect(hapd, sta)) {
+               wpa_printf(MSG_DEBUG,
+                          "WPS: Indicate EAP completion on ACK for EAP-Failure");
+               hostapd_wps_eap_completed(hapd);
+       }
+#endif /* CONFIG_WPS */
+
        if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
                return 0;
 
@@ -2737,15 +2747,6 @@ static void ieee802_1x_finished(struct hostapd_data *hapd,
                 * EAP-FAST with anonymous provisioning, may require another
                 * EAPOL authentication to be started to complete connection.
                 */
-               wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
-                       "disconnection after EAP-Failure");
-               /* Add a small sleep to increase likelihood of previously
-                * requested EAP-Failure TX getting out before this should the
-                * driver reorder operations.
-                */
-               os_sleep(0, 10000);
-               ap_sta_disconnect(hapd, sta, sta->addr,
-                                 WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
-               hostapd_wps_eap_completed(hapd);
+               ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
        }
 }
index f12d4088b1314d7528220fb075a5d18faa846c2f..527c34f6fa89048b6a4cb7c7538c8ebc285f2c28 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2016, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -36,6 +36,7 @@
 #include "ndisc_snoop.h"
 #include "sta_info.h"
 #include "vlan.h"
+#include "wps_hostapd.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
                                       struct sta_info *sta);
@@ -47,6 +48,7 @@ static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
 static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_IEEE80211W */
 static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx);
 
 int ap_for_each_sta(struct hostapd_data *hapd,
                    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -1275,6 +1277,15 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
                           "%s: Removed ap_sta_disassoc_cb_timeout timeout for "
                           MACSTR,
                           hapd->conf->iface, MAC2STR(sta->addr));
+       if (eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta) > 0)
+       {
+               wpa_printf(MSG_DEBUG,
+                          "%s: Removed ap_sta_delayed_1x_auth_fail_cb timeout for "
+                          MACSTR,
+                          hapd->conf->iface, MAC2STR(sta->addr));
+               if (sta->flags & WLAN_STA_WPS)
+                       hostapd_wps_eap_completed(hapd);
+       }
 }
 
 
@@ -1309,3 +1320,45 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
 
        return res;
 }
+
+
+static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
+{
+       struct hostapd_data *hapd = eloop_ctx;
+       struct sta_info *sta = timeout_ctx;
+
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+               "IEEE 802.1X: Scheduled disconnection of " MACSTR
+               " after EAP-Failure", MAC2STR(sta->addr));
+
+       ap_sta_disconnect(hapd, sta, sta->addr,
+                         WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+       if (sta->flags & WLAN_STA_WPS)
+               hostapd_wps_eap_completed(hapd);
+}
+
+
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+                                           struct sta_info *sta)
+{
+       wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+               "IEEE 802.1X: Force disconnection of " MACSTR
+               " after EAP-Failure in 10 ms", MAC2STR(sta->addr));
+
+       /*
+        * Add a small sleep to increase likelihood of previously requested
+        * EAP-Failure TX getting out before this should the driver reorder
+        * operations.
+        */
+       eloop_cancel_timeout(ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
+       eloop_register_timeout(0, 10000, ap_sta_delayed_1x_auth_fail_cb,
+                              hapd, sta);
+}
+
+
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+                                                  struct sta_info *sta)
+{
+       return eloop_is_timeout_registered(ap_sta_delayed_1x_auth_fail_cb,
+                                          hapd, sta);
+}
index a41633714feb20ec316ba82cd140c475b95f3c4c..980afedfe37a19360d3b6d0cfc7ad85ddf9c709f 100644 (file)
@@ -296,5 +296,9 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
                                      struct sta_info *sta);
 
 int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen);
+void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+                                           struct sta_info *sta);
+int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
+                                                  struct sta_info *sta);
 
 #endif /* STA_INFO_H */