Fixed retransmission of EAP requests if no response is received

It looks like this never survived the move from IEEE 802.1X-2001 to
IEEE 802.1X-2004 and EAP state machine (RFC 4137). The retransmission
scheduling and control is now in EAP authenticator and the
calculateTimeout() producedure is used to determine timeout for
retransmission (either dynamic backoff or value from EAP method hint).

The recommended calculations based on SRTT and RTTVAR (RFC 2988) are not
yet implemented since there is no round-trip time measurement available
yet.

This should make EAP authentication much more robust in environments
where initial packets are lost for any reason. If the EAP method does
not provide a hint on timeout, default schedule of 3, 6, 12, 20, 20, 20,
... seconds will be used.
This commit is contained in:
Jouni Malinen 2008-12-29 18:10:34 +02:00 committed by Jouni Malinen
parent 65d50f0ac6
commit 8e09c6d253
4 changed files with 69 additions and 33 deletions

View file

@ -19,6 +19,7 @@ ChangeLog for hostapd
* added support for using driver_test over UDP socket
* changed EAP-GPSK to use the IANA assigned EAP method type 51
* updated management frame protection to use IEEE 802.11w/D7.0
* fixed retransmission of EAP requests if no response is received
2008-11-23 - v0.6.6
* added a new configuration option, wpa_ptk_rekey, that can be used to

View file

@ -174,6 +174,15 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
}
}
if (state->eap_if->retransWhile > 0) {
state->eap_if->retransWhile--;
if (state->eap_if->retransWhile == 0) {
wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
" - (EAP) retransWhile --> 0",
MAC2STR(state->addr));
}
}
eapol_sm_step_run(state);
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);

View file

@ -105,19 +105,6 @@ void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
}
static void ieee802_1x_eap_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct sta_info *sta = eloop_ctx;
struct eapol_state_machine *sm = sta->eapol_sm;
if (sm == NULL)
return;
hostapd_logger(sm->hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "EAP timeout");
sm->eap_if->eapTimeout = TRUE;
eapol_auth_step(sm);
}
static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
struct sta_info *sta,
int idx, int broadcast,
@ -594,7 +581,6 @@ static void handle_eap_response(struct hostapd_data *hapd,
}
sm->eap_type_supp = type = data[0];
eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL);
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
@ -940,8 +926,6 @@ void ieee802_1x_free_station(struct sta_info *sta)
{
struct eapol_state_machine *sm = sta->eapol_sm;
eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL);
if (sm == NULL)
return;
@ -1211,7 +1195,6 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
struct sta_info *sta;
u32 session_timeout = 0, termination_action, acct_interim_interval;
int session_timeout_set, old_vlanid = 0;
int eap_timeout;
struct eapol_state_machine *sm;
int override_eapReq = 0;
@ -1337,18 +1320,20 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
sm->eap_if->aaaEapReq = TRUE;
if (session_timeout_set) {
/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
eap_timeout = session_timeout;
} else
eap_timeout = 30;
hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
"using EAP timeout of %d seconds%s",
eap_timeout,
session_timeout_set ? " (from RADIUS)" : "");
eloop_cancel_timeout(ieee802_1x_eap_timeout, sta, NULL);
eloop_register_timeout(eap_timeout, 0, ieee802_1x_eap_timeout,
sta, NULL);
sm->eap_if->eapTimeout = FALSE;
sm->eap_if->aaaMethodTimeout = session_timeout;
hostapd_logger(hapd, sm->addr,
HOSTAPD_MODULE_IEEE8021X,
HOSTAPD_LEVEL_DEBUG,
"using EAP timeout of %d seconds (from "
"RADIUS)",
sm->eap_if->aaaMethodTimeout);
} else {
/*
* Use dynamic retransmission behavior per EAP
* specification.
*/
sm->eap_if->aaaMethodTimeout = 0;
}
break;
}

View file

@ -792,10 +792,51 @@ static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
int eapSRTT, int eapRTTVAR,
int methodTimeout)
{
/* For now, retransmission is done in EAPOL state machines, so make
* sure EAP state machine does not end up trying to retransmit packets.
int rto, i;
if (methodTimeout) {
/*
* EAP method (either internal or through AAA server, provided
* timeout hint. Use that as-is as a timeout for retransmitting
* the EAP request if no response is received.
*/
wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
"(from EAP method hint)", methodTimeout);
return methodTimeout;
}
/*
* RFC 3748 recommends algorithms described in RFC 2988 for estimation
* of the retransmission timeout. This should be implemented once
* round-trip time measurements are available. For nowm a simple
* backoff mechanism is used instead if there are no EAP method
* specific hints.
*
* SRTT = smoothed round-trip time
* RTTVAR = round-trip time variation
* RTO = retransmission timeout
*/
return 1;
/*
* RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
* initial retransmission and then double the RTO to provide back off
* per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
* modified RTOmax.
*/
rto = 3;
for (i = 0; i < retransCount; i++) {
rto *= 2;
if (rto >= 20) {
rto = 20;
break;
}
}
wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
"(from dynamic back off; retransCount=%d)",
rto, retransCount);
return rto;
}
@ -1158,7 +1199,7 @@ struct eap_sm * eap_server_sm_init(void *eapol_ctx,
return NULL;
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->MaxRetrans = 10;
sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
sm->ssl_ctx = conf->ssl_ctx;
sm->eap_sim_db_priv = conf->eap_sim_db_priv;
sm->backend_auth = conf->backend_auth;