xref: /dflybsd-src/contrib/wpa_supplicant/src/eapol_auth/eapol_auth_sm.c (revision 3a84a4273475ed07d0ab1c2dfeffdfedef35d9cd)
13ff40c12SJohn Marino /*
23ff40c12SJohn Marino  * IEEE 802.1X-2004 Authenticator - EAPOL state machine
3*a1157835SDaniel Fojt  * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
43ff40c12SJohn Marino  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
73ff40c12SJohn Marino  */
83ff40c12SJohn Marino 
93ff40c12SJohn Marino #include "includes.h"
103ff40c12SJohn Marino 
113ff40c12SJohn Marino #include "common.h"
123ff40c12SJohn Marino #include "eloop.h"
133ff40c12SJohn Marino #include "state_machine.h"
143ff40c12SJohn Marino #include "common/eapol_common.h"
153ff40c12SJohn Marino #include "eap_common/eap_defs.h"
163ff40c12SJohn Marino #include "eap_common/eap_common.h"
173ff40c12SJohn Marino #include "eap_server/eap.h"
183ff40c12SJohn Marino #include "eapol_auth_sm.h"
193ff40c12SJohn Marino #include "eapol_auth_sm_i.h"
203ff40c12SJohn Marino 
213ff40c12SJohn Marino #define STATE_MACHINE_DATA struct eapol_state_machine
223ff40c12SJohn Marino #define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
233ff40c12SJohn Marino #define STATE_MACHINE_ADDR sm->addr
243ff40c12SJohn Marino 
25*a1157835SDaniel Fojt static const struct eapol_callbacks eapol_cb;
263ff40c12SJohn Marino 
273ff40c12SJohn Marino /* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
283ff40c12SJohn Marino 
293ff40c12SJohn Marino #define setPortAuthorized() \
303ff40c12SJohn Marino sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
313ff40c12SJohn Marino #define setPortUnauthorized() \
323ff40c12SJohn Marino sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
333ff40c12SJohn Marino 
343ff40c12SJohn Marino /* procedures */
353ff40c12SJohn Marino #define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
363ff40c12SJohn Marino #define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
373ff40c12SJohn Marino #define txReq() eapol_auth_tx_req(sm)
383ff40c12SJohn Marino #define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
393ff40c12SJohn Marino #define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
403ff40c12SJohn Marino #define processKey() do { } while (0)
413ff40c12SJohn Marino 
423ff40c12SJohn Marino 
433ff40c12SJohn Marino static void eapol_sm_step_run(struct eapol_state_machine *sm);
443ff40c12SJohn Marino static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
453ff40c12SJohn Marino static void eapol_auth_initialize(struct eapol_state_machine *sm);
46*a1157835SDaniel Fojt static void eapol_auth_conf_free(struct eapol_auth_config *conf);
473ff40c12SJohn Marino 
483ff40c12SJohn Marino 
eapol_auth_logger(struct eapol_authenticator * eapol,const u8 * addr,eapol_logger_level level,const char * txt)493ff40c12SJohn Marino static void eapol_auth_logger(struct eapol_authenticator *eapol,
503ff40c12SJohn Marino 			      const u8 *addr, eapol_logger_level level,
513ff40c12SJohn Marino 			      const char *txt)
523ff40c12SJohn Marino {
533ff40c12SJohn Marino 	if (eapol->cb.logger == NULL)
543ff40c12SJohn Marino 		return;
553ff40c12SJohn Marino 	eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
563ff40c12SJohn Marino }
573ff40c12SJohn Marino 
583ff40c12SJohn Marino 
eapol_auth_vlogger(struct eapol_authenticator * eapol,const u8 * addr,eapol_logger_level level,const char * fmt,...)593ff40c12SJohn Marino static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
603ff40c12SJohn Marino 			       const u8 *addr, eapol_logger_level level,
613ff40c12SJohn Marino 			       const char *fmt, ...)
623ff40c12SJohn Marino {
633ff40c12SJohn Marino 	char *format;
643ff40c12SJohn Marino 	int maxlen;
653ff40c12SJohn Marino 	va_list ap;
663ff40c12SJohn Marino 
673ff40c12SJohn Marino 	if (eapol->cb.logger == NULL)
683ff40c12SJohn Marino 		return;
693ff40c12SJohn Marino 
703ff40c12SJohn Marino 	maxlen = os_strlen(fmt) + 100;
713ff40c12SJohn Marino 	format = os_malloc(maxlen);
723ff40c12SJohn Marino 	if (!format)
733ff40c12SJohn Marino 		return;
743ff40c12SJohn Marino 
753ff40c12SJohn Marino 	va_start(ap, fmt);
763ff40c12SJohn Marino 	vsnprintf(format, maxlen, fmt, ap);
773ff40c12SJohn Marino 	va_end(ap);
783ff40c12SJohn Marino 
793ff40c12SJohn Marino 	eapol_auth_logger(eapol, addr, level, format);
803ff40c12SJohn Marino 
813ff40c12SJohn Marino 	os_free(format);
823ff40c12SJohn Marino }
833ff40c12SJohn Marino 
843ff40c12SJohn Marino 
eapol_auth_tx_canned_eap(struct eapol_state_machine * sm,int success)853ff40c12SJohn Marino static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
863ff40c12SJohn Marino 				     int success)
873ff40c12SJohn Marino {
883ff40c12SJohn Marino 	struct eap_hdr eap;
893ff40c12SJohn Marino 
903ff40c12SJohn Marino 	os_memset(&eap, 0, sizeof(eap));
913ff40c12SJohn Marino 
923ff40c12SJohn Marino 	eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
933ff40c12SJohn Marino 	eap.identifier = ++sm->last_eap_id;
943ff40c12SJohn Marino 	eap.length = host_to_be16(sizeof(eap));
953ff40c12SJohn Marino 
963ff40c12SJohn Marino 	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
973ff40c12SJohn Marino 			   "Sending canned EAP packet %s (identifier %d)",
983ff40c12SJohn Marino 			   success ? "SUCCESS" : "FAILURE", eap.identifier);
993ff40c12SJohn Marino 	sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
1003ff40c12SJohn Marino 				 IEEE802_1X_TYPE_EAP_PACKET,
1013ff40c12SJohn Marino 				 (u8 *) &eap, sizeof(eap));
1023ff40c12SJohn Marino 	sm->dot1xAuthEapolFramesTx++;
1033ff40c12SJohn Marino }
1043ff40c12SJohn Marino 
1053ff40c12SJohn Marino 
eapol_auth_tx_req(struct eapol_state_machine * sm)1063ff40c12SJohn Marino static void eapol_auth_tx_req(struct eapol_state_machine *sm)
1073ff40c12SJohn Marino {
1083ff40c12SJohn Marino 	if (sm->eap_if->eapReqData == NULL ||
1093ff40c12SJohn Marino 	    wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
1103ff40c12SJohn Marino 		eapol_auth_logger(sm->eapol, sm->addr,
1113ff40c12SJohn Marino 				  EAPOL_LOGGER_DEBUG,
1123ff40c12SJohn Marino 				  "TxReq called, but there is no EAP request "
1133ff40c12SJohn Marino 				  "from authentication server");
1143ff40c12SJohn Marino 		return;
1153ff40c12SJohn Marino 	}
1163ff40c12SJohn Marino 
1173ff40c12SJohn Marino 	if (sm->flags & EAPOL_SM_WAIT_START) {
1183ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
1193ff40c12SJohn Marino 			   " while waiting for EAPOL-Start",
1203ff40c12SJohn Marino 			   MAC2STR(sm->addr));
1213ff40c12SJohn Marino 		return;
1223ff40c12SJohn Marino 	}
1233ff40c12SJohn Marino 
1243ff40c12SJohn Marino 	sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
1253ff40c12SJohn Marino 	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
1263ff40c12SJohn Marino 			   "Sending EAP Packet (identifier %d)",
1273ff40c12SJohn Marino 			   sm->last_eap_id);
1283ff40c12SJohn Marino 	sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
1293ff40c12SJohn Marino 				 IEEE802_1X_TYPE_EAP_PACKET,
1303ff40c12SJohn Marino 				 wpabuf_head(sm->eap_if->eapReqData),
1313ff40c12SJohn Marino 				 wpabuf_len(sm->eap_if->eapReqData));
1323ff40c12SJohn Marino 	sm->dot1xAuthEapolFramesTx++;
1333ff40c12SJohn Marino 	if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
1343ff40c12SJohn Marino 		sm->dot1xAuthEapolReqIdFramesTx++;
1353ff40c12SJohn Marino 	else
1363ff40c12SJohn Marino 		sm->dot1xAuthEapolReqFramesTx++;
1373ff40c12SJohn Marino }
1383ff40c12SJohn Marino 
1393ff40c12SJohn Marino 
1403ff40c12SJohn Marino /**
1413ff40c12SJohn Marino  * eapol_port_timers_tick - Port Timers state machine
1423ff40c12SJohn Marino  * @eloop_ctx: struct eapol_state_machine *
1433ff40c12SJohn Marino  * @timeout_ctx: Not used
1443ff40c12SJohn Marino  *
1453ff40c12SJohn Marino  * This statemachine is implemented as a function that will be called
1463ff40c12SJohn Marino  * once a second as a registered event loop timeout.
1473ff40c12SJohn Marino  */
eapol_port_timers_tick(void * eloop_ctx,void * timeout_ctx)1483ff40c12SJohn Marino static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
1493ff40c12SJohn Marino {
1503ff40c12SJohn Marino 	struct eapol_state_machine *state = timeout_ctx;
1513ff40c12SJohn Marino 
1523ff40c12SJohn Marino 	if (state->aWhile > 0) {
1533ff40c12SJohn Marino 		state->aWhile--;
1543ff40c12SJohn Marino 		if (state->aWhile == 0) {
1553ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
1563ff40c12SJohn Marino 				   " - aWhile --> 0",
1573ff40c12SJohn Marino 				   MAC2STR(state->addr));
1583ff40c12SJohn Marino 		}
1593ff40c12SJohn Marino 	}
1603ff40c12SJohn Marino 
1613ff40c12SJohn Marino 	if (state->quietWhile > 0) {
1623ff40c12SJohn Marino 		state->quietWhile--;
1633ff40c12SJohn Marino 		if (state->quietWhile == 0) {
1643ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
1653ff40c12SJohn Marino 				   " - quietWhile --> 0",
1663ff40c12SJohn Marino 				   MAC2STR(state->addr));
1673ff40c12SJohn Marino 		}
1683ff40c12SJohn Marino 	}
1693ff40c12SJohn Marino 
1703ff40c12SJohn Marino 	if (state->reAuthWhen > 0) {
1713ff40c12SJohn Marino 		state->reAuthWhen--;
1723ff40c12SJohn Marino 		if (state->reAuthWhen == 0) {
1733ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
1743ff40c12SJohn Marino 				   " - reAuthWhen --> 0",
1753ff40c12SJohn Marino 				   MAC2STR(state->addr));
1763ff40c12SJohn Marino 		}
1773ff40c12SJohn Marino 	}
1783ff40c12SJohn Marino 
1793ff40c12SJohn Marino 	if (state->eap_if->retransWhile > 0) {
1803ff40c12SJohn Marino 		state->eap_if->retransWhile--;
1813ff40c12SJohn Marino 		if (state->eap_if->retransWhile == 0) {
1823ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
1833ff40c12SJohn Marino 				   " - (EAP) retransWhile --> 0",
1843ff40c12SJohn Marino 				   MAC2STR(state->addr));
1853ff40c12SJohn Marino 		}
1863ff40c12SJohn Marino 	}
1873ff40c12SJohn Marino 
1883ff40c12SJohn Marino 	eapol_sm_step_run(state);
1893ff40c12SJohn Marino 
1903ff40c12SJohn Marino 	eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
1913ff40c12SJohn Marino }
1923ff40c12SJohn Marino 
1933ff40c12SJohn Marino 
1943ff40c12SJohn Marino 
1953ff40c12SJohn Marino /* Authenticator PAE state machine */
1963ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,INITIALIZE)1973ff40c12SJohn Marino SM_STATE(AUTH_PAE, INITIALIZE)
1983ff40c12SJohn Marino {
1993ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
2003ff40c12SJohn Marino 	sm->portMode = Auto;
201*a1157835SDaniel Fojt 
202*a1157835SDaniel Fojt 	/*
203*a1157835SDaniel Fojt 	 * Clearing keyRun here is not specified in IEEE Std 802.1X-2004, but
204*a1157835SDaniel Fojt 	 * it looks like this would be logical thing to do here since the
205*a1157835SDaniel Fojt 	 * EAPOL-Key exchange is not possible in this state. It is possible to
206*a1157835SDaniel Fojt 	 * get here on disconnection event without advancing to the
207*a1157835SDaniel Fojt 	 * AUTHENTICATING state to clear keyRun before the IEEE 802.11 RSN
208*a1157835SDaniel Fojt 	 * authenticator state machine runs and that may advance from
209*a1157835SDaniel Fojt 	 * AUTHENTICATION2 to INITPMK if keyRun = TRUE has been left from the
210*a1157835SDaniel Fojt 	 * last association. This can be avoided by clearing keyRun here.
211*a1157835SDaniel Fojt 	 */
212*a1157835SDaniel Fojt 	sm->keyRun = FALSE;
2133ff40c12SJohn Marino }
2143ff40c12SJohn Marino 
2153ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,DISCONNECTED)2163ff40c12SJohn Marino SM_STATE(AUTH_PAE, DISCONNECTED)
2173ff40c12SJohn Marino {
2183ff40c12SJohn Marino 	int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
2193ff40c12SJohn Marino 
2203ff40c12SJohn Marino 	if (sm->eapolLogoff) {
2213ff40c12SJohn Marino 		if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
2223ff40c12SJohn Marino 			sm->authEapLogoffsWhileConnecting++;
2233ff40c12SJohn Marino 		else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
2243ff40c12SJohn Marino 			sm->authAuthEapLogoffWhileAuthenticated++;
2253ff40c12SJohn Marino 	}
2263ff40c12SJohn Marino 
2273ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
2283ff40c12SJohn Marino 
2293ff40c12SJohn Marino 	sm->authPortStatus = Unauthorized;
2303ff40c12SJohn Marino 	setPortUnauthorized();
2313ff40c12SJohn Marino 	sm->reAuthCount = 0;
2323ff40c12SJohn Marino 	sm->eapolLogoff = FALSE;
2333ff40c12SJohn Marino 	if (!from_initialize) {
2343ff40c12SJohn Marino 		sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
235*a1157835SDaniel Fojt 				       sm->flags & EAPOL_SM_PREAUTH,
236*a1157835SDaniel Fojt 				       sm->remediation);
2373ff40c12SJohn Marino 	}
2383ff40c12SJohn Marino }
2393ff40c12SJohn Marino 
2403ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,RESTART)2413ff40c12SJohn Marino SM_STATE(AUTH_PAE, RESTART)
2423ff40c12SJohn Marino {
2433ff40c12SJohn Marino 	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
2443ff40c12SJohn Marino 		if (sm->reAuthenticate)
2453ff40c12SJohn Marino 			sm->authAuthReauthsWhileAuthenticated++;
2463ff40c12SJohn Marino 		if (sm->eapolStart)
2473ff40c12SJohn Marino 			sm->authAuthEapStartsWhileAuthenticated++;
2483ff40c12SJohn Marino 		if (sm->eapolLogoff)
2493ff40c12SJohn Marino 			sm->authAuthEapLogoffWhileAuthenticated++;
2503ff40c12SJohn Marino 	}
2513ff40c12SJohn Marino 
2523ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
2533ff40c12SJohn Marino 
2543ff40c12SJohn Marino 	sm->eap_if->eapRestart = TRUE;
2553ff40c12SJohn Marino }
2563ff40c12SJohn Marino 
2573ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,CONNECTING)2583ff40c12SJohn Marino SM_STATE(AUTH_PAE, CONNECTING)
2593ff40c12SJohn Marino {
2603ff40c12SJohn Marino 	if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
2613ff40c12SJohn Marino 		sm->authEntersConnecting++;
2623ff40c12SJohn Marino 
2633ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
2643ff40c12SJohn Marino 
2653ff40c12SJohn Marino 	sm->reAuthenticate = FALSE;
2663ff40c12SJohn Marino 	sm->reAuthCount++;
2673ff40c12SJohn Marino }
2683ff40c12SJohn Marino 
2693ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,HELD)2703ff40c12SJohn Marino SM_STATE(AUTH_PAE, HELD)
2713ff40c12SJohn Marino {
2723ff40c12SJohn Marino 	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
2733ff40c12SJohn Marino 		sm->authAuthFailWhileAuthenticating++;
2743ff40c12SJohn Marino 
2753ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
2763ff40c12SJohn Marino 
2773ff40c12SJohn Marino 	sm->authPortStatus = Unauthorized;
2783ff40c12SJohn Marino 	setPortUnauthorized();
2793ff40c12SJohn Marino 	sm->quietWhile = sm->quietPeriod;
2803ff40c12SJohn Marino 	sm->eapolLogoff = FALSE;
2813ff40c12SJohn Marino 
2823ff40c12SJohn Marino 	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
2833ff40c12SJohn Marino 			   "authentication failed - EAP type: %d (%s)",
2843ff40c12SJohn Marino 			   sm->eap_type_authsrv,
2853ff40c12SJohn Marino 			   eap_server_get_name(0, sm->eap_type_authsrv));
2863ff40c12SJohn Marino 	if (sm->eap_type_authsrv != sm->eap_type_supp) {
2873ff40c12SJohn Marino 		eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
2883ff40c12SJohn Marino 				   "Supplicant used different EAP type: "
2893ff40c12SJohn Marino 				   "%d (%s)", sm->eap_type_supp,
2903ff40c12SJohn Marino 				   eap_server_get_name(0, sm->eap_type_supp));
2913ff40c12SJohn Marino 	}
2923ff40c12SJohn Marino 	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
293*a1157835SDaniel Fojt 			       sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
2943ff40c12SJohn Marino }
2953ff40c12SJohn Marino 
2963ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,AUTHENTICATED)2973ff40c12SJohn Marino SM_STATE(AUTH_PAE, AUTHENTICATED)
2983ff40c12SJohn Marino {
2993ff40c12SJohn Marino 	char *extra = "";
3003ff40c12SJohn Marino 
3013ff40c12SJohn Marino 	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
3023ff40c12SJohn Marino 		sm->authAuthSuccessesWhileAuthenticating++;
3033ff40c12SJohn Marino 
3043ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
3053ff40c12SJohn Marino 
3063ff40c12SJohn Marino 	sm->authPortStatus = Authorized;
3073ff40c12SJohn Marino 	setPortAuthorized();
3083ff40c12SJohn Marino 	sm->reAuthCount = 0;
3093ff40c12SJohn Marino 	if (sm->flags & EAPOL_SM_PREAUTH)
3103ff40c12SJohn Marino 		extra = " (pre-authentication)";
3113ff40c12SJohn Marino 	else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
3123ff40c12SJohn Marino 		extra = " (PMKSA cache)";
3133ff40c12SJohn Marino 	eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
3143ff40c12SJohn Marino 			   "authenticated - EAP type: %d (%s)%s",
3153ff40c12SJohn Marino 			   sm->eap_type_authsrv,
3163ff40c12SJohn Marino 			   eap_server_get_name(0, sm->eap_type_authsrv),
3173ff40c12SJohn Marino 			   extra);
3183ff40c12SJohn Marino 	sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
319*a1157835SDaniel Fojt 			       sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
3203ff40c12SJohn Marino }
3213ff40c12SJohn Marino 
3223ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,AUTHENTICATING)3233ff40c12SJohn Marino SM_STATE(AUTH_PAE, AUTHENTICATING)
3243ff40c12SJohn Marino {
3253ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
3263ff40c12SJohn Marino 
3273ff40c12SJohn Marino 	sm->eapolStart = FALSE;
3283ff40c12SJohn Marino 	sm->authSuccess = FALSE;
3293ff40c12SJohn Marino 	sm->authFail = FALSE;
3303ff40c12SJohn Marino 	sm->authTimeout = FALSE;
3313ff40c12SJohn Marino 	sm->authStart = TRUE;
3323ff40c12SJohn Marino 	sm->keyRun = FALSE;
3333ff40c12SJohn Marino 	sm->keyDone = FALSE;
3343ff40c12SJohn Marino }
3353ff40c12SJohn Marino 
3363ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,ABORTING)3373ff40c12SJohn Marino SM_STATE(AUTH_PAE, ABORTING)
3383ff40c12SJohn Marino {
3393ff40c12SJohn Marino 	if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
3403ff40c12SJohn Marino 		if (sm->authTimeout)
3413ff40c12SJohn Marino 			sm->authAuthTimeoutsWhileAuthenticating++;
3423ff40c12SJohn Marino 		if (sm->eapolStart)
3433ff40c12SJohn Marino 			sm->authAuthEapStartsWhileAuthenticating++;
3443ff40c12SJohn Marino 		if (sm->eapolLogoff)
3453ff40c12SJohn Marino 			sm->authAuthEapLogoffWhileAuthenticating++;
3463ff40c12SJohn Marino 	}
3473ff40c12SJohn Marino 
3483ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
3493ff40c12SJohn Marino 
3503ff40c12SJohn Marino 	sm->authAbort = TRUE;
3513ff40c12SJohn Marino 	sm->keyRun = FALSE;
3523ff40c12SJohn Marino 	sm->keyDone = FALSE;
3533ff40c12SJohn Marino }
3543ff40c12SJohn Marino 
3553ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,FORCE_AUTH)3563ff40c12SJohn Marino SM_STATE(AUTH_PAE, FORCE_AUTH)
3573ff40c12SJohn Marino {
3583ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
3593ff40c12SJohn Marino 
3603ff40c12SJohn Marino 	sm->authPortStatus = Authorized;
3613ff40c12SJohn Marino 	setPortAuthorized();
3623ff40c12SJohn Marino 	sm->portMode = ForceAuthorized;
3633ff40c12SJohn Marino 	sm->eapolStart = FALSE;
3643ff40c12SJohn Marino 	txCannedSuccess();
3653ff40c12SJohn Marino }
3663ff40c12SJohn Marino 
3673ff40c12SJohn Marino 
SM_STATE(AUTH_PAE,FORCE_UNAUTH)3683ff40c12SJohn Marino SM_STATE(AUTH_PAE, FORCE_UNAUTH)
3693ff40c12SJohn Marino {
3703ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
3713ff40c12SJohn Marino 
3723ff40c12SJohn Marino 	sm->authPortStatus = Unauthorized;
3733ff40c12SJohn Marino 	setPortUnauthorized();
3743ff40c12SJohn Marino 	sm->portMode = ForceUnauthorized;
3753ff40c12SJohn Marino 	sm->eapolStart = FALSE;
3763ff40c12SJohn Marino 	txCannedFail();
3773ff40c12SJohn Marino }
3783ff40c12SJohn Marino 
3793ff40c12SJohn Marino 
SM_STEP(AUTH_PAE)3803ff40c12SJohn Marino SM_STEP(AUTH_PAE)
3813ff40c12SJohn Marino {
3823ff40c12SJohn Marino 	if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
3833ff40c12SJohn Marino 	    sm->initialize || !sm->eap_if->portEnabled)
3843ff40c12SJohn Marino 		SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
3853ff40c12SJohn Marino 	else if (sm->portControl == ForceAuthorized &&
3863ff40c12SJohn Marino 		 sm->portMode != sm->portControl &&
3873ff40c12SJohn Marino 		 !(sm->initialize || !sm->eap_if->portEnabled))
3883ff40c12SJohn Marino 		SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
3893ff40c12SJohn Marino 	else if (sm->portControl == ForceUnauthorized &&
3903ff40c12SJohn Marino 		 sm->portMode != sm->portControl &&
3913ff40c12SJohn Marino 		 !(sm->initialize || !sm->eap_if->portEnabled))
3923ff40c12SJohn Marino 		SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
3933ff40c12SJohn Marino 	else {
3943ff40c12SJohn Marino 		switch (sm->auth_pae_state) {
3953ff40c12SJohn Marino 		case AUTH_PAE_INITIALIZE:
3963ff40c12SJohn Marino 			SM_ENTER(AUTH_PAE, DISCONNECTED);
3973ff40c12SJohn Marino 			break;
3983ff40c12SJohn Marino 		case AUTH_PAE_DISCONNECTED:
3993ff40c12SJohn Marino 			SM_ENTER(AUTH_PAE, RESTART);
4003ff40c12SJohn Marino 			break;
4013ff40c12SJohn Marino 		case AUTH_PAE_RESTART:
4023ff40c12SJohn Marino 			if (!sm->eap_if->eapRestart)
4033ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, CONNECTING);
4043ff40c12SJohn Marino 			break;
4053ff40c12SJohn Marino 		case AUTH_PAE_HELD:
4063ff40c12SJohn Marino 			if (sm->quietWhile == 0)
4073ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, RESTART);
4083ff40c12SJohn Marino 			break;
4093ff40c12SJohn Marino 		case AUTH_PAE_CONNECTING:
4103ff40c12SJohn Marino 			if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
4113ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, DISCONNECTED);
4123ff40c12SJohn Marino 			else if ((sm->eap_if->eapReq &&
4133ff40c12SJohn Marino 				  sm->reAuthCount <= sm->reAuthMax) ||
4143ff40c12SJohn Marino 				 sm->eap_if->eapSuccess || sm->eap_if->eapFail)
4153ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, AUTHENTICATING);
4163ff40c12SJohn Marino 			break;
4173ff40c12SJohn Marino 		case AUTH_PAE_AUTHENTICATED:
4183ff40c12SJohn Marino 			if (sm->eapolStart || sm->reAuthenticate)
4193ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, RESTART);
4203ff40c12SJohn Marino 			else if (sm->eapolLogoff || !sm->portValid)
4213ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, DISCONNECTED);
4223ff40c12SJohn Marino 			break;
4233ff40c12SJohn Marino 		case AUTH_PAE_AUTHENTICATING:
4243ff40c12SJohn Marino 			if (sm->authSuccess && sm->portValid)
4253ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, AUTHENTICATED);
4263ff40c12SJohn Marino 			else if (sm->authFail ||
4273ff40c12SJohn Marino 				 (sm->keyDone && !sm->portValid))
4283ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, HELD);
4293ff40c12SJohn Marino 			else if (sm->eapolStart || sm->eapolLogoff ||
4303ff40c12SJohn Marino 				 sm->authTimeout)
4313ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, ABORTING);
4323ff40c12SJohn Marino 			break;
4333ff40c12SJohn Marino 		case AUTH_PAE_ABORTING:
4343ff40c12SJohn Marino 			if (sm->eapolLogoff && !sm->authAbort)
4353ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, DISCONNECTED);
4363ff40c12SJohn Marino 			else if (!sm->eapolLogoff && !sm->authAbort)
4373ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, RESTART);
4383ff40c12SJohn Marino 			break;
4393ff40c12SJohn Marino 		case AUTH_PAE_FORCE_AUTH:
4403ff40c12SJohn Marino 			if (sm->eapolStart)
4413ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, FORCE_AUTH);
4423ff40c12SJohn Marino 			break;
4433ff40c12SJohn Marino 		case AUTH_PAE_FORCE_UNAUTH:
4443ff40c12SJohn Marino 			if (sm->eapolStart)
4453ff40c12SJohn Marino 				SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
4463ff40c12SJohn Marino 			break;
4473ff40c12SJohn Marino 		}
4483ff40c12SJohn Marino 	}
4493ff40c12SJohn Marino }
4503ff40c12SJohn Marino 
4513ff40c12SJohn Marino 
4523ff40c12SJohn Marino 
4533ff40c12SJohn Marino /* Backend Authentication state machine */
4543ff40c12SJohn Marino 
SM_STATE(BE_AUTH,INITIALIZE)4553ff40c12SJohn Marino SM_STATE(BE_AUTH, INITIALIZE)
4563ff40c12SJohn Marino {
4573ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
4583ff40c12SJohn Marino 
4593ff40c12SJohn Marino 	abortAuth();
4603ff40c12SJohn Marino 	sm->eap_if->eapNoReq = FALSE;
4613ff40c12SJohn Marino 	sm->authAbort = FALSE;
4623ff40c12SJohn Marino }
4633ff40c12SJohn Marino 
4643ff40c12SJohn Marino 
SM_STATE(BE_AUTH,REQUEST)4653ff40c12SJohn Marino SM_STATE(BE_AUTH, REQUEST)
4663ff40c12SJohn Marino {
4673ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
4683ff40c12SJohn Marino 
4693ff40c12SJohn Marino 	txReq();
4703ff40c12SJohn Marino 	sm->eap_if->eapReq = FALSE;
4713ff40c12SJohn Marino 	sm->backendOtherRequestsToSupplicant++;
4723ff40c12SJohn Marino 
4733ff40c12SJohn Marino 	/*
4743ff40c12SJohn Marino 	 * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
4753ff40c12SJohn Marino 	 * it looks like this would be logical thing to do there since the old
4763ff40c12SJohn Marino 	 * EAP response would not be valid anymore after the new EAP request
4773ff40c12SJohn Marino 	 * was sent out.
4783ff40c12SJohn Marino 	 *
4793ff40c12SJohn Marino 	 * A race condition has been reported, in which hostapd ended up
4803ff40c12SJohn Marino 	 * sending out EAP-Response/Identity as a response to the first
4813ff40c12SJohn Marino 	 * EAP-Request from the main EAP method. This can be avoided by
4823ff40c12SJohn Marino 	 * clearing eapolEap here.
4833ff40c12SJohn Marino 	 */
4843ff40c12SJohn Marino 	sm->eapolEap = FALSE;
4853ff40c12SJohn Marino }
4863ff40c12SJohn Marino 
4873ff40c12SJohn Marino 
SM_STATE(BE_AUTH,RESPONSE)4883ff40c12SJohn Marino SM_STATE(BE_AUTH, RESPONSE)
4893ff40c12SJohn Marino {
4903ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
4913ff40c12SJohn Marino 
4923ff40c12SJohn Marino 	sm->authTimeout = FALSE;
4933ff40c12SJohn Marino 	sm->eapolEap = FALSE;
4943ff40c12SJohn Marino 	sm->eap_if->eapNoReq = FALSE;
4953ff40c12SJohn Marino 	sm->aWhile = sm->serverTimeout;
4963ff40c12SJohn Marino 	sm->eap_if->eapResp = TRUE;
4973ff40c12SJohn Marino 	/* sendRespToServer(); */
4983ff40c12SJohn Marino 	sm->backendResponses++;
4993ff40c12SJohn Marino }
5003ff40c12SJohn Marino 
5013ff40c12SJohn Marino 
SM_STATE(BE_AUTH,SUCCESS)5023ff40c12SJohn Marino SM_STATE(BE_AUTH, SUCCESS)
5033ff40c12SJohn Marino {
5043ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
5053ff40c12SJohn Marino 
5063ff40c12SJohn Marino 	txReq();
5073ff40c12SJohn Marino 	sm->authSuccess = TRUE;
5083ff40c12SJohn Marino 	sm->keyRun = TRUE;
5093ff40c12SJohn Marino }
5103ff40c12SJohn Marino 
5113ff40c12SJohn Marino 
SM_STATE(BE_AUTH,FAIL)5123ff40c12SJohn Marino SM_STATE(BE_AUTH, FAIL)
5133ff40c12SJohn Marino {
5143ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
5153ff40c12SJohn Marino 
5163ff40c12SJohn Marino 	txReq();
5173ff40c12SJohn Marino 	sm->authFail = TRUE;
5183ff40c12SJohn Marino }
5193ff40c12SJohn Marino 
5203ff40c12SJohn Marino 
SM_STATE(BE_AUTH,TIMEOUT)5213ff40c12SJohn Marino SM_STATE(BE_AUTH, TIMEOUT)
5223ff40c12SJohn Marino {
5233ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
5243ff40c12SJohn Marino 
5253ff40c12SJohn Marino 	sm->authTimeout = TRUE;
5263ff40c12SJohn Marino }
5273ff40c12SJohn Marino 
5283ff40c12SJohn Marino 
SM_STATE(BE_AUTH,IDLE)5293ff40c12SJohn Marino SM_STATE(BE_AUTH, IDLE)
5303ff40c12SJohn Marino {
5313ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
5323ff40c12SJohn Marino 
5333ff40c12SJohn Marino 	sm->authStart = FALSE;
5343ff40c12SJohn Marino }
5353ff40c12SJohn Marino 
5363ff40c12SJohn Marino 
SM_STATE(BE_AUTH,IGNORE)5373ff40c12SJohn Marino SM_STATE(BE_AUTH, IGNORE)
5383ff40c12SJohn Marino {
5393ff40c12SJohn Marino 	SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
5403ff40c12SJohn Marino 
5413ff40c12SJohn Marino 	sm->eap_if->eapNoReq = FALSE;
5423ff40c12SJohn Marino }
5433ff40c12SJohn Marino 
5443ff40c12SJohn Marino 
SM_STEP(BE_AUTH)5453ff40c12SJohn Marino SM_STEP(BE_AUTH)
5463ff40c12SJohn Marino {
5473ff40c12SJohn Marino 	if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
5483ff40c12SJohn Marino 		SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
5493ff40c12SJohn Marino 		return;
5503ff40c12SJohn Marino 	}
5513ff40c12SJohn Marino 
5523ff40c12SJohn Marino 	switch (sm->be_auth_state) {
5533ff40c12SJohn Marino 	case BE_AUTH_INITIALIZE:
5543ff40c12SJohn Marino 		SM_ENTER(BE_AUTH, IDLE);
5553ff40c12SJohn Marino 		break;
5563ff40c12SJohn Marino 	case BE_AUTH_REQUEST:
5573ff40c12SJohn Marino 		if (sm->eapolEap)
5583ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, RESPONSE);
5593ff40c12SJohn Marino 		else if (sm->eap_if->eapReq)
5603ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, REQUEST);
5613ff40c12SJohn Marino 		else if (sm->eap_if->eapTimeout)
5623ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, TIMEOUT);
5633ff40c12SJohn Marino 		break;
5643ff40c12SJohn Marino 	case BE_AUTH_RESPONSE:
5653ff40c12SJohn Marino 		if (sm->eap_if->eapNoReq)
5663ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, IGNORE);
5673ff40c12SJohn Marino 		if (sm->eap_if->eapReq) {
5683ff40c12SJohn Marino 			sm->backendAccessChallenges++;
5693ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, REQUEST);
5703ff40c12SJohn Marino 		} else if (sm->aWhile == 0)
5713ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, TIMEOUT);
5723ff40c12SJohn Marino 		else if (sm->eap_if->eapFail) {
5733ff40c12SJohn Marino 			sm->backendAuthFails++;
5743ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, FAIL);
5753ff40c12SJohn Marino 		} else if (sm->eap_if->eapSuccess) {
5763ff40c12SJohn Marino 			sm->backendAuthSuccesses++;
5773ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, SUCCESS);
5783ff40c12SJohn Marino 		}
5793ff40c12SJohn Marino 		break;
5803ff40c12SJohn Marino 	case BE_AUTH_SUCCESS:
5813ff40c12SJohn Marino 		SM_ENTER(BE_AUTH, IDLE);
5823ff40c12SJohn Marino 		break;
5833ff40c12SJohn Marino 	case BE_AUTH_FAIL:
5843ff40c12SJohn Marino 		SM_ENTER(BE_AUTH, IDLE);
5853ff40c12SJohn Marino 		break;
5863ff40c12SJohn Marino 	case BE_AUTH_TIMEOUT:
5873ff40c12SJohn Marino 		SM_ENTER(BE_AUTH, IDLE);
5883ff40c12SJohn Marino 		break;
5893ff40c12SJohn Marino 	case BE_AUTH_IDLE:
5903ff40c12SJohn Marino 		if (sm->eap_if->eapFail && sm->authStart)
5913ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, FAIL);
5923ff40c12SJohn Marino 		else if (sm->eap_if->eapReq && sm->authStart)
5933ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, REQUEST);
5943ff40c12SJohn Marino 		else if (sm->eap_if->eapSuccess && sm->authStart)
5953ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, SUCCESS);
5963ff40c12SJohn Marino 		break;
5973ff40c12SJohn Marino 	case BE_AUTH_IGNORE:
5983ff40c12SJohn Marino 		if (sm->eapolEap)
5993ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, RESPONSE);
6003ff40c12SJohn Marino 		else if (sm->eap_if->eapReq)
6013ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, REQUEST);
6023ff40c12SJohn Marino 		else if (sm->eap_if->eapTimeout)
6033ff40c12SJohn Marino 			SM_ENTER(BE_AUTH, TIMEOUT);
6043ff40c12SJohn Marino 		break;
6053ff40c12SJohn Marino 	}
6063ff40c12SJohn Marino }
6073ff40c12SJohn Marino 
6083ff40c12SJohn Marino 
6093ff40c12SJohn Marino 
6103ff40c12SJohn Marino /* Reauthentication Timer state machine */
6113ff40c12SJohn Marino 
SM_STATE(REAUTH_TIMER,INITIALIZE)6123ff40c12SJohn Marino SM_STATE(REAUTH_TIMER, INITIALIZE)
6133ff40c12SJohn Marino {
6143ff40c12SJohn Marino 	SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
6153ff40c12SJohn Marino 
6163ff40c12SJohn Marino 	sm->reAuthWhen = sm->reAuthPeriod;
6173ff40c12SJohn Marino }
6183ff40c12SJohn Marino 
6193ff40c12SJohn Marino 
SM_STATE(REAUTH_TIMER,REAUTHENTICATE)6203ff40c12SJohn Marino SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
6213ff40c12SJohn Marino {
6223ff40c12SJohn Marino 	SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
6233ff40c12SJohn Marino 
6243ff40c12SJohn Marino 	sm->reAuthenticate = TRUE;
6253ff40c12SJohn Marino 	sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
6263ff40c12SJohn Marino 				  EAPOL_AUTH_REAUTHENTICATE);
6273ff40c12SJohn Marino }
6283ff40c12SJohn Marino 
6293ff40c12SJohn Marino 
SM_STEP(REAUTH_TIMER)6303ff40c12SJohn Marino SM_STEP(REAUTH_TIMER)
6313ff40c12SJohn Marino {
6323ff40c12SJohn Marino 	if (sm->portControl != Auto || sm->initialize ||
6333ff40c12SJohn Marino 	    sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
6343ff40c12SJohn Marino 		SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
6353ff40c12SJohn Marino 		return;
6363ff40c12SJohn Marino 	}
6373ff40c12SJohn Marino 
6383ff40c12SJohn Marino 	switch (sm->reauth_timer_state) {
6393ff40c12SJohn Marino 	case REAUTH_TIMER_INITIALIZE:
6403ff40c12SJohn Marino 		if (sm->reAuthWhen == 0)
6413ff40c12SJohn Marino 			SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
6423ff40c12SJohn Marino 		break;
6433ff40c12SJohn Marino 	case REAUTH_TIMER_REAUTHENTICATE:
6443ff40c12SJohn Marino 		SM_ENTER(REAUTH_TIMER, INITIALIZE);
6453ff40c12SJohn Marino 		break;
6463ff40c12SJohn Marino 	}
6473ff40c12SJohn Marino }
6483ff40c12SJohn Marino 
6493ff40c12SJohn Marino 
6503ff40c12SJohn Marino 
6513ff40c12SJohn Marino /* Authenticator Key Transmit state machine */
6523ff40c12SJohn Marino 
SM_STATE(AUTH_KEY_TX,NO_KEY_TRANSMIT)6533ff40c12SJohn Marino SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
6543ff40c12SJohn Marino {
6553ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
6563ff40c12SJohn Marino }
6573ff40c12SJohn Marino 
6583ff40c12SJohn Marino 
SM_STATE(AUTH_KEY_TX,KEY_TRANSMIT)6593ff40c12SJohn Marino SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
6603ff40c12SJohn Marino {
6613ff40c12SJohn Marino 	SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
6623ff40c12SJohn Marino 
6633ff40c12SJohn Marino 	txKey();
6643ff40c12SJohn Marino 	sm->eap_if->eapKeyAvailable = FALSE;
6653ff40c12SJohn Marino 	sm->keyDone = TRUE;
6663ff40c12SJohn Marino }
6673ff40c12SJohn Marino 
6683ff40c12SJohn Marino 
SM_STEP(AUTH_KEY_TX)6693ff40c12SJohn Marino SM_STEP(AUTH_KEY_TX)
6703ff40c12SJohn Marino {
6713ff40c12SJohn Marino 	if (sm->initialize || sm->portControl != Auto) {
6723ff40c12SJohn Marino 		SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
6733ff40c12SJohn Marino 		return;
6743ff40c12SJohn Marino 	}
6753ff40c12SJohn Marino 
6763ff40c12SJohn Marino 	switch (sm->auth_key_tx_state) {
6773ff40c12SJohn Marino 	case AUTH_KEY_TX_NO_KEY_TRANSMIT:
6783ff40c12SJohn Marino 		if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
6793ff40c12SJohn Marino 		    sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
6803ff40c12SJohn Marino 			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
6813ff40c12SJohn Marino 		break;
6823ff40c12SJohn Marino 	case AUTH_KEY_TX_KEY_TRANSMIT:
6833ff40c12SJohn Marino 		if (!sm->keyTxEnabled || !sm->keyRun)
6843ff40c12SJohn Marino 			SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
6853ff40c12SJohn Marino 		else if (sm->eap_if->eapKeyAvailable)
6863ff40c12SJohn Marino 			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
6873ff40c12SJohn Marino 		break;
6883ff40c12SJohn Marino 	}
6893ff40c12SJohn Marino }
6903ff40c12SJohn Marino 
6913ff40c12SJohn Marino 
6923ff40c12SJohn Marino 
6933ff40c12SJohn Marino /* Key Receive state machine */
6943ff40c12SJohn Marino 
SM_STATE(KEY_RX,NO_KEY_RECEIVE)6953ff40c12SJohn Marino SM_STATE(KEY_RX, NO_KEY_RECEIVE)
6963ff40c12SJohn Marino {
6973ff40c12SJohn Marino 	SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
6983ff40c12SJohn Marino }
6993ff40c12SJohn Marino 
7003ff40c12SJohn Marino 
SM_STATE(KEY_RX,KEY_RECEIVE)7013ff40c12SJohn Marino SM_STATE(KEY_RX, KEY_RECEIVE)
7023ff40c12SJohn Marino {
7033ff40c12SJohn Marino 	SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
7043ff40c12SJohn Marino 
7053ff40c12SJohn Marino 	processKey();
7063ff40c12SJohn Marino 	sm->rxKey = FALSE;
7073ff40c12SJohn Marino }
7083ff40c12SJohn Marino 
7093ff40c12SJohn Marino 
SM_STEP(KEY_RX)7103ff40c12SJohn Marino SM_STEP(KEY_RX)
7113ff40c12SJohn Marino {
7123ff40c12SJohn Marino 	if (sm->initialize || !sm->eap_if->portEnabled) {
7133ff40c12SJohn Marino 		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
7143ff40c12SJohn Marino 		return;
7153ff40c12SJohn Marino 	}
7163ff40c12SJohn Marino 
7173ff40c12SJohn Marino 	switch (sm->key_rx_state) {
7183ff40c12SJohn Marino 	case KEY_RX_NO_KEY_RECEIVE:
7193ff40c12SJohn Marino 		if (sm->rxKey)
7203ff40c12SJohn Marino 			SM_ENTER(KEY_RX, KEY_RECEIVE);
7213ff40c12SJohn Marino 		break;
7223ff40c12SJohn Marino 	case KEY_RX_KEY_RECEIVE:
7233ff40c12SJohn Marino 		if (sm->rxKey)
7243ff40c12SJohn Marino 			SM_ENTER(KEY_RX, KEY_RECEIVE);
7253ff40c12SJohn Marino 		break;
7263ff40c12SJohn Marino 	}
7273ff40c12SJohn Marino }
7283ff40c12SJohn Marino 
7293ff40c12SJohn Marino 
7303ff40c12SJohn Marino 
7313ff40c12SJohn Marino /* Controlled Directions state machine */
7323ff40c12SJohn Marino 
SM_STATE(CTRL_DIR,FORCE_BOTH)7333ff40c12SJohn Marino SM_STATE(CTRL_DIR, FORCE_BOTH)
7343ff40c12SJohn Marino {
7353ff40c12SJohn Marino 	SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
7363ff40c12SJohn Marino 	sm->operControlledDirections = Both;
7373ff40c12SJohn Marino }
7383ff40c12SJohn Marino 
7393ff40c12SJohn Marino 
SM_STATE(CTRL_DIR,IN_OR_BOTH)7403ff40c12SJohn Marino SM_STATE(CTRL_DIR, IN_OR_BOTH)
7413ff40c12SJohn Marino {
7423ff40c12SJohn Marino 	SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
7433ff40c12SJohn Marino 	sm->operControlledDirections = sm->adminControlledDirections;
7443ff40c12SJohn Marino }
7453ff40c12SJohn Marino 
7463ff40c12SJohn Marino 
SM_STEP(CTRL_DIR)7473ff40c12SJohn Marino SM_STEP(CTRL_DIR)
7483ff40c12SJohn Marino {
7493ff40c12SJohn Marino 	if (sm->initialize) {
7503ff40c12SJohn Marino 		SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
7513ff40c12SJohn Marino 		return;
7523ff40c12SJohn Marino 	}
7533ff40c12SJohn Marino 
7543ff40c12SJohn Marino 	switch (sm->ctrl_dir_state) {
7553ff40c12SJohn Marino 	case CTRL_DIR_FORCE_BOTH:
7563ff40c12SJohn Marino 		if (sm->eap_if->portEnabled && sm->operEdge)
7573ff40c12SJohn Marino 			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
7583ff40c12SJohn Marino 		break;
7593ff40c12SJohn Marino 	case CTRL_DIR_IN_OR_BOTH:
7603ff40c12SJohn Marino 		if (sm->operControlledDirections !=
7613ff40c12SJohn Marino 		    sm->adminControlledDirections)
7623ff40c12SJohn Marino 			SM_ENTER(CTRL_DIR, IN_OR_BOTH);
7633ff40c12SJohn Marino 		if (!sm->eap_if->portEnabled || !sm->operEdge)
7643ff40c12SJohn Marino 			SM_ENTER(CTRL_DIR, FORCE_BOTH);
7653ff40c12SJohn Marino 		break;
7663ff40c12SJohn Marino 	}
7673ff40c12SJohn Marino }
7683ff40c12SJohn Marino 
7693ff40c12SJohn Marino 
7703ff40c12SJohn Marino 
7713ff40c12SJohn Marino struct eapol_state_machine *
eapol_auth_alloc(struct eapol_authenticator * eapol,const u8 * addr,int flags,const struct wpabuf * assoc_wps_ie,const struct wpabuf * assoc_p2p_ie,void * sta_ctx,const char * identity,const char * radius_cui)7723ff40c12SJohn Marino eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
7733ff40c12SJohn Marino 		 int flags, const struct wpabuf *assoc_wps_ie,
7743ff40c12SJohn Marino 		 const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
7753ff40c12SJohn Marino 		 const char *identity, const char *radius_cui)
7763ff40c12SJohn Marino {
7773ff40c12SJohn Marino 	struct eapol_state_machine *sm;
7783ff40c12SJohn Marino 	struct eap_config eap_conf;
7793ff40c12SJohn Marino 
7803ff40c12SJohn Marino 	if (eapol == NULL)
7813ff40c12SJohn Marino 		return NULL;
7823ff40c12SJohn Marino 
7833ff40c12SJohn Marino 	sm = os_zalloc(sizeof(*sm));
7843ff40c12SJohn Marino 	if (sm == NULL) {
7853ff40c12SJohn Marino 		wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
7863ff40c12SJohn Marino 			   "failed");
7873ff40c12SJohn Marino 		return NULL;
7883ff40c12SJohn Marino 	}
7893ff40c12SJohn Marino 	sm->radius_identifier = -1;
7903ff40c12SJohn Marino 	os_memcpy(sm->addr, addr, ETH_ALEN);
7913ff40c12SJohn Marino 	sm->flags = flags;
7923ff40c12SJohn Marino 
7933ff40c12SJohn Marino 	sm->eapol = eapol;
7943ff40c12SJohn Marino 	sm->sta = sta_ctx;
7953ff40c12SJohn Marino 
7963ff40c12SJohn Marino 	/* Set default values for state machine constants */
7973ff40c12SJohn Marino 	sm->auth_pae_state = AUTH_PAE_INITIALIZE;
7983ff40c12SJohn Marino 	sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
7993ff40c12SJohn Marino 	sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
8003ff40c12SJohn Marino 
8013ff40c12SJohn Marino 	sm->be_auth_state = BE_AUTH_INITIALIZE;
8023ff40c12SJohn Marino 	sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
8033ff40c12SJohn Marino 
8043ff40c12SJohn Marino 	sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
8053ff40c12SJohn Marino 	sm->reAuthPeriod = eapol->conf.eap_reauth_period;
8063ff40c12SJohn Marino 	sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
8073ff40c12SJohn Marino 
8083ff40c12SJohn Marino 	sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
8093ff40c12SJohn Marino 
8103ff40c12SJohn Marino 	sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
8113ff40c12SJohn Marino 
8123ff40c12SJohn Marino 	sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
8133ff40c12SJohn Marino 
8143ff40c12SJohn Marino 	sm->portControl = Auto;
8153ff40c12SJohn Marino 
8163ff40c12SJohn Marino 	if (!eapol->conf.wpa &&
8173ff40c12SJohn Marino 	    (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
8183ff40c12SJohn Marino 		sm->keyTxEnabled = TRUE;
8193ff40c12SJohn Marino 	else
8203ff40c12SJohn Marino 		sm->keyTxEnabled = FALSE;
8213ff40c12SJohn Marino 	if (eapol->conf.wpa)
8223ff40c12SJohn Marino 		sm->portValid = FALSE;
8233ff40c12SJohn Marino 	else
8243ff40c12SJohn Marino 		sm->portValid = TRUE;
8253ff40c12SJohn Marino 
8263ff40c12SJohn Marino 	os_memset(&eap_conf, 0, sizeof(eap_conf));
8273ff40c12SJohn Marino 	eap_conf.eap_server = eapol->conf.eap_server;
8283ff40c12SJohn Marino 	eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
8293ff40c12SJohn Marino 	eap_conf.msg_ctx = eapol->conf.msg_ctx;
8303ff40c12SJohn Marino 	eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
8313ff40c12SJohn Marino 	eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
8323ff40c12SJohn Marino 	eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
8333ff40c12SJohn Marino 	eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
8343ff40c12SJohn Marino 	eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
8353ff40c12SJohn Marino 	eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
8363ff40c12SJohn Marino 	eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
8373ff40c12SJohn Marino 	eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
838*a1157835SDaniel Fojt 	eap_conf.eap_teap_auth = eapol->conf.eap_teap_auth;
839*a1157835SDaniel Fojt 	eap_conf.eap_teap_pac_no_inner = eapol->conf.eap_teap_pac_no_inner;
8403ff40c12SJohn Marino 	eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
841*a1157835SDaniel Fojt 	eap_conf.eap_sim_id = eapol->conf.eap_sim_id;
8423ff40c12SJohn Marino 	eap_conf.tnc = eapol->conf.tnc;
8433ff40c12SJohn Marino 	eap_conf.wps = eapol->conf.wps;
8443ff40c12SJohn Marino 	eap_conf.assoc_wps_ie = assoc_wps_ie;
8453ff40c12SJohn Marino 	eap_conf.assoc_p2p_ie = assoc_p2p_ie;
8463ff40c12SJohn Marino 	eap_conf.peer_addr = addr;
8473ff40c12SJohn Marino 	eap_conf.fragment_size = eapol->conf.fragment_size;
8483ff40c12SJohn Marino 	eap_conf.pwd_group = eapol->conf.pwd_group;
8493ff40c12SJohn Marino 	eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
8503ff40c12SJohn Marino 	eap_conf.server_id = eapol->conf.server_id;
8513ff40c12SJohn Marino 	eap_conf.server_id_len = eapol->conf.server_id_len;
852*a1157835SDaniel Fojt 	eap_conf.erp = eapol->conf.erp;
853*a1157835SDaniel Fojt 	eap_conf.tls_session_lifetime = eapol->conf.tls_session_lifetime;
854*a1157835SDaniel Fojt 	eap_conf.tls_flags = eapol->conf.tls_flags;
8553ff40c12SJohn Marino 	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
8563ff40c12SJohn Marino 	if (sm->eap == NULL) {
8573ff40c12SJohn Marino 		eapol_auth_free(sm);
8583ff40c12SJohn Marino 		return NULL;
8593ff40c12SJohn Marino 	}
8603ff40c12SJohn Marino 	sm->eap_if = eap_get_interface(sm->eap);
8613ff40c12SJohn Marino 
8623ff40c12SJohn Marino 	eapol_auth_initialize(sm);
8633ff40c12SJohn Marino 
8643ff40c12SJohn Marino 	if (identity) {
8653ff40c12SJohn Marino 		sm->identity = (u8 *) os_strdup(identity);
8663ff40c12SJohn Marino 		if (sm->identity)
8673ff40c12SJohn Marino 			sm->identity_len = os_strlen(identity);
8683ff40c12SJohn Marino 	}
8693ff40c12SJohn Marino 	if (radius_cui)
8703ff40c12SJohn Marino 		sm->radius_cui = wpabuf_alloc_copy(radius_cui,
8713ff40c12SJohn Marino 						   os_strlen(radius_cui));
8723ff40c12SJohn Marino 
873*a1157835SDaniel Fojt #ifndef CONFIG_NO_RADIUS
874*a1157835SDaniel Fojt 	if (radius_gen_session_id((u8 *) &sm->acct_multi_session_id,
875*a1157835SDaniel Fojt 				  sizeof(sm->acct_multi_session_id)) < 0) {
876*a1157835SDaniel Fojt 		eapol_auth_free(sm);
877*a1157835SDaniel Fojt 		return NULL;
878*a1157835SDaniel Fojt 	}
879*a1157835SDaniel Fojt #endif /* CONFIG_NO_RADIUS */
880*a1157835SDaniel Fojt 
8813ff40c12SJohn Marino 	return sm;
8823ff40c12SJohn Marino }
8833ff40c12SJohn Marino 
8843ff40c12SJohn Marino 
eapol_auth_free(struct eapol_state_machine * sm)8853ff40c12SJohn Marino void eapol_auth_free(struct eapol_state_machine *sm)
8863ff40c12SJohn Marino {
8873ff40c12SJohn Marino 	if (sm == NULL)
8883ff40c12SJohn Marino 		return;
8893ff40c12SJohn Marino 
8903ff40c12SJohn Marino 	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
8913ff40c12SJohn Marino 	eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
8923ff40c12SJohn Marino 	if (sm->eap)
8933ff40c12SJohn Marino 		eap_server_sm_deinit(sm->eap);
894*a1157835SDaniel Fojt 
895*a1157835SDaniel Fojt 	wpabuf_free(sm->radius_cui);
896*a1157835SDaniel Fojt 	os_free(sm->identity);
8973ff40c12SJohn Marino 	os_free(sm);
8983ff40c12SJohn Marino }
8993ff40c12SJohn Marino 
9003ff40c12SJohn Marino 
eapol_sm_sta_entry_alive(struct eapol_authenticator * eapol,const u8 * addr)9013ff40c12SJohn Marino static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
9023ff40c12SJohn Marino 				    const u8 *addr)
9033ff40c12SJohn Marino {
9043ff40c12SJohn Marino 	return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
9053ff40c12SJohn Marino }
9063ff40c12SJohn Marino 
9073ff40c12SJohn Marino 
eapol_sm_step_run(struct eapol_state_machine * sm)9083ff40c12SJohn Marino static void eapol_sm_step_run(struct eapol_state_machine *sm)
9093ff40c12SJohn Marino {
9103ff40c12SJohn Marino 	struct eapol_authenticator *eapol = sm->eapol;
9113ff40c12SJohn Marino 	u8 addr[ETH_ALEN];
9123ff40c12SJohn Marino 	unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
9133ff40c12SJohn Marino 		prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
9143ff40c12SJohn Marino 	int max_steps = 100;
9153ff40c12SJohn Marino 
9163ff40c12SJohn Marino 	os_memcpy(addr, sm->addr, ETH_ALEN);
9173ff40c12SJohn Marino 
9183ff40c12SJohn Marino 	/*
9193ff40c12SJohn Marino 	 * Allow EAPOL state machines to run as long as there are state
9203ff40c12SJohn Marino 	 * changes, but exit and return here through event loop if more than
9213ff40c12SJohn Marino 	 * 100 steps is needed as a precaution against infinite loops inside
9223ff40c12SJohn Marino 	 * eloop callback.
9233ff40c12SJohn Marino 	 */
9243ff40c12SJohn Marino restart:
9253ff40c12SJohn Marino 	prev_auth_pae = sm->auth_pae_state;
9263ff40c12SJohn Marino 	prev_be_auth = sm->be_auth_state;
9273ff40c12SJohn Marino 	prev_reauth_timer = sm->reauth_timer_state;
9283ff40c12SJohn Marino 	prev_auth_key_tx = sm->auth_key_tx_state;
9293ff40c12SJohn Marino 	prev_key_rx = sm->key_rx_state;
9303ff40c12SJohn Marino 	prev_ctrl_dir = sm->ctrl_dir_state;
9313ff40c12SJohn Marino 
9323ff40c12SJohn Marino 	SM_STEP_RUN(AUTH_PAE);
9333ff40c12SJohn Marino 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
9343ff40c12SJohn Marino 		SM_STEP_RUN(BE_AUTH);
9353ff40c12SJohn Marino 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
9363ff40c12SJohn Marino 		SM_STEP_RUN(REAUTH_TIMER);
9373ff40c12SJohn Marino 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
9383ff40c12SJohn Marino 		SM_STEP_RUN(AUTH_KEY_TX);
9393ff40c12SJohn Marino 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
9403ff40c12SJohn Marino 		SM_STEP_RUN(KEY_RX);
9413ff40c12SJohn Marino 	if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
9423ff40c12SJohn Marino 		SM_STEP_RUN(CTRL_DIR);
9433ff40c12SJohn Marino 
9443ff40c12SJohn Marino 	if (prev_auth_pae != sm->auth_pae_state ||
9453ff40c12SJohn Marino 	    prev_be_auth != sm->be_auth_state ||
9463ff40c12SJohn Marino 	    prev_reauth_timer != sm->reauth_timer_state ||
9473ff40c12SJohn Marino 	    prev_auth_key_tx != sm->auth_key_tx_state ||
9483ff40c12SJohn Marino 	    prev_key_rx != sm->key_rx_state ||
9493ff40c12SJohn Marino 	    prev_ctrl_dir != sm->ctrl_dir_state) {
9503ff40c12SJohn Marino 		if (--max_steps > 0)
9513ff40c12SJohn Marino 			goto restart;
9523ff40c12SJohn Marino 		/* Re-run from eloop timeout */
9533ff40c12SJohn Marino 		eapol_auth_step(sm);
9543ff40c12SJohn Marino 		return;
9553ff40c12SJohn Marino 	}
9563ff40c12SJohn Marino 
9573ff40c12SJohn Marino 	if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
9583ff40c12SJohn Marino 		if (eap_server_sm_step(sm->eap)) {
9593ff40c12SJohn Marino 			if (--max_steps > 0)
9603ff40c12SJohn Marino 				goto restart;
9613ff40c12SJohn Marino 			/* Re-run from eloop timeout */
9623ff40c12SJohn Marino 			eapol_auth_step(sm);
9633ff40c12SJohn Marino 			return;
9643ff40c12SJohn Marino 		}
9653ff40c12SJohn Marino 
9663ff40c12SJohn Marino 		/* TODO: find a better location for this */
9673ff40c12SJohn Marino 		if (sm->eap_if->aaaEapResp) {
9683ff40c12SJohn Marino 			sm->eap_if->aaaEapResp = FALSE;
9693ff40c12SJohn Marino 			if (sm->eap_if->aaaEapRespData == NULL) {
9703ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
9713ff40c12SJohn Marino 					   "but no aaaEapRespData available");
9723ff40c12SJohn Marino 				return;
9733ff40c12SJohn Marino 			}
9743ff40c12SJohn Marino 			sm->eapol->cb.aaa_send(
9753ff40c12SJohn Marino 				sm->eapol->conf.ctx, sm->sta,
9763ff40c12SJohn Marino 				wpabuf_head(sm->eap_if->aaaEapRespData),
9773ff40c12SJohn Marino 				wpabuf_len(sm->eap_if->aaaEapRespData));
9783ff40c12SJohn Marino 		}
9793ff40c12SJohn Marino 	}
9803ff40c12SJohn Marino 
9813ff40c12SJohn Marino 	if (eapol_sm_sta_entry_alive(eapol, addr))
9823ff40c12SJohn Marino 		sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
9833ff40c12SJohn Marino 					  EAPOL_AUTH_SM_CHANGE);
9843ff40c12SJohn Marino }
9853ff40c12SJohn Marino 
9863ff40c12SJohn Marino 
eapol_sm_step_cb(void * eloop_ctx,void * timeout_ctx)9873ff40c12SJohn Marino static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
9883ff40c12SJohn Marino {
9893ff40c12SJohn Marino 	struct eapol_state_machine *sm = eloop_ctx;
9903ff40c12SJohn Marino 	eapol_sm_step_run(sm);
9913ff40c12SJohn Marino }
9923ff40c12SJohn Marino 
9933ff40c12SJohn Marino 
9943ff40c12SJohn Marino /**
9953ff40c12SJohn Marino  * eapol_auth_step - Advance EAPOL state machines
9963ff40c12SJohn Marino  * @sm: EAPOL state machine
9973ff40c12SJohn Marino  *
9983ff40c12SJohn Marino  * This function is called to advance EAPOL state machines after any change
9993ff40c12SJohn Marino  * that could affect their state.
10003ff40c12SJohn Marino  */
eapol_auth_step(struct eapol_state_machine * sm)10013ff40c12SJohn Marino void eapol_auth_step(struct eapol_state_machine *sm)
10023ff40c12SJohn Marino {
10033ff40c12SJohn Marino 	/*
10043ff40c12SJohn Marino 	 * Run eapol_sm_step_run from a registered timeout to make sure that
10053ff40c12SJohn Marino 	 * other possible timeouts/events are processed and to avoid long
10063ff40c12SJohn Marino 	 * function call chains.
10073ff40c12SJohn Marino 	 */
10083ff40c12SJohn Marino 
10093ff40c12SJohn Marino 	eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
10103ff40c12SJohn Marino }
10113ff40c12SJohn Marino 
10123ff40c12SJohn Marino 
eapol_auth_initialize(struct eapol_state_machine * sm)10133ff40c12SJohn Marino static void eapol_auth_initialize(struct eapol_state_machine *sm)
10143ff40c12SJohn Marino {
10153ff40c12SJohn Marino 	sm->initializing = TRUE;
10163ff40c12SJohn Marino 	/* Initialize the state machines by asserting initialize and then
10173ff40c12SJohn Marino 	 * deasserting it after one step */
10183ff40c12SJohn Marino 	sm->initialize = TRUE;
10193ff40c12SJohn Marino 	eapol_sm_step_run(sm);
10203ff40c12SJohn Marino 	sm->initialize = FALSE;
10213ff40c12SJohn Marino 	eapol_sm_step_run(sm);
10223ff40c12SJohn Marino 	sm->initializing = FALSE;
10233ff40c12SJohn Marino 
10243ff40c12SJohn Marino 	/* Start one second tick for port timers state machine */
10253ff40c12SJohn Marino 	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
10263ff40c12SJohn Marino 	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
10273ff40c12SJohn Marino }
10283ff40c12SJohn Marino 
10293ff40c12SJohn Marino 
eapol_sm_get_eap_user(void * ctx,const u8 * identity,size_t identity_len,int phase2,struct eap_user * user)10303ff40c12SJohn Marino static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
10313ff40c12SJohn Marino 				 size_t identity_len, int phase2,
10323ff40c12SJohn Marino 				 struct eap_user *user)
10333ff40c12SJohn Marino {
10343ff40c12SJohn Marino 	struct eapol_state_machine *sm = ctx;
1035*a1157835SDaniel Fojt 	int ret;
1036*a1157835SDaniel Fojt 
1037*a1157835SDaniel Fojt 	ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
10383ff40c12SJohn Marino 					 identity_len, phase2, user);
1039*a1157835SDaniel Fojt 	if (user->remediation)
1040*a1157835SDaniel Fojt 		sm->remediation = 1;
1041*a1157835SDaniel Fojt 	return ret;
10423ff40c12SJohn Marino }
10433ff40c12SJohn Marino 
10443ff40c12SJohn Marino 
eapol_sm_get_eap_req_id_text(void * ctx,size_t * len)10453ff40c12SJohn Marino static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
10463ff40c12SJohn Marino {
10473ff40c12SJohn Marino 	struct eapol_state_machine *sm = ctx;
10483ff40c12SJohn Marino 	*len = sm->eapol->conf.eap_req_id_text_len;
10493ff40c12SJohn Marino 	return sm->eapol->conf.eap_req_id_text;
10503ff40c12SJohn Marino }
10513ff40c12SJohn Marino 
10523ff40c12SJohn Marino 
eapol_sm_get_erp_send_reauth_start(void * ctx)1053*a1157835SDaniel Fojt static int eapol_sm_get_erp_send_reauth_start(void *ctx)
1054*a1157835SDaniel Fojt {
1055*a1157835SDaniel Fojt 	struct eapol_state_machine *sm = ctx;
1056*a1157835SDaniel Fojt 	return sm->eapol->conf.erp_send_reauth_start;
1057*a1157835SDaniel Fojt }
1058*a1157835SDaniel Fojt 
1059*a1157835SDaniel Fojt 
eapol_sm_get_erp_domain(void * ctx)1060*a1157835SDaniel Fojt static const char * eapol_sm_get_erp_domain(void *ctx)
1061*a1157835SDaniel Fojt {
1062*a1157835SDaniel Fojt 	struct eapol_state_machine *sm = ctx;
1063*a1157835SDaniel Fojt 	return sm->eapol->conf.erp_domain;
1064*a1157835SDaniel Fojt }
1065*a1157835SDaniel Fojt 
1066*a1157835SDaniel Fojt 
eapol_sm_erp_get_key(void * ctx,const char * keyname)1067*a1157835SDaniel Fojt static struct eap_server_erp_key * eapol_sm_erp_get_key(void *ctx,
1068*a1157835SDaniel Fojt 							const char *keyname)
1069*a1157835SDaniel Fojt {
1070*a1157835SDaniel Fojt 	struct eapol_state_machine *sm = ctx;
1071*a1157835SDaniel Fojt 	return sm->eapol->cb.erp_get_key(sm->eapol->conf.ctx, keyname);
1072*a1157835SDaniel Fojt }
1073*a1157835SDaniel Fojt 
1074*a1157835SDaniel Fojt 
eapol_sm_erp_add_key(void * ctx,struct eap_server_erp_key * erp)1075*a1157835SDaniel Fojt static int eapol_sm_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
1076*a1157835SDaniel Fojt {
1077*a1157835SDaniel Fojt 	struct eapol_state_machine *sm = ctx;
1078*a1157835SDaniel Fojt 	return sm->eapol->cb.erp_add_key(sm->eapol->conf.ctx, erp);
1079*a1157835SDaniel Fojt }
1080*a1157835SDaniel Fojt 
1081*a1157835SDaniel Fojt 
1082*a1157835SDaniel Fojt static const struct eapol_callbacks eapol_cb =
10833ff40c12SJohn Marino {
10843ff40c12SJohn Marino 	eapol_sm_get_eap_user,
1085*a1157835SDaniel Fojt 	eapol_sm_get_eap_req_id_text,
1086*a1157835SDaniel Fojt 	NULL,
1087*a1157835SDaniel Fojt 	eapol_sm_get_erp_send_reauth_start,
1088*a1157835SDaniel Fojt 	eapol_sm_get_erp_domain,
1089*a1157835SDaniel Fojt 	eapol_sm_erp_get_key,
1090*a1157835SDaniel Fojt 	eapol_sm_erp_add_key,
10913ff40c12SJohn Marino };
10923ff40c12SJohn Marino 
10933ff40c12SJohn Marino 
eapol_auth_eap_pending_cb(struct eapol_state_machine * sm,void * ctx)10943ff40c12SJohn Marino int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
10953ff40c12SJohn Marino {
10963ff40c12SJohn Marino 	if (sm == NULL || ctx == NULL || ctx != sm->eap)
10973ff40c12SJohn Marino 		return -1;
10983ff40c12SJohn Marino 
10993ff40c12SJohn Marino 	eap_sm_pending_cb(sm->eap);
11003ff40c12SJohn Marino 	eapol_auth_step(sm);
11013ff40c12SJohn Marino 
11023ff40c12SJohn Marino 	return 0;
11033ff40c12SJohn Marino }
11043ff40c12SJohn Marino 
11053ff40c12SJohn Marino 
eapol_auth_reauthenticate(struct eapol_state_machine * sm)1106*a1157835SDaniel Fojt void eapol_auth_reauthenticate(struct eapol_state_machine *sm)
1107*a1157835SDaniel Fojt {
1108*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAPOL: External reauthentication trigger for "
1109*a1157835SDaniel Fojt 		   MACSTR, MAC2STR(sm->addr));
1110*a1157835SDaniel Fojt 	sm->reAuthenticate = TRUE;
1111*a1157835SDaniel Fojt 	eapol_auth_step(sm);
1112*a1157835SDaniel Fojt }
1113*a1157835SDaniel Fojt 
1114*a1157835SDaniel Fojt 
eapol_auth_set_conf(struct eapol_state_machine * sm,const char * param,const char * value)1115*a1157835SDaniel Fojt int eapol_auth_set_conf(struct eapol_state_machine *sm, const char *param,
1116*a1157835SDaniel Fojt 			const char *value)
1117*a1157835SDaniel Fojt {
1118*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "EAPOL: External configuration operation for "
1119*a1157835SDaniel Fojt 		   MACSTR " - param=%s value=%s",
1120*a1157835SDaniel Fojt 		   MAC2STR(sm->addr), param, value);
1121*a1157835SDaniel Fojt 
1122*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "AdminControlledDirections") == 0) {
1123*a1157835SDaniel Fojt 		if (os_strcmp(value, "Both") == 0)
1124*a1157835SDaniel Fojt 			sm->adminControlledDirections = Both;
1125*a1157835SDaniel Fojt 		else if (os_strcmp(value, "In") == 0)
1126*a1157835SDaniel Fojt 			sm->adminControlledDirections = In;
1127*a1157835SDaniel Fojt 		else
1128*a1157835SDaniel Fojt 			return -1;
1129*a1157835SDaniel Fojt 		eapol_auth_step(sm);
1130*a1157835SDaniel Fojt 		return 0;
1131*a1157835SDaniel Fojt 	}
1132*a1157835SDaniel Fojt 
1133*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "AdminControlledPortControl") == 0) {
1134*a1157835SDaniel Fojt 		if (os_strcmp(value, "ForceAuthorized") == 0)
1135*a1157835SDaniel Fojt 			sm->portControl = ForceAuthorized;
1136*a1157835SDaniel Fojt 		else if (os_strcmp(value, "ForceUnauthorized") == 0)
1137*a1157835SDaniel Fojt 			sm->portControl = ForceUnauthorized;
1138*a1157835SDaniel Fojt 		else if (os_strcmp(value, "Auto") == 0)
1139*a1157835SDaniel Fojt 			sm->portControl = Auto;
1140*a1157835SDaniel Fojt 		else
1141*a1157835SDaniel Fojt 			return -1;
1142*a1157835SDaniel Fojt 		eapol_auth_step(sm);
1143*a1157835SDaniel Fojt 		return 0;
1144*a1157835SDaniel Fojt 	}
1145*a1157835SDaniel Fojt 
1146*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "quietPeriod") == 0) {
1147*a1157835SDaniel Fojt 		sm->quietPeriod = atoi(value);
1148*a1157835SDaniel Fojt 		return 0;
1149*a1157835SDaniel Fojt 	}
1150*a1157835SDaniel Fojt 
1151*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "serverTimeout") == 0) {
1152*a1157835SDaniel Fojt 		sm->serverTimeout = atoi(value);
1153*a1157835SDaniel Fojt 		return 0;
1154*a1157835SDaniel Fojt 	}
1155*a1157835SDaniel Fojt 
1156*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "reAuthPeriod") == 0) {
1157*a1157835SDaniel Fojt 		sm->reAuthPeriod = atoi(value);
1158*a1157835SDaniel Fojt 		return 0;
1159*a1157835SDaniel Fojt 	}
1160*a1157835SDaniel Fojt 
1161*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "reAuthEnabled") == 0) {
1162*a1157835SDaniel Fojt 		if (os_strcmp(value, "TRUE") == 0)
1163*a1157835SDaniel Fojt 			sm->reAuthEnabled = TRUE;
1164*a1157835SDaniel Fojt 		else if (os_strcmp(value, "FALSE") == 0)
1165*a1157835SDaniel Fojt 			sm->reAuthEnabled = FALSE;
1166*a1157835SDaniel Fojt 		else
1167*a1157835SDaniel Fojt 			return -1;
1168*a1157835SDaniel Fojt 		eapol_auth_step(sm);
1169*a1157835SDaniel Fojt 		return 0;
1170*a1157835SDaniel Fojt 	}
1171*a1157835SDaniel Fojt 
1172*a1157835SDaniel Fojt 	if (os_strcasecmp(param, "KeyTransmissionEnabled") == 0) {
1173*a1157835SDaniel Fojt 		if (os_strcmp(value, "TRUE") == 0)
1174*a1157835SDaniel Fojt 			sm->keyTxEnabled = TRUE;
1175*a1157835SDaniel Fojt 		else if (os_strcmp(value, "FALSE") == 0)
1176*a1157835SDaniel Fojt 			sm->keyTxEnabled = FALSE;
1177*a1157835SDaniel Fojt 		else
1178*a1157835SDaniel Fojt 			return -1;
1179*a1157835SDaniel Fojt 		eapol_auth_step(sm);
1180*a1157835SDaniel Fojt 		return 0;
1181*a1157835SDaniel Fojt 	}
1182*a1157835SDaniel Fojt 
1183*a1157835SDaniel Fojt 	return -1;
1184*a1157835SDaniel Fojt }
1185*a1157835SDaniel Fojt 
1186*a1157835SDaniel Fojt 
eapol_auth_conf_clone(struct eapol_auth_config * dst,struct eapol_auth_config * src)11873ff40c12SJohn Marino static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
11883ff40c12SJohn Marino 				 struct eapol_auth_config *src)
11893ff40c12SJohn Marino {
11903ff40c12SJohn Marino 	dst->ctx = src->ctx;
11913ff40c12SJohn Marino 	dst->eap_reauth_period = src->eap_reauth_period;
11923ff40c12SJohn Marino 	dst->wpa = src->wpa;
11933ff40c12SJohn Marino 	dst->individual_wep_key_len = src->individual_wep_key_len;
11943ff40c12SJohn Marino 	dst->eap_server = src->eap_server;
11953ff40c12SJohn Marino 	dst->ssl_ctx = src->ssl_ctx;
11963ff40c12SJohn Marino 	dst->msg_ctx = src->msg_ctx;
11973ff40c12SJohn Marino 	dst->eap_sim_db_priv = src->eap_sim_db_priv;
11983ff40c12SJohn Marino 	os_free(dst->eap_req_id_text);
11993ff40c12SJohn Marino 	dst->pwd_group = src->pwd_group;
12003ff40c12SJohn Marino 	dst->pbc_in_m1 = src->pbc_in_m1;
12013ff40c12SJohn Marino 	dst->server_id = src->server_id;
12023ff40c12SJohn Marino 	dst->server_id_len = src->server_id_len;
12033ff40c12SJohn Marino 	if (src->eap_req_id_text) {
1204*a1157835SDaniel Fojt 		dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
1205*a1157835SDaniel Fojt 						 src->eap_req_id_text_len);
12063ff40c12SJohn Marino 		if (dst->eap_req_id_text == NULL)
12073ff40c12SJohn Marino 			return -1;
12083ff40c12SJohn Marino 		dst->eap_req_id_text_len = src->eap_req_id_text_len;
12093ff40c12SJohn Marino 	} else {
12103ff40c12SJohn Marino 		dst->eap_req_id_text = NULL;
12113ff40c12SJohn Marino 		dst->eap_req_id_text_len = 0;
12123ff40c12SJohn Marino 	}
12133ff40c12SJohn Marino 	if (src->pac_opaque_encr_key) {
1214*a1157835SDaniel Fojt 		dst->pac_opaque_encr_key = os_memdup(src->pac_opaque_encr_key,
12153ff40c12SJohn Marino 						     16);
1216*a1157835SDaniel Fojt 		if (dst->pac_opaque_encr_key == NULL)
1217*a1157835SDaniel Fojt 			goto fail;
12183ff40c12SJohn Marino 	} else
12193ff40c12SJohn Marino 		dst->pac_opaque_encr_key = NULL;
12203ff40c12SJohn Marino 	if (src->eap_fast_a_id) {
1221*a1157835SDaniel Fojt 		dst->eap_fast_a_id = os_memdup(src->eap_fast_a_id,
12223ff40c12SJohn Marino 					       src->eap_fast_a_id_len);
1223*a1157835SDaniel Fojt 		if (dst->eap_fast_a_id == NULL)
1224*a1157835SDaniel Fojt 			goto fail;
12253ff40c12SJohn Marino 		dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
12263ff40c12SJohn Marino 	} else
12273ff40c12SJohn Marino 		dst->eap_fast_a_id = NULL;
12283ff40c12SJohn Marino 	if (src->eap_fast_a_id_info) {
12293ff40c12SJohn Marino 		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
1230*a1157835SDaniel Fojt 		if (dst->eap_fast_a_id_info == NULL)
1231*a1157835SDaniel Fojt 			goto fail;
12323ff40c12SJohn Marino 	} else
12333ff40c12SJohn Marino 		dst->eap_fast_a_id_info = NULL;
12343ff40c12SJohn Marino 	dst->eap_fast_prov = src->eap_fast_prov;
12353ff40c12SJohn Marino 	dst->pac_key_lifetime = src->pac_key_lifetime;
12363ff40c12SJohn Marino 	dst->pac_key_refresh_time = src->pac_key_refresh_time;
1237*a1157835SDaniel Fojt 	dst->eap_teap_auth = src->eap_teap_auth;
1238*a1157835SDaniel Fojt 	dst->eap_teap_pac_no_inner = src->eap_teap_pac_no_inner;
12393ff40c12SJohn Marino 	dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
1240*a1157835SDaniel Fojt 	dst->eap_sim_id = src->eap_sim_id;
12413ff40c12SJohn Marino 	dst->tnc = src->tnc;
12423ff40c12SJohn Marino 	dst->wps = src->wps;
12433ff40c12SJohn Marino 	dst->fragment_size = src->fragment_size;
1244*a1157835SDaniel Fojt 
1245*a1157835SDaniel Fojt 	os_free(dst->erp_domain);
1246*a1157835SDaniel Fojt 	if (src->erp_domain) {
1247*a1157835SDaniel Fojt 		dst->erp_domain = os_strdup(src->erp_domain);
1248*a1157835SDaniel Fojt 		if (dst->erp_domain == NULL)
1249*a1157835SDaniel Fojt 			goto fail;
1250*a1157835SDaniel Fojt 	} else {
1251*a1157835SDaniel Fojt 		dst->erp_domain = NULL;
1252*a1157835SDaniel Fojt 	}
1253*a1157835SDaniel Fojt 	dst->erp_send_reauth_start = src->erp_send_reauth_start;
1254*a1157835SDaniel Fojt 	dst->erp = src->erp;
1255*a1157835SDaniel Fojt 	dst->tls_session_lifetime = src->tls_session_lifetime;
1256*a1157835SDaniel Fojt 	dst->tls_flags = src->tls_flags;
1257*a1157835SDaniel Fojt 
12583ff40c12SJohn Marino 	return 0;
1259*a1157835SDaniel Fojt 
1260*a1157835SDaniel Fojt fail:
1261*a1157835SDaniel Fojt 	eapol_auth_conf_free(dst);
1262*a1157835SDaniel Fojt 	return -1;
12633ff40c12SJohn Marino }
12643ff40c12SJohn Marino 
12653ff40c12SJohn Marino 
eapol_auth_conf_free(struct eapol_auth_config * conf)12663ff40c12SJohn Marino static void eapol_auth_conf_free(struct eapol_auth_config *conf)
12673ff40c12SJohn Marino {
12683ff40c12SJohn Marino 	os_free(conf->eap_req_id_text);
12693ff40c12SJohn Marino 	conf->eap_req_id_text = NULL;
12703ff40c12SJohn Marino 	os_free(conf->pac_opaque_encr_key);
12713ff40c12SJohn Marino 	conf->pac_opaque_encr_key = NULL;
12723ff40c12SJohn Marino 	os_free(conf->eap_fast_a_id);
12733ff40c12SJohn Marino 	conf->eap_fast_a_id = NULL;
12743ff40c12SJohn Marino 	os_free(conf->eap_fast_a_id_info);
12753ff40c12SJohn Marino 	conf->eap_fast_a_id_info = NULL;
1276*a1157835SDaniel Fojt 	os_free(conf->erp_domain);
1277*a1157835SDaniel Fojt 	conf->erp_domain = NULL;
12783ff40c12SJohn Marino }
12793ff40c12SJohn Marino 
12803ff40c12SJohn Marino 
eapol_auth_init(struct eapol_auth_config * conf,struct eapol_auth_cb * cb)12813ff40c12SJohn Marino struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
12823ff40c12SJohn Marino 					     struct eapol_auth_cb *cb)
12833ff40c12SJohn Marino {
12843ff40c12SJohn Marino 	struct eapol_authenticator *eapol;
12853ff40c12SJohn Marino 
12863ff40c12SJohn Marino 	eapol = os_zalloc(sizeof(*eapol));
12873ff40c12SJohn Marino 	if (eapol == NULL)
12883ff40c12SJohn Marino 		return NULL;
12893ff40c12SJohn Marino 
12903ff40c12SJohn Marino 	if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
12913ff40c12SJohn Marino 		os_free(eapol);
12923ff40c12SJohn Marino 		return NULL;
12933ff40c12SJohn Marino 	}
12943ff40c12SJohn Marino 
12953ff40c12SJohn Marino 	if (conf->individual_wep_key_len > 0) {
12963ff40c12SJohn Marino 		/* use key0 in individual key and key1 in broadcast key */
12973ff40c12SJohn Marino 		eapol->default_wep_key_idx = 1;
12983ff40c12SJohn Marino 	}
12993ff40c12SJohn Marino 
13003ff40c12SJohn Marino 	eapol->cb.eapol_send = cb->eapol_send;
13013ff40c12SJohn Marino 	eapol->cb.aaa_send = cb->aaa_send;
13023ff40c12SJohn Marino 	eapol->cb.finished = cb->finished;
13033ff40c12SJohn Marino 	eapol->cb.get_eap_user = cb->get_eap_user;
13043ff40c12SJohn Marino 	eapol->cb.sta_entry_alive = cb->sta_entry_alive;
13053ff40c12SJohn Marino 	eapol->cb.logger = cb->logger;
13063ff40c12SJohn Marino 	eapol->cb.set_port_authorized = cb->set_port_authorized;
13073ff40c12SJohn Marino 	eapol->cb.abort_auth = cb->abort_auth;
13083ff40c12SJohn Marino 	eapol->cb.tx_key = cb->tx_key;
13093ff40c12SJohn Marino 	eapol->cb.eapol_event = cb->eapol_event;
1310*a1157835SDaniel Fojt 	eapol->cb.erp_get_key = cb->erp_get_key;
1311*a1157835SDaniel Fojt 	eapol->cb.erp_add_key = cb->erp_add_key;
13123ff40c12SJohn Marino 
13133ff40c12SJohn Marino 	return eapol;
13143ff40c12SJohn Marino }
13153ff40c12SJohn Marino 
13163ff40c12SJohn Marino 
eapol_auth_deinit(struct eapol_authenticator * eapol)13173ff40c12SJohn Marino void eapol_auth_deinit(struct eapol_authenticator *eapol)
13183ff40c12SJohn Marino {
13193ff40c12SJohn Marino 	if (eapol == NULL)
13203ff40c12SJohn Marino 		return;
13213ff40c12SJohn Marino 
13223ff40c12SJohn Marino 	eapol_auth_conf_free(&eapol->conf);
13233ff40c12SJohn Marino 	os_free(eapol->default_wep_key);
13243ff40c12SJohn Marino 	os_free(eapol);
13253ff40c12SJohn Marino }
1326