diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog index 2c863d18c..09b34cd9b 100644 --- a/hostapd/ChangeLog +++ b/hostapd/ChangeLog @@ -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 diff --git a/hostapd/eapol_sm.c b/hostapd/eapol_sm.c index 826d71d74..49a557a35 100644 --- a/hostapd/eapol_sm.c +++ b/hostapd/eapol_sm.c @@ -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); diff --git a/hostapd/ieee802_1x.c b/hostapd/ieee802_1x.c index d0d8e0946..17c743fc3 100644 --- a/hostapd/ieee802_1x.c +++ b/hostapd/ieee802_1x.c @@ -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; } diff --git a/src/eap_server/eap.c b/src/eap_server/eap.c index 289337f98..dea91e635 100644 --- a/src/eap_server/eap.c +++ b/src/eap_server/eap.c @@ -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;