16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer  * EAPOL supplicant state machines
33ff40c12SJohn Marino  * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer  *
53ff40c12SJohn Marino  * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino  * See README for more details.
76d49e1aeSJan Lentfer  */
86d49e1aeSJan Lentfer 
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer 
116d49e1aeSJan Lentfer #include "common.h"
126d49e1aeSJan Lentfer #include "state_machine.h"
136d49e1aeSJan Lentfer #include "wpabuf.h"
143ff40c12SJohn Marino #include "eloop.h"
153ff40c12SJohn Marino #include "crypto/crypto.h"
163ff40c12SJohn Marino #include "crypto/md5.h"
173ff40c12SJohn Marino #include "common/eapol_common.h"
183ff40c12SJohn Marino #include "eap_peer/eap.h"
19*a1157835SDaniel Fojt #include "eap_peer/eap_config.h"
203ff40c12SJohn Marino #include "eap_peer/eap_proxy.h"
213ff40c12SJohn Marino #include "eapol_supp_sm.h"
226d49e1aeSJan Lentfer 
236d49e1aeSJan Lentfer #define STATE_MACHINE_DATA struct eapol_sm
246d49e1aeSJan Lentfer #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
256d49e1aeSJan Lentfer 
266d49e1aeSJan Lentfer 
276d49e1aeSJan Lentfer /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
286d49e1aeSJan Lentfer 
296d49e1aeSJan Lentfer /**
306d49e1aeSJan Lentfer  * struct eapol_sm - Internal data for EAPOL state machines
316d49e1aeSJan Lentfer  */
326d49e1aeSJan Lentfer struct eapol_sm {
336d49e1aeSJan Lentfer 	/* Timers */
346d49e1aeSJan Lentfer 	unsigned int authWhile;
356d49e1aeSJan Lentfer 	unsigned int heldWhile;
366d49e1aeSJan Lentfer 	unsigned int startWhen;
376d49e1aeSJan Lentfer 	unsigned int idleWhile; /* for EAP state machine */
386d49e1aeSJan Lentfer 	int timer_tick_enabled;
396d49e1aeSJan Lentfer 
406d49e1aeSJan Lentfer 	/* Global variables */
416d49e1aeSJan Lentfer 	Boolean eapFail;
426d49e1aeSJan Lentfer 	Boolean eapolEap;
436d49e1aeSJan Lentfer 	Boolean eapSuccess;
446d49e1aeSJan Lentfer 	Boolean initialize;
456d49e1aeSJan Lentfer 	Boolean keyDone;
466d49e1aeSJan Lentfer 	Boolean keyRun;
476d49e1aeSJan Lentfer 	PortControl portControl;
486d49e1aeSJan Lentfer 	Boolean portEnabled;
496d49e1aeSJan Lentfer 	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
506d49e1aeSJan Lentfer 	Boolean portValid;
516d49e1aeSJan Lentfer 	Boolean suppAbort;
526d49e1aeSJan Lentfer 	Boolean suppFail;
536d49e1aeSJan Lentfer 	Boolean suppStart;
546d49e1aeSJan Lentfer 	Boolean suppSuccess;
556d49e1aeSJan Lentfer 	Boolean suppTimeout;
566d49e1aeSJan Lentfer 
576d49e1aeSJan Lentfer 	/* Supplicant PAE state machine */
586d49e1aeSJan Lentfer 	enum {
596d49e1aeSJan Lentfer 		SUPP_PAE_UNKNOWN = 0,
606d49e1aeSJan Lentfer 		SUPP_PAE_DISCONNECTED = 1,
616d49e1aeSJan Lentfer 		SUPP_PAE_LOGOFF = 2,
626d49e1aeSJan Lentfer 		SUPP_PAE_CONNECTING = 3,
636d49e1aeSJan Lentfer 		SUPP_PAE_AUTHENTICATING = 4,
646d49e1aeSJan Lentfer 		SUPP_PAE_AUTHENTICATED = 5,
656d49e1aeSJan Lentfer 		/* unused(6) */
666d49e1aeSJan Lentfer 		SUPP_PAE_HELD = 7,
676d49e1aeSJan Lentfer 		SUPP_PAE_RESTART = 8,
686d49e1aeSJan Lentfer 		SUPP_PAE_S_FORCE_AUTH = 9,
696d49e1aeSJan Lentfer 		SUPP_PAE_S_FORCE_UNAUTH = 10
706d49e1aeSJan Lentfer 	} SUPP_PAE_state; /* dot1xSuppPaeState */
716d49e1aeSJan Lentfer 	/* Variables */
726d49e1aeSJan Lentfer 	Boolean userLogoff;
736d49e1aeSJan Lentfer 	Boolean logoffSent;
746d49e1aeSJan Lentfer 	unsigned int startCount;
756d49e1aeSJan Lentfer 	Boolean eapRestart;
766d49e1aeSJan Lentfer 	PortControl sPortMode;
776d49e1aeSJan Lentfer 	/* Constants */
786d49e1aeSJan Lentfer 	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
796d49e1aeSJan Lentfer 	unsigned int startPeriod; /* dot1xSuppStartPeriod */
806d49e1aeSJan Lentfer 	unsigned int maxStart; /* dot1xSuppMaxStart */
816d49e1aeSJan Lentfer 
826d49e1aeSJan Lentfer 	/* Key Receive state machine */
836d49e1aeSJan Lentfer 	enum {
846d49e1aeSJan Lentfer 		KEY_RX_UNKNOWN = 0,
856d49e1aeSJan Lentfer 		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
866d49e1aeSJan Lentfer 	} KEY_RX_state;
876d49e1aeSJan Lentfer 	/* Variables */
886d49e1aeSJan Lentfer 	Boolean rxKey;
896d49e1aeSJan Lentfer 
906d49e1aeSJan Lentfer 	/* Supplicant Backend state machine */
916d49e1aeSJan Lentfer 	enum {
926d49e1aeSJan Lentfer 		SUPP_BE_UNKNOWN = 0,
936d49e1aeSJan Lentfer 		SUPP_BE_INITIALIZE = 1,
946d49e1aeSJan Lentfer 		SUPP_BE_IDLE = 2,
956d49e1aeSJan Lentfer 		SUPP_BE_REQUEST = 3,
966d49e1aeSJan Lentfer 		SUPP_BE_RECEIVE = 4,
976d49e1aeSJan Lentfer 		SUPP_BE_RESPONSE = 5,
986d49e1aeSJan Lentfer 		SUPP_BE_FAIL = 6,
996d49e1aeSJan Lentfer 		SUPP_BE_TIMEOUT = 7,
1006d49e1aeSJan Lentfer 		SUPP_BE_SUCCESS = 8
1016d49e1aeSJan Lentfer 	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
1026d49e1aeSJan Lentfer 	/* Variables */
1036d49e1aeSJan Lentfer 	Boolean eapNoResp;
1046d49e1aeSJan Lentfer 	Boolean eapReq;
1056d49e1aeSJan Lentfer 	Boolean eapResp;
1066d49e1aeSJan Lentfer 	/* Constants */
1076d49e1aeSJan Lentfer 	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
1086d49e1aeSJan Lentfer 
1096d49e1aeSJan Lentfer 	/* Statistics */
1106d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolFramesRx;
1116d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolFramesTx;
1126d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolStartFramesTx;
1136d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolLogoffFramesTx;
1146d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolRespFramesTx;
1156d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolReqIdFramesRx;
1166d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapolReqFramesRx;
1176d49e1aeSJan Lentfer 	unsigned int dot1xSuppInvalidEapolFramesRx;
1186d49e1aeSJan Lentfer 	unsigned int dot1xSuppEapLengthErrorFramesRx;
1196d49e1aeSJan Lentfer 	unsigned int dot1xSuppLastEapolFrameVersion;
1206d49e1aeSJan Lentfer 	unsigned char dot1xSuppLastEapolFrameSource[6];
1216d49e1aeSJan Lentfer 
1226d49e1aeSJan Lentfer 	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
1236d49e1aeSJan Lentfer 	Boolean changed;
1246d49e1aeSJan Lentfer 	struct eap_sm *eap;
1256d49e1aeSJan Lentfer 	struct eap_peer_config *config;
1266d49e1aeSJan Lentfer 	Boolean initial_req;
1276d49e1aeSJan Lentfer 	u8 *last_rx_key;
1286d49e1aeSJan Lentfer 	size_t last_rx_key_len;
1296d49e1aeSJan Lentfer 	struct wpabuf *eapReqData; /* for EAP */
1306d49e1aeSJan Lentfer 	Boolean altAccept; /* for EAP */
1316d49e1aeSJan Lentfer 	Boolean altReject; /* for EAP */
132*a1157835SDaniel Fojt 	Boolean eapTriggerStart;
1336d49e1aeSJan Lentfer 	Boolean replay_counter_valid;
1346d49e1aeSJan Lentfer 	u8 last_replay_counter[16];
1356d49e1aeSJan Lentfer 	struct eapol_config conf;
1366d49e1aeSJan Lentfer 	struct eapol_ctx *ctx;
1376d49e1aeSJan Lentfer 	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
1386d49e1aeSJan Lentfer 		cb_status;
1396d49e1aeSJan Lentfer 	Boolean cached_pmk;
1406d49e1aeSJan Lentfer 
1416d49e1aeSJan Lentfer 	Boolean unicast_key_received, broadcast_key_received;
1423ff40c12SJohn Marino 
1433ff40c12SJohn Marino 	Boolean force_authorized_update;
1443ff40c12SJohn Marino 
1453ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
1463ff40c12SJohn Marino 	Boolean use_eap_proxy;
1473ff40c12SJohn Marino 	struct eap_proxy_sm *eap_proxy;
1483ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
1496d49e1aeSJan Lentfer };
1506d49e1aeSJan Lentfer 
1516d49e1aeSJan Lentfer 
1526d49e1aeSJan Lentfer static void eapol_sm_txLogoff(struct eapol_sm *sm);
1536d49e1aeSJan Lentfer static void eapol_sm_txStart(struct eapol_sm *sm);
1546d49e1aeSJan Lentfer static void eapol_sm_processKey(struct eapol_sm *sm);
1556d49e1aeSJan Lentfer static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
1566d49e1aeSJan Lentfer static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
1576d49e1aeSJan Lentfer static void eapol_sm_abortSupp(struct eapol_sm *sm);
1586d49e1aeSJan Lentfer static void eapol_sm_abort_cached(struct eapol_sm *sm);
1596d49e1aeSJan Lentfer static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
1603ff40c12SJohn Marino static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
1613ff40c12SJohn Marino static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
1626d49e1aeSJan Lentfer 
1636d49e1aeSJan Lentfer 
1646d49e1aeSJan Lentfer /* Port Timers state machine - implemented as a function that will be called
1656d49e1aeSJan Lentfer  * once a second as a registered event loop timeout */
eapol_port_timers_tick(void * eloop_ctx,void * timeout_ctx)1666d49e1aeSJan Lentfer static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
1676d49e1aeSJan Lentfer {
1686d49e1aeSJan Lentfer 	struct eapol_sm *sm = timeout_ctx;
1696d49e1aeSJan Lentfer 
1706d49e1aeSJan Lentfer 	if (sm->authWhile > 0) {
1716d49e1aeSJan Lentfer 		sm->authWhile--;
1726d49e1aeSJan Lentfer 		if (sm->authWhile == 0)
1736d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
1746d49e1aeSJan Lentfer 	}
1756d49e1aeSJan Lentfer 	if (sm->heldWhile > 0) {
1766d49e1aeSJan Lentfer 		sm->heldWhile--;
1776d49e1aeSJan Lentfer 		if (sm->heldWhile == 0)
1786d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
1796d49e1aeSJan Lentfer 	}
1806d49e1aeSJan Lentfer 	if (sm->startWhen > 0) {
1816d49e1aeSJan Lentfer 		sm->startWhen--;
1826d49e1aeSJan Lentfer 		if (sm->startWhen == 0)
1836d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
1846d49e1aeSJan Lentfer 	}
1856d49e1aeSJan Lentfer 	if (sm->idleWhile > 0) {
1866d49e1aeSJan Lentfer 		sm->idleWhile--;
1876d49e1aeSJan Lentfer 		if (sm->idleWhile == 0)
1886d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
1896d49e1aeSJan Lentfer 	}
1906d49e1aeSJan Lentfer 
1916d49e1aeSJan Lentfer 	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
192*a1157835SDaniel Fojt 		if (eloop_register_timeout(1, 0, eapol_port_timers_tick,
193*a1157835SDaniel Fojt 					   eloop_ctx, sm) < 0)
194*a1157835SDaniel Fojt 			sm->timer_tick_enabled = 0;
1956d49e1aeSJan Lentfer 	} else {
1966d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
1976d49e1aeSJan Lentfer 		sm->timer_tick_enabled = 0;
1986d49e1aeSJan Lentfer 	}
1996d49e1aeSJan Lentfer 	eapol_sm_step(sm);
2006d49e1aeSJan Lentfer }
2016d49e1aeSJan Lentfer 
2026d49e1aeSJan Lentfer 
eapol_enable_timer_tick(struct eapol_sm * sm)2036d49e1aeSJan Lentfer static void eapol_enable_timer_tick(struct eapol_sm *sm)
2046d49e1aeSJan Lentfer {
2056d49e1aeSJan Lentfer 	if (sm->timer_tick_enabled)
2066d49e1aeSJan Lentfer 		return;
2076d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
2086d49e1aeSJan Lentfer 	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
209*a1157835SDaniel Fojt 	if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
210*a1157835SDaniel Fojt 		sm->timer_tick_enabled = 1;
2116d49e1aeSJan Lentfer }
2126d49e1aeSJan Lentfer 
2136d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,LOGOFF)2146d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, LOGOFF)
2156d49e1aeSJan Lentfer {
2166d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, LOGOFF);
2176d49e1aeSJan Lentfer 	eapol_sm_txLogoff(sm);
2186d49e1aeSJan Lentfer 	sm->logoffSent = TRUE;
2193ff40c12SJohn Marino 	eapol_sm_set_port_unauthorized(sm);
2206d49e1aeSJan Lentfer }
2216d49e1aeSJan Lentfer 
2226d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,DISCONNECTED)2236d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, DISCONNECTED)
2246d49e1aeSJan Lentfer {
2256d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, DISCONNECTED);
2266d49e1aeSJan Lentfer 	sm->sPortMode = Auto;
2276d49e1aeSJan Lentfer 	sm->startCount = 0;
228*a1157835SDaniel Fojt 	sm->eapTriggerStart = FALSE;
2296d49e1aeSJan Lentfer 	sm->logoffSent = FALSE;
2303ff40c12SJohn Marino 	eapol_sm_set_port_unauthorized(sm);
2316d49e1aeSJan Lentfer 	sm->suppAbort = TRUE;
2326d49e1aeSJan Lentfer 
2336d49e1aeSJan Lentfer 	sm->unicast_key_received = FALSE;
2346d49e1aeSJan Lentfer 	sm->broadcast_key_received = FALSE;
2353ff40c12SJohn Marino 
2363ff40c12SJohn Marino 	/*
2373ff40c12SJohn Marino 	 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
2383ff40c12SJohn Marino 	 * allows the timer tick to be stopped more quickly when the port is
2393ff40c12SJohn Marino 	 * not enabled. Since this variable is used only within HELD state,
2403ff40c12SJohn Marino 	 * clearing it on initialization does not change actual state machine
2413ff40c12SJohn Marino 	 * behavior.
2423ff40c12SJohn Marino 	 */
2433ff40c12SJohn Marino 	sm->heldWhile = 0;
2446d49e1aeSJan Lentfer }
2456d49e1aeSJan Lentfer 
2466d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,CONNECTING)2476d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, CONNECTING)
2486d49e1aeSJan Lentfer {
249*a1157835SDaniel Fojt 	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING ||
250*a1157835SDaniel Fojt 		sm->SUPP_PAE_state == SUPP_PAE_HELD;
2516d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, CONNECTING);
252*a1157835SDaniel Fojt 
253*a1157835SDaniel Fojt 	if (sm->eapTriggerStart)
254*a1157835SDaniel Fojt 		send_start = 1;
255*a1157835SDaniel Fojt 	if (sm->ctx->preauth)
256*a1157835SDaniel Fojt 		send_start = 1;
257*a1157835SDaniel Fojt 	sm->eapTriggerStart = FALSE;
258*a1157835SDaniel Fojt 
2596d49e1aeSJan Lentfer 	if (send_start) {
2606d49e1aeSJan Lentfer 		sm->startWhen = sm->startPeriod;
2616d49e1aeSJan Lentfer 		sm->startCount++;
2626d49e1aeSJan Lentfer 	} else {
2636d49e1aeSJan Lentfer 		/*
2646d49e1aeSJan Lentfer 		 * Do not send EAPOL-Start immediately since in most cases,
2656d49e1aeSJan Lentfer 		 * Authenticator is going to start authentication immediately
2666d49e1aeSJan Lentfer 		 * after association and an extra EAPOL-Start is just going to
2676d49e1aeSJan Lentfer 		 * delay authentication. Use a short timeout to send the first
2686d49e1aeSJan Lentfer 		 * EAPOL-Start if Authenticator does not start authentication.
2696d49e1aeSJan Lentfer 		 */
270*a1157835SDaniel Fojt 		if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
2716d49e1aeSJan Lentfer 			/* Reduce latency on starting WPS negotiation. */
272*a1157835SDaniel Fojt 			wpa_printf(MSG_DEBUG,
273*a1157835SDaniel Fojt 				   "EAPOL: Using shorter startWhen for WPS");
2746d49e1aeSJan Lentfer 			sm->startWhen = 1;
275*a1157835SDaniel Fojt 		} else {
276*a1157835SDaniel Fojt 			sm->startWhen = 2;
277*a1157835SDaniel Fojt 		}
2786d49e1aeSJan Lentfer 	}
2796d49e1aeSJan Lentfer 	eapol_enable_timer_tick(sm);
2806d49e1aeSJan Lentfer 	sm->eapolEap = FALSE;
2816d49e1aeSJan Lentfer 	if (send_start)
2826d49e1aeSJan Lentfer 		eapol_sm_txStart(sm);
2836d49e1aeSJan Lentfer }
2846d49e1aeSJan Lentfer 
2856d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,AUTHENTICATING)2866d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, AUTHENTICATING)
2876d49e1aeSJan Lentfer {
2886d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
2896d49e1aeSJan Lentfer 	sm->startCount = 0;
2906d49e1aeSJan Lentfer 	sm->suppSuccess = FALSE;
2916d49e1aeSJan Lentfer 	sm->suppFail = FALSE;
2926d49e1aeSJan Lentfer 	sm->suppTimeout = FALSE;
2936d49e1aeSJan Lentfer 	sm->keyRun = FALSE;
2946d49e1aeSJan Lentfer 	sm->keyDone = FALSE;
2956d49e1aeSJan Lentfer 	sm->suppStart = TRUE;
2966d49e1aeSJan Lentfer }
2976d49e1aeSJan Lentfer 
2986d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,HELD)2996d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, HELD)
3006d49e1aeSJan Lentfer {
3016d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, HELD);
3026d49e1aeSJan Lentfer 	sm->heldWhile = sm->heldPeriod;
3036d49e1aeSJan Lentfer 	eapol_enable_timer_tick(sm);
3043ff40c12SJohn Marino 	eapol_sm_set_port_unauthorized(sm);
3056d49e1aeSJan Lentfer 	sm->cb_status = EAPOL_CB_FAILURE;
3066d49e1aeSJan Lentfer }
3076d49e1aeSJan Lentfer 
3086d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,AUTHENTICATED)3096d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, AUTHENTICATED)
3106d49e1aeSJan Lentfer {
3116d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
3123ff40c12SJohn Marino 	eapol_sm_set_port_authorized(sm);
3136d49e1aeSJan Lentfer 	sm->cb_status = EAPOL_CB_SUCCESS;
3146d49e1aeSJan Lentfer }
3156d49e1aeSJan Lentfer 
3166d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,RESTART)3176d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, RESTART)
3186d49e1aeSJan Lentfer {
3196d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, RESTART);
3206d49e1aeSJan Lentfer 	sm->eapRestart = TRUE;
321*a1157835SDaniel Fojt 	if (sm->altAccept) {
322*a1157835SDaniel Fojt 		/*
323*a1157835SDaniel Fojt 		 * Prevent EAP peer state machine from failing due to prior
324*a1157835SDaniel Fojt 		 * external EAP success notification (altSuccess=TRUE in the
325*a1157835SDaniel Fojt 		 * IDLE state could result in a transition to the FAILURE state.
326*a1157835SDaniel Fojt 		 */
327*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
328*a1157835SDaniel Fojt 		sm->eapSuccess = FALSE;
329*a1157835SDaniel Fojt 		sm->altAccept = FALSE;
330*a1157835SDaniel Fojt 	}
3316d49e1aeSJan Lentfer }
3326d49e1aeSJan Lentfer 
3336d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,S_FORCE_AUTH)3346d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, S_FORCE_AUTH)
3356d49e1aeSJan Lentfer {
3366d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
3373ff40c12SJohn Marino 	eapol_sm_set_port_authorized(sm);
3386d49e1aeSJan Lentfer 	sm->sPortMode = ForceAuthorized;
3396d49e1aeSJan Lentfer }
3406d49e1aeSJan Lentfer 
3416d49e1aeSJan Lentfer 
SM_STATE(SUPP_PAE,S_FORCE_UNAUTH)3426d49e1aeSJan Lentfer SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
3436d49e1aeSJan Lentfer {
3446d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
3453ff40c12SJohn Marino 	eapol_sm_set_port_unauthorized(sm);
3466d49e1aeSJan Lentfer 	sm->sPortMode = ForceUnauthorized;
3476d49e1aeSJan Lentfer 	eapol_sm_txLogoff(sm);
3486d49e1aeSJan Lentfer }
3496d49e1aeSJan Lentfer 
3506d49e1aeSJan Lentfer 
SM_STEP(SUPP_PAE)3516d49e1aeSJan Lentfer SM_STEP(SUPP_PAE)
3526d49e1aeSJan Lentfer {
3536d49e1aeSJan Lentfer 	if ((sm->userLogoff && !sm->logoffSent) &&
3546d49e1aeSJan Lentfer 	    !(sm->initialize || !sm->portEnabled))
3556d49e1aeSJan Lentfer 		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
3566d49e1aeSJan Lentfer 	else if (((sm->portControl == Auto) &&
3576d49e1aeSJan Lentfer 		  (sm->sPortMode != sm->portControl)) ||
3586d49e1aeSJan Lentfer 		 sm->initialize || !sm->portEnabled)
3596d49e1aeSJan Lentfer 		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
3606d49e1aeSJan Lentfer 	else if ((sm->portControl == ForceAuthorized) &&
3616d49e1aeSJan Lentfer 		 (sm->sPortMode != sm->portControl) &&
3626d49e1aeSJan Lentfer 		 !(sm->initialize || !sm->portEnabled))
3636d49e1aeSJan Lentfer 		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
3646d49e1aeSJan Lentfer 	else if ((sm->portControl == ForceUnauthorized) &&
3656d49e1aeSJan Lentfer 		 (sm->sPortMode != sm->portControl) &&
3666d49e1aeSJan Lentfer 		 !(sm->initialize || !sm->portEnabled))
3676d49e1aeSJan Lentfer 		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
3686d49e1aeSJan Lentfer 	else switch (sm->SUPP_PAE_state) {
3696d49e1aeSJan Lentfer 	case SUPP_PAE_UNKNOWN:
3706d49e1aeSJan Lentfer 		break;
3716d49e1aeSJan Lentfer 	case SUPP_PAE_LOGOFF:
3726d49e1aeSJan Lentfer 		if (!sm->userLogoff)
3736d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, DISCONNECTED);
3746d49e1aeSJan Lentfer 		break;
3756d49e1aeSJan Lentfer 	case SUPP_PAE_DISCONNECTED:
3766d49e1aeSJan Lentfer 		SM_ENTER(SUPP_PAE, CONNECTING);
3776d49e1aeSJan Lentfer 		break;
3786d49e1aeSJan Lentfer 	case SUPP_PAE_CONNECTING:
3796d49e1aeSJan Lentfer 		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
3806d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, CONNECTING);
3816d49e1aeSJan Lentfer 		else if (sm->startWhen == 0 &&
3826d49e1aeSJan Lentfer 			 sm->startCount >= sm->maxStart &&
3836d49e1aeSJan Lentfer 			 sm->portValid)
3846d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, AUTHENTICATED);
3856d49e1aeSJan Lentfer 		else if (sm->eapSuccess || sm->eapFail)
3866d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, AUTHENTICATING);
3876d49e1aeSJan Lentfer 		else if (sm->eapolEap)
3886d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, RESTART);
3896d49e1aeSJan Lentfer 		else if (sm->startWhen == 0 &&
3906d49e1aeSJan Lentfer 			 sm->startCount >= sm->maxStart &&
3916d49e1aeSJan Lentfer 			 !sm->portValid)
3926d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, HELD);
3936d49e1aeSJan Lentfer 		break;
3946d49e1aeSJan Lentfer 	case SUPP_PAE_AUTHENTICATING:
3956d49e1aeSJan Lentfer 		if (sm->eapSuccess && !sm->portValid &&
3966d49e1aeSJan Lentfer 		    sm->conf.accept_802_1x_keys &&
3976d49e1aeSJan Lentfer 		    sm->conf.required_keys == 0) {
3986d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
3996d49e1aeSJan Lentfer 				   "plaintext connection; no EAPOL-Key frames "
4006d49e1aeSJan Lentfer 				   "required");
4016d49e1aeSJan Lentfer 			sm->portValid = TRUE;
4026d49e1aeSJan Lentfer 			if (sm->ctx->eapol_done_cb)
4036d49e1aeSJan Lentfer 				sm->ctx->eapol_done_cb(sm->ctx->ctx);
4046d49e1aeSJan Lentfer 		}
4056d49e1aeSJan Lentfer 		if (sm->eapSuccess && sm->portValid)
4066d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, AUTHENTICATED);
4076d49e1aeSJan Lentfer 		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
4086d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, HELD);
4096d49e1aeSJan Lentfer 		else if (sm->suppTimeout)
4106d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, CONNECTING);
411*a1157835SDaniel Fojt 		else if (sm->eapTriggerStart)
412*a1157835SDaniel Fojt 			SM_ENTER(SUPP_PAE, CONNECTING);
4136d49e1aeSJan Lentfer 		break;
4146d49e1aeSJan Lentfer 	case SUPP_PAE_HELD:
4156d49e1aeSJan Lentfer 		if (sm->heldWhile == 0)
4166d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, CONNECTING);
4176d49e1aeSJan Lentfer 		else if (sm->eapolEap)
4186d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, RESTART);
4196d49e1aeSJan Lentfer 		break;
4206d49e1aeSJan Lentfer 	case SUPP_PAE_AUTHENTICATED:
4216d49e1aeSJan Lentfer 		if (sm->eapolEap && sm->portValid)
4226d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, RESTART);
4236d49e1aeSJan Lentfer 		else if (!sm->portValid)
4246d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, DISCONNECTED);
4256d49e1aeSJan Lentfer 		break;
4266d49e1aeSJan Lentfer 	case SUPP_PAE_RESTART:
4276d49e1aeSJan Lentfer 		if (!sm->eapRestart)
4286d49e1aeSJan Lentfer 			SM_ENTER(SUPP_PAE, AUTHENTICATING);
4296d49e1aeSJan Lentfer 		break;
4306d49e1aeSJan Lentfer 	case SUPP_PAE_S_FORCE_AUTH:
4316d49e1aeSJan Lentfer 		break;
4326d49e1aeSJan Lentfer 	case SUPP_PAE_S_FORCE_UNAUTH:
4336d49e1aeSJan Lentfer 		break;
4346d49e1aeSJan Lentfer 	}
4356d49e1aeSJan Lentfer }
4366d49e1aeSJan Lentfer 
4376d49e1aeSJan Lentfer 
SM_STATE(KEY_RX,NO_KEY_RECEIVE)4386d49e1aeSJan Lentfer SM_STATE(KEY_RX, NO_KEY_RECEIVE)
4396d49e1aeSJan Lentfer {
4406d49e1aeSJan Lentfer 	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
4416d49e1aeSJan Lentfer }
4426d49e1aeSJan Lentfer 
4436d49e1aeSJan Lentfer 
SM_STATE(KEY_RX,KEY_RECEIVE)4446d49e1aeSJan Lentfer SM_STATE(KEY_RX, KEY_RECEIVE)
4456d49e1aeSJan Lentfer {
4466d49e1aeSJan Lentfer 	SM_ENTRY(KEY_RX, KEY_RECEIVE);
4476d49e1aeSJan Lentfer 	eapol_sm_processKey(sm);
4486d49e1aeSJan Lentfer 	sm->rxKey = FALSE;
4496d49e1aeSJan Lentfer }
4506d49e1aeSJan Lentfer 
4516d49e1aeSJan Lentfer 
SM_STEP(KEY_RX)4526d49e1aeSJan Lentfer SM_STEP(KEY_RX)
4536d49e1aeSJan Lentfer {
4546d49e1aeSJan Lentfer 	if (sm->initialize || !sm->portEnabled)
4556d49e1aeSJan Lentfer 		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
4566d49e1aeSJan Lentfer 	switch (sm->KEY_RX_state) {
4576d49e1aeSJan Lentfer 	case KEY_RX_UNKNOWN:
4586d49e1aeSJan Lentfer 		break;
4596d49e1aeSJan Lentfer 	case KEY_RX_NO_KEY_RECEIVE:
4606d49e1aeSJan Lentfer 		if (sm->rxKey)
4616d49e1aeSJan Lentfer 			SM_ENTER(KEY_RX, KEY_RECEIVE);
4626d49e1aeSJan Lentfer 		break;
4636d49e1aeSJan Lentfer 	case KEY_RX_KEY_RECEIVE:
4646d49e1aeSJan Lentfer 		if (sm->rxKey)
4656d49e1aeSJan Lentfer 			SM_ENTER(KEY_RX, KEY_RECEIVE);
4666d49e1aeSJan Lentfer 		break;
4676d49e1aeSJan Lentfer 	}
4686d49e1aeSJan Lentfer }
4696d49e1aeSJan Lentfer 
4706d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,REQUEST)4716d49e1aeSJan Lentfer SM_STATE(SUPP_BE, REQUEST)
4726d49e1aeSJan Lentfer {
4736d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, REQUEST);
4746d49e1aeSJan Lentfer 	sm->authWhile = 0;
4756d49e1aeSJan Lentfer 	sm->eapReq = TRUE;
4766d49e1aeSJan Lentfer 	eapol_sm_getSuppRsp(sm);
4776d49e1aeSJan Lentfer }
4786d49e1aeSJan Lentfer 
4796d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,RESPONSE)4806d49e1aeSJan Lentfer SM_STATE(SUPP_BE, RESPONSE)
4816d49e1aeSJan Lentfer {
4826d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, RESPONSE);
4836d49e1aeSJan Lentfer 	eapol_sm_txSuppRsp(sm);
4846d49e1aeSJan Lentfer 	sm->eapResp = FALSE;
4856d49e1aeSJan Lentfer }
4866d49e1aeSJan Lentfer 
4876d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,SUCCESS)4886d49e1aeSJan Lentfer SM_STATE(SUPP_BE, SUCCESS)
4896d49e1aeSJan Lentfer {
4906d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, SUCCESS);
4916d49e1aeSJan Lentfer 	sm->keyRun = TRUE;
4926d49e1aeSJan Lentfer 	sm->suppSuccess = TRUE;
4936d49e1aeSJan Lentfer 
4943ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
4953ff40c12SJohn Marino 	if (sm->use_eap_proxy) {
4963ff40c12SJohn Marino 		if (eap_proxy_key_available(sm->eap_proxy)) {
497*a1157835SDaniel Fojt 			u8 *session_id, *emsk;
498*a1157835SDaniel Fojt 			size_t session_id_len, emsk_len;
499*a1157835SDaniel Fojt 
5003ff40c12SJohn Marino 			/* New key received - clear IEEE 802.1X EAPOL-Key replay
5013ff40c12SJohn Marino 			 * counter */
5023ff40c12SJohn Marino 			sm->replay_counter_valid = FALSE;
503*a1157835SDaniel Fojt 
504*a1157835SDaniel Fojt 			session_id = eap_proxy_get_eap_session_id(
505*a1157835SDaniel Fojt 				sm->eap_proxy, &session_id_len);
506*a1157835SDaniel Fojt 			emsk = eap_proxy_get_emsk(sm->eap_proxy, &emsk_len);
507*a1157835SDaniel Fojt 			if (sm->config->erp && session_id && emsk) {
508*a1157835SDaniel Fojt 				eap_peer_erp_init(sm->eap, session_id,
509*a1157835SDaniel Fojt 						  session_id_len, emsk,
510*a1157835SDaniel Fojt 						  emsk_len);
511*a1157835SDaniel Fojt 			} else {
512*a1157835SDaniel Fojt 				os_free(session_id);
513*a1157835SDaniel Fojt 				bin_clear_free(emsk, emsk_len);
514*a1157835SDaniel Fojt 			}
5153ff40c12SJohn Marino 		}
5163ff40c12SJohn Marino 		return;
5173ff40c12SJohn Marino 	}
5183ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
5193ff40c12SJohn Marino 
5206d49e1aeSJan Lentfer 	if (eap_key_available(sm->eap)) {
5216d49e1aeSJan Lentfer 		/* New key received - clear IEEE 802.1X EAPOL-Key replay
5226d49e1aeSJan Lentfer 		 * counter */
5236d49e1aeSJan Lentfer 		sm->replay_counter_valid = FALSE;
5246d49e1aeSJan Lentfer 	}
5256d49e1aeSJan Lentfer }
5266d49e1aeSJan Lentfer 
5276d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,FAIL)5286d49e1aeSJan Lentfer SM_STATE(SUPP_BE, FAIL)
5296d49e1aeSJan Lentfer {
5306d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, FAIL);
5316d49e1aeSJan Lentfer 	sm->suppFail = TRUE;
5326d49e1aeSJan Lentfer }
5336d49e1aeSJan Lentfer 
5346d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,TIMEOUT)5356d49e1aeSJan Lentfer SM_STATE(SUPP_BE, TIMEOUT)
5366d49e1aeSJan Lentfer {
5376d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, TIMEOUT);
5386d49e1aeSJan Lentfer 	sm->suppTimeout = TRUE;
5396d49e1aeSJan Lentfer }
5406d49e1aeSJan Lentfer 
5416d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,IDLE)5426d49e1aeSJan Lentfer SM_STATE(SUPP_BE, IDLE)
5436d49e1aeSJan Lentfer {
5446d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, IDLE);
5456d49e1aeSJan Lentfer 	sm->suppStart = FALSE;
5466d49e1aeSJan Lentfer 	sm->initial_req = TRUE;
5476d49e1aeSJan Lentfer }
5486d49e1aeSJan Lentfer 
5496d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,INITIALIZE)5506d49e1aeSJan Lentfer SM_STATE(SUPP_BE, INITIALIZE)
5516d49e1aeSJan Lentfer {
5526d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, INITIALIZE);
5536d49e1aeSJan Lentfer 	eapol_sm_abortSupp(sm);
5546d49e1aeSJan Lentfer 	sm->suppAbort = FALSE;
5553ff40c12SJohn Marino 
5563ff40c12SJohn Marino 	/*
5573ff40c12SJohn Marino 	 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
5583ff40c12SJohn Marino 	 * allows the timer tick to be stopped more quickly when the port is
5593ff40c12SJohn Marino 	 * not enabled. Since this variable is used only within RECEIVE state,
5603ff40c12SJohn Marino 	 * clearing it on initialization does not change actual state machine
5613ff40c12SJohn Marino 	 * behavior.
5623ff40c12SJohn Marino 	 */
5633ff40c12SJohn Marino 	sm->authWhile = 0;
5646d49e1aeSJan Lentfer }
5656d49e1aeSJan Lentfer 
5666d49e1aeSJan Lentfer 
SM_STATE(SUPP_BE,RECEIVE)5676d49e1aeSJan Lentfer SM_STATE(SUPP_BE, RECEIVE)
5686d49e1aeSJan Lentfer {
5696d49e1aeSJan Lentfer 	SM_ENTRY(SUPP_BE, RECEIVE);
5706d49e1aeSJan Lentfer 	sm->authWhile = sm->authPeriod;
5716d49e1aeSJan Lentfer 	eapol_enable_timer_tick(sm);
5726d49e1aeSJan Lentfer 	sm->eapolEap = FALSE;
5736d49e1aeSJan Lentfer 	sm->eapNoResp = FALSE;
5746d49e1aeSJan Lentfer 	sm->initial_req = FALSE;
5756d49e1aeSJan Lentfer }
5766d49e1aeSJan Lentfer 
5776d49e1aeSJan Lentfer 
SM_STEP(SUPP_BE)5786d49e1aeSJan Lentfer SM_STEP(SUPP_BE)
5796d49e1aeSJan Lentfer {
5806d49e1aeSJan Lentfer 	if (sm->initialize || sm->suppAbort)
5816d49e1aeSJan Lentfer 		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
5826d49e1aeSJan Lentfer 	else switch (sm->SUPP_BE_state) {
5836d49e1aeSJan Lentfer 	case SUPP_BE_UNKNOWN:
5846d49e1aeSJan Lentfer 		break;
5856d49e1aeSJan Lentfer 	case SUPP_BE_REQUEST:
5866d49e1aeSJan Lentfer 		/*
5876d49e1aeSJan Lentfer 		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
5886d49e1aeSJan Lentfer 		 * and SUCCESS based on eapFail and eapSuccess, respectively.
5896d49e1aeSJan Lentfer 		 * However, IEEE Std 802.1X-2004 is also specifying that
5903ff40c12SJohn Marino 		 * eapNoResp should be set in conjunction with eapSuccess and
5916d49e1aeSJan Lentfer 		 * eapFail which would mean that more than one of the
5926d49e1aeSJan Lentfer 		 * transitions here would be activated at the same time.
5936d49e1aeSJan Lentfer 		 * Skipping RESPONSE and/or RECEIVE states in these cases can
5946d49e1aeSJan Lentfer 		 * cause problems and the direct transitions to do not seem
5956d49e1aeSJan Lentfer 		 * correct. Because of this, the conditions for these
5966d49e1aeSJan Lentfer 		 * transitions are verified only after eapNoResp. They are
5976d49e1aeSJan Lentfer 		 * unlikely to be used since eapNoResp should always be set if
5986d49e1aeSJan Lentfer 		 * either of eapSuccess or eapFail is set.
5996d49e1aeSJan Lentfer 		 */
6006d49e1aeSJan Lentfer 		if (sm->eapResp && sm->eapNoResp) {
6016d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
6026d49e1aeSJan Lentfer 				   "eapResp and eapNoResp set?!");
6036d49e1aeSJan Lentfer 		}
6046d49e1aeSJan Lentfer 		if (sm->eapResp)
6056d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, RESPONSE);
6066d49e1aeSJan Lentfer 		else if (sm->eapNoResp)
6076d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, RECEIVE);
6086d49e1aeSJan Lentfer 		else if (sm->eapFail)
6096d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, FAIL);
6106d49e1aeSJan Lentfer 		else if (sm->eapSuccess)
6116d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, SUCCESS);
6126d49e1aeSJan Lentfer 		break;
6136d49e1aeSJan Lentfer 	case SUPP_BE_RESPONSE:
6146d49e1aeSJan Lentfer 		SM_ENTER(SUPP_BE, RECEIVE);
6156d49e1aeSJan Lentfer 		break;
6166d49e1aeSJan Lentfer 	case SUPP_BE_SUCCESS:
6176d49e1aeSJan Lentfer 		SM_ENTER(SUPP_BE, IDLE);
6186d49e1aeSJan Lentfer 		break;
6196d49e1aeSJan Lentfer 	case SUPP_BE_FAIL:
6206d49e1aeSJan Lentfer 		SM_ENTER(SUPP_BE, IDLE);
6216d49e1aeSJan Lentfer 		break;
6226d49e1aeSJan Lentfer 	case SUPP_BE_TIMEOUT:
6236d49e1aeSJan Lentfer 		SM_ENTER(SUPP_BE, IDLE);
6246d49e1aeSJan Lentfer 		break;
6256d49e1aeSJan Lentfer 	case SUPP_BE_IDLE:
6266d49e1aeSJan Lentfer 		if (sm->eapFail && sm->suppStart)
6276d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, FAIL);
6286d49e1aeSJan Lentfer 		else if (sm->eapolEap && sm->suppStart)
6296d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, REQUEST);
6306d49e1aeSJan Lentfer 		else if (sm->eapSuccess && sm->suppStart)
6316d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, SUCCESS);
6326d49e1aeSJan Lentfer 		break;
6336d49e1aeSJan Lentfer 	case SUPP_BE_INITIALIZE:
6346d49e1aeSJan Lentfer 		SM_ENTER(SUPP_BE, IDLE);
6356d49e1aeSJan Lentfer 		break;
6366d49e1aeSJan Lentfer 	case SUPP_BE_RECEIVE:
6376d49e1aeSJan Lentfer 		if (sm->eapolEap)
6386d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, REQUEST);
6396d49e1aeSJan Lentfer 		else if (sm->eapFail)
6406d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, FAIL);
6416d49e1aeSJan Lentfer 		else if (sm->authWhile == 0)
6426d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, TIMEOUT);
6436d49e1aeSJan Lentfer 		else if (sm->eapSuccess)
6446d49e1aeSJan Lentfer 			SM_ENTER(SUPP_BE, SUCCESS);
6456d49e1aeSJan Lentfer 		break;
6466d49e1aeSJan Lentfer 	}
6476d49e1aeSJan Lentfer }
6486d49e1aeSJan Lentfer 
6496d49e1aeSJan Lentfer 
eapol_sm_txLogoff(struct eapol_sm * sm)6506d49e1aeSJan Lentfer static void eapol_sm_txLogoff(struct eapol_sm *sm)
6516d49e1aeSJan Lentfer {
6526d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
6536d49e1aeSJan Lentfer 	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
6546d49e1aeSJan Lentfer 			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
6556d49e1aeSJan Lentfer 	sm->dot1xSuppEapolLogoffFramesTx++;
6566d49e1aeSJan Lentfer 	sm->dot1xSuppEapolFramesTx++;
6576d49e1aeSJan Lentfer }
6586d49e1aeSJan Lentfer 
6596d49e1aeSJan Lentfer 
eapol_sm_txStart(struct eapol_sm * sm)6606d49e1aeSJan Lentfer static void eapol_sm_txStart(struct eapol_sm *sm)
6616d49e1aeSJan Lentfer {
6626d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
6636d49e1aeSJan Lentfer 	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
6646d49e1aeSJan Lentfer 			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
6656d49e1aeSJan Lentfer 	sm->dot1xSuppEapolStartFramesTx++;
6666d49e1aeSJan Lentfer 	sm->dot1xSuppEapolFramesTx++;
6676d49e1aeSJan Lentfer }
6686d49e1aeSJan Lentfer 
6696d49e1aeSJan Lentfer 
6706d49e1aeSJan Lentfer #define IEEE8021X_ENCR_KEY_LEN 32
6716d49e1aeSJan Lentfer #define IEEE8021X_SIGN_KEY_LEN 32
6726d49e1aeSJan Lentfer 
6736d49e1aeSJan Lentfer struct eap_key_data {
6746d49e1aeSJan Lentfer 	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
6756d49e1aeSJan Lentfer 	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
6766d49e1aeSJan Lentfer };
6776d49e1aeSJan Lentfer 
6786d49e1aeSJan Lentfer 
eapol_sm_processKey(struct eapol_sm * sm)6796d49e1aeSJan Lentfer static void eapol_sm_processKey(struct eapol_sm *sm)
6806d49e1aeSJan Lentfer {
6813ff40c12SJohn Marino #ifndef CONFIG_FIPS
6826d49e1aeSJan Lentfer 	struct ieee802_1x_hdr *hdr;
6836d49e1aeSJan Lentfer 	struct ieee802_1x_eapol_key *key;
6846d49e1aeSJan Lentfer 	struct eap_key_data keydata;
6856d49e1aeSJan Lentfer 	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
686*a1157835SDaniel Fojt #ifndef CONFIG_NO_RC4
6876d49e1aeSJan Lentfer 	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
688*a1157835SDaniel Fojt #endif /* CONFIG_NO_RC4 */
6896d49e1aeSJan Lentfer 	int key_len, res, sign_key_len, encr_key_len;
6906d49e1aeSJan Lentfer 	u16 rx_key_length;
6913ff40c12SJohn Marino 	size_t plen;
6926d49e1aeSJan Lentfer 
6936d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
6946d49e1aeSJan Lentfer 	if (sm->last_rx_key == NULL)
6956d49e1aeSJan Lentfer 		return;
6966d49e1aeSJan Lentfer 
6976d49e1aeSJan Lentfer 	if (!sm->conf.accept_802_1x_keys) {
6986d49e1aeSJan Lentfer 		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
6996d49e1aeSJan Lentfer 			   " even though this was not accepted - "
7006d49e1aeSJan Lentfer 			   "ignoring this packet");
7016d49e1aeSJan Lentfer 		return;
7026d49e1aeSJan Lentfer 	}
7036d49e1aeSJan Lentfer 
7043ff40c12SJohn Marino 	if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
7053ff40c12SJohn Marino 		return;
7066d49e1aeSJan Lentfer 	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
7076d49e1aeSJan Lentfer 	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
7083ff40c12SJohn Marino 	plen = be_to_host16(hdr->length);
7093ff40c12SJohn Marino 	if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
7106d49e1aeSJan Lentfer 		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
7116d49e1aeSJan Lentfer 		return;
7126d49e1aeSJan Lentfer 	}
7136d49e1aeSJan Lentfer 	rx_key_length = WPA_GET_BE16(key->key_length);
7146d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
7156d49e1aeSJan Lentfer 		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
7166d49e1aeSJan Lentfer 		   hdr->version, hdr->type, be_to_host16(hdr->length),
7176d49e1aeSJan Lentfer 		   key->type, rx_key_length, key->key_index);
7186d49e1aeSJan Lentfer 
7196d49e1aeSJan Lentfer 	eapol_sm_notify_lower_layer_success(sm, 1);
7206d49e1aeSJan Lentfer 	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
7216d49e1aeSJan Lentfer 	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
7226d49e1aeSJan Lentfer 	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
7236d49e1aeSJan Lentfer 	if (res < 0) {
7246d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
7256d49e1aeSJan Lentfer 			   "decrypting EAPOL-Key keys");
7266d49e1aeSJan Lentfer 		return;
7276d49e1aeSJan Lentfer 	}
7286d49e1aeSJan Lentfer 	if (res == 16) {
7296d49e1aeSJan Lentfer 		/* LEAP derives only 16 bytes of keying material. */
7306d49e1aeSJan Lentfer 		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
7316d49e1aeSJan Lentfer 		if (res) {
7326d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
7336d49e1aeSJan Lentfer 				   "master key for decrypting EAPOL-Key keys");
7346d49e1aeSJan Lentfer 			return;
7356d49e1aeSJan Lentfer 		}
7366d49e1aeSJan Lentfer 		sign_key_len = 16;
7376d49e1aeSJan Lentfer 		encr_key_len = 16;
7386d49e1aeSJan Lentfer 		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
7396d49e1aeSJan Lentfer 	} else if (res) {
7406d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
7416d49e1aeSJan Lentfer 			   "data for decrypting EAPOL-Key keys (res=%d)", res);
7426d49e1aeSJan Lentfer 		return;
7436d49e1aeSJan Lentfer 	}
7446d49e1aeSJan Lentfer 
7456d49e1aeSJan Lentfer 	/* The key replay_counter must increase when same master key */
7466d49e1aeSJan Lentfer 	if (sm->replay_counter_valid &&
7476d49e1aeSJan Lentfer 	    os_memcmp(sm->last_replay_counter, key->replay_counter,
7486d49e1aeSJan Lentfer 		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
7496d49e1aeSJan Lentfer 		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
7506d49e1aeSJan Lentfer 			   "not increase - ignoring key");
7516d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
7526d49e1aeSJan Lentfer 			    sm->last_replay_counter,
7536d49e1aeSJan Lentfer 			    IEEE8021X_REPLAY_COUNTER_LEN);
7546d49e1aeSJan Lentfer 		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
7556d49e1aeSJan Lentfer 			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
7566d49e1aeSJan Lentfer 		return;
7576d49e1aeSJan Lentfer 	}
7586d49e1aeSJan Lentfer 
7596d49e1aeSJan Lentfer 	/* Verify key signature (HMAC-MD5) */
7606d49e1aeSJan Lentfer 	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
7616d49e1aeSJan Lentfer 	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
7626d49e1aeSJan Lentfer 	hmac_md5(keydata.sign_key, sign_key_len,
7636d49e1aeSJan Lentfer 		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
7646d49e1aeSJan Lentfer 		 key->key_signature);
765*a1157835SDaniel Fojt 	if (os_memcmp_const(orig_key_sign, key->key_signature,
7666d49e1aeSJan Lentfer 			    IEEE8021X_KEY_SIGN_LEN) != 0) {
7676d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
7686d49e1aeSJan Lentfer 			   "EAPOL-Key packet");
7696d49e1aeSJan Lentfer 		os_memcpy(key->key_signature, orig_key_sign,
7706d49e1aeSJan Lentfer 			  IEEE8021X_KEY_SIGN_LEN);
7716d49e1aeSJan Lentfer 		return;
7726d49e1aeSJan Lentfer 	}
7736d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
7746d49e1aeSJan Lentfer 
7753ff40c12SJohn Marino 	key_len = plen - sizeof(*key);
7766d49e1aeSJan Lentfer 	if (key_len > 32 || rx_key_length > 32) {
7776d49e1aeSJan Lentfer 		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
7786d49e1aeSJan Lentfer 			   key_len ? key_len : rx_key_length);
7796d49e1aeSJan Lentfer 		return;
7806d49e1aeSJan Lentfer 	}
7816d49e1aeSJan Lentfer 	if (key_len == rx_key_length) {
782*a1157835SDaniel Fojt #ifdef CONFIG_NO_RC4
783*a1157835SDaniel Fojt 		if (encr_key_len) {
784*a1157835SDaniel Fojt 			/* otherwise unused */
785*a1157835SDaniel Fojt 		}
786*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "EAPOL: RC4 not supported in the build");
787*a1157835SDaniel Fojt 		return;
788*a1157835SDaniel Fojt #else /* CONFIG_NO_RC4 */
7896d49e1aeSJan Lentfer 		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
7906d49e1aeSJan Lentfer 		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
7916d49e1aeSJan Lentfer 			  encr_key_len);
7926d49e1aeSJan Lentfer 		os_memcpy(datakey, key + 1, key_len);
7936d49e1aeSJan Lentfer 		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
7946d49e1aeSJan Lentfer 			 datakey, key_len);
7956d49e1aeSJan Lentfer 		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
7966d49e1aeSJan Lentfer 				datakey, key_len);
797*a1157835SDaniel Fojt #endif /* CONFIG_NO_RC4 */
7986d49e1aeSJan Lentfer 	} else if (key_len == 0) {
7996d49e1aeSJan Lentfer 		/*
8006d49e1aeSJan Lentfer 		 * IEEE 802.1X-2004 specifies that least significant Key Length
8016d49e1aeSJan Lentfer 		 * octets from MS-MPPE-Send-Key are used as the key if the key
8026d49e1aeSJan Lentfer 		 * data is not present. This seems to be meaning the beginning
8036d49e1aeSJan Lentfer 		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
8046d49e1aeSJan Lentfer 		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
8056d49e1aeSJan Lentfer 		 * Anyway, taking the beginning of the keying material from EAP
8066d49e1aeSJan Lentfer 		 * seems to interoperate with Authenticators.
8076d49e1aeSJan Lentfer 		 */
8086d49e1aeSJan Lentfer 		key_len = rx_key_length;
8096d49e1aeSJan Lentfer 		os_memcpy(datakey, keydata.encr_key, key_len);
8106d49e1aeSJan Lentfer 		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
8116d49e1aeSJan Lentfer 				"material data encryption key",
8126d49e1aeSJan Lentfer 				datakey, key_len);
8136d49e1aeSJan Lentfer 	} else {
8146d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
8156d49e1aeSJan Lentfer 			   "(key_length=%d)", key_len, rx_key_length);
8166d49e1aeSJan Lentfer 		return;
8176d49e1aeSJan Lentfer 	}
8186d49e1aeSJan Lentfer 
8196d49e1aeSJan Lentfer 	sm->replay_counter_valid = TRUE;
8206d49e1aeSJan Lentfer 	os_memcpy(sm->last_replay_counter, key->replay_counter,
8216d49e1aeSJan Lentfer 		  IEEE8021X_REPLAY_COUNTER_LEN);
8226d49e1aeSJan Lentfer 
8236d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
8246d49e1aeSJan Lentfer 		   "len %d",
8256d49e1aeSJan Lentfer 		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
8266d49e1aeSJan Lentfer 		   "unicast" : "broadcast",
8276d49e1aeSJan Lentfer 		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
8286d49e1aeSJan Lentfer 
8296d49e1aeSJan Lentfer 	if (sm->ctx->set_wep_key &&
8306d49e1aeSJan Lentfer 	    sm->ctx->set_wep_key(sm->ctx->ctx,
8316d49e1aeSJan Lentfer 				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
8326d49e1aeSJan Lentfer 				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
8336d49e1aeSJan Lentfer 				 datakey, key_len) < 0) {
8346d49e1aeSJan Lentfer 		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
8356d49e1aeSJan Lentfer 			   " driver.");
8366d49e1aeSJan Lentfer 	} else {
8376d49e1aeSJan Lentfer 		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
8386d49e1aeSJan Lentfer 			sm->unicast_key_received = TRUE;
8396d49e1aeSJan Lentfer 		else
8406d49e1aeSJan Lentfer 			sm->broadcast_key_received = TRUE;
8416d49e1aeSJan Lentfer 
8426d49e1aeSJan Lentfer 		if ((sm->unicast_key_received ||
8436d49e1aeSJan Lentfer 		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
8446d49e1aeSJan Lentfer 		    (sm->broadcast_key_received ||
8456d49e1aeSJan Lentfer 		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
8466d49e1aeSJan Lentfer 		{
8476d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
8486d49e1aeSJan Lentfer 				   "frames received");
8496d49e1aeSJan Lentfer 			sm->portValid = TRUE;
8506d49e1aeSJan Lentfer 			if (sm->ctx->eapol_done_cb)
8516d49e1aeSJan Lentfer 				sm->ctx->eapol_done_cb(sm->ctx->ctx);
8526d49e1aeSJan Lentfer 		}
8536d49e1aeSJan Lentfer 	}
8543ff40c12SJohn Marino #endif /* CONFIG_FIPS */
8556d49e1aeSJan Lentfer }
8566d49e1aeSJan Lentfer 
8576d49e1aeSJan Lentfer 
eapol_sm_getSuppRsp(struct eapol_sm * sm)8586d49e1aeSJan Lentfer static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
8596d49e1aeSJan Lentfer {
8606d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
8616d49e1aeSJan Lentfer 	/* EAP layer processing; no special code is needed, since Supplicant
8626d49e1aeSJan Lentfer 	 * Backend state machine is waiting for eapNoResp or eapResp to be set
8636d49e1aeSJan Lentfer 	 * and these are only set in the EAP state machine when the processing
8646d49e1aeSJan Lentfer 	 * has finished. */
8656d49e1aeSJan Lentfer }
8666d49e1aeSJan Lentfer 
8676d49e1aeSJan Lentfer 
eapol_sm_txSuppRsp(struct eapol_sm * sm)8686d49e1aeSJan Lentfer static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
8696d49e1aeSJan Lentfer {
8706d49e1aeSJan Lentfer 	struct wpabuf *resp;
8716d49e1aeSJan Lentfer 
8726d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
8733ff40c12SJohn Marino 
8743ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
8753ff40c12SJohn Marino 	if (sm->use_eap_proxy) {
8763ff40c12SJohn Marino 		/* Get EAP Response from EAP Proxy */
8773ff40c12SJohn Marino 		resp = eap_proxy_get_eapRespData(sm->eap_proxy);
8783ff40c12SJohn Marino 		if (resp == NULL) {
8793ff40c12SJohn Marino 			wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
8803ff40c12SJohn Marino 				   "response data not available");
8813ff40c12SJohn Marino 			return;
8823ff40c12SJohn Marino 		}
8833ff40c12SJohn Marino 	} else
8843ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
8853ff40c12SJohn Marino 
8866d49e1aeSJan Lentfer 	resp = eap_get_eapRespData(sm->eap);
8876d49e1aeSJan Lentfer 	if (resp == NULL) {
8886d49e1aeSJan Lentfer 		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
8896d49e1aeSJan Lentfer 			   "not available");
8906d49e1aeSJan Lentfer 		return;
8916d49e1aeSJan Lentfer 	}
8926d49e1aeSJan Lentfer 
8936d49e1aeSJan Lentfer 	/* Send EAP-Packet from the EAP layer to the Authenticator */
8946d49e1aeSJan Lentfer 	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
8956d49e1aeSJan Lentfer 			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
8966d49e1aeSJan Lentfer 			    wpabuf_len(resp));
8976d49e1aeSJan Lentfer 
8986d49e1aeSJan Lentfer 	/* eapRespData is not used anymore, so free it here */
8996d49e1aeSJan Lentfer 	wpabuf_free(resp);
9006d49e1aeSJan Lentfer 
9016d49e1aeSJan Lentfer 	if (sm->initial_req)
9026d49e1aeSJan Lentfer 		sm->dot1xSuppEapolReqIdFramesRx++;
9036d49e1aeSJan Lentfer 	else
9046d49e1aeSJan Lentfer 		sm->dot1xSuppEapolReqFramesRx++;
9056d49e1aeSJan Lentfer 	sm->dot1xSuppEapolRespFramesTx++;
9066d49e1aeSJan Lentfer 	sm->dot1xSuppEapolFramesTx++;
9076d49e1aeSJan Lentfer }
9086d49e1aeSJan Lentfer 
9096d49e1aeSJan Lentfer 
eapol_sm_abortSupp(struct eapol_sm * sm)9106d49e1aeSJan Lentfer static void eapol_sm_abortSupp(struct eapol_sm *sm)
9116d49e1aeSJan Lentfer {
9126d49e1aeSJan Lentfer 	/* release system resources that may have been allocated for the
9136d49e1aeSJan Lentfer 	 * authentication session */
9146d49e1aeSJan Lentfer 	os_free(sm->last_rx_key);
9156d49e1aeSJan Lentfer 	sm->last_rx_key = NULL;
9166d49e1aeSJan Lentfer 	wpabuf_free(sm->eapReqData);
9176d49e1aeSJan Lentfer 	sm->eapReqData = NULL;
9186d49e1aeSJan Lentfer 	eap_sm_abort(sm->eap);
919*a1157835SDaniel Fojt #ifdef CONFIG_EAP_PROXY
920*a1157835SDaniel Fojt 	eap_proxy_sm_abort(sm->eap_proxy);
921*a1157835SDaniel Fojt #endif /* CONFIG_EAP_PROXY */
9226d49e1aeSJan Lentfer }
9236d49e1aeSJan Lentfer 
9246d49e1aeSJan Lentfer 
eapol_sm_step_timeout(void * eloop_ctx,void * timeout_ctx)9256d49e1aeSJan Lentfer static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
9266d49e1aeSJan Lentfer {
9276d49e1aeSJan Lentfer 	eapol_sm_step(timeout_ctx);
9286d49e1aeSJan Lentfer }
9296d49e1aeSJan Lentfer 
9306d49e1aeSJan Lentfer 
eapol_sm_set_port_authorized(struct eapol_sm * sm)9313ff40c12SJohn Marino static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
9323ff40c12SJohn Marino {
9333ff40c12SJohn Marino 	int cb;
9343ff40c12SJohn Marino 
9353ff40c12SJohn Marino 	cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
9363ff40c12SJohn Marino 	sm->force_authorized_update = FALSE;
9373ff40c12SJohn Marino 	sm->suppPortStatus = Authorized;
9383ff40c12SJohn Marino 	if (cb && sm->ctx->port_cb)
9393ff40c12SJohn Marino 		sm->ctx->port_cb(sm->ctx->ctx, 1);
9403ff40c12SJohn Marino }
9413ff40c12SJohn Marino 
9423ff40c12SJohn Marino 
eapol_sm_set_port_unauthorized(struct eapol_sm * sm)9433ff40c12SJohn Marino static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
9443ff40c12SJohn Marino {
9453ff40c12SJohn Marino 	int cb;
9463ff40c12SJohn Marino 
9473ff40c12SJohn Marino 	cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
9483ff40c12SJohn Marino 	sm->force_authorized_update = FALSE;
9493ff40c12SJohn Marino 	sm->suppPortStatus = Unauthorized;
9503ff40c12SJohn Marino 	if (cb && sm->ctx->port_cb)
9513ff40c12SJohn Marino 		sm->ctx->port_cb(sm->ctx->ctx, 0);
9523ff40c12SJohn Marino }
9533ff40c12SJohn Marino 
9543ff40c12SJohn Marino 
9556d49e1aeSJan Lentfer /**
9566d49e1aeSJan Lentfer  * eapol_sm_step - EAPOL state machine step function
9576d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
9586d49e1aeSJan Lentfer  *
9596d49e1aeSJan Lentfer  * This function is called to notify the state machine about changed external
9606d49e1aeSJan Lentfer  * variables. It will step through the EAPOL state machines in loop to process
9616d49e1aeSJan Lentfer  * all triggered state changes.
9626d49e1aeSJan Lentfer  */
eapol_sm_step(struct eapol_sm * sm)9636d49e1aeSJan Lentfer void eapol_sm_step(struct eapol_sm *sm)
9646d49e1aeSJan Lentfer {
9656d49e1aeSJan Lentfer 	int i;
9666d49e1aeSJan Lentfer 
9676d49e1aeSJan Lentfer 	/* In theory, it should be ok to run this in loop until !changed.
9686d49e1aeSJan Lentfer 	 * However, it is better to use a limit on number of iterations to
9696d49e1aeSJan Lentfer 	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
9706d49e1aeSJan Lentfer 	 * state machine were to generate a busy loop. */
9716d49e1aeSJan Lentfer 	for (i = 0; i < 100; i++) {
9726d49e1aeSJan Lentfer 		sm->changed = FALSE;
9736d49e1aeSJan Lentfer 		SM_STEP_RUN(SUPP_PAE);
9746d49e1aeSJan Lentfer 		SM_STEP_RUN(KEY_RX);
9756d49e1aeSJan Lentfer 		SM_STEP_RUN(SUPP_BE);
9763ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
9773ff40c12SJohn Marino 		if (sm->use_eap_proxy) {
9783ff40c12SJohn Marino 			/* Drive the EAP proxy state machine */
9793ff40c12SJohn Marino 			if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
9803ff40c12SJohn Marino 				sm->changed = TRUE;
9813ff40c12SJohn Marino 		} else
9823ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
9836d49e1aeSJan Lentfer 		if (eap_peer_sm_step(sm->eap))
9846d49e1aeSJan Lentfer 			sm->changed = TRUE;
9856d49e1aeSJan Lentfer 		if (!sm->changed)
9866d49e1aeSJan Lentfer 			break;
9876d49e1aeSJan Lentfer 	}
9886d49e1aeSJan Lentfer 
9896d49e1aeSJan Lentfer 	if (sm->changed) {
9906d49e1aeSJan Lentfer 		/* restart EAPOL state machine step from timeout call in order
9916d49e1aeSJan Lentfer 		 * to allow other events to be processed. */
9926d49e1aeSJan Lentfer 		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
9936d49e1aeSJan Lentfer 		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
9946d49e1aeSJan Lentfer 	}
9956d49e1aeSJan Lentfer 
9966d49e1aeSJan Lentfer 	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
9973ff40c12SJohn Marino 		enum eapol_supp_result result;
9983ff40c12SJohn Marino 		if (sm->cb_status == EAPOL_CB_SUCCESS)
9993ff40c12SJohn Marino 			result = EAPOL_SUPP_RESULT_SUCCESS;
10003ff40c12SJohn Marino 		else if (eap_peer_was_failure_expected(sm->eap))
10013ff40c12SJohn Marino 			result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
10023ff40c12SJohn Marino 		else
10033ff40c12SJohn Marino 			result = EAPOL_SUPP_RESULT_FAILURE;
10046d49e1aeSJan Lentfer 		sm->cb_status = EAPOL_CB_IN_PROGRESS;
10053ff40c12SJohn Marino 		sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
10066d49e1aeSJan Lentfer 	}
10076d49e1aeSJan Lentfer }
10086d49e1aeSJan Lentfer 
10096d49e1aeSJan Lentfer 
10106d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE
eapol_supp_pae_state(int state)10116d49e1aeSJan Lentfer static const char *eapol_supp_pae_state(int state)
10126d49e1aeSJan Lentfer {
10136d49e1aeSJan Lentfer 	switch (state) {
10146d49e1aeSJan Lentfer 	case SUPP_PAE_LOGOFF:
10156d49e1aeSJan Lentfer 		return "LOGOFF";
10166d49e1aeSJan Lentfer 	case SUPP_PAE_DISCONNECTED:
10176d49e1aeSJan Lentfer 		return "DISCONNECTED";
10186d49e1aeSJan Lentfer 	case SUPP_PAE_CONNECTING:
10196d49e1aeSJan Lentfer 		return "CONNECTING";
10206d49e1aeSJan Lentfer 	case SUPP_PAE_AUTHENTICATING:
10216d49e1aeSJan Lentfer 		return "AUTHENTICATING";
10226d49e1aeSJan Lentfer 	case SUPP_PAE_HELD:
10236d49e1aeSJan Lentfer 		return "HELD";
10246d49e1aeSJan Lentfer 	case SUPP_PAE_AUTHENTICATED:
10256d49e1aeSJan Lentfer 		return "AUTHENTICATED";
10266d49e1aeSJan Lentfer 	case SUPP_PAE_RESTART:
10276d49e1aeSJan Lentfer 		return "RESTART";
10286d49e1aeSJan Lentfer 	default:
10296d49e1aeSJan Lentfer 		return "UNKNOWN";
10306d49e1aeSJan Lentfer 	}
10316d49e1aeSJan Lentfer }
10326d49e1aeSJan Lentfer 
10336d49e1aeSJan Lentfer 
eapol_supp_be_state(int state)10346d49e1aeSJan Lentfer static const char *eapol_supp_be_state(int state)
10356d49e1aeSJan Lentfer {
10366d49e1aeSJan Lentfer 	switch (state) {
10376d49e1aeSJan Lentfer 	case SUPP_BE_REQUEST:
10386d49e1aeSJan Lentfer 		return "REQUEST";
10396d49e1aeSJan Lentfer 	case SUPP_BE_RESPONSE:
10406d49e1aeSJan Lentfer 		return "RESPONSE";
10416d49e1aeSJan Lentfer 	case SUPP_BE_SUCCESS:
10426d49e1aeSJan Lentfer 		return "SUCCESS";
10436d49e1aeSJan Lentfer 	case SUPP_BE_FAIL:
10446d49e1aeSJan Lentfer 		return "FAIL";
10456d49e1aeSJan Lentfer 	case SUPP_BE_TIMEOUT:
10466d49e1aeSJan Lentfer 		return "TIMEOUT";
10476d49e1aeSJan Lentfer 	case SUPP_BE_IDLE:
10486d49e1aeSJan Lentfer 		return "IDLE";
10496d49e1aeSJan Lentfer 	case SUPP_BE_INITIALIZE:
10506d49e1aeSJan Lentfer 		return "INITIALIZE";
10516d49e1aeSJan Lentfer 	case SUPP_BE_RECEIVE:
10526d49e1aeSJan Lentfer 		return "RECEIVE";
10536d49e1aeSJan Lentfer 	default:
10546d49e1aeSJan Lentfer 		return "UNKNOWN";
10556d49e1aeSJan Lentfer 	}
10566d49e1aeSJan Lentfer }
10576d49e1aeSJan Lentfer 
10586d49e1aeSJan Lentfer 
eapol_port_status(PortStatus status)10596d49e1aeSJan Lentfer static const char * eapol_port_status(PortStatus status)
10606d49e1aeSJan Lentfer {
10616d49e1aeSJan Lentfer 	if (status == Authorized)
10626d49e1aeSJan Lentfer 		return "Authorized";
10636d49e1aeSJan Lentfer 	else
10646d49e1aeSJan Lentfer 		return "Unauthorized";
10656d49e1aeSJan Lentfer }
10666d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE */
10676d49e1aeSJan Lentfer 
10686d49e1aeSJan Lentfer 
10696d49e1aeSJan Lentfer #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
eapol_port_control(PortControl ctrl)10706d49e1aeSJan Lentfer static const char * eapol_port_control(PortControl ctrl)
10716d49e1aeSJan Lentfer {
10726d49e1aeSJan Lentfer 	switch (ctrl) {
10736d49e1aeSJan Lentfer 	case Auto:
10746d49e1aeSJan Lentfer 		return "Auto";
10756d49e1aeSJan Lentfer 	case ForceUnauthorized:
10766d49e1aeSJan Lentfer 		return "ForceUnauthorized";
10776d49e1aeSJan Lentfer 	case ForceAuthorized:
10786d49e1aeSJan Lentfer 		return "ForceAuthorized";
10796d49e1aeSJan Lentfer 	default:
10806d49e1aeSJan Lentfer 		return "Unknown";
10816d49e1aeSJan Lentfer 	}
10826d49e1aeSJan Lentfer }
10836d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
10846d49e1aeSJan Lentfer 
10856d49e1aeSJan Lentfer 
10866d49e1aeSJan Lentfer /**
10876d49e1aeSJan Lentfer  * eapol_sm_configure - Set EAPOL variables
10886d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
10896d49e1aeSJan Lentfer  * @heldPeriod: dot1xSuppHeldPeriod
10906d49e1aeSJan Lentfer  * @authPeriod: dot1xSuppAuthPeriod
10916d49e1aeSJan Lentfer  * @startPeriod: dot1xSuppStartPeriod
10926d49e1aeSJan Lentfer  * @maxStart: dot1xSuppMaxStart
10936d49e1aeSJan Lentfer  *
10946d49e1aeSJan Lentfer  * Set configurable EAPOL state machine variables. Each variable can be set to
10956d49e1aeSJan Lentfer  * the given value or ignored if set to -1 (to set only some of the variables).
10966d49e1aeSJan Lentfer  */
eapol_sm_configure(struct eapol_sm * sm,int heldPeriod,int authPeriod,int startPeriod,int maxStart)10976d49e1aeSJan Lentfer void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
10986d49e1aeSJan Lentfer 			int startPeriod, int maxStart)
10996d49e1aeSJan Lentfer {
11006d49e1aeSJan Lentfer 	if (sm == NULL)
11016d49e1aeSJan Lentfer 		return;
11026d49e1aeSJan Lentfer 	if (heldPeriod >= 0)
11036d49e1aeSJan Lentfer 		sm->heldPeriod = heldPeriod;
11046d49e1aeSJan Lentfer 	if (authPeriod >= 0)
11056d49e1aeSJan Lentfer 		sm->authPeriod = authPeriod;
11066d49e1aeSJan Lentfer 	if (startPeriod >= 0)
11076d49e1aeSJan Lentfer 		sm->startPeriod = startPeriod;
11086d49e1aeSJan Lentfer 	if (maxStart >= 0)
11096d49e1aeSJan Lentfer 		sm->maxStart = maxStart;
11106d49e1aeSJan Lentfer }
11116d49e1aeSJan Lentfer 
11126d49e1aeSJan Lentfer 
11133ff40c12SJohn Marino /**
11143ff40c12SJohn Marino  * eapol_sm_get_method_name - Get EAPOL method name
11153ff40c12SJohn Marino  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
11163ff40c12SJohn Marino  * Returns: Static string containing name of current eap method or NULL
11173ff40c12SJohn Marino  */
eapol_sm_get_method_name(struct eapol_sm * sm)11183ff40c12SJohn Marino const char * eapol_sm_get_method_name(struct eapol_sm *sm)
11193ff40c12SJohn Marino {
11203ff40c12SJohn Marino 	if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
11213ff40c12SJohn Marino 	    sm->suppPortStatus != Authorized)
11223ff40c12SJohn Marino 		return NULL;
11233ff40c12SJohn Marino 
11243ff40c12SJohn Marino 	return eap_sm_get_method_name(sm->eap);
11253ff40c12SJohn Marino }
11263ff40c12SJohn Marino 
11273ff40c12SJohn Marino 
11286d49e1aeSJan Lentfer #ifdef CONFIG_CTRL_IFACE
11296d49e1aeSJan Lentfer /**
11306d49e1aeSJan Lentfer  * eapol_sm_get_status - Get EAPOL state machine status
11316d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
11326d49e1aeSJan Lentfer  * @buf: Buffer for status information
11336d49e1aeSJan Lentfer  * @buflen: Maximum buffer length
11346d49e1aeSJan Lentfer  * @verbose: Whether to include verbose status information
11356d49e1aeSJan Lentfer  * Returns: Number of bytes written to buf.
11366d49e1aeSJan Lentfer  *
11376d49e1aeSJan Lentfer  * Query EAPOL state machine for status information. This function fills in a
11386d49e1aeSJan Lentfer  * text area with current status information from the EAPOL state machine. If
11396d49e1aeSJan Lentfer  * the buffer (buf) is not large enough, status information will be truncated
11406d49e1aeSJan Lentfer  * to fit the buffer.
11416d49e1aeSJan Lentfer  */
eapol_sm_get_status(struct eapol_sm * sm,char * buf,size_t buflen,int verbose)11426d49e1aeSJan Lentfer int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
11436d49e1aeSJan Lentfer 			int verbose)
11446d49e1aeSJan Lentfer {
11456d49e1aeSJan Lentfer 	int len, ret;
11466d49e1aeSJan Lentfer 	if (sm == NULL)
11476d49e1aeSJan Lentfer 		return 0;
11486d49e1aeSJan Lentfer 
11496d49e1aeSJan Lentfer 	len = os_snprintf(buf, buflen,
11506d49e1aeSJan Lentfer 			  "Supplicant PAE state=%s\n"
11516d49e1aeSJan Lentfer 			  "suppPortStatus=%s\n",
11526d49e1aeSJan Lentfer 			  eapol_supp_pae_state(sm->SUPP_PAE_state),
11536d49e1aeSJan Lentfer 			  eapol_port_status(sm->suppPortStatus));
1154*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen, len))
11556d49e1aeSJan Lentfer 		return 0;
11566d49e1aeSJan Lentfer 
11576d49e1aeSJan Lentfer 	if (verbose) {
11586d49e1aeSJan Lentfer 		ret = os_snprintf(buf + len, buflen - len,
11596d49e1aeSJan Lentfer 				  "heldPeriod=%u\n"
11606d49e1aeSJan Lentfer 				  "authPeriod=%u\n"
11616d49e1aeSJan Lentfer 				  "startPeriod=%u\n"
11626d49e1aeSJan Lentfer 				  "maxStart=%u\n"
11636d49e1aeSJan Lentfer 				  "portControl=%s\n"
11646d49e1aeSJan Lentfer 				  "Supplicant Backend state=%s\n",
11656d49e1aeSJan Lentfer 				  sm->heldPeriod,
11666d49e1aeSJan Lentfer 				  sm->authPeriod,
11676d49e1aeSJan Lentfer 				  sm->startPeriod,
11686d49e1aeSJan Lentfer 				  sm->maxStart,
11696d49e1aeSJan Lentfer 				  eapol_port_control(sm->portControl),
11706d49e1aeSJan Lentfer 				  eapol_supp_be_state(sm->SUPP_BE_state));
1171*a1157835SDaniel Fojt 		if (os_snprintf_error(buflen - len, ret))
11726d49e1aeSJan Lentfer 			return len;
11736d49e1aeSJan Lentfer 		len += ret;
11746d49e1aeSJan Lentfer 	}
11756d49e1aeSJan Lentfer 
11763ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
11773ff40c12SJohn Marino 	if (sm->use_eap_proxy)
11783ff40c12SJohn Marino 		len += eap_proxy_sm_get_status(sm->eap_proxy,
11793ff40c12SJohn Marino 					       buf + len, buflen - len,
11803ff40c12SJohn Marino 					       verbose);
11813ff40c12SJohn Marino 	else
11823ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
11836d49e1aeSJan Lentfer 	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
11846d49e1aeSJan Lentfer 
11856d49e1aeSJan Lentfer 	return len;
11866d49e1aeSJan Lentfer }
11876d49e1aeSJan Lentfer 
11886d49e1aeSJan Lentfer 
11896d49e1aeSJan Lentfer /**
11906d49e1aeSJan Lentfer  * eapol_sm_get_mib - Get EAPOL state machine MIBs
11916d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
11926d49e1aeSJan Lentfer  * @buf: Buffer for MIB information
11936d49e1aeSJan Lentfer  * @buflen: Maximum buffer length
11946d49e1aeSJan Lentfer  * Returns: Number of bytes written to buf.
11956d49e1aeSJan Lentfer  *
11966d49e1aeSJan Lentfer  * Query EAPOL state machine for MIB information. This function fills in a
11976d49e1aeSJan Lentfer  * text area with current MIB information from the EAPOL state machine. If
11986d49e1aeSJan Lentfer  * the buffer (buf) is not large enough, MIB information will be truncated to
11996d49e1aeSJan Lentfer  * fit the buffer.
12006d49e1aeSJan Lentfer  */
eapol_sm_get_mib(struct eapol_sm * sm,char * buf,size_t buflen)12016d49e1aeSJan Lentfer int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
12026d49e1aeSJan Lentfer {
12036d49e1aeSJan Lentfer 	size_t len;
12046d49e1aeSJan Lentfer 	int ret;
12056d49e1aeSJan Lentfer 
12066d49e1aeSJan Lentfer 	if (sm == NULL)
12076d49e1aeSJan Lentfer 		return 0;
12086d49e1aeSJan Lentfer 	ret = os_snprintf(buf, buflen,
12096d49e1aeSJan Lentfer 			  "dot1xSuppPaeState=%d\n"
12106d49e1aeSJan Lentfer 			  "dot1xSuppHeldPeriod=%u\n"
12116d49e1aeSJan Lentfer 			  "dot1xSuppAuthPeriod=%u\n"
12126d49e1aeSJan Lentfer 			  "dot1xSuppStartPeriod=%u\n"
12136d49e1aeSJan Lentfer 			  "dot1xSuppMaxStart=%u\n"
12146d49e1aeSJan Lentfer 			  "dot1xSuppSuppControlledPortStatus=%s\n"
12156d49e1aeSJan Lentfer 			  "dot1xSuppBackendPaeState=%d\n",
12166d49e1aeSJan Lentfer 			  sm->SUPP_PAE_state,
12176d49e1aeSJan Lentfer 			  sm->heldPeriod,
12186d49e1aeSJan Lentfer 			  sm->authPeriod,
12196d49e1aeSJan Lentfer 			  sm->startPeriod,
12206d49e1aeSJan Lentfer 			  sm->maxStart,
12216d49e1aeSJan Lentfer 			  sm->suppPortStatus == Authorized ?
12226d49e1aeSJan Lentfer 			  "Authorized" : "Unauthorized",
12236d49e1aeSJan Lentfer 			  sm->SUPP_BE_state);
12246d49e1aeSJan Lentfer 
1225*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen, ret))
12266d49e1aeSJan Lentfer 		return 0;
12276d49e1aeSJan Lentfer 	len = ret;
12286d49e1aeSJan Lentfer 
12296d49e1aeSJan Lentfer 	ret = os_snprintf(buf + len, buflen - len,
12306d49e1aeSJan Lentfer 			  "dot1xSuppEapolFramesRx=%u\n"
12316d49e1aeSJan Lentfer 			  "dot1xSuppEapolFramesTx=%u\n"
12326d49e1aeSJan Lentfer 			  "dot1xSuppEapolStartFramesTx=%u\n"
12336d49e1aeSJan Lentfer 			  "dot1xSuppEapolLogoffFramesTx=%u\n"
12346d49e1aeSJan Lentfer 			  "dot1xSuppEapolRespFramesTx=%u\n"
12356d49e1aeSJan Lentfer 			  "dot1xSuppEapolReqIdFramesRx=%u\n"
12366d49e1aeSJan Lentfer 			  "dot1xSuppEapolReqFramesRx=%u\n"
12376d49e1aeSJan Lentfer 			  "dot1xSuppInvalidEapolFramesRx=%u\n"
12386d49e1aeSJan Lentfer 			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
12396d49e1aeSJan Lentfer 			  "dot1xSuppLastEapolFrameVersion=%u\n"
12406d49e1aeSJan Lentfer 			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
12416d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolFramesRx,
12426d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolFramesTx,
12436d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolStartFramesTx,
12446d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolLogoffFramesTx,
12456d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolRespFramesTx,
12466d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolReqIdFramesRx,
12476d49e1aeSJan Lentfer 			  sm->dot1xSuppEapolReqFramesRx,
12486d49e1aeSJan Lentfer 			  sm->dot1xSuppInvalidEapolFramesRx,
12496d49e1aeSJan Lentfer 			  sm->dot1xSuppEapLengthErrorFramesRx,
12506d49e1aeSJan Lentfer 			  sm->dot1xSuppLastEapolFrameVersion,
12516d49e1aeSJan Lentfer 			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
12526d49e1aeSJan Lentfer 
1253*a1157835SDaniel Fojt 	if (os_snprintf_error(buflen - len, ret))
12546d49e1aeSJan Lentfer 		return len;
12556d49e1aeSJan Lentfer 	len += ret;
12566d49e1aeSJan Lentfer 
12576d49e1aeSJan Lentfer 	return len;
12586d49e1aeSJan Lentfer }
12596d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE */
12606d49e1aeSJan Lentfer 
12616d49e1aeSJan Lentfer 
12626d49e1aeSJan Lentfer /**
12636d49e1aeSJan Lentfer  * eapol_sm_rx_eapol - Process received EAPOL frames
12646d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
12656d49e1aeSJan Lentfer  * @src: Source MAC address of the EAPOL packet
12666d49e1aeSJan Lentfer  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
12676d49e1aeSJan Lentfer  * @len: Length of the EAPOL frame
12686d49e1aeSJan Lentfer  * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
12696d49e1aeSJan Lentfer  * -1 failure
12706d49e1aeSJan Lentfer  */
eapol_sm_rx_eapol(struct eapol_sm * sm,const u8 * src,const u8 * buf,size_t len)12716d49e1aeSJan Lentfer int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
12726d49e1aeSJan Lentfer 		      size_t len)
12736d49e1aeSJan Lentfer {
12746d49e1aeSJan Lentfer 	const struct ieee802_1x_hdr *hdr;
12756d49e1aeSJan Lentfer 	const struct ieee802_1x_eapol_key *key;
12766d49e1aeSJan Lentfer 	int data_len;
12776d49e1aeSJan Lentfer 	int res = 1;
12786d49e1aeSJan Lentfer 	size_t plen;
12796d49e1aeSJan Lentfer 
12806d49e1aeSJan Lentfer 	if (sm == NULL)
12816d49e1aeSJan Lentfer 		return 0;
12826d49e1aeSJan Lentfer 	sm->dot1xSuppEapolFramesRx++;
12836d49e1aeSJan Lentfer 	if (len < sizeof(*hdr)) {
12846d49e1aeSJan Lentfer 		sm->dot1xSuppInvalidEapolFramesRx++;
12856d49e1aeSJan Lentfer 		return 0;
12866d49e1aeSJan Lentfer 	}
12876d49e1aeSJan Lentfer 	hdr = (const struct ieee802_1x_hdr *) buf;
12886d49e1aeSJan Lentfer 	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
12896d49e1aeSJan Lentfer 	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
12906d49e1aeSJan Lentfer 	if (hdr->version < EAPOL_VERSION) {
12916d49e1aeSJan Lentfer 		/* TODO: backwards compatibility */
12926d49e1aeSJan Lentfer 	}
12936d49e1aeSJan Lentfer 	plen = be_to_host16(hdr->length);
12946d49e1aeSJan Lentfer 	if (plen > len - sizeof(*hdr)) {
12956d49e1aeSJan Lentfer 		sm->dot1xSuppEapLengthErrorFramesRx++;
12966d49e1aeSJan Lentfer 		return 0;
12976d49e1aeSJan Lentfer 	}
12986d49e1aeSJan Lentfer #ifdef CONFIG_WPS
1299*a1157835SDaniel Fojt 	if (sm->conf.wps && sm->conf.workaround &&
13006d49e1aeSJan Lentfer 	    plen < len - sizeof(*hdr) &&
13016d49e1aeSJan Lentfer 	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
13026d49e1aeSJan Lentfer 	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
13036d49e1aeSJan Lentfer 		const struct eap_hdr *ehdr =
13046d49e1aeSJan Lentfer 			(const struct eap_hdr *) (hdr + 1);
13056d49e1aeSJan Lentfer 		u16 elen;
13066d49e1aeSJan Lentfer 
13076d49e1aeSJan Lentfer 		elen = be_to_host16(ehdr->length);
13086d49e1aeSJan Lentfer 		if (elen > plen && elen <= len - sizeof(*hdr)) {
13096d49e1aeSJan Lentfer 			/*
13106d49e1aeSJan Lentfer 			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
13116d49e1aeSJan Lentfer 			 * packets with too short EAPOL header length field
13126d49e1aeSJan Lentfer 			 * (14 octets). This is fixed in firmware Ver.1.49.
13136d49e1aeSJan Lentfer 			 * As a workaround, fix the EAPOL header based on the
13146d49e1aeSJan Lentfer 			 * correct length in the EAP packet.
13156d49e1aeSJan Lentfer 			 */
13166d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
13176d49e1aeSJan Lentfer 				   "payload length based on EAP header: "
13186d49e1aeSJan Lentfer 				   "%d -> %d", (int) plen, elen);
13196d49e1aeSJan Lentfer 			plen = elen;
13206d49e1aeSJan Lentfer 		}
13216d49e1aeSJan Lentfer 	}
13226d49e1aeSJan Lentfer #endif /* CONFIG_WPS */
13236d49e1aeSJan Lentfer 	data_len = plen + sizeof(*hdr);
13246d49e1aeSJan Lentfer 
13256d49e1aeSJan Lentfer 	switch (hdr->type) {
13266d49e1aeSJan Lentfer 	case IEEE802_1X_TYPE_EAP_PACKET:
13273ff40c12SJohn Marino 		if (sm->conf.workaround) {
13283ff40c12SJohn Marino 			/*
13293ff40c12SJohn Marino 			 * An AP has been reported to send out EAP message with
13303ff40c12SJohn Marino 			 * undocumented code 10 at some point near the
13313ff40c12SJohn Marino 			 * completion of EAP authentication. This can result in
13323ff40c12SJohn Marino 			 * issues with the unexpected EAP message triggering
13333ff40c12SJohn Marino 			 * restart of EAPOL authentication. Avoid this by
13343ff40c12SJohn Marino 			 * skipping the message without advancing the state
13353ff40c12SJohn Marino 			 * machine.
13363ff40c12SJohn Marino 			 */
13373ff40c12SJohn Marino 			const struct eap_hdr *ehdr =
13383ff40c12SJohn Marino 				(const struct eap_hdr *) (hdr + 1);
13393ff40c12SJohn Marino 			if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
13403ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
13413ff40c12SJohn Marino 				break;
13423ff40c12SJohn Marino 			}
13433ff40c12SJohn Marino 		}
13443ff40c12SJohn Marino 
13456d49e1aeSJan Lentfer 		if (sm->cached_pmk) {
13466d49e1aeSJan Lentfer 			/* Trying to use PMKSA caching, but Authenticator did
13476d49e1aeSJan Lentfer 			 * not seem to have a matching entry. Need to restart
13486d49e1aeSJan Lentfer 			 * EAPOL state machines.
13496d49e1aeSJan Lentfer 			 */
13506d49e1aeSJan Lentfer 			eapol_sm_abort_cached(sm);
13516d49e1aeSJan Lentfer 		}
13526d49e1aeSJan Lentfer 		wpabuf_free(sm->eapReqData);
13536d49e1aeSJan Lentfer 		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
13546d49e1aeSJan Lentfer 		if (sm->eapReqData) {
13556d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
13566d49e1aeSJan Lentfer 				   "frame");
13576d49e1aeSJan Lentfer 			sm->eapolEap = TRUE;
13583ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
13593ff40c12SJohn Marino 			if (sm->use_eap_proxy) {
13603ff40c12SJohn Marino 				eap_proxy_packet_update(
13613ff40c12SJohn Marino 					sm->eap_proxy,
13623ff40c12SJohn Marino 					wpabuf_mhead_u8(sm->eapReqData),
13633ff40c12SJohn Marino 					wpabuf_len(sm->eapReqData));
13643ff40c12SJohn Marino 				wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
13653ff40c12SJohn Marino 					   "EAP Req updated");
13663ff40c12SJohn Marino 			}
13673ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
13686d49e1aeSJan Lentfer 			eapol_sm_step(sm);
13696d49e1aeSJan Lentfer 		}
13706d49e1aeSJan Lentfer 		break;
13716d49e1aeSJan Lentfer 	case IEEE802_1X_TYPE_EAPOL_KEY:
13726d49e1aeSJan Lentfer 		if (plen < sizeof(*key)) {
13736d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
13746d49e1aeSJan Lentfer 				   "frame received");
13756d49e1aeSJan Lentfer 			break;
13766d49e1aeSJan Lentfer 		}
13776d49e1aeSJan Lentfer 		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
13786d49e1aeSJan Lentfer 		if (key->type == EAPOL_KEY_TYPE_WPA ||
13796d49e1aeSJan Lentfer 		    key->type == EAPOL_KEY_TYPE_RSN) {
13806d49e1aeSJan Lentfer 			/* WPA Supplicant takes care of this frame. */
13816d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
13826d49e1aeSJan Lentfer 				   "frame in EAPOL state machines");
13836d49e1aeSJan Lentfer 			res = 0;
13846d49e1aeSJan Lentfer 			break;
13856d49e1aeSJan Lentfer 		}
13866d49e1aeSJan Lentfer 		if (key->type != EAPOL_KEY_TYPE_RC4) {
13876d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
13886d49e1aeSJan Lentfer 				   "EAPOL-Key type %d", key->type);
13896d49e1aeSJan Lentfer 			break;
13906d49e1aeSJan Lentfer 		}
13916d49e1aeSJan Lentfer 		os_free(sm->last_rx_key);
13926d49e1aeSJan Lentfer 		sm->last_rx_key = os_malloc(data_len);
13936d49e1aeSJan Lentfer 		if (sm->last_rx_key) {
13946d49e1aeSJan Lentfer 			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
13956d49e1aeSJan Lentfer 				   "frame");
13966d49e1aeSJan Lentfer 			os_memcpy(sm->last_rx_key, buf, data_len);
13976d49e1aeSJan Lentfer 			sm->last_rx_key_len = data_len;
13986d49e1aeSJan Lentfer 			sm->rxKey = TRUE;
13996d49e1aeSJan Lentfer 			eapol_sm_step(sm);
14006d49e1aeSJan Lentfer 		}
14016d49e1aeSJan Lentfer 		break;
1402*a1157835SDaniel Fojt #ifdef CONFIG_MACSEC
1403*a1157835SDaniel Fojt 	case IEEE802_1X_TYPE_EAPOL_MKA:
1404*a1157835SDaniel Fojt 		wpa_printf(MSG_EXCESSIVE,
1405*a1157835SDaniel Fojt 			   "EAPOL type %d will be handled by MKA",
1406*a1157835SDaniel Fojt 			   hdr->type);
1407*a1157835SDaniel Fojt 		break;
1408*a1157835SDaniel Fojt #endif /* CONFIG_MACSEC */
14096d49e1aeSJan Lentfer 	default:
14106d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
14116d49e1aeSJan Lentfer 			   hdr->type);
14126d49e1aeSJan Lentfer 		sm->dot1xSuppInvalidEapolFramesRx++;
14136d49e1aeSJan Lentfer 		break;
14146d49e1aeSJan Lentfer 	}
14156d49e1aeSJan Lentfer 
14166d49e1aeSJan Lentfer 	return res;
14176d49e1aeSJan Lentfer }
14186d49e1aeSJan Lentfer 
14196d49e1aeSJan Lentfer 
14206d49e1aeSJan Lentfer /**
14216d49e1aeSJan Lentfer  * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
14226d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14236d49e1aeSJan Lentfer  *
14246d49e1aeSJan Lentfer  * Notify EAPOL state machine about transmitted EAPOL packet from an external
14256d49e1aeSJan Lentfer  * component, e.g., WPA. This will update the statistics.
14266d49e1aeSJan Lentfer  */
eapol_sm_notify_tx_eapol_key(struct eapol_sm * sm)14276d49e1aeSJan Lentfer void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
14286d49e1aeSJan Lentfer {
14296d49e1aeSJan Lentfer 	if (sm)
14306d49e1aeSJan Lentfer 		sm->dot1xSuppEapolFramesTx++;
14316d49e1aeSJan Lentfer }
14326d49e1aeSJan Lentfer 
14336d49e1aeSJan Lentfer 
14346d49e1aeSJan Lentfer /**
14356d49e1aeSJan Lentfer  * eapol_sm_notify_portEnabled - Notification about portEnabled change
14366d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14376d49e1aeSJan Lentfer  * @enabled: New portEnabled value
14386d49e1aeSJan Lentfer  *
14396d49e1aeSJan Lentfer  * Notify EAPOL state machine about new portEnabled value.
14406d49e1aeSJan Lentfer  */
eapol_sm_notify_portEnabled(struct eapol_sm * sm,Boolean enabled)14416d49e1aeSJan Lentfer void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
14426d49e1aeSJan Lentfer {
14436d49e1aeSJan Lentfer 	if (sm == NULL)
14446d49e1aeSJan Lentfer 		return;
14456d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
14466d49e1aeSJan Lentfer 		   "portEnabled=%d", enabled);
14473ff40c12SJohn Marino 	if (sm->portEnabled != enabled)
14483ff40c12SJohn Marino 		sm->force_authorized_update = TRUE;
14496d49e1aeSJan Lentfer 	sm->portEnabled = enabled;
14506d49e1aeSJan Lentfer 	eapol_sm_step(sm);
14516d49e1aeSJan Lentfer }
14526d49e1aeSJan Lentfer 
14536d49e1aeSJan Lentfer 
14546d49e1aeSJan Lentfer /**
14556d49e1aeSJan Lentfer  * eapol_sm_notify_portValid - Notification about portValid change
14566d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14576d49e1aeSJan Lentfer  * @valid: New portValid value
14586d49e1aeSJan Lentfer  *
14596d49e1aeSJan Lentfer  * Notify EAPOL state machine about new portValid value.
14606d49e1aeSJan Lentfer  */
eapol_sm_notify_portValid(struct eapol_sm * sm,Boolean valid)14616d49e1aeSJan Lentfer void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
14626d49e1aeSJan Lentfer {
14636d49e1aeSJan Lentfer 	if (sm == NULL)
14646d49e1aeSJan Lentfer 		return;
14656d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
14666d49e1aeSJan Lentfer 		   "portValid=%d", valid);
14676d49e1aeSJan Lentfer 	sm->portValid = valid;
14686d49e1aeSJan Lentfer 	eapol_sm_step(sm);
14696d49e1aeSJan Lentfer }
14706d49e1aeSJan Lentfer 
14716d49e1aeSJan Lentfer 
14726d49e1aeSJan Lentfer /**
14736d49e1aeSJan Lentfer  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
14746d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14756d49e1aeSJan Lentfer  * @success: %TRUE = set success, %FALSE = clear success
14766d49e1aeSJan Lentfer  *
14776d49e1aeSJan Lentfer  * Notify the EAPOL state machine that external event has forced EAP state to
14786d49e1aeSJan Lentfer  * success (success = %TRUE). This can be cleared by setting success = %FALSE.
14796d49e1aeSJan Lentfer  *
14806d49e1aeSJan Lentfer  * This function is called to update EAP state when WPA-PSK key handshake has
14816d49e1aeSJan Lentfer  * been completed successfully since WPA-PSK does not use EAP state machine.
14826d49e1aeSJan Lentfer  */
eapol_sm_notify_eap_success(struct eapol_sm * sm,Boolean success)14836d49e1aeSJan Lentfer void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
14846d49e1aeSJan Lentfer {
14856d49e1aeSJan Lentfer 	if (sm == NULL)
14866d49e1aeSJan Lentfer 		return;
14876d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
14886d49e1aeSJan Lentfer 		   "EAP success=%d", success);
14896d49e1aeSJan Lentfer 	sm->eapSuccess = success;
14906d49e1aeSJan Lentfer 	sm->altAccept = success;
14916d49e1aeSJan Lentfer 	if (success)
14926d49e1aeSJan Lentfer 		eap_notify_success(sm->eap);
14936d49e1aeSJan Lentfer 	eapol_sm_step(sm);
14946d49e1aeSJan Lentfer }
14956d49e1aeSJan Lentfer 
14966d49e1aeSJan Lentfer 
14976d49e1aeSJan Lentfer /**
14986d49e1aeSJan Lentfer  * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
14996d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
15006d49e1aeSJan Lentfer  * @fail: %TRUE = set failure, %FALSE = clear failure
15016d49e1aeSJan Lentfer  *
15026d49e1aeSJan Lentfer  * Notify EAPOL state machine that external event has forced EAP state to
15036d49e1aeSJan Lentfer  * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
15046d49e1aeSJan Lentfer  */
eapol_sm_notify_eap_fail(struct eapol_sm * sm,Boolean fail)15056d49e1aeSJan Lentfer void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
15066d49e1aeSJan Lentfer {
15076d49e1aeSJan Lentfer 	if (sm == NULL)
15086d49e1aeSJan Lentfer 		return;
15096d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
15106d49e1aeSJan Lentfer 		   "EAP fail=%d", fail);
15116d49e1aeSJan Lentfer 	sm->eapFail = fail;
15126d49e1aeSJan Lentfer 	sm->altReject = fail;
15136d49e1aeSJan Lentfer 	eapol_sm_step(sm);
15146d49e1aeSJan Lentfer }
15156d49e1aeSJan Lentfer 
15166d49e1aeSJan Lentfer 
15176d49e1aeSJan Lentfer /**
15186d49e1aeSJan Lentfer  * eapol_sm_notify_config - Notification of EAPOL configuration change
15196d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
15206d49e1aeSJan Lentfer  * @config: Pointer to current network EAP configuration
15216d49e1aeSJan Lentfer  * @conf: Pointer to EAPOL configuration data
15226d49e1aeSJan Lentfer  *
15236d49e1aeSJan Lentfer  * Notify EAPOL state machine that configuration has changed. config will be
15246d49e1aeSJan Lentfer  * stored as a backpointer to network configuration. This can be %NULL to clear
15256d49e1aeSJan Lentfer  * the stored pointed. conf will be copied to local EAPOL/EAP configuration
15266d49e1aeSJan Lentfer  * data. If conf is %NULL, this part of the configuration change will be
15276d49e1aeSJan Lentfer  * skipped.
15286d49e1aeSJan Lentfer  */
eapol_sm_notify_config(struct eapol_sm * sm,struct eap_peer_config * config,const struct eapol_config * conf)15296d49e1aeSJan Lentfer void eapol_sm_notify_config(struct eapol_sm *sm,
15306d49e1aeSJan Lentfer 			    struct eap_peer_config *config,
15316d49e1aeSJan Lentfer 			    const struct eapol_config *conf)
15326d49e1aeSJan Lentfer {
15336d49e1aeSJan Lentfer 	if (sm == NULL)
15346d49e1aeSJan Lentfer 		return;
15356d49e1aeSJan Lentfer 
15366d49e1aeSJan Lentfer 	sm->config = config;
15373ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
15383ff40c12SJohn Marino 	sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
15393ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
15406d49e1aeSJan Lentfer 
15416d49e1aeSJan Lentfer 	if (conf == NULL)
15426d49e1aeSJan Lentfer 		return;
15436d49e1aeSJan Lentfer 
15446d49e1aeSJan Lentfer 	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
15456d49e1aeSJan Lentfer 	sm->conf.required_keys = conf->required_keys;
15466d49e1aeSJan Lentfer 	sm->conf.fast_reauth = conf->fast_reauth;
15476d49e1aeSJan Lentfer 	sm->conf.workaround = conf->workaround;
1548*a1157835SDaniel Fojt 	sm->conf.wps = conf->wps;
15493ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
15503ff40c12SJohn Marino 	if (sm->use_eap_proxy) {
15513ff40c12SJohn Marino 		/* Using EAP Proxy, so skip EAP state machine update */
15523ff40c12SJohn Marino 		return;
15533ff40c12SJohn Marino 	}
15543ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
15556d49e1aeSJan Lentfer 	if (sm->eap) {
15566d49e1aeSJan Lentfer 		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
15576d49e1aeSJan Lentfer 		eap_set_workaround(sm->eap, conf->workaround);
15586d49e1aeSJan Lentfer 		eap_set_force_disabled(sm->eap, conf->eap_disabled);
15593ff40c12SJohn Marino 		eap_set_external_sim(sm->eap, conf->external_sim);
15606d49e1aeSJan Lentfer 	}
15616d49e1aeSJan Lentfer }
15626d49e1aeSJan Lentfer 
15636d49e1aeSJan Lentfer 
15646d49e1aeSJan Lentfer /**
15656d49e1aeSJan Lentfer  * eapol_sm_get_key - Get master session key (MSK) from EAP
15666d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
15676d49e1aeSJan Lentfer  * @key: Pointer for key buffer
15686d49e1aeSJan Lentfer  * @len: Number of bytes to copy to key
15696d49e1aeSJan Lentfer  * Returns: 0 on success (len of key available), maximum available key len
15706d49e1aeSJan Lentfer  * (>0) if key is available but it is shorter than len, or -1 on failure.
15716d49e1aeSJan Lentfer  *
15726d49e1aeSJan Lentfer  * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
15736d49e1aeSJan Lentfer  * is available only after a successful authentication.
15746d49e1aeSJan Lentfer  */
eapol_sm_get_key(struct eapol_sm * sm,u8 * key,size_t len)15756d49e1aeSJan Lentfer int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
15766d49e1aeSJan Lentfer {
15776d49e1aeSJan Lentfer 	const u8 *eap_key;
15786d49e1aeSJan Lentfer 	size_t eap_len;
15796d49e1aeSJan Lentfer 
15803ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
1581*a1157835SDaniel Fojt 	if (sm && sm->use_eap_proxy) {
15823ff40c12SJohn Marino 		/* Get key from EAP proxy */
15833ff40c12SJohn Marino 		if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
15843ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
15853ff40c12SJohn Marino 			return -1;
15863ff40c12SJohn Marino 		}
15873ff40c12SJohn Marino 		eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
15883ff40c12SJohn Marino 		if (eap_key == NULL) {
15893ff40c12SJohn Marino 			wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
15903ff40c12SJohn Marino 				   "eapKeyData");
15913ff40c12SJohn Marino 			return -1;
15923ff40c12SJohn Marino 		}
15933ff40c12SJohn Marino 		goto key_fetched;
15943ff40c12SJohn Marino 	}
15953ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
15966d49e1aeSJan Lentfer 	if (sm == NULL || !eap_key_available(sm->eap)) {
15976d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
15986d49e1aeSJan Lentfer 		return -1;
15996d49e1aeSJan Lentfer 	}
16006d49e1aeSJan Lentfer 	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
16016d49e1aeSJan Lentfer 	if (eap_key == NULL) {
16026d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
16036d49e1aeSJan Lentfer 		return -1;
16046d49e1aeSJan Lentfer 	}
16053ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
16063ff40c12SJohn Marino key_fetched:
16073ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
16086d49e1aeSJan Lentfer 	if (len > eap_len) {
16096d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
16106d49e1aeSJan Lentfer 			   "available (len=%lu)",
16116d49e1aeSJan Lentfer 			   (unsigned long) len, (unsigned long) eap_len);
16126d49e1aeSJan Lentfer 		return eap_len;
16136d49e1aeSJan Lentfer 	}
16146d49e1aeSJan Lentfer 	os_memcpy(key, eap_key, len);
16156d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
16166d49e1aeSJan Lentfer 		   (unsigned long) len);
16176d49e1aeSJan Lentfer 	return 0;
16186d49e1aeSJan Lentfer }
16196d49e1aeSJan Lentfer 
16206d49e1aeSJan Lentfer 
16216d49e1aeSJan Lentfer /**
1622*a1157835SDaniel Fojt  * eapol_sm_get_session_id - Get EAP Session-Id
1623*a1157835SDaniel Fojt  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1624*a1157835SDaniel Fojt  * @len: Pointer to variable that will be set to number of bytes in the session
1625*a1157835SDaniel Fojt  * Returns: Pointer to the EAP Session-Id or %NULL on failure
1626*a1157835SDaniel Fojt  *
1627*a1157835SDaniel Fojt  * The Session-Id is available only after a successful authentication.
1628*a1157835SDaniel Fojt  */
eapol_sm_get_session_id(struct eapol_sm * sm,size_t * len)1629*a1157835SDaniel Fojt const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
1630*a1157835SDaniel Fojt {
1631*a1157835SDaniel Fojt 	if (sm == NULL || !eap_key_available(sm->eap)) {
1632*a1157835SDaniel Fojt 		wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
1633*a1157835SDaniel Fojt 		return NULL;
1634*a1157835SDaniel Fojt 	}
1635*a1157835SDaniel Fojt 	return eap_get_eapSessionId(sm->eap, len);
1636*a1157835SDaniel Fojt }
1637*a1157835SDaniel Fojt 
1638*a1157835SDaniel Fojt 
1639*a1157835SDaniel Fojt /**
16406d49e1aeSJan Lentfer  * eapol_sm_notify_logoff - Notification of logon/logoff commands
16416d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16426d49e1aeSJan Lentfer  * @logoff: Whether command was logoff
16436d49e1aeSJan Lentfer  *
16446d49e1aeSJan Lentfer  * Notify EAPOL state machines that user requested logon/logoff.
16456d49e1aeSJan Lentfer  */
eapol_sm_notify_logoff(struct eapol_sm * sm,Boolean logoff)16466d49e1aeSJan Lentfer void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
16476d49e1aeSJan Lentfer {
16486d49e1aeSJan Lentfer 	if (sm) {
16496d49e1aeSJan Lentfer 		sm->userLogoff = logoff;
16503ff40c12SJohn Marino 		if (!logoff) {
16513ff40c12SJohn Marino 			/* If there is a delayed txStart queued, start now. */
16523ff40c12SJohn Marino 			sm->startWhen = 0;
16533ff40c12SJohn Marino 		}
16546d49e1aeSJan Lentfer 		eapol_sm_step(sm);
16556d49e1aeSJan Lentfer 	}
16566d49e1aeSJan Lentfer }
16576d49e1aeSJan Lentfer 
16586d49e1aeSJan Lentfer 
16596d49e1aeSJan Lentfer /**
16606d49e1aeSJan Lentfer  * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
16616d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16626d49e1aeSJan Lentfer  *
16636d49e1aeSJan Lentfer  * Notify EAPOL state machines that PMKSA caching was successful. This is used
16646d49e1aeSJan Lentfer  * to move EAPOL and EAP state machines into authenticated/successful state.
16656d49e1aeSJan Lentfer  */
eapol_sm_notify_cached(struct eapol_sm * sm)16666d49e1aeSJan Lentfer void eapol_sm_notify_cached(struct eapol_sm *sm)
16676d49e1aeSJan Lentfer {
16686d49e1aeSJan Lentfer 	if (sm == NULL)
16696d49e1aeSJan Lentfer 		return;
16706d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
16713ff40c12SJohn Marino 	sm->eapSuccess = TRUE;
16726d49e1aeSJan Lentfer 	eap_notify_success(sm->eap);
16736d49e1aeSJan Lentfer 	eapol_sm_step(sm);
16746d49e1aeSJan Lentfer }
16756d49e1aeSJan Lentfer 
16766d49e1aeSJan Lentfer 
16776d49e1aeSJan Lentfer /**
16786d49e1aeSJan Lentfer  * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
16796d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16806d49e1aeSJan Lentfer  *
1681*a1157835SDaniel Fojt  * Notify EAPOL state machines if PMKSA caching is used.
16826d49e1aeSJan Lentfer  */
eapol_sm_notify_pmkid_attempt(struct eapol_sm * sm)1683*a1157835SDaniel Fojt void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
16846d49e1aeSJan Lentfer {
16856d49e1aeSJan Lentfer 	if (sm == NULL)
16866d49e1aeSJan Lentfer 		return;
16876d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
16886d49e1aeSJan Lentfer 	sm->cached_pmk = TRUE;
16896d49e1aeSJan Lentfer }
16906d49e1aeSJan Lentfer 
16916d49e1aeSJan Lentfer 
eapol_sm_abort_cached(struct eapol_sm * sm)16926d49e1aeSJan Lentfer static void eapol_sm_abort_cached(struct eapol_sm *sm)
16936d49e1aeSJan Lentfer {
16946d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
16956d49e1aeSJan Lentfer 		   "doing full EAP authentication");
16966d49e1aeSJan Lentfer 	if (sm == NULL)
16976d49e1aeSJan Lentfer 		return;
16986d49e1aeSJan Lentfer 	sm->cached_pmk = FALSE;
16996d49e1aeSJan Lentfer 	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
17003ff40c12SJohn Marino 	eapol_sm_set_port_unauthorized(sm);
17016d49e1aeSJan Lentfer 
17026d49e1aeSJan Lentfer 	/* Make sure we do not start sending EAPOL-Start frames first, but
17036d49e1aeSJan Lentfer 	 * instead move to RESTART state to start EAPOL authentication. */
17046d49e1aeSJan Lentfer 	sm->startWhen = 3;
17056d49e1aeSJan Lentfer 	eapol_enable_timer_tick(sm);
17066d49e1aeSJan Lentfer 
17076d49e1aeSJan Lentfer 	if (sm->ctx->aborted_cached)
17086d49e1aeSJan Lentfer 		sm->ctx->aborted_cached(sm->ctx->ctx);
17096d49e1aeSJan Lentfer }
17106d49e1aeSJan Lentfer 
17116d49e1aeSJan Lentfer 
17126d49e1aeSJan Lentfer /**
17136d49e1aeSJan Lentfer  * eapol_sm_register_scard_ctx - Notification of smart card context
17146d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17156d49e1aeSJan Lentfer  * @ctx: Context data for smart card operations
17166d49e1aeSJan Lentfer  *
17176d49e1aeSJan Lentfer  * Notify EAPOL state machines of context data for smart card operations. This
17186d49e1aeSJan Lentfer  * context data will be used as a parameter for scard_*() functions.
17196d49e1aeSJan Lentfer  */
eapol_sm_register_scard_ctx(struct eapol_sm * sm,void * ctx)17206d49e1aeSJan Lentfer void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
17216d49e1aeSJan Lentfer {
17226d49e1aeSJan Lentfer 	if (sm) {
17236d49e1aeSJan Lentfer 		sm->ctx->scard_ctx = ctx;
17246d49e1aeSJan Lentfer 		eap_register_scard_ctx(sm->eap, ctx);
17256d49e1aeSJan Lentfer 	}
17266d49e1aeSJan Lentfer }
17276d49e1aeSJan Lentfer 
17286d49e1aeSJan Lentfer 
17296d49e1aeSJan Lentfer /**
17306d49e1aeSJan Lentfer  * eapol_sm_notify_portControl - Notification of portControl changes
17316d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17326d49e1aeSJan Lentfer  * @portControl: New value for portControl variable
17336d49e1aeSJan Lentfer  *
17346d49e1aeSJan Lentfer  * Notify EAPOL state machines that portControl variable has changed.
17356d49e1aeSJan Lentfer  */
eapol_sm_notify_portControl(struct eapol_sm * sm,PortControl portControl)17366d49e1aeSJan Lentfer void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
17376d49e1aeSJan Lentfer {
17386d49e1aeSJan Lentfer 	if (sm == NULL)
17396d49e1aeSJan Lentfer 		return;
17406d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
17416d49e1aeSJan Lentfer 		   "portControl=%s", eapol_port_control(portControl));
17426d49e1aeSJan Lentfer 	sm->portControl = portControl;
17436d49e1aeSJan Lentfer 	eapol_sm_step(sm);
17446d49e1aeSJan Lentfer }
17456d49e1aeSJan Lentfer 
17466d49e1aeSJan Lentfer 
17476d49e1aeSJan Lentfer /**
17486d49e1aeSJan Lentfer  * eapol_sm_notify_ctrl_attached - Notification of attached monitor
17496d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17506d49e1aeSJan Lentfer  *
17516d49e1aeSJan Lentfer  * Notify EAPOL state machines that a monitor was attached to the control
17526d49e1aeSJan Lentfer  * interface to trigger re-sending of pending requests for user input.
17536d49e1aeSJan Lentfer  */
eapol_sm_notify_ctrl_attached(struct eapol_sm * sm)17546d49e1aeSJan Lentfer void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
17556d49e1aeSJan Lentfer {
17566d49e1aeSJan Lentfer 	if (sm == NULL)
17576d49e1aeSJan Lentfer 		return;
17586d49e1aeSJan Lentfer 	eap_sm_notify_ctrl_attached(sm->eap);
17596d49e1aeSJan Lentfer }
17606d49e1aeSJan Lentfer 
17616d49e1aeSJan Lentfer 
17626d49e1aeSJan Lentfer /**
17636d49e1aeSJan Lentfer  * eapol_sm_notify_ctrl_response - Notification of received user input
17646d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17656d49e1aeSJan Lentfer  *
17666d49e1aeSJan Lentfer  * Notify EAPOL state machines that a control response, i.e., user
17676d49e1aeSJan Lentfer  * input, was received in order to trigger retrying of a pending EAP request.
17686d49e1aeSJan Lentfer  */
eapol_sm_notify_ctrl_response(struct eapol_sm * sm)17696d49e1aeSJan Lentfer void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
17706d49e1aeSJan Lentfer {
17716d49e1aeSJan Lentfer 	if (sm == NULL)
17726d49e1aeSJan Lentfer 		return;
17736d49e1aeSJan Lentfer 	if (sm->eapReqData && !sm->eapReq) {
17746d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
17756d49e1aeSJan Lentfer 			   "input) notification - retrying pending EAP "
17766d49e1aeSJan Lentfer 			   "Request");
17776d49e1aeSJan Lentfer 		sm->eapolEap = TRUE;
17786d49e1aeSJan Lentfer 		sm->eapReq = TRUE;
17796d49e1aeSJan Lentfer 		eapol_sm_step(sm);
17806d49e1aeSJan Lentfer 	}
17816d49e1aeSJan Lentfer }
17826d49e1aeSJan Lentfer 
17836d49e1aeSJan Lentfer 
17846d49e1aeSJan Lentfer /**
17856d49e1aeSJan Lentfer  * eapol_sm_request_reauth - Request reauthentication
17866d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17876d49e1aeSJan Lentfer  *
17886d49e1aeSJan Lentfer  * This function can be used to request EAPOL reauthentication, e.g., when the
17896d49e1aeSJan Lentfer  * current PMKSA entry is nearing expiration.
17906d49e1aeSJan Lentfer  */
eapol_sm_request_reauth(struct eapol_sm * sm)17916d49e1aeSJan Lentfer void eapol_sm_request_reauth(struct eapol_sm *sm)
17926d49e1aeSJan Lentfer {
17936d49e1aeSJan Lentfer 	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
17946d49e1aeSJan Lentfer 		return;
17956d49e1aeSJan Lentfer 	eapol_sm_txStart(sm);
17966d49e1aeSJan Lentfer }
17976d49e1aeSJan Lentfer 
17986d49e1aeSJan Lentfer 
17996d49e1aeSJan Lentfer /**
18006d49e1aeSJan Lentfer  * eapol_sm_notify_lower_layer_success - Notification of lower layer success
18016d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
18026d49e1aeSJan Lentfer  * @in_eapol_sm: Whether the caller is already running inside EAPOL state
18036d49e1aeSJan Lentfer  * machine loop (eapol_sm_step())
18046d49e1aeSJan Lentfer  *
18056d49e1aeSJan Lentfer  * Notify EAPOL (and EAP) state machines that a lower layer has detected a
18066d49e1aeSJan Lentfer  * successful authentication. This is used to recover from dropped EAP-Success
18076d49e1aeSJan Lentfer  * messages.
18086d49e1aeSJan Lentfer  */
eapol_sm_notify_lower_layer_success(struct eapol_sm * sm,int in_eapol_sm)18096d49e1aeSJan Lentfer void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
18106d49e1aeSJan Lentfer {
18116d49e1aeSJan Lentfer 	if (sm == NULL)
18126d49e1aeSJan Lentfer 		return;
18136d49e1aeSJan Lentfer 	eap_notify_lower_layer_success(sm->eap);
18146d49e1aeSJan Lentfer 	if (!in_eapol_sm)
18156d49e1aeSJan Lentfer 		eapol_sm_step(sm);
18166d49e1aeSJan Lentfer }
18176d49e1aeSJan Lentfer 
18186d49e1aeSJan Lentfer 
18196d49e1aeSJan Lentfer /**
18206d49e1aeSJan Lentfer  * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
18216d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
18226d49e1aeSJan Lentfer  */
eapol_sm_invalidate_cached_session(struct eapol_sm * sm)18236d49e1aeSJan Lentfer void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
18246d49e1aeSJan Lentfer {
18256d49e1aeSJan Lentfer 	if (sm)
18266d49e1aeSJan Lentfer 		eap_invalidate_cached_session(sm->eap);
18276d49e1aeSJan Lentfer }
18286d49e1aeSJan Lentfer 
18296d49e1aeSJan Lentfer 
eapol_sm_get_config(void * ctx)18306d49e1aeSJan Lentfer static struct eap_peer_config * eapol_sm_get_config(void *ctx)
18316d49e1aeSJan Lentfer {
18326d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
18336d49e1aeSJan Lentfer 	return sm ? sm->config : NULL;
18346d49e1aeSJan Lentfer }
18356d49e1aeSJan Lentfer 
18366d49e1aeSJan Lentfer 
eapol_sm_get_eapReqData(void * ctx)18376d49e1aeSJan Lentfer static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
18386d49e1aeSJan Lentfer {
18396d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
18406d49e1aeSJan Lentfer 	if (sm == NULL || sm->eapReqData == NULL)
18416d49e1aeSJan Lentfer 		return NULL;
18426d49e1aeSJan Lentfer 
18436d49e1aeSJan Lentfer 	return sm->eapReqData;
18446d49e1aeSJan Lentfer }
18456d49e1aeSJan Lentfer 
18466d49e1aeSJan Lentfer 
eapol_sm_get_bool(void * ctx,enum eapol_bool_var variable)18476d49e1aeSJan Lentfer static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
18486d49e1aeSJan Lentfer {
18496d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
18506d49e1aeSJan Lentfer 	if (sm == NULL)
18516d49e1aeSJan Lentfer 		return FALSE;
18526d49e1aeSJan Lentfer 	switch (variable) {
18536d49e1aeSJan Lentfer 	case EAPOL_eapSuccess:
18546d49e1aeSJan Lentfer 		return sm->eapSuccess;
18556d49e1aeSJan Lentfer 	case EAPOL_eapRestart:
18566d49e1aeSJan Lentfer 		return sm->eapRestart;
18576d49e1aeSJan Lentfer 	case EAPOL_eapFail:
18586d49e1aeSJan Lentfer 		return sm->eapFail;
18596d49e1aeSJan Lentfer 	case EAPOL_eapResp:
18606d49e1aeSJan Lentfer 		return sm->eapResp;
18616d49e1aeSJan Lentfer 	case EAPOL_eapNoResp:
18626d49e1aeSJan Lentfer 		return sm->eapNoResp;
18636d49e1aeSJan Lentfer 	case EAPOL_eapReq:
18646d49e1aeSJan Lentfer 		return sm->eapReq;
18656d49e1aeSJan Lentfer 	case EAPOL_portEnabled:
18666d49e1aeSJan Lentfer 		return sm->portEnabled;
18676d49e1aeSJan Lentfer 	case EAPOL_altAccept:
18686d49e1aeSJan Lentfer 		return sm->altAccept;
18696d49e1aeSJan Lentfer 	case EAPOL_altReject:
18706d49e1aeSJan Lentfer 		return sm->altReject;
1871*a1157835SDaniel Fojt 	case EAPOL_eapTriggerStart:
1872*a1157835SDaniel Fojt 		return sm->eapTriggerStart;
18736d49e1aeSJan Lentfer 	}
18746d49e1aeSJan Lentfer 	return FALSE;
18756d49e1aeSJan Lentfer }
18766d49e1aeSJan Lentfer 
18776d49e1aeSJan Lentfer 
eapol_sm_set_bool(void * ctx,enum eapol_bool_var variable,Boolean value)18786d49e1aeSJan Lentfer static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
18796d49e1aeSJan Lentfer 			      Boolean value)
18806d49e1aeSJan Lentfer {
18816d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
18826d49e1aeSJan Lentfer 	if (sm == NULL)
18836d49e1aeSJan Lentfer 		return;
18846d49e1aeSJan Lentfer 	switch (variable) {
18856d49e1aeSJan Lentfer 	case EAPOL_eapSuccess:
18866d49e1aeSJan Lentfer 		sm->eapSuccess = value;
18876d49e1aeSJan Lentfer 		break;
18886d49e1aeSJan Lentfer 	case EAPOL_eapRestart:
18896d49e1aeSJan Lentfer 		sm->eapRestart = value;
18906d49e1aeSJan Lentfer 		break;
18916d49e1aeSJan Lentfer 	case EAPOL_eapFail:
18926d49e1aeSJan Lentfer 		sm->eapFail = value;
18936d49e1aeSJan Lentfer 		break;
18946d49e1aeSJan Lentfer 	case EAPOL_eapResp:
18956d49e1aeSJan Lentfer 		sm->eapResp = value;
18966d49e1aeSJan Lentfer 		break;
18976d49e1aeSJan Lentfer 	case EAPOL_eapNoResp:
18986d49e1aeSJan Lentfer 		sm->eapNoResp = value;
18996d49e1aeSJan Lentfer 		break;
19006d49e1aeSJan Lentfer 	case EAPOL_eapReq:
19016d49e1aeSJan Lentfer 		sm->eapReq = value;
19026d49e1aeSJan Lentfer 		break;
19036d49e1aeSJan Lentfer 	case EAPOL_portEnabled:
19046d49e1aeSJan Lentfer 		sm->portEnabled = value;
19056d49e1aeSJan Lentfer 		break;
19066d49e1aeSJan Lentfer 	case EAPOL_altAccept:
19076d49e1aeSJan Lentfer 		sm->altAccept = value;
19086d49e1aeSJan Lentfer 		break;
19096d49e1aeSJan Lentfer 	case EAPOL_altReject:
19106d49e1aeSJan Lentfer 		sm->altReject = value;
19116d49e1aeSJan Lentfer 		break;
1912*a1157835SDaniel Fojt 	case EAPOL_eapTriggerStart:
1913*a1157835SDaniel Fojt 		sm->eapTriggerStart = value;
1914*a1157835SDaniel Fojt 		break;
19156d49e1aeSJan Lentfer 	}
19166d49e1aeSJan Lentfer }
19176d49e1aeSJan Lentfer 
19186d49e1aeSJan Lentfer 
eapol_sm_get_int(void * ctx,enum eapol_int_var variable)19196d49e1aeSJan Lentfer static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
19206d49e1aeSJan Lentfer {
19216d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
19226d49e1aeSJan Lentfer 	if (sm == NULL)
19236d49e1aeSJan Lentfer 		return 0;
19246d49e1aeSJan Lentfer 	switch (variable) {
19256d49e1aeSJan Lentfer 	case EAPOL_idleWhile:
19266d49e1aeSJan Lentfer 		return sm->idleWhile;
19276d49e1aeSJan Lentfer 	}
19286d49e1aeSJan Lentfer 	return 0;
19296d49e1aeSJan Lentfer }
19306d49e1aeSJan Lentfer 
19316d49e1aeSJan Lentfer 
eapol_sm_set_int(void * ctx,enum eapol_int_var variable,unsigned int value)19326d49e1aeSJan Lentfer static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
19336d49e1aeSJan Lentfer 			     unsigned int value)
19346d49e1aeSJan Lentfer {
19356d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
19366d49e1aeSJan Lentfer 	if (sm == NULL)
19376d49e1aeSJan Lentfer 		return;
19386d49e1aeSJan Lentfer 	switch (variable) {
19396d49e1aeSJan Lentfer 	case EAPOL_idleWhile:
19406d49e1aeSJan Lentfer 		sm->idleWhile = value;
19413ff40c12SJohn Marino 		if (sm->idleWhile > 0)
19426d49e1aeSJan Lentfer 			eapol_enable_timer_tick(sm);
19436d49e1aeSJan Lentfer 		break;
19446d49e1aeSJan Lentfer 	}
19456d49e1aeSJan Lentfer }
19466d49e1aeSJan Lentfer 
19476d49e1aeSJan Lentfer 
eapol_sm_set_config_blob(void * ctx,struct wpa_config_blob * blob)19486d49e1aeSJan Lentfer static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
19496d49e1aeSJan Lentfer {
19506d49e1aeSJan Lentfer #ifndef CONFIG_NO_CONFIG_BLOBS
19516d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
19526d49e1aeSJan Lentfer 	if (sm && sm->ctx && sm->ctx->set_config_blob)
19536d49e1aeSJan Lentfer 		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
19546d49e1aeSJan Lentfer #endif /* CONFIG_NO_CONFIG_BLOBS */
19556d49e1aeSJan Lentfer }
19566d49e1aeSJan Lentfer 
19576d49e1aeSJan Lentfer 
19586d49e1aeSJan Lentfer static const struct wpa_config_blob *
eapol_sm_get_config_blob(void * ctx,const char * name)19596d49e1aeSJan Lentfer eapol_sm_get_config_blob(void *ctx, const char *name)
19606d49e1aeSJan Lentfer {
19616d49e1aeSJan Lentfer #ifndef CONFIG_NO_CONFIG_BLOBS
19626d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
19636d49e1aeSJan Lentfer 	if (sm && sm->ctx && sm->ctx->get_config_blob)
19646d49e1aeSJan Lentfer 		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
19656d49e1aeSJan Lentfer 	else
19666d49e1aeSJan Lentfer 		return NULL;
19676d49e1aeSJan Lentfer #else /* CONFIG_NO_CONFIG_BLOBS */
19686d49e1aeSJan Lentfer 	return NULL;
19696d49e1aeSJan Lentfer #endif /* CONFIG_NO_CONFIG_BLOBS */
19706d49e1aeSJan Lentfer }
19716d49e1aeSJan Lentfer 
19726d49e1aeSJan Lentfer 
eapol_sm_notify_pending(void * ctx)19736d49e1aeSJan Lentfer static void eapol_sm_notify_pending(void *ctx)
19746d49e1aeSJan Lentfer {
19756d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
19766d49e1aeSJan Lentfer 	if (sm == NULL)
19776d49e1aeSJan Lentfer 		return;
19786d49e1aeSJan Lentfer 	if (sm->eapReqData && !sm->eapReq) {
19796d49e1aeSJan Lentfer 		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
19806d49e1aeSJan Lentfer 			   "state machine - retrying pending EAP Request");
19816d49e1aeSJan Lentfer 		sm->eapolEap = TRUE;
19826d49e1aeSJan Lentfer 		sm->eapReq = TRUE;
19836d49e1aeSJan Lentfer 		eapol_sm_step(sm);
19846d49e1aeSJan Lentfer 	}
19856d49e1aeSJan Lentfer }
19866d49e1aeSJan Lentfer 
19876d49e1aeSJan Lentfer 
19886d49e1aeSJan Lentfer #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
eapol_sm_eap_param_needed(void * ctx,enum wpa_ctrl_req_type field,const char * txt)19893ff40c12SJohn Marino static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
19906d49e1aeSJan Lentfer 				      const char *txt)
19916d49e1aeSJan Lentfer {
19926d49e1aeSJan Lentfer 	struct eapol_sm *sm = ctx;
19936d49e1aeSJan Lentfer 	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
19946d49e1aeSJan Lentfer 	if (sm->ctx->eap_param_needed)
19956d49e1aeSJan Lentfer 		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
19966d49e1aeSJan Lentfer }
19976d49e1aeSJan Lentfer #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
19986d49e1aeSJan Lentfer #define eapol_sm_eap_param_needed NULL
19996d49e1aeSJan Lentfer #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
20006d49e1aeSJan Lentfer 
eapol_sm_notify_cert(void * ctx,struct tls_cert_data * cert,const char * cert_hash)2001*a1157835SDaniel Fojt static void eapol_sm_notify_cert(void *ctx, struct tls_cert_data *cert,
2002*a1157835SDaniel Fojt 				 const char *cert_hash)
20033ff40c12SJohn Marino {
20043ff40c12SJohn Marino 	struct eapol_sm *sm = ctx;
20053ff40c12SJohn Marino 	if (sm->ctx->cert_cb)
2006*a1157835SDaniel Fojt 		sm->ctx->cert_cb(sm->ctx->ctx, cert, cert_hash);
20073ff40c12SJohn Marino }
20083ff40c12SJohn Marino 
20093ff40c12SJohn Marino 
eapol_sm_notify_status(void * ctx,const char * status,const char * parameter)20103ff40c12SJohn Marino static void eapol_sm_notify_status(void *ctx, const char *status,
20113ff40c12SJohn Marino 				   const char *parameter)
20123ff40c12SJohn Marino {
20133ff40c12SJohn Marino 	struct eapol_sm *sm = ctx;
20143ff40c12SJohn Marino 
20153ff40c12SJohn Marino 	if (sm->ctx->status_cb)
20163ff40c12SJohn Marino 		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
20173ff40c12SJohn Marino }
20183ff40c12SJohn Marino 
20193ff40c12SJohn Marino 
eapol_sm_notify_eap_error(void * ctx,int error_code)2020*a1157835SDaniel Fojt static void eapol_sm_notify_eap_error(void *ctx, int error_code)
2021*a1157835SDaniel Fojt {
2022*a1157835SDaniel Fojt 	struct eapol_sm *sm = ctx;
2023*a1157835SDaniel Fojt 
2024*a1157835SDaniel Fojt 	if (sm->ctx->eap_error_cb)
2025*a1157835SDaniel Fojt 		sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
2026*a1157835SDaniel Fojt }
2027*a1157835SDaniel Fojt 
2028*a1157835SDaniel Fojt 
2029*a1157835SDaniel Fojt #ifdef CONFIG_EAP_PROXY
2030*a1157835SDaniel Fojt 
eapol_sm_eap_proxy_cb(void * ctx)2031*a1157835SDaniel Fojt static void eapol_sm_eap_proxy_cb(void *ctx)
2032*a1157835SDaniel Fojt {
2033*a1157835SDaniel Fojt 	struct eapol_sm *sm = ctx;
2034*a1157835SDaniel Fojt 
2035*a1157835SDaniel Fojt 	if (sm->ctx->eap_proxy_cb)
2036*a1157835SDaniel Fojt 		sm->ctx->eap_proxy_cb(sm->ctx->ctx);
2037*a1157835SDaniel Fojt }
2038*a1157835SDaniel Fojt 
2039*a1157835SDaniel Fojt 
2040*a1157835SDaniel Fojt static void
eapol_sm_eap_proxy_notify_sim_status(void * ctx,enum eap_proxy_sim_state sim_state)2041*a1157835SDaniel Fojt eapol_sm_eap_proxy_notify_sim_status(void *ctx,
2042*a1157835SDaniel Fojt 				     enum eap_proxy_sim_state sim_state)
2043*a1157835SDaniel Fojt {
2044*a1157835SDaniel Fojt 	struct eapol_sm *sm = ctx;
2045*a1157835SDaniel Fojt 
2046*a1157835SDaniel Fojt 	if (sm->ctx->eap_proxy_notify_sim_status)
2047*a1157835SDaniel Fojt 		sm->ctx->eap_proxy_notify_sim_status(sm->ctx->ctx, sim_state);
2048*a1157835SDaniel Fojt }
2049*a1157835SDaniel Fojt 
2050*a1157835SDaniel Fojt #endif /* CONFIG_EAP_PROXY */
2051*a1157835SDaniel Fojt 
2052*a1157835SDaniel Fojt 
eapol_sm_set_anon_id(void * ctx,const u8 * id,size_t len)20533ff40c12SJohn Marino static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
20543ff40c12SJohn Marino {
20553ff40c12SJohn Marino 	struct eapol_sm *sm = ctx;
20563ff40c12SJohn Marino 
20573ff40c12SJohn Marino 	if (sm->ctx->set_anon_id)
20583ff40c12SJohn Marino 		sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
20593ff40c12SJohn Marino }
20603ff40c12SJohn Marino 
20616d49e1aeSJan Lentfer 
2062*a1157835SDaniel Fojt static const struct eapol_callbacks eapol_cb =
20636d49e1aeSJan Lentfer {
20646d49e1aeSJan Lentfer 	eapol_sm_get_config,
20656d49e1aeSJan Lentfer 	eapol_sm_get_bool,
20666d49e1aeSJan Lentfer 	eapol_sm_set_bool,
20676d49e1aeSJan Lentfer 	eapol_sm_get_int,
20686d49e1aeSJan Lentfer 	eapol_sm_set_int,
20696d49e1aeSJan Lentfer 	eapol_sm_get_eapReqData,
20706d49e1aeSJan Lentfer 	eapol_sm_set_config_blob,
20716d49e1aeSJan Lentfer 	eapol_sm_get_config_blob,
20726d49e1aeSJan Lentfer 	eapol_sm_notify_pending,
20733ff40c12SJohn Marino 	eapol_sm_eap_param_needed,
20743ff40c12SJohn Marino 	eapol_sm_notify_cert,
20753ff40c12SJohn Marino 	eapol_sm_notify_status,
2076*a1157835SDaniel Fojt 	eapol_sm_notify_eap_error,
2077*a1157835SDaniel Fojt #ifdef CONFIG_EAP_PROXY
2078*a1157835SDaniel Fojt 	eapol_sm_eap_proxy_cb,
2079*a1157835SDaniel Fojt 	eapol_sm_eap_proxy_notify_sim_status,
2080*a1157835SDaniel Fojt 	eapol_sm_get_eap_proxy_imsi,
2081*a1157835SDaniel Fojt #endif /* CONFIG_EAP_PROXY */
20823ff40c12SJohn Marino 	eapol_sm_set_anon_id
20836d49e1aeSJan Lentfer };
20846d49e1aeSJan Lentfer 
20856d49e1aeSJan Lentfer 
20866d49e1aeSJan Lentfer /**
20876d49e1aeSJan Lentfer  * eapol_sm_init - Initialize EAPOL state machine
20886d49e1aeSJan Lentfer  * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
20896d49e1aeSJan Lentfer  * and EAPOL state machine will free it in eapol_sm_deinit()
20906d49e1aeSJan Lentfer  * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
20916d49e1aeSJan Lentfer  *
20926d49e1aeSJan Lentfer  * Allocate and initialize an EAPOL state machine.
20936d49e1aeSJan Lentfer  */
eapol_sm_init(struct eapol_ctx * ctx)20946d49e1aeSJan Lentfer struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
20956d49e1aeSJan Lentfer {
20966d49e1aeSJan Lentfer 	struct eapol_sm *sm;
20976d49e1aeSJan Lentfer 	struct eap_config conf;
20986d49e1aeSJan Lentfer 	sm = os_zalloc(sizeof(*sm));
20996d49e1aeSJan Lentfer 	if (sm == NULL)
21006d49e1aeSJan Lentfer 		return NULL;
21016d49e1aeSJan Lentfer 	sm->ctx = ctx;
21026d49e1aeSJan Lentfer 
21036d49e1aeSJan Lentfer 	sm->portControl = Auto;
21046d49e1aeSJan Lentfer 
21056d49e1aeSJan Lentfer 	/* Supplicant PAE state machine */
21066d49e1aeSJan Lentfer 	sm->heldPeriod = 60;
21076d49e1aeSJan Lentfer 	sm->startPeriod = 30;
21086d49e1aeSJan Lentfer 	sm->maxStart = 3;
21096d49e1aeSJan Lentfer 
21106d49e1aeSJan Lentfer 	/* Supplicant Backend state machine */
21116d49e1aeSJan Lentfer 	sm->authPeriod = 30;
21126d49e1aeSJan Lentfer 
21136d49e1aeSJan Lentfer 	os_memset(&conf, 0, sizeof(conf));
21146d49e1aeSJan Lentfer 	conf.opensc_engine_path = ctx->opensc_engine_path;
21156d49e1aeSJan Lentfer 	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
21166d49e1aeSJan Lentfer 	conf.pkcs11_module_path = ctx->pkcs11_module_path;
2117*a1157835SDaniel Fojt 	conf.openssl_ciphers = ctx->openssl_ciphers;
21186d49e1aeSJan Lentfer 	conf.wps = ctx->wps;
21193ff40c12SJohn Marino 	conf.cert_in_cb = ctx->cert_in_cb;
21206d49e1aeSJan Lentfer 
21216d49e1aeSJan Lentfer 	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
21226d49e1aeSJan Lentfer 	if (sm->eap == NULL) {
21236d49e1aeSJan Lentfer 		os_free(sm);
21246d49e1aeSJan Lentfer 		return NULL;
21256d49e1aeSJan Lentfer 	}
21266d49e1aeSJan Lentfer 
21273ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
21283ff40c12SJohn Marino 	sm->use_eap_proxy = FALSE;
21293ff40c12SJohn Marino 	sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
21303ff40c12SJohn Marino 	if (sm->eap_proxy == NULL) {
21313ff40c12SJohn Marino 		wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
21323ff40c12SJohn Marino 	}
21333ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
21343ff40c12SJohn Marino 
21356d49e1aeSJan Lentfer 	/* Initialize EAPOL state machines */
21363ff40c12SJohn Marino 	sm->force_authorized_update = TRUE;
21376d49e1aeSJan Lentfer 	sm->initialize = TRUE;
21386d49e1aeSJan Lentfer 	eapol_sm_step(sm);
21396d49e1aeSJan Lentfer 	sm->initialize = FALSE;
21406d49e1aeSJan Lentfer 	eapol_sm_step(sm);
21416d49e1aeSJan Lentfer 
2142*a1157835SDaniel Fojt 	if (eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm) == 0)
21436d49e1aeSJan Lentfer 		sm->timer_tick_enabled = 1;
21446d49e1aeSJan Lentfer 
21456d49e1aeSJan Lentfer 	return sm;
21466d49e1aeSJan Lentfer }
21476d49e1aeSJan Lentfer 
21486d49e1aeSJan Lentfer 
21496d49e1aeSJan Lentfer /**
21506d49e1aeSJan Lentfer  * eapol_sm_deinit - Deinitialize EAPOL state machine
21516d49e1aeSJan Lentfer  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
21526d49e1aeSJan Lentfer  *
21536d49e1aeSJan Lentfer  * Deinitialize and free EAPOL state machine.
21546d49e1aeSJan Lentfer  */
eapol_sm_deinit(struct eapol_sm * sm)21556d49e1aeSJan Lentfer void eapol_sm_deinit(struct eapol_sm *sm)
21566d49e1aeSJan Lentfer {
21576d49e1aeSJan Lentfer 	if (sm == NULL)
21586d49e1aeSJan Lentfer 		return;
21596d49e1aeSJan Lentfer 	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
21606d49e1aeSJan Lentfer 	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
21616d49e1aeSJan Lentfer 	eap_peer_sm_deinit(sm->eap);
21623ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
21633ff40c12SJohn Marino 	eap_proxy_deinit(sm->eap_proxy);
21643ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
21656d49e1aeSJan Lentfer 	os_free(sm->last_rx_key);
21666d49e1aeSJan Lentfer 	wpabuf_free(sm->eapReqData);
21676d49e1aeSJan Lentfer 	os_free(sm->ctx);
21686d49e1aeSJan Lentfer 	os_free(sm);
21696d49e1aeSJan Lentfer }
21703ff40c12SJohn Marino 
21713ff40c12SJohn Marino 
eapol_sm_set_ext_pw_ctx(struct eapol_sm * sm,struct ext_password_data * ext)21723ff40c12SJohn Marino void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
21733ff40c12SJohn Marino 			     struct ext_password_data *ext)
21743ff40c12SJohn Marino {
21753ff40c12SJohn Marino 	if (sm && sm->eap)
21763ff40c12SJohn Marino 		eap_sm_set_ext_pw_ctx(sm->eap, ext);
21773ff40c12SJohn Marino }
21783ff40c12SJohn Marino 
21793ff40c12SJohn Marino 
eapol_sm_failed(struct eapol_sm * sm)21803ff40c12SJohn Marino int eapol_sm_failed(struct eapol_sm *sm)
21813ff40c12SJohn Marino {
21823ff40c12SJohn Marino 	if (sm == NULL)
21833ff40c12SJohn Marino 		return 0;
21843ff40c12SJohn Marino 	return !sm->eapSuccess && sm->eapFail;
21853ff40c12SJohn Marino }
21863ff40c12SJohn Marino 
21873ff40c12SJohn Marino 
21883ff40c12SJohn Marino #ifdef CONFIG_EAP_PROXY
eapol_sm_get_eap_proxy_imsi(void * ctx,int sim_num,char * imsi,size_t * len)2189*a1157835SDaniel Fojt int eapol_sm_get_eap_proxy_imsi(void *ctx, int sim_num, char *imsi, size_t *len)
2190*a1157835SDaniel Fojt {
2191*a1157835SDaniel Fojt 	struct eapol_sm *sm = ctx;
2192*a1157835SDaniel Fojt 
21933ff40c12SJohn Marino 	if (sm->eap_proxy == NULL)
21943ff40c12SJohn Marino 		return -1;
2195*a1157835SDaniel Fojt 	return eap_proxy_get_imsi(sm->eap_proxy, sim_num, imsi, len);
2196*a1157835SDaniel Fojt }
21973ff40c12SJohn Marino #endif /* CONFIG_EAP_PROXY */
2198*a1157835SDaniel Fojt 
2199*a1157835SDaniel Fojt 
eapol_sm_erp_flush(struct eapol_sm * sm)2200*a1157835SDaniel Fojt void eapol_sm_erp_flush(struct eapol_sm *sm)
2201*a1157835SDaniel Fojt {
2202*a1157835SDaniel Fojt 	if (sm)
2203*a1157835SDaniel Fojt 		eap_peer_erp_free_keys(sm->eap);
2204*a1157835SDaniel Fojt }
2205*a1157835SDaniel Fojt 
2206*a1157835SDaniel Fojt 
eapol_sm_build_erp_reauth_start(struct eapol_sm * sm)2207*a1157835SDaniel Fojt struct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
2208*a1157835SDaniel Fojt {
2209*a1157835SDaniel Fojt #ifdef CONFIG_ERP
2210*a1157835SDaniel Fojt 	if (!sm)
2211*a1157835SDaniel Fojt 		return NULL;
2212*a1157835SDaniel Fojt 	return eap_peer_build_erp_reauth_start(sm->eap, 0);
2213*a1157835SDaniel Fojt #else /* CONFIG_ERP */
2214*a1157835SDaniel Fojt 	return NULL;
2215*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
2216*a1157835SDaniel Fojt }
2217*a1157835SDaniel Fojt 
2218*a1157835SDaniel Fojt 
eapol_sm_process_erp_finish(struct eapol_sm * sm,const u8 * buf,size_t len)2219*a1157835SDaniel Fojt void eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
2220*a1157835SDaniel Fojt 				 size_t len)
2221*a1157835SDaniel Fojt {
2222*a1157835SDaniel Fojt #ifdef CONFIG_ERP
2223*a1157835SDaniel Fojt 	if (!sm)
2224*a1157835SDaniel Fojt 		return;
2225*a1157835SDaniel Fojt 	eap_peer_finish(sm->eap, (const struct eap_hdr *) buf, len);
2226*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
2227*a1157835SDaniel Fojt }
2228*a1157835SDaniel Fojt 
2229*a1157835SDaniel Fojt 
eapol_sm_update_erp_next_seq_num(struct eapol_sm * sm,u16 next_seq_num)2230*a1157835SDaniel Fojt int eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm, u16 next_seq_num)
2231*a1157835SDaniel Fojt {
2232*a1157835SDaniel Fojt #ifdef CONFIG_ERP
2233*a1157835SDaniel Fojt 	if (!sm)
2234*a1157835SDaniel Fojt 		return -1;
2235*a1157835SDaniel Fojt 	return eap_peer_update_erp_next_seq_num(sm->eap, next_seq_num);
2236*a1157835SDaniel Fojt #else /* CONFIG_ERP */
2237*a1157835SDaniel Fojt 	return -1;
2238*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
2239*a1157835SDaniel Fojt }
2240*a1157835SDaniel Fojt 
2241*a1157835SDaniel Fojt 
eapol_sm_get_erp_info(struct eapol_sm * sm,struct eap_peer_config * config,const u8 ** username,size_t * username_len,const u8 ** realm,size_t * realm_len,u16 * erp_next_seq_num,const u8 ** rrk,size_t * rrk_len)2242*a1157835SDaniel Fojt int eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config,
2243*a1157835SDaniel Fojt 			  const u8 **username, size_t *username_len,
2244*a1157835SDaniel Fojt 			  const u8 **realm, size_t *realm_len,
2245*a1157835SDaniel Fojt 			  u16 *erp_next_seq_num, const u8 **rrk,
2246*a1157835SDaniel Fojt 			  size_t *rrk_len)
2247*a1157835SDaniel Fojt {
2248*a1157835SDaniel Fojt #ifdef CONFIG_ERP
2249*a1157835SDaniel Fojt 	if (!sm)
2250*a1157835SDaniel Fojt 		return -1;
2251*a1157835SDaniel Fojt 	return eap_peer_get_erp_info(sm->eap, config, username, username_len,
2252*a1157835SDaniel Fojt 				     realm, realm_len, erp_next_seq_num, rrk,
2253*a1157835SDaniel Fojt 				     rrk_len);
2254*a1157835SDaniel Fojt #else /* CONFIG_ERP */
2255*a1157835SDaniel Fojt 	return -1;
2256*a1157835SDaniel Fojt #endif /* CONFIG_ERP */
22573ff40c12SJohn Marino }
2258