18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * EAPOL supplicant state machines
361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
5c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * This software may be distributed under the terms of the BSD license.
6c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt * See README for more details.
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "includes.h"
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common.h"
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "state_machine.h"
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "wpabuf.h"
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eloop.h"
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/crypto.h"
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "crypto/md5.h"
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "common/eapol_common.h"
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eap_peer/eap.h"
19d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#include "eap_peer/eap_config.h"
20f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#include "eap_peer/eap_proxy.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "eapol_supp_sm.h"
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define STATE_MACHINE_DATA struct eapol_sm
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * struct eapol_sm - Internal data for EAPOL state machines
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eapol_sm {
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Timers */
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int authWhile;
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int heldWhile;
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int startWhen;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int idleWhile; /* for EAP state machine */
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int timer_tick_enabled;
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Global variables */
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapFail;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapolEap;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapSuccess;
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean initialize;
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean keyDone;
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean keyRun;
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	PortControl portControl;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean portEnabled;
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean portValid;
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean suppAbort;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean suppFail;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean suppStart;
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean suppSuccess;
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean suppTimeout;
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Supplicant PAE state machine */
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum {
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_UNKNOWN = 0,
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_DISCONNECTED = 1,
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_LOGOFF = 2,
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_CONNECTING = 3,
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_AUTHENTICATING = 4,
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_AUTHENTICATED = 5,
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* unused(6) */
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_HELD = 7,
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_RESTART = 8,
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_S_FORCE_AUTH = 9,
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_PAE_S_FORCE_UNAUTH = 10
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} SUPP_PAE_state; /* dot1xSuppPaeState */
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variables */
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean userLogoff;
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean logoffSent;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int startCount;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapRestart;
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	PortControl sPortMode;
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Constants */
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int startPeriod; /* dot1xSuppStartPeriod */
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int maxStart; /* dot1xSuppMaxStart */
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Key Receive state machine */
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum {
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		KEY_RX_UNKNOWN = 0,
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} KEY_RX_state;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variables */
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean rxKey;
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Supplicant Backend state machine */
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum {
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_UNKNOWN = 0,
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_INITIALIZE = 1,
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_IDLE = 2,
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_REQUEST = 3,
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_RECEIVE = 4,
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_RESPONSE = 5,
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_FAIL = 6,
99293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt		SUPP_BE_TIMEOUT = 7,
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SUPP_BE_SUCCESS = 8
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Variables */
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapNoResp;
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapReq;
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean eapResp;
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Constants */
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Statistics */
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolFramesRx;
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolFramesTx;
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolStartFramesTx;
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolLogoffFramesTx;
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolRespFramesTx;
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolReqIdFramesRx;
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapolReqFramesRx;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppInvalidEapolFramesRx;
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppEapLengthErrorFramesRx;
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned int dot1xSuppLastEapolFrameVersion;
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	unsigned char dot1xSuppLastEapolFrameSource[6];
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean changed;
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_sm *eap;
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_peer_config *config;
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean initial_req;
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *last_rx_key;
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t last_rx_key_len;
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *eapReqData; /* for EAP */
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean altAccept; /* for EAP */
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean altReject; /* for EAP */
1326c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	Boolean eapTriggerStart;
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean replay_counter_valid;
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 last_replay_counter[16];
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_config conf;
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_ctx *ctx;
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cb_status;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean cached_pmk;
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	Boolean unicast_key_received, broadcast_key_received;
142fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
143fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	Boolean force_authorized_update;
144fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
145f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
146f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	Boolean use_eap_proxy;
147f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	struct eap_proxy_sm *eap_proxy;
148f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_txLogoff(struct eapol_sm *sm);
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_txStart(struct eapol_sm *sm);
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_processKey(struct eapol_sm *sm);
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_getSuppRsp(struct eapol_sm *sm);
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_txSuppRsp(struct eapol_sm *sm);
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_abortSupp(struct eapol_sm *sm);
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_abort_cached(struct eapol_sm *sm);
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_port_authorized(struct eapol_sm *sm);
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/* Port Timers state machine - implemented as a function that will be called
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * once a second as a registered event loop timeout */
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = timeout_ctx;
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->authWhile > 0) {
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->authWhile--;
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->authWhile == 0)
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->heldWhile > 0) {
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->heldWhile--;
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->heldWhile == 0)
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->startWhen > 0) {
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->startWhen--;
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->startWhen == 0)
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->idleWhile > 0) {
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->idleWhile--;
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->idleWhile == 0)
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       sm);
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->timer_tick_enabled = 0;
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_enable_timer_tick(struct eapol_sm *sm)
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->timer_tick_enabled)
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->timer_tick_enabled = 1;
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, LOGOFF)
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, LOGOFF);
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_txLogoff(sm);
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->logoffSent = TRUE;
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_unauthorized(sm);
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, DISCONNECTED)
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, DISCONNECTED);
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->sPortMode = Auto;
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->startCount = 0;
2276c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sm->eapTriggerStart = FALSE;
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->logoffSent = FALSE;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_unauthorized(sm);
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppAbort = TRUE;
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->unicast_key_received = FALSE;
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->broadcast_key_received = FALSE;
234c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
235c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
236c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
237c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * allows the timer tick to be stopped more quickly when the port is
238c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * not enabled. Since this variable is used only within HELD state,
239c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * clearing it on initialization does not change actual state machine
240c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * behavior.
241c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
242c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	sm->heldWhile = 0;
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, CONNECTING)
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
248d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING ||
249d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		sm->SUPP_PAE_state == SUPP_PAE_HELD;
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, CONNECTING);
2516c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2526c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sm->eapTriggerStart)
2536c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		send_start = 1;
254ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt	if (sm->ctx->preauth)
255ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt		send_start = 1;
2566c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	sm->eapTriggerStart = FALSE;
2576c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_start) {
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->startWhen = sm->startPeriod;
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->startCount++;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Do not send EAPOL-Start immediately since in most cases,
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Authenticator is going to start authentication immediately
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * after association and an extra EAPOL-Start is just going to
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * delay authentication. Use a short timeout to send the first
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * EAPOL-Start if Authenticator does not start authentication.
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
2696c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
270661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			/* Reduce latency on starting WPS negotiation. */
271661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			wpa_printf(MSG_DEBUG,
272661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt				   "EAPOL: Using shorter startWhen for WPS");
273661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			sm->startWhen = 1;
274661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		} else {
275661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt			sm->startWhen = 2;
276661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt		}
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_enable_timer_tick(sm);
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapolEap = FALSE;
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (send_start)
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol_sm_txStart(sm);
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, AUTHENTICATING)
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->startCount = 0;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppSuccess = FALSE;
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppFail = FALSE;
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppTimeout = FALSE;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->keyRun = FALSE;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->keyDone = FALSE;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppStart = TRUE;
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, HELD)
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, HELD);
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->heldWhile = sm->heldPeriod;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_enable_timer_tick(sm);
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_unauthorized(sm);
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->cb_status = EAPOL_CB_FAILURE;
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, AUTHENTICATED)
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_authorized(sm);
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->cb_status = EAPOL_CB_SUCCESS;
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, RESTART)
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, RESTART);
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapRestart = TRUE;
320d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	if (sm->altAccept) {
321d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		/*
322d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * Prevent EAP peer state machine from failing due to prior
323d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * external EAP success notification (altSuccess=TRUE in the
324d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 * IDLE state could result in a transition to the FAILURE state.
325d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		 */
326d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Clearing prior altAccept TRUE");
327d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		sm->eapSuccess = FALSE;
328d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt		sm->altAccept = FALSE;
329d7ff03d48f825360eec2a371e3361306f2fd721bDmitry Shmidt	}
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, S_FORCE_AUTH)
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_authorized(sm);
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->sPortMode = ForceAuthorized;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_unauthorized(sm);
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->sPortMode = ForceUnauthorized;
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_txLogoff(sm);
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STEP(SUPP_PAE)
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if ((sm->userLogoff && !sm->logoffSent) &&
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !(sm->initialize || !sm->portEnabled))
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if (((sm->portControl == Auto) &&
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  (sm->sPortMode != sm->portControl)) ||
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 sm->initialize || !sm->portEnabled)
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if ((sm->portControl == ForceAuthorized) &&
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 (sm->sPortMode != sm->portControl) &&
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 !(sm->initialize || !sm->portEnabled))
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else if ((sm->portControl == ForceUnauthorized) &&
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 (sm->sPortMode != sm->portControl) &&
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 !(sm->initialize || !sm->portEnabled))
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else switch (sm->SUPP_PAE_state) {
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_UNKNOWN:
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_LOGOFF:
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!sm->userLogoff)
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, DISCONNECTED);
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_DISCONNECTED:
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER(SUPP_PAE, CONNECTING);
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_CONNECTING:
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, CONNECTING);
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->startWhen == 0 &&
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 sm->startCount >= sm->maxStart &&
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 sm->portValid)
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, AUTHENTICATED);
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapSuccess || sm->eapFail)
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, AUTHENTICATING);
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapolEap)
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, RESTART);
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->startWhen == 0 &&
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 sm->startCount >= sm->maxStart &&
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 !sm->portValid)
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, HELD);
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_AUTHENTICATING:
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapSuccess && !sm->portValid &&
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    sm->conf.accept_802_1x_keys &&
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    sm->conf.required_keys == 0) {
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "plaintext connection; no EAPOL-Key frames "
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "required");
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->portValid = TRUE;
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (sm->ctx->eapol_done_cb)
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				sm->ctx->eapol_done_cb(sm->ctx->ctx);
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapSuccess && sm->portValid)
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, AUTHENTICATED);
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, HELD);
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->suppTimeout)
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, CONNECTING);
4106c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		else if (sm->eapTriggerStart)
4116c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt			SM_ENTER(SUPP_PAE, CONNECTING);
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_HELD:
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->heldWhile == 0)
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, CONNECTING);
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapolEap)
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, RESTART);
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_AUTHENTICATED:
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapolEap && sm->portValid)
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, RESTART);
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (!sm->portValid)
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, DISCONNECTED);
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_RESTART:
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!sm->eapRestart)
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_PAE, AUTHENTICATING);
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_S_FORCE_AUTH:
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_S_FORCE_UNAUTH:
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(KEY_RX, NO_KEY_RECEIVE)
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(KEY_RX, KEY_RECEIVE)
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(KEY_RX, KEY_RECEIVE);
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_processKey(sm);
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->rxKey = FALSE;
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STEP(KEY_RX)
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->initialize || !sm->portEnabled)
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (sm->KEY_RX_state) {
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case KEY_RX_UNKNOWN:
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case KEY_RX_NO_KEY_RECEIVE:
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->rxKey)
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(KEY_RX, KEY_RECEIVE);
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case KEY_RX_KEY_RECEIVE:
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->rxKey)
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(KEY_RX, KEY_RECEIVE);
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, REQUEST)
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, REQUEST);
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->authWhile = 0;
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapReq = TRUE;
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_getSuppRsp(sm);
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, RESPONSE)
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, RESPONSE);
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_txSuppRsp(sm);
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapResp = FALSE;
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, SUCCESS)
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, SUCCESS);
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->keyRun = TRUE;
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppSuccess = TRUE;
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
493f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
494f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (sm->use_eap_proxy) {
495f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (eap_proxy_key_available(sm->eap_proxy)) {
496d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			u8 *session_id, *emsk;
497d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			size_t session_id_len, emsk_len;
498d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
499f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			/* New key received - clear IEEE 802.1X EAPOL-Key replay
500f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			 * counter */
501f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			sm->replay_counter_valid = FALSE;
502d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
503d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			session_id = eap_proxy_get_eap_session_id(
504d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				sm->eap_proxy, &session_id_len);
505d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			emsk = eap_proxy_get_emsk(sm->eap_proxy, &emsk_len);
506d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			if (sm->config->erp && session_id && emsk)
507d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				eap_peer_erp_init(sm->eap, session_id,
508d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt						  session_id_len, emsk,
509d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt						  emsk_len);
510f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		}
511f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return;
512f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
513f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
514f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_key_available(sm->eap)) {
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* New key received - clear IEEE 802.1X EAPOL-Key replay
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * counter */
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->replay_counter_valid = FALSE;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, FAIL)
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, FAIL);
5268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppFail = TRUE;
5278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5308d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, TIMEOUT)
5318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, TIMEOUT);
5338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppTimeout = TRUE;
5348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5378d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, IDLE)
5388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, IDLE);
5408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppStart = FALSE;
5418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->initial_req = TRUE;
5428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5458d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, INITIALIZE)
5468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, INITIALIZE);
5488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_abortSupp(sm);
5498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->suppAbort = FALSE;
550c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt
551c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	/*
552c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
553c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * allows the timer tick to be stopped more quickly when the port is
554c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * not enabled. Since this variable is used only within RECEIVE state,
555c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * clearing it on initialization does not change actual state machine
556c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 * behavior.
557c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	 */
558c5ec7f57ead87efa365800228aa0b09a12d9e6c4Dmitry Shmidt	sm->authWhile = 0;
5598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5628d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STATE(SUPP_BE, RECEIVE)
5638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	SM_ENTRY(SUPP_BE, RECEIVE);
5658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->authWhile = sm->authPeriod;
5668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_enable_timer_tick(sm);
5678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapolEap = FALSE;
5688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapNoResp = FALSE;
5698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->initial_req = FALSE;
5708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5738d520ff1dc2da35cdca849e982051b86468016d8Dmitry ShmidtSM_STEP(SUPP_BE)
5748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->initialize || sm->suppAbort)
5768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
5778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else switch (sm->SUPP_BE_state) {
5788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_UNKNOWN:
5798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
5808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_REQUEST:
5818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
5828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
5838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * and SUCCESS based on eapFail and eapSuccess, respectively.
5848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * However, IEEE Std 802.1X-2004 is also specifying that
5851f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt		 * eapNoResp should be set in conjunction with eapSuccess and
5868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * eapFail which would mean that more than one of the
5878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * transitions here would be activated at the same time.
5888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Skipping RESPONSE and/or RECEIVE states in these cases can
5898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * cause problems and the direct transitions to do not seem
5908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * correct. Because of this, the conditions for these
5918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * transitions are verified only after eapNoResp. They are
5928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * unlikely to be used since eapNoResp should always be set if
5938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * either of eapSuccess or eapFail is set.
5948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
5958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapResp && sm->eapNoResp) {
5968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
5978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "eapResp and eapNoResp set?!");
5988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
5998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapResp)
6008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, RESPONSE);
6018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapNoResp)
6028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, RECEIVE);
6038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapFail)
6048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, FAIL);
6058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapSuccess)
6068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, SUCCESS);
6078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_RESPONSE:
6098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER(SUPP_BE, RECEIVE);
6108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_SUCCESS:
6128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER(SUPP_BE, IDLE);
6138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_FAIL:
6158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER(SUPP_BE, IDLE);
6168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_TIMEOUT:
6188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER(SUPP_BE, IDLE);
6198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_IDLE:
6218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapFail && sm->suppStart)
6228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, FAIL);
6238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapolEap && sm->suppStart)
6248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, REQUEST);
6258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapSuccess && sm->suppStart)
6268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, SUCCESS);
6278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_INITIALIZE:
6298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_ENTER(SUPP_BE, IDLE);
6308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_RECEIVE:
6328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapolEap)
6338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, REQUEST);
6348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapFail)
6358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, FAIL);
6368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->authWhile == 0)
6378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, TIMEOUT);
6388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else if (sm->eapSuccess)
6398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			SM_ENTER(SUPP_BE, SUCCESS);
6408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
6418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_txLogoff(struct eapol_sm *sm)
6468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
6488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
6498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
6508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolLogoffFramesTx++;
6518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolFramesTx++;
6528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_txStart(struct eapol_sm *sm)
6568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
6578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
6588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
6598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
6608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolStartFramesTx++;
6618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolFramesTx++;
6628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
6638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IEEE8021X_ENCR_KEY_LEN 32
6668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define IEEE8021X_SIGN_KEY_LEN 32
6678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eap_key_data {
6698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
6708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
6718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
6728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_processKey(struct eapol_sm *sm)
6758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
67661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#ifndef CONFIG_FIPS
6778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee802_1x_hdr *hdr;
6788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct ieee802_1x_eapol_key *key;
6798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_key_data keydata;
6808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
681d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifndef CONFIG_NO_RC4
6828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
683d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_RC4 */
6848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int key_len, res, sign_key_len, encr_key_len;
6858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u16 rx_key_length;
68661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	size_t plen;
6878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
6898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->last_rx_key == NULL)
6908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
6928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!sm->conf.accept_802_1x_keys) {
6938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
6948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " even though this was not accepted - "
6958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "ignoring this packet");
6968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
6978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
6988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
69961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
70061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return;
7018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
7028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
70361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	plen = be_to_host16(hdr->length);
70461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
7058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
7068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	rx_key_length = WPA_GET_BE16(key->key_length);
7098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
7108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
7118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   hdr->version, hdr->type, be_to_host16(hdr->length),
7128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   key->type, rx_key_length, key->key_index);
7138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_notify_lower_layer_success(sm, 1);
7158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
7168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
7178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
7188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res < 0) {
7198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
7208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "decrypting EAPOL-Key keys");
7218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (res == 16) {
7248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* LEAP derives only 16 bytes of keying material. */
7258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
7268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res) {
7278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
7288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "master key for decrypting EAPOL-Key keys");
7298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return;
7308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
7318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sign_key_len = 16;
7328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		encr_key_len = 16;
7338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
7348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (res) {
7358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
7368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "data for decrypting EAPOL-Key keys (res=%d)", res);
7378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* The key replay_counter must increase when same master key */
7418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->replay_counter_valid &&
7428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    os_memcmp(sm->last_replay_counter, key->replay_counter,
7438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
7448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
7458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "not increase - ignoring key");
7468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
7478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    sm->last_replay_counter,
7488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    IEEE8021X_REPLAY_COUNTER_LEN);
7498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
7508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
7518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
7548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Verify key signature (HMAC-MD5) */
7558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
7568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
7578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hmac_md5(keydata.sign_key, sign_key_len,
7588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
7598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 key->key_signature);
760c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt	if (os_memcmp_const(orig_key_sign, key->key_signature,
761c28170251eb54dbf64a9074a07fee377587425b2Dmitry Shmidt			    IEEE8021X_KEY_SIGN_LEN) != 0) {
7628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
7638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "EAPOL-Key packet");
7648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(key->key_signature, orig_key_sign,
7658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  IEEE8021X_KEY_SIGN_LEN);
7668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
7698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
77061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	key_len = plen - sizeof(*key);
7718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key_len > 32 || rx_key_length > 32) {
7728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
7738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   key_len ? key_len : rx_key_length);
7748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
7758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
7768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (key_len == rx_key_length) {
777d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#ifdef CONFIG_NO_RC4
778d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		if (encr_key_len) {
779d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt			/* otherwise unused */
780d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		}
781d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		wpa_printf(MSG_ERROR, "EAPOL: RC4 not supported in the build");
782d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt		return;
783d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#else /* CONFIG_NO_RC4 */
7848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
7858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
7868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  encr_key_len);
7878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(datakey, key + 1, key_len);
7888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
7898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 datakey, key_len);
7908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
7918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				datakey, key_len);
792d80a401aed31d06f261efd19223cf55d1a2a8228Dmitry Shmidt#endif /* CONFIG_NO_RC4 */
7938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else if (key_len == 0) {
7948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/*
7958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * IEEE 802.1X-2004 specifies that least significant Key Length
7968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * octets from MS-MPPE-Send-Key are used as the key if the key
7978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * data is not present. This seems to be meaning the beginning
7988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
7998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
8008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * Anyway, taking the beginning of the keying material from EAP
8018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * seems to interoperate with Authenticators.
8028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 */
8038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		key_len = rx_key_length;
8048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(datakey, keydata.encr_key, key_len);
8058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
8068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				"material data encryption key",
8078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				datakey, key_len);
8088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
8098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
8108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "(key_length=%d)", key_len, rx_key_length);
8118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->replay_counter_valid = TRUE;
8158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(sm->last_replay_counter, key->replay_counter,
8168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		  IEEE8021X_REPLAY_COUNTER_LEN);
8178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
8198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "len %d",
8208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
8218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "unicast" : "broadcast",
8228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
8238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->ctx->set_wep_key &&
8258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    sm->ctx->set_wep_key(sm->ctx->ctx,
8268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
8278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
8288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 datakey, key_len) < 0) {
8298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
8308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   " driver.");
8318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else {
8328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
8338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->unicast_key_received = TRUE;
8348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
8358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->broadcast_key_received = TRUE;
8368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if ((sm->unicast_key_received ||
8388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
8398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    (sm->broadcast_key_received ||
8408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
8418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		{
8428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
8438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "frames received");
8448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->portValid = TRUE;
8458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (sm->ctx->eapol_done_cb)
8468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				sm->ctx->eapol_done_cb(sm->ctx->ctx);
8478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
8488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
84961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt#endif /* CONFIG_FIPS */
8508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_getSuppRsp(struct eapol_sm *sm)
8548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
8568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* EAP layer processing; no special code is needed, since Supplicant
8578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * Backend state machine is waiting for eapNoResp or eapResp to be set
8588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * and these are only set in the EAP state machine when the processing
8598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * has finished. */
8608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
8618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_txSuppRsp(struct eapol_sm *sm)
8648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
8658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct wpabuf *resp;
8668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
868f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
869f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
870f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (sm->use_eap_proxy) {
871f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		/* Get EAP Response from EAP Proxy */
872f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		resp = eap_proxy_get_eapRespData(sm->eap_proxy);
873f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (resp == NULL) {
874f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
875f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				   "response data not available");
876f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return;
877f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		}
878f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	} else
879f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
880f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
8818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	resp = eap_get_eapRespData(sm->eap);
8828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (resp == NULL) {
8838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
8848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "not available");
8858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
8868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
8878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Send EAP-Packet from the EAP layer to the Authenticator */
8898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
8908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
8918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    wpabuf_len(resp));
8928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* eapRespData is not used anymore, so free it here */
8948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(resp);
8958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
8968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->initial_req)
8978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->dot1xSuppEapolReqIdFramesRx++;
8988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
8998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->dot1xSuppEapolReqFramesRx++;
9008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolRespFramesTx++;
9018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolFramesTx++;
9028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_abortSupp(struct eapol_sm *sm)
9068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* release system resources that may have been allocated for the
9088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * authentication session */
9098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sm->last_rx_key);
9108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->last_rx_key = NULL;
9118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(sm->eapReqData);
9128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapReqData = NULL;
9138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sm_abort(sm->eap);
914d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
915d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	eap_proxy_sm_abort(sm->eap_proxy);
916d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
9178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
9218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(timeout_ctx);
9238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_port_authorized(struct eapol_sm *sm)
9278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
928fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	int cb;
929fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
930fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
931fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	sm->force_authorized_update = FALSE;
932fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	sm->suppPortStatus = Authorized;
933fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cb && sm->ctx->port_cb)
9348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->ctx->port_cb(sm->ctx->ctx, 1);
9358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
9398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
940fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	int cb;
941fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt
942fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
943fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	sm->force_authorized_update = FALSE;
944fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	sm->suppPortStatus = Unauthorized;
945fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (cb && sm->ctx->port_cb)
9468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->ctx->port_cb(sm->ctx->ctx, 0);
9478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
9488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
9518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_step - EAPOL state machine step function
9528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
9538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
9548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called to notify the state machine about changed external
9558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * variables. It will step through the EAPOL state machines in loop to process
9568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * all triggered state changes.
9578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
9588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_step(struct eapol_sm *sm)
9598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
9608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int i;
9618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* In theory, it should be ok to run this in loop until !changed.
9638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * However, it is better to use a limit on number of iterations to
9648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
9658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * state machine were to generate a busy loop. */
9668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	for (i = 0; i < 100; i++) {
9678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->changed = FALSE;
9688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_STEP_RUN(SUPP_PAE);
9698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_STEP_RUN(KEY_RX);
9708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		SM_STEP_RUN(SUPP_BE);
971f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
972f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (sm->use_eap_proxy) {
973f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			/* Drive the EAP proxy state machine */
974f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
975f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				sm->changed = TRUE;
976f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		} else
977f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
9788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (eap_peer_sm_step(sm->eap))
9798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->changed = TRUE;
9808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!sm->changed)
9818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
9828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->changed) {
9858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* restart EAPOL state machine step from timeout call in order
9868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * to allow other events to be processed. */
9878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
9888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
9898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
9908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
9918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
992344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		enum eapol_supp_result result;
993344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		if (sm->cb_status == EAPOL_CB_SUCCESS)
994344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt			result = EAPOL_SUPP_RESULT_SUCCESS;
995344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		else if (eap_peer_was_failure_expected(sm->eap))
996344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt			result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
997344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		else
998344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt			result = EAPOL_SUPP_RESULT_FAILURE;
9998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->cb_status = EAPOL_CB_IN_PROGRESS;
1000344abd362cfe2d03ed956666527352826b67bde5Dmitry Shmidt		sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
10018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE
10068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *eapol_supp_pae_state(int state)
10078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (state) {
10098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_LOGOFF:
10108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "LOGOFF";
10118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_DISCONNECTED:
10128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "DISCONNECTED";
10138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_CONNECTING:
10148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "CONNECTING";
10158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_AUTHENTICATING:
10168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "AUTHENTICATING";
10178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_HELD:
10188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "HELD";
10198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_AUTHENTICATED:
10208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "AUTHENTICATED";
10218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_PAE_RESTART:
10228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "RESTART";
10238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
10248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "UNKNOWN";
10258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char *eapol_supp_be_state(int state)
10308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (state) {
10328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_REQUEST:
10338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "REQUEST";
10348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_RESPONSE:
10358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "RESPONSE";
10368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_SUCCESS:
10378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "SUCCESS";
10388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_FAIL:
10398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "FAIL";
10408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_TIMEOUT:
10418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "TIMEOUT";
10428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_IDLE:
10438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "IDLE";
10448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_INITIALIZE:
10458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "INITIALIZE";
10468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case SUPP_BE_RECEIVE:
10478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "RECEIVE";
10488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
10498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "UNKNOWN";
10508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eapol_port_status(PortStatus status)
10558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (status == Authorized)
10578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "Authorized";
10588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
10598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "Unauthorized";
10608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE */
10628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
10658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const char * eapol_port_control(PortControl ctrl)
10668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (ctrl) {
10688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case Auto:
10698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "Auto";
10708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ForceUnauthorized:
10718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "ForceUnauthorized";
10728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case ForceAuthorized:
10738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "ForceAuthorized";
10748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
10758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return "Unknown";
10768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
10778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
10788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
10798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
10818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
10828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_configure - Set EAPOL variables
10838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
10848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @heldPeriod: dot1xSuppHeldPeriod
10858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @authPeriod: dot1xSuppAuthPeriod
10868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @startPeriod: dot1xSuppStartPeriod
10878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @maxStart: dot1xSuppMaxStart
10888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
10898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Set configurable EAPOL state machine variables. Each variable can be set to
10908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the given value or ignored if set to -1 (to set only some of the variables).
10918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
10928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
10938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int startPeriod, int maxStart)
10948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
10958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
10968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
10978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (heldPeriod >= 0)
10988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->heldPeriod = heldPeriod;
10998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (authPeriod >= 0)
11008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->authPeriod = authPeriod;
11018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (startPeriod >= 0)
11028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->startPeriod = startPeriod;
11038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (maxStart >= 0)
11048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->maxStart = maxStart;
11058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
11098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_get_method_name - Get EAPOL method name
11108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
11118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Static string containing name of current eap method or NULL
11128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
11138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtconst char * eapol_sm_get_method_name(struct eapol_sm *sm)
11148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
11168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    sm->suppPortStatus != Authorized)
11178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
11188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return eap_sm_get_method_name(sm->eap);
11208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_CTRL_IFACE
11248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
11258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_get_status - Get EAPOL state machine status
11268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
11278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Buffer for status information
11288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buflen: Maximum buffer length
11298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @verbose: Whether to include verbose status information
11308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Number of bytes written to buf.
11318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
11328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Query EAPOL state machine for status information. This function fills in a
11338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * text area with current status information from the EAPOL state machine. If
11348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the buffer (buf) is not large enough, status information will be truncated
11358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to fit the buffer.
11368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
11378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
11388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			int verbose)
11398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int len, ret;
11418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
11428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
11438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = os_snprintf(buf, buflen,
11458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "Supplicant PAE state=%s\n"
11468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "suppPortStatus=%s\n",
11478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  eapol_supp_pae_state(sm->SUPP_PAE_state),
11488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  eapol_port_status(sm->suppPortStatus));
11496c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(buflen, len))
11508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
11518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (verbose) {
11538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		ret = os_snprintf(buf + len, buflen - len,
11548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "heldPeriod=%u\n"
11558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "authPeriod=%u\n"
11568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "startPeriod=%u\n"
11578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "maxStart=%u\n"
11588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "portControl=%s\n"
11598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  "Supplicant Backend state=%s\n",
11608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  sm->heldPeriod,
11618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  sm->authPeriod,
11628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  sm->startPeriod,
11638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  sm->maxStart,
11648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  eapol_port_control(sm->portControl),
11658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  eapol_supp_be_state(sm->SUPP_BE_state));
11666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		if (os_snprintf_error(buflen - len, ret))
11678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return len;
11688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		len += ret;
11698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
11708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1171f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
1172f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (sm->use_eap_proxy)
1173f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		len += eap_proxy_sm_get_status(sm->eap_proxy,
1174f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					       buf + len, buflen - len,
1175f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					       verbose);
1176f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	else
1177f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
11788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
11798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
11818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
11828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
11848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
11858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_get_mib - Get EAPOL state machine MIBs
11868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
11878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Buffer for MIB information
11888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buflen: Maximum buffer length
11898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Number of bytes written to buf.
11908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
11918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Query EAPOL state machine for MIB information. This function fills in a
11928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * text area with current MIB information from the EAPOL state machine. If
11938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the buffer (buf) is not large enough, MIB information will be truncated to
11948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * fit the buffer.
11958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
11968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
11978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
11988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t len;
11998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int ret;
12008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
12028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
12038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf, buflen,
12048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppPaeState=%d\n"
12058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppHeldPeriod=%u\n"
12068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppAuthPeriod=%u\n"
12078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppStartPeriod=%u\n"
12088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppMaxStart=%u\n"
12098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppSuppControlledPortStatus=%s\n"
12108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppBackendPaeState=%d\n",
12118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->SUPP_PAE_state,
12128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->heldPeriod,
12138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->authPeriod,
12148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->startPeriod,
12158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->maxStart,
12168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->suppPortStatus == Authorized ?
12178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "Authorized" : "Unauthorized",
12188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->SUPP_BE_state);
12198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12206c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(buflen, ret))
12218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
12228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len = ret;
12238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ret = os_snprintf(buf + len, buflen - len,
12258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolFramesRx=%u\n"
12268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolFramesTx=%u\n"
12278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolStartFramesTx=%u\n"
12288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolLogoffFramesTx=%u\n"
12298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolRespFramesTx=%u\n"
12308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolReqIdFramesRx=%u\n"
12318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapolReqFramesRx=%u\n"
12328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppInvalidEapolFramesRx=%u\n"
12338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
12348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppLastEapolFrameVersion=%u\n"
12358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
12368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolFramesRx,
12378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolFramesTx,
12388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolStartFramesTx,
12398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolLogoffFramesTx,
12408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolRespFramesTx,
12418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolReqIdFramesRx,
12428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapolReqFramesRx,
12438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppInvalidEapolFramesRx,
12448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppEapLengthErrorFramesRx,
12458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  sm->dot1xSuppLastEapolFrameVersion,
12468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
12478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12486c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (os_snprintf_error(buflen - len, ret))
12498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return len;
12508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	len += ret;
12518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return len;
12538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
12548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE */
12558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
12588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_rx_eapol - Process received EAPOL frames
12598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
12608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @src: Source MAC address of the EAPOL packet
12618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
12628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of the EAPOL frame
12638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
12648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * -1 failure
12658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
12668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
12678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		      size_t len)
12688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
12698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee802_1x_hdr *hdr;
12708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const struct ieee802_1x_eapol_key *key;
12718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int data_len;
12728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int res = 1;
12738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t plen;
12748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
12758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
12768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
12778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppEapolFramesRx++;
12788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len < sizeof(*hdr)) {
12798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->dot1xSuppInvalidEapolFramesRx++;
12808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
12818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hdr = (const struct ieee802_1x_hdr *) buf;
12838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
12848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
12858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->version < EAPOL_VERSION) {
12868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* TODO: backwards compatibility */
12878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	plen = be_to_host16(hdr->length);
12898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (plen > len - sizeof(*hdr)) {
12908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->dot1xSuppEapLengthErrorFramesRx++;
12918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
12928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
12938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_WPS
1294661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	if (sm->conf.wps && sm->conf.workaround &&
12958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    plen < len - sizeof(*hdr) &&
12968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
12978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
12988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		const struct eap_hdr *ehdr =
12998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			(const struct eap_hdr *) (hdr + 1);
13008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		u16 elen;
13018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		elen = be_to_host16(ehdr->length);
13038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (elen > plen && elen <= len - sizeof(*hdr)) {
13048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/*
13058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
13068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * packets with too short EAPOL header length field
13078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * (14 octets). This is fixed in firmware Ver.1.49.
13088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * As a workaround, fix the EAPOL header based on the
13098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * correct length in the EAP packet.
13108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
13118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
13128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "payload length based on EAP header: "
13138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "%d -> %d", (int) plen, elen);
13148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			plen = elen;
13158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
13178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_WPS */
13188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	data_len = plen + sizeof(*hdr);
13198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
13208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (hdr->type) {
13218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case IEEE802_1X_TYPE_EAP_PACKET:
13225605286c30e1701491bd3af974ae423727750eddDmitry Shmidt		if (sm->conf.workaround) {
13235605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			/*
13245605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * An AP has been reported to send out EAP message with
13255605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * undocumented code 10 at some point near the
13265605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * completion of EAP authentication. This can result in
13275605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * issues with the unexpected EAP message triggering
13285605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * restart of EAPOL authentication. Avoid this by
13295605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * skipping the message without advancing the state
13305605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 * machine.
13315605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			 */
13325605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			const struct eap_hdr *ehdr =
13335605286c30e1701491bd3af974ae423727750eddDmitry Shmidt				(const struct eap_hdr *) (hdr + 1);
13345605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
13355605286c30e1701491bd3af974ae423727750eddDmitry Shmidt				wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
13365605286c30e1701491bd3af974ae423727750eddDmitry Shmidt				break;
13375605286c30e1701491bd3af974ae423727750eddDmitry Shmidt			}
13385605286c30e1701491bd3af974ae423727750eddDmitry Shmidt		}
13395605286c30e1701491bd3af974ae423727750eddDmitry Shmidt
13408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->cached_pmk) {
13418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* Trying to use PMKSA caching, but Authenticator did
13428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * not seem to have a matching entry. Need to restart
13438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 * EAPOL state machines.
13448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			 */
13458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eapol_sm_abort_cached(sm);
13468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpabuf_free(sm->eapReqData);
13488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
13498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->eapReqData) {
13508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
13518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "frame");
13528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->eapolEap = TRUE;
1353f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
1354f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			if (sm->use_eap_proxy) {
1355f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				eap_proxy_packet_update(
1356f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					sm->eap_proxy,
1357f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					wpabuf_mhead_u8(sm->eapReqData),
1358f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					wpabuf_len(sm->eapReqData));
1359f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
1360f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt					   "EAP Req updated");
1361f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			}
1362f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
13638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eapol_sm_step(sm);
13648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
13668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case IEEE802_1X_TYPE_EAPOL_KEY:
13678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (plen < sizeof(*key)) {
13688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
13698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "frame received");
13708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
13718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
13738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key->type == EAPOL_KEY_TYPE_WPA ||
13748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    key->type == EAPOL_KEY_TYPE_RSN) {
13758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			/* WPA Supplicant takes care of this frame. */
13768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
13778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "frame in EAPOL state machines");
13788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			res = 0;
13798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
13808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (key->type != EAPOL_KEY_TYPE_RC4) {
13828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
13838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "EAPOL-Key type %d", key->type);
13848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
13858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sm->last_rx_key);
13878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->last_rx_key = os_malloc(data_len);
13888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (sm->last_rx_key) {
13898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
13908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "frame");
13918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_memcpy(sm->last_rx_key, buf, data_len);
13928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->last_rx_key_len = data_len;
13938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			sm->rxKey = TRUE;
13948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			eapol_sm_step(sm);
13958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
13968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
13975a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt#ifdef CONFIG_MACSEC
13985a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	case IEEE802_1X_TYPE_EAPOL_MKA:
13995a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt		wpa_printf(MSG_EXCESSIVE,
14005a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt			   "EAPOL type %d will be handled by MKA",
14015a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt			   hdr->type);
14025a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt		break;
14035a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt#endif /* CONFIG_MACSEC */
14048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	default:
14058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
14068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   hdr->type);
14078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->dot1xSuppInvalidEapolFramesRx++;
14088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
14098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
14108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return res;
14128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
14168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
14178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
14198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machine about transmitted EAPOL packet from an external
14208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * component, e.g., WPA. This will update the statistics.
14218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
14228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
14238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm)
14258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->dot1xSuppEapolFramesTx++;
14268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
14308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_portEnabled - Notification about portEnabled change
14318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @enabled: New portEnabled value
14338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
14348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machine about new portEnabled value.
14358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
14368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
14378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
14398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
14418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "portEnabled=%d", enabled);
1442fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	if (sm->portEnabled != enabled)
1443fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt		sm->force_authorized_update = TRUE;
14448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->portEnabled = enabled;
14458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
14468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
14508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_portValid - Notification about portValid change
14518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @valid: New portValid value
14538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
14548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machine about new portValid value.
14558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
14568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
14578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
14598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
14618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "portValid=%d", valid);
14628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->portValid = valid;
14638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
14648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
14688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_eap_success - Notification of external EAP success trigger
14698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @success: %TRUE = set success, %FALSE = clear success
14718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
14728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify the EAPOL state machine that external event has forced EAP state to
14738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * success (success = %TRUE). This can be cleared by setting success = %FALSE.
14748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
14758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function is called to update EAP state when WPA-PSK key handshake has
14768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * been completed successfully since WPA-PSK does not use EAP state machine.
14778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
14788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
14798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
14808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
14818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
14828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
14838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "EAP success=%d", success);
14848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapSuccess = success;
14858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->altAccept = success;
14868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (success)
14878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_notify_success(sm->eap);
14888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
14898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
14908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
14928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
14938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
14948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
14958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @fail: %TRUE = set failure, %FALSE = clear failure
14968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
14978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machine that external event has forced EAP state to
14988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
14998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
15008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
15018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
15038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
15058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "EAP fail=%d", fail);
15068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eapFail = fail;
15078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->altReject = fail;
15088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
15098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
15138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_config - Notification of EAPOL configuration change
15148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
15158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @config: Pointer to current network EAP configuration
15168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @conf: Pointer to EAPOL configuration data
15178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
15188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machine that configuration has changed. config will be
15198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * stored as a backpointer to network configuration. This can be %NULL to clear
15208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * the stored pointed. conf will be copied to local EAPOL/EAP configuration
15218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * data. If conf is %NULL, this part of the configuration change will be
15228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * skipped.
15238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
15248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_config(struct eapol_sm *sm,
15258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    struct eap_peer_config *config,
15268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const struct eapol_config *conf)
15278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
15298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->config = config;
1532f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
1533f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
1534f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
15358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (conf == NULL)
15378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
15388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
15408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->conf.required_keys = conf->required_keys;
15418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->conf.fast_reauth = conf->fast_reauth;
15428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->conf.workaround = conf->workaround;
1543661b4f78e48c697429dc46154a4125892c001718Dmitry Shmidt	sm->conf.wps = conf->wps;
1544f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
1545f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (sm->use_eap_proxy) {
1546f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		/* Using EAP Proxy, so skip EAP state machine update */
1547f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		return;
1548f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1549f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
15508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->eap) {
15518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
15528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_set_workaround(sm->eap, conf->workaround);
15538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_set_force_disabled(sm->eap, conf->eap_disabled);
1554051af73b8f8014eff33330aead0f36944b3403e6Dmitry Shmidt		eap_set_external_sim(sm->eap, conf->external_sim);
15558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
15578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
15598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
15608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_get_key - Get master session key (MSK) from EAP
15618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
15628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @key: Pointer for key buffer
15638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Number of bytes to copy to key
15648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success (len of key available), maximum available key len
15658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * (>0) if key is available but it is shorter than len, or -1 on failure.
15668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
15678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
15688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * is available only after a successful authentication.
15698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
15708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
15718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
15728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	const u8 *eap_key;
15738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t eap_len;
15748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1575f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
157609f57babfc1e4473db20ced4f58a4c9f082c8ed8Dmitry Shmidt	if (sm && sm->use_eap_proxy) {
1577f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		/* Get key from EAP proxy */
1578f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
1579f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1580f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return -1;
1581f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		}
1582f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
1583f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		if (eap_key == NULL) {
1584f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
1585f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt				   "eapKeyData");
1586f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt			return -1;
1587f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		}
1588f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		goto key_fetched;
1589f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
1590f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
15918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL || !eap_key_available(sm->eap)) {
15928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
15938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
15958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
15968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (eap_key == NULL) {
15978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
15988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
15998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1600f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
1601f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidtkey_fetched:
1602f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
16038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (len > eap_len) {
16048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
16058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "available (len=%lu)",
16068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   (unsigned long) len, (unsigned long) eap_len);
16078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return eap_len;
16088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(key, eap_key, len);
16108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
16118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   (unsigned long) len);
16128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
16138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
16175a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * eapol_sm_get_session_id - Get EAP Session-Id
16185a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16195a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * @len: Pointer to variable that will be set to number of bytes in the session
16205a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * Returns: Pointer to the EAP Session-Id or %NULL on failure
16215a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt *
16225a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt * The Session-Id is available only after a successful authentication.
16235a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt */
16245a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidtconst u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
16255a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt{
16265a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	if (sm == NULL || !eap_key_available(sm->eap)) {
16275a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
16285a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt		return NULL;
16295a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	}
16305a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt	return eap_get_eapSessionId(sm->eap, len);
16315a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt}
16325a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt
16335a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt
16345a1480c7c46c4236d93bfd303dde32062bee04acDmitry Shmidt/**
16358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_logoff - Notification of logon/logoff commands
16368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @logoff: Whether command was logoff
16388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
16398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machines that user requested logon/logoff.
16408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
16418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
16428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm) {
16448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->userLogoff = logoff;
16458da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		if (!logoff) {
16468da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			/* If there is a delayed txStart queued, start now. */
16478da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt			sm->startWhen = 0;
16488da800a193fb6f8832218715f82a7b4e2d2ad338Dmitry Shmidt		}
16498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol_sm_step(sm);
16508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
16518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
16558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
16568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
16588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machines that PMKSA caching was successful. This is used
16598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * to move EAPOL and EAP state machines into authenticated/successful state.
16608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
16618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_cached(struct eapol_sm *sm)
16628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
16648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
16658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1666d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	sm->eapSuccess = TRUE;
16678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_notify_success(sm->eap);
16688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
16698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
16738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
16748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
16758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
1676216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt * Notify EAPOL state machines if PMKSA caching is used.
16778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
1678216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidtvoid eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
16798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
16818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1682216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1683216983bceec7c450951e2fbcd076b5c75d432e57Dmitry Shmidt	sm->cached_pmk = TRUE;
16848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
16858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_abort_cached(struct eapol_sm *sm)
16888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
16898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
16908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "doing full EAP authentication");
16918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
16928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
16938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->cached_pmk = FALSE;
16948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
16958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_port_unauthorized(sm);
16968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
16978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Make sure we do not start sending EAPOL-Start frames first, but
16988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	 * instead move to RESTART state to start EAPOL authentication. */
16998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->startWhen = 3;
17008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_enable_timer_tick(sm);
17018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->ctx->aborted_cached)
17038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->ctx->aborted_cached(sm->ctx->ctx);
17048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
17088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_register_scard_ctx - Notification of smart card context
17098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ctx: Context data for smart card operations
17118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
17128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machines of context data for smart card operations. This
17138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * context data will be used as a parameter for scard_*() functions.
17148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
17158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
17168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm) {
17188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->ctx->scard_ctx = ctx;
17198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_register_scard_ctx(sm->eap, ctx);
17208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
17258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_portControl - Notification of portControl changes
17268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @portControl: New value for portControl variable
17288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
17298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machines that portControl variable has changed.
17308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
17318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
17328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
17348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
17368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "portControl=%s", eapol_port_control(portControl));
17378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->portControl = portControl;
17388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
17398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
17438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_ctrl_attached - Notification of attached monitor
17448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
17468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machines that a monitor was attached to the control
17478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * interface to trigger re-sending of pending requests for user input.
17488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
17498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
17508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
17528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_sm_notify_ctrl_attached(sm->eap);
17548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
17588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_ctrl_response - Notification of received user input
17598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
17618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL state machines that a control response, i.e., user
17628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * input, was received in order to trigger retrying of a pending EAP request.
17638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
17648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
17658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
17678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->eapReqData && !sm->eapReq) {
17698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
17708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "input) notification - retrying pending EAP "
17718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "Request");
17728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapolEap = TRUE;
17738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapReq = TRUE;
17748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol_sm_step(sm);
17758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
17768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
17808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_request_reauth - Request reauthentication
17818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
17838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This function can be used to request EAPOL reauthentication, e.g., when the
17848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * current PMKSA entry is nearing expiration.
17858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
17868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_request_reauth(struct eapol_sm *sm)
17878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
17888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
17898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
17908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_txStart(sm);
17918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
17928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
17948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
17958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_notify_lower_layer_success - Notification of lower layer success
17968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
17978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @in_eapol_sm: Whether the caller is already running inside EAPOL state
17988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * machine loop (eapol_sm_step())
17998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
18008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Notify EAPOL (and EAP) state machines that a lower layer has detected a
18018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * successful authentication. This is used to recover from dropped EAP-Success
18028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * messages.
18038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
18048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
18058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
18078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_notify_lower_layer_success(sm->eap);
18098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!in_eapol_sm)
18108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol_sm_step(sm);
18118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
18158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
18168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
18178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
18188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
18198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm)
18218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eap_invalidate_cached_session(sm->eap);
18228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct eap_peer_config * eapol_sm_get_config(void *ctx)
18268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
18288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return sm ? sm->config : NULL;
18298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
18338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
18358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL || sm->eapReqData == NULL)
18368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
18378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return sm->eapReqData;
18398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
18438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
18458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
18468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return FALSE;
18478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (variable) {
18488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapSuccess:
18498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->eapSuccess;
18508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapRestart:
18518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->eapRestart;
18528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapFail:
18538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->eapFail;
18548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapResp:
18558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->eapResp;
18568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapNoResp:
18578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->eapNoResp;
18588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapReq:
18598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->eapReq;
18608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_portEnabled:
18618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->portEnabled;
18628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_altAccept:
18638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->altAccept;
18648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_altReject:
18658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->altReject;
18666c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case EAPOL_eapTriggerStart:
18676c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		return sm->eapTriggerStart;
18688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
18698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return FALSE;
18708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
18718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
18738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
18748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			      Boolean value)
18758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
18768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
18778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
18788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
18798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (variable) {
18808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapSuccess:
18818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapSuccess = value;
18828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapRestart:
18848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapRestart = value;
18858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapFail:
18878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapFail = value;
18888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapResp:
18908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapResp = value;
18918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapNoResp:
18938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapNoResp = value;
18948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_eapReq:
18968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapReq = value;
18978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
18988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_portEnabled:
18998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->portEnabled = value;
19008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_altAccept:
19028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->altAccept = value;
19038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_altReject:
19058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->altReject = value;
19068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19076c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	case EAPOL_eapTriggerStart:
19086c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		sm->eapTriggerStart = value;
19096c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		break;
19108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
19158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
19178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
19188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return 0;
19198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (variable) {
19208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_idleWhile:
19218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->idleWhile;
19228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
19248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
19288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			     unsigned int value)
19298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
19318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
19328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
19338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	switch (variable) {
19348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	case EAPOL_idleWhile:
19358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->idleWhile = value;
193661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (sm->idleWhile > 0)
193761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			eapol_enable_timer_tick(sm);
19388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		break;
19398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
19448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_CONFIG_BLOBS
19468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
19478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm && sm->ctx && sm->ctx->set_config_blob)
19488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
19498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_CONFIG_BLOBS */
19508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic const struct wpa_config_blob *
19548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidteapol_sm_get_config_blob(void *ctx, const char *name)
19558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_CONFIG_BLOBS
19578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
19588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm && sm->ctx && sm->ctx->get_config_blob)
19598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
19608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
19618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
19628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_NO_CONFIG_BLOBS */
19638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return NULL;
19648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_CONFIG_BLOBS */
19658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void eapol_sm_notify_pending(void *ctx)
19698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
19718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
19728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
19738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->eapReqData && !sm->eapReq) {
19748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
19758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "state machine - retrying pending EAP Request");
19768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapolEap = TRUE;
19778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->eapReq = TRUE;
19788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		eapol_sm_step(sm);
19798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
19808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
19838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
19841f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidtstatic void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
19858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				      const char *txt)
19868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
19878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm = ctx;
19888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
19898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->ctx->eap_param_needed)
19908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
19918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
19928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
19938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define eapol_sm_eap_param_needed NULL
19948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
19958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1996c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidtstatic void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
19972f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				 const char *altsubject[],
19982f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				 int num_altsubject, const char *cert_hash,
1999c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt				 const struct wpabuf *cert)
2000c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt{
2001c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	struct eapol_sm *sm = ctx;
2002c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	if (sm->ctx->cert_cb)
20032f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
20042f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				 num_altsubject, cert_hash, cert);
2005c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt}
20068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
200704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
200804949598a23f501be6eec21697465fd46a28840aDmitry Shmidtstatic void eapol_sm_notify_status(void *ctx, const char *status,
200904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt				   const char *parameter)
201004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
201104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct eapol_sm *sm = ctx;
201204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
201304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (sm->ctx->status_cb)
201404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
201504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
201604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
20179c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawystatic void eapol_sm_notify_eap_error(void *ctx, int error_code)
20189c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy{
20199c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy	struct eapol_sm *sm = ctx;
20209c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy
20219c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy	if (sm->ctx->eap_error_cb)
20229c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy		sm->ctx->eap_error_cb(sm->ctx->ctx, error_code);
20239c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy}
202404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2025203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt#ifdef CONFIG_EAP_PROXY
2026293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt
2027203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidtstatic void eapol_sm_eap_proxy_cb(void *ctx)
2028203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt{
2029203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	struct eapol_sm *sm = ctx;
2030203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
2031203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (sm->ctx->eap_proxy_cb)
2032203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		sm->ctx->eap_proxy_cb(sm->ctx->ctx);
2033203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt}
2034293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt
2035293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt
2036293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidtstatic void
2037293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidteapol_sm_eap_proxy_notify_sim_status(void *ctx,
2038293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt				     enum eap_proxy_sim_state sim_state)
2039293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt{
2040293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt	struct eapol_sm *sm = ctx;
2041293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt
2042293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt	if (sm->ctx->eap_proxy_notify_sim_status)
2043293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt		sm->ctx->eap_proxy_notify_sim_status(sm->ctx->ctx, sim_state);
2044293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt}
2045293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt
2046203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt#endif /* CONFIG_EAP_PROXY */
2047203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
2048203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
20494530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidtstatic void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
20504530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt{
20514530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	struct eapol_sm *sm = ctx;
20524530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
20534530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	if (sm->ctx->set_anon_id)
20544530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt		sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
20554530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt}
20564530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
20574530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt
20581d755d025b206e22b06aeb322e25a79f98ca7777Dmitry Shmidtstatic const struct eapol_callbacks eapol_cb =
20598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_get_config,
20618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_get_bool,
20628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_bool,
20638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_get_int,
20648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_int,
20658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_get_eapReqData,
20668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_set_config_blob,
20678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_get_config_blob,
20688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_notify_pending,
2069c55524ad84d13014e8019491c2b17e5dcf13545aDmitry Shmidt	eapol_sm_eap_param_needed,
207004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	eapol_sm_notify_cert,
20714530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	eapol_sm_notify_status,
20729c86a7f3b4994b1346418f183a9e71c82c87de65Ahmed ElArabawy	eapol_sm_notify_eap_error,
2073203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt#ifdef CONFIG_EAP_PROXY
2074203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	eapol_sm_eap_proxy_cb,
2075293335998d38c497293b1c41f7ad8342b507d458Dmitry Shmidt	eapol_sm_eap_proxy_notify_sim_status,
2076d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	eapol_sm_get_eap_proxy_imsi,
2077203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt#endif /* CONFIG_EAP_PROXY */
20784530cfd4d14a77c58e35393b91e40f8dd9d62697Dmitry Shmidt	eapol_sm_set_anon_id
20798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
20808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
20838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_init - Initialize EAPOL state machine
20848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
20858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * and EAPOL state machine will free it in eapol_sm_deinit()
20868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
20878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
20888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Allocate and initialize an EAPOL state machine.
20898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
20908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
20918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
20928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eapol_sm *sm;
20938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct eap_config conf;
20948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm = os_zalloc(sizeof(*sm));
20958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
20968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
20978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->ctx = ctx;
20988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
20998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->portControl = Auto;
21008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Supplicant PAE state machine */
21028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->heldPeriod = 60;
21038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->startPeriod = 30;
21048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->maxStart = 3;
21058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Supplicant Backend state machine */
21078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->authPeriod = 30;
21088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memset(&conf, 0, sizeof(conf));
21108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.opensc_engine_path = ctx->opensc_engine_path;
21118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
21128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.pkcs11_module_path = ctx->pkcs11_module_path;
21136c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	conf.openssl_ciphers = ctx->openssl_ciphers;
21148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	conf.wps = ctx->wps;
21151f69aa52ea2e0a73ac502565df8c666ee49cab6aDmitry Shmidt	conf.cert_in_cb = ctx->cert_in_cb;
21168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
21188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm->eap == NULL) {
21198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(sm);
21208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return NULL;
21218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
21228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2123f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
2124f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	sm->use_eap_proxy = FALSE;
2125f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
2126f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	if (sm->eap_proxy == NULL) {
2127f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt		wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
2128f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	}
2129f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
2130f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt
21318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Initialize EAPOL state machines */
2132fb79edc9df1f20461e90e478363d207348213d35Dmitry Shmidt	sm->force_authorized_update = TRUE;
21338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->initialize = TRUE;
21348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
21358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->initialize = FALSE;
21368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eapol_sm_step(sm);
21378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	sm->timer_tick_enabled = 1;
21398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
21408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return sm;
21428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
21438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
21458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
21468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * eapol_sm_deinit - Deinitialize EAPOL state machine
21478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
21488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
21498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Deinitialize and free EAPOL state machine.
21508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
21518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid eapol_sm_deinit(struct eapol_sm *sm)
21528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
21538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (sm == NULL)
21548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
21558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
21568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
21578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eap_peer_sm_deinit(sm->eap);
2158f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#ifdef CONFIG_EAP_PROXY
2159f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt	eap_proxy_deinit(sm->eap_proxy);
2160f86232838cf712377867cb42417c1613ab5dc425Dmitry Shmidt#endif /* CONFIG_EAP_PROXY */
21618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sm->last_rx_key);
21628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpabuf_free(sm->eapReqData);
21638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sm->ctx);
21648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(sm);
21658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
216661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
216761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
216861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtvoid eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
216961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			     struct ext_password_data *ext)
217061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
217161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sm && sm->eap)
217261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		eap_sm_set_ext_pw_ctx(sm->eap, ext);
217361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
217461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
217561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
217661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtint eapol_sm_failed(struct eapol_sm *sm)
217761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
217861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sm == NULL)
217961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return 0;
218061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return !sm->eapSuccess && sm->eapFail;
218161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
21824ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt
21834ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt
2184ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#ifdef CONFIG_EAP_PROXY
2185d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtint eapol_sm_get_eap_proxy_imsi(void *ctx, int sim_num, char *imsi, size_t *len)
21864ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt{
2187d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	struct eapol_sm *sm = ctx;
2188d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
21894ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt	if (sm->eap_proxy == NULL)
21904ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt		return -1;
2191d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return eap_proxy_get_imsi(sm->eap_proxy, sim_num, imsi, len);
21924ce9c87407c036fc83eb5a6044ddf976c86f53fcDmitry Shmidt}
2193ebd93af924f6e54fb4982b3312ff875a4896b62bDmitry Shmidt#endif /* CONFIG_EAP_PROXY */
21946c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
21956c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt
21966c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidtvoid eapol_sm_erp_flush(struct eapol_sm *sm)
21976c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt{
21986c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt	if (sm)
21996c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt		eap_peer_erp_free_keys(sm->eap);
22006c0da2bb83f6915d8260912362692d1a742e057bDmitry Shmidt}
22019839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt
22029839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt
22039839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidtstruct wpabuf * eapol_sm_build_erp_reauth_start(struct eapol_sm *sm)
22049839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt{
22059839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt#ifdef CONFIG_ERP
22069839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt	if (!sm)
22079839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt		return NULL;
22089839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt	return eap_peer_build_erp_reauth_start(sm->eap, 0);
22099839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt#else /* CONFIG_ERP */
22109839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt	return NULL;
22119839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt#endif /* CONFIG_ERP */
22129839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt}
22139839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt
22149839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt
22159839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidtvoid eapol_sm_process_erp_finish(struct eapol_sm *sm, const u8 *buf,
22169839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt				 size_t len)
22179839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt{
22189839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt#ifdef CONFIG_ERP
22199839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt	if (!sm)
22209839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt		return;
22219839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt	eap_peer_finish(sm->eap, (const struct eap_hdr *) buf, len);
22229839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt#endif /* CONFIG_ERP */
22239839ecd75c832023d4d13fd2917a8c28261ff668Dmitry Shmidt}
2224d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
2225d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
2226d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtint eapol_sm_update_erp_next_seq_num(struct eapol_sm *sm, u16 next_seq_num)
2227d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{
2228d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#ifdef CONFIG_ERP
2229d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	if (!sm)
2230d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		return -1;
2231d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return eap_peer_update_erp_next_seq_num(sm->eap, next_seq_num);
2232d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#else /* CONFIG_ERP */
2233d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return -1;
2234d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#endif /* CONFIG_ERP */
2235d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt}
2236d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
2237d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt
2238d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidtint eapol_sm_get_erp_info(struct eapol_sm *sm, struct eap_peer_config *config,
2239d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			  const u8 **username, size_t *username_len,
2240d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			  const u8 **realm, size_t *realm_len,
2241d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			  u16 *erp_next_seq_num, const u8 **rrk,
2242d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt			  size_t *rrk_len)
2243d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt{
2244d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#ifdef CONFIG_ERP
2245d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	if (!sm)
2246d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt		return -1;
2247d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return eap_peer_get_erp_info(sm->eap, config, username, username_len,
2248d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				     realm, realm_len, erp_next_seq_num, rrk,
2249d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt				     rrk_len);
2250d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#else /* CONFIG_ERP */
2251d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt	return -1;
2252d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt#endif /* CONFIG_ERP */
2253d2986c2e737a8441ff5a791b6b56c1c8322ef3c9Dmitry Shmidt}
2254