[prev in list] [next in list] [prev in thread] [next in thread] 

List:       hostap
Subject:    [patch] Disconnect the STA if EAP timeout is reached
From:       Andriy Tkachuk <andriy.v.tkachuk () globallogic ! com>
Date:       2009-03-23 16:16:12
Message-ID: 49C7B5CC.6010604 () globallogic ! com
[Download RAW message or body]

Hi all.

Attached patch is the merge of Jouni's two fixes to EAP state machine 
from 0.6 branch to 0.5:

   1. Fixed retransmission of EAP requests if no response is received
      (http://hostap.epitest.fi/gitweb/gitweb.cgi?p=hostap-06.git;a=commit;h=8e09c6d25306135106c12a013966102ab01ddc38)
  2. Disconnect the STA if EAP timeout is reached
      (http://hostap.epitest.fi/gitweb/gitweb.cgi?p=hostap-06.git;a=commit;h=805e6dc66326764b3d20c5113fb538b2be6aa662)


Jouni, I would appreciate your review. Also I have a question - is it 
possible to commit this to 0.5 branch?

Thank you,
    Andriy


["eap-timeout.patch" (text/plain)]

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 3621)
+++ ChangeLog	(working copy)
@@ -1,10 +1,12 @@
 ChangeLog for hostapd
 
+	* fixed retransmission of EAP requests if no response is received
+
 2008-11-28 - v0.5.11
 	* driver_madwifi: Fixed NULL pointer dereference on error path
 	  [Bug 273]
 	* avoid possible NULL pointer dereference on SIGHUP with MAC ACLs
 	* update previous BSSID into STA data only after full validation of the
 	  reassociation request
 	* avoid NULL pointer dereference if initialization of EAP-TTLS Phase 2
 	  EAP method fails
Index: eap.c
===================================================================
--- eap.c	(revision 3621)
+++ eap.c	(working copy)
@@ -199,18 +199,21 @@ SM_STATE(EAP, IDLE)
 						   sm->methodTimeout);
 }
 
 
 SM_STATE(EAP, RETRANSMIT)
 {
 	SM_ENTRY(EAP, RETRANSMIT);
 
-	/* TODO: Is this needed since EAPOL state machines take care of
-	 * retransmit? */
+	sm->retransCount++;
+	if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
+		eapol_set_eapReqData(sm, sm->lastReqData, sm->lastReqDataLen);
+		eapol_set_bool(sm, EAPOL_eapReq, TRUE);
+	}
 }
 
 
 SM_STATE(EAP, RECEIVED)
 {
 	SM_ENTRY(EAP, RECEIVED);
 
 	/* parse rxResp, respId, respMethod */
@@ -606,20 +609,61 @@ SM_STEP(EAP)
 	}
 }
 
 
 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;
 }
 
 
 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
 {
 	struct eap_hdr *hdr;
 	size_t plen;
 
@@ -955,17 +999,17 @@ struct eap_sm * eap_sm_init(void *eapol_
 {
 	struct eap_sm *sm;
 
 	sm = wpa_zalloc(sizeof(*sm));
 	if (sm == NULL)
 		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;
 
 	wpa_printf(MSG_DEBUG, "EAP: State machine created");
 
 	return sm;
 }
Index: eapol_sm.c
===================================================================
--- eapol_sm.c	(revision 3621)
+++ eapol_sm.c	(working copy)
@@ -80,16 +80,25 @@ static void eapol_port_timers_tick(void 
 		state->reAuthWhen--;
 		if (state->reAuthWhen == 0) {
 			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
 				   " - reAuthWhen --> 0",
 				   MAC2STR(state->addr));
 		}
 	}
 
+	if (state->eap->retransWhile > 0) {
+		state->eap->retransWhile--;
+		if (state->eap->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);
 }
 
 
 
 /* Authenticator PAE state machine */
Index: eapol_sm.h
===================================================================
--- eapol_sm.h	(revision 3621)
+++ eapol_sm.h	(working copy)
@@ -11,27 +11,26 @@
  *
  * See README and COPYING for more details.
  */
 
 #ifndef EAPOL_SM_H
 #define EAPOL_SM_H
 
 #include "defs.h"
+#include "eap_i.h"
 
 /* IEEE Std 802.1X-2004, Ch. 8.2 */
 
 typedef enum { ForceUnauthorized = 1, ForceAuthorized = 3, Auto = 2 }
 	PortTypes;
 typedef enum { Unauthorized = 2, Authorized = 1 } PortState;
 typedef enum { Both = 0, In = 1 } ControlledDirection;
 typedef unsigned int Counter;
 
-struct eap_sm;
-
 struct radius_attr_data {
 	u8 *data;
 	size_t len;
 };
 
 struct radius_class_data {
 	struct radius_attr_data *attr;
 	size_t count;
Index: ieee802_1x.c
===================================================================
--- ieee802_1x.c	(revision 3621)
+++ ieee802_1x.c	(working copy)
@@ -27,16 +27,17 @@
 #include "sta_info.h"
 #include "wpa.h"
 #include "preauth.h"
 #include "pmksa_cache.h"
 #include "driver.h"
 #include "hw_features.h"
 #include "eap.h"
 #include "eap_wsc.h"
+#include "ieee802_11.h"
 
 
 static void ieee802_1x_new_auth_session(struct hostapd_data *hapd,
 					struct sta_info *sta);
 
 
 void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
 			    u8 type, u8 *data, size_t datalen)
@@ -1478,20 +1479,17 @@ ieee802_1x_receive_auth(struct radius_ms
 			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->eapTimeout = FALSE;
+		sm->eap->methodTimeout = eap_timeout;
 		break;
 	}
 
 	ieee802_1x_decapsulate_radius(hapd, sta);
 	if (override_eapReq)
 		sm->eapReq = FALSE;
 
 	eapol_sm_step(sm);
@@ -1534,16 +1532,32 @@ void ieee802_1x_abort_auth(struct hostap
 		sm->last_recv_radius = NULL;
 	}
 	free(sm->last_eap_supp);
 	sm->last_eap_supp = NULL;
 	sm->last_eap_supp_len = 0;
 	free(sm->last_eap_radius);
 	sm->last_eap_radius = NULL;
 	sm->last_eap_radius_len = 0;
+
+	if (sm->eapTimeout) {
+		/*
+		 * Disconnect the STA since it did not reply to the last EAP
+		 * request and we cannot continue EAP processing (EAP-Failure
+		 * could only be sent if the EAP peer actually replied).
+		 */
+		sm->portEnabled = FALSE;
+		hostapd_sta_deauth(hapd, sta->addr,
+				   WLAN_REASON_PREV_AUTH_NOT_VALID);
+		sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+				WLAN_STA_AUTHORIZED);
+		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+		eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+		sta->timeout_next = STA_REMOVE;
+	}
 }
 
 
 #ifdef HOSTAPD_DUMP_STATE
 static void fprint_char(FILE *f, char c)
 {
 	if (c >= 32 && c < 127)
 		fprintf(f, "%c", c);


_______________________________________________
HostAP mailing list
HostAP@lists.shmoo.com
http://lists.shmoo.com/mailman/listinfo/hostap


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic