Do not disconnect EAPOL-Logoff before authentication

Some station devices are apparently sending the EAPOL-Logoff message in
some cases before the initial authentication for WPA2/WPA3-Enterprise.
hostapd would have forced a "post EAP-Failure" disconnection in 10 ms
for such cases while still allowing the EAP authentication to try to
complete.

This is not ideal and could result in interoperability issues, so skip
the forced disconnection in the particular case where the EAPOL-Logoff
message is received before the first authentication is completed.

In addition, disconnect the STA without starting new EAP authentication
and the 10 ms delay if an EAPOL-Logoff message is received after
authentication has been completed successfully. This results in cleaner
behavior by avoiding the extra start of a new EAP authentication in a
case where the STA is going to be disconnected shortly.

Signed-off-by: Jouni Malinen <quic_jouni@quicinc.com>
This commit is contained in:
Jouni Malinen 2023-05-04 10:18:34 +03:00 committed by Jouni Malinen
parent 7337232203
commit 386d59e00d
6 changed files with 49 additions and 24 deletions

View file

@ -43,9 +43,9 @@
#ifdef CONFIG_HS20
static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx);
#endif /* CONFIG_HS20 */
static void ieee802_1x_finished(struct hostapd_data *hapd,
static bool ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation);
int remediation, bool logoff);
static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
@ -2287,16 +2287,18 @@ static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
}
static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
int preauth, int remediation)
static bool _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
int preauth, int remediation, bool logoff)
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta = sta_ctx;
if (preauth)
if (preauth) {
rsn_preauth_finished(hapd, sta, success);
else
ieee802_1x_finished(hapd, sta, success, remediation);
return false;
}
return ieee802_1x_finished(hapd, sta, success, remediation, logoff);
}
@ -2977,9 +2979,9 @@ static void ieee802_1x_wnm_notif_send(void *eloop_ctx, void *timeout_ctx)
#endif /* CONFIG_HS20 */
static void ieee802_1x_finished(struct hostapd_data *hapd,
static bool ieee802_1x_finished(struct hostapd_data *hapd,
struct sta_info *sta, int success,
int remediation)
int remediation, bool logoff)
{
const u8 *key;
size_t len;
@ -3039,6 +3041,11 @@ 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.
*/
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta);
ap_sta_delayed_1x_auth_fail_disconnect(hapd, sta,
logoff ? 0 : 10);
if (logoff && sta->wpa_sm)
return true;
}
return false;
}

View file

@ -1536,11 +1536,12 @@ static void ap_sta_delayed_1x_auth_fail_cb(void *eloop_ctx, void *timeout_ctx)
void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta)
struct sta_info *sta,
unsigned timeout)
{
wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
"IEEE 802.1X: Force disconnection of " MACSTR
" after EAP-Failure in 10 ms", MAC2STR(sta->addr));
" after EAP-Failure in %u ms", MAC2STR(sta->addr), timeout);
/*
* Add a small sleep to increase likelihood of previously requested
@ -1548,8 +1549,8 @@ void ap_sta_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
* 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);
eloop_register_timeout(0, timeout * 1000,
ap_sta_delayed_1x_auth_fail_cb, hapd, sta);
}

View file

@ -373,7 +373,8 @@ void ap_sta_clear_disconnect_timeouts(struct hostapd_data *hapd,
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);
struct sta_info *sta,
unsigned timeout);
int ap_sta_pending_delayed_1x_auth_fail_disconnect(struct hostapd_data *hapd,
struct sta_info *sta);
int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta);

View file

@ -217,6 +217,9 @@ SM_STATE(AUTH_PAE, INITIALIZE)
SM_STATE(AUTH_PAE, DISCONNECTED)
{
int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
bool pre_auth_logoff = sm->auth_pae_state == AUTH_PAE_ABORTING &&
sm->eapolLogoff && !sm->authenticated;
bool logoff = sm->eapolLogoff;
if (sm->eapolLogoff) {
if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
@ -231,10 +234,14 @@ SM_STATE(AUTH_PAE, DISCONNECTED)
setPortUnauthorized();
sm->reAuthCount = 0;
sm->eapolLogoff = false;
if (!from_initialize) {
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
if (!from_initialize && !pre_auth_logoff) {
if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
sm->flags & EAPOL_SM_PREAUTH,
sm->remediation);
sm->remediation, logoff)) {
wpa_printf(MSG_DEBUG,
"EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff");
sm->stopped = true;
}
}
}
@ -291,7 +298,8 @@ SM_STATE(AUTH_PAE, HELD)
eap_server_get_name(0, sm->eap_type_supp));
}
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
false);
}
@ -316,8 +324,11 @@ SM_STATE(AUTH_PAE, AUTHENTICATED)
sm->eap_type_authsrv,
eap_server_get_name(0, sm->eap_type_authsrv),
extra);
if (sm->authSuccess)
sm->authenticated++;
sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
sm->flags & EAPOL_SM_PREAUTH, sm->remediation,
false);
}
@ -397,6 +408,7 @@ SM_STEP(AUTH_PAE)
SM_ENTER(AUTH_PAE, DISCONNECTED);
break;
case AUTH_PAE_DISCONNECTED:
if (!sm->stopped)
SM_ENTER(AUTH_PAE, RESTART);
break;
case AUTH_PAE_RESTART:

View file

@ -46,8 +46,8 @@ struct eapol_auth_cb {
size_t datalen);
void (*aaa_send)(void *ctx, void *sta_ctx, const u8 *data,
size_t datalen);
void (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
int remediation);
bool (*finished)(void *ctx, void *sta_ctx, int success, int preauth,
int remediation, bool logoff);
int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
int phase2, struct eap_user *user);
int (*sta_entry_alive)(void *ctx, const u8 *addr);

View file

@ -171,6 +171,10 @@ struct eapol_state_machine {
int remediation;
u64 acct_multi_session_id;
unsigned int authenticated; /* The number of times authentication has
* been completed successfully. */
bool stopped;
};
#endif /* EAPOL_AUTH_SM_I_H */