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