eapol_supp_sm.c revision d5e4923d04122f81300fa68fb07d64ede28fd44d
1/*
2 * EAPOL supplicant state machines
3 * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "state_machine.h"
13#include "wpabuf.h"
14#include "eloop.h"
15#include "crypto/crypto.h"
16#include "crypto/md5.h"
17#include "common/eapol_common.h"
18#include "eap_peer/eap.h"
19#include "eapol_supp_sm.h"
20
21#define STATE_MACHINE_DATA struct eapol_sm
22#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
23
24
25/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
26
27/**
28 * struct eapol_sm - Internal data for EAPOL state machines
29 */
30struct eapol_sm {
31	/* Timers */
32	unsigned int authWhile;
33	unsigned int heldWhile;
34	unsigned int startWhen;
35	unsigned int idleWhile; /* for EAP state machine */
36	int timer_tick_enabled;
37
38	/* Global variables */
39	Boolean eapFail;
40	Boolean eapolEap;
41	Boolean eapSuccess;
42	Boolean initialize;
43	Boolean keyDone;
44	Boolean keyRun;
45	PortControl portControl;
46	Boolean portEnabled;
47	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
48	Boolean portValid;
49	Boolean suppAbort;
50	Boolean suppFail;
51	Boolean suppStart;
52	Boolean suppSuccess;
53	Boolean suppTimeout;
54
55	/* Supplicant PAE state machine */
56	enum {
57		SUPP_PAE_UNKNOWN = 0,
58		SUPP_PAE_DISCONNECTED = 1,
59		SUPP_PAE_LOGOFF = 2,
60		SUPP_PAE_CONNECTING = 3,
61		SUPP_PAE_AUTHENTICATING = 4,
62		SUPP_PAE_AUTHENTICATED = 5,
63		/* unused(6) */
64		SUPP_PAE_HELD = 7,
65		SUPP_PAE_RESTART = 8,
66		SUPP_PAE_S_FORCE_AUTH = 9,
67		SUPP_PAE_S_FORCE_UNAUTH = 10
68	} SUPP_PAE_state; /* dot1xSuppPaeState */
69	/* Variables */
70	Boolean userLogoff;
71	Boolean logoffSent;
72	unsigned int startCount;
73	Boolean eapRestart;
74	PortControl sPortMode;
75	/* Constants */
76	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
77	unsigned int startPeriod; /* dot1xSuppStartPeriod */
78	unsigned int maxStart; /* dot1xSuppMaxStart */
79
80	/* Key Receive state machine */
81	enum {
82		KEY_RX_UNKNOWN = 0,
83		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
84	} KEY_RX_state;
85	/* Variables */
86	Boolean rxKey;
87
88	/* Supplicant Backend state machine */
89	enum {
90		SUPP_BE_UNKNOWN = 0,
91		SUPP_BE_INITIALIZE = 1,
92		SUPP_BE_IDLE = 2,
93		SUPP_BE_REQUEST = 3,
94		SUPP_BE_RECEIVE = 4,
95		SUPP_BE_RESPONSE = 5,
96		SUPP_BE_FAIL = 6,
97		SUPP_BE_TIMEOUT = 7,
98		SUPP_BE_SUCCESS = 8
99	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
100	/* Variables */
101	Boolean eapNoResp;
102	Boolean eapReq;
103	Boolean eapResp;
104	/* Constants */
105	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
106
107	/* Statistics */
108	unsigned int dot1xSuppEapolFramesRx;
109	unsigned int dot1xSuppEapolFramesTx;
110	unsigned int dot1xSuppEapolStartFramesTx;
111	unsigned int dot1xSuppEapolLogoffFramesTx;
112	unsigned int dot1xSuppEapolRespFramesTx;
113	unsigned int dot1xSuppEapolReqIdFramesRx;
114	unsigned int dot1xSuppEapolReqFramesRx;
115	unsigned int dot1xSuppInvalidEapolFramesRx;
116	unsigned int dot1xSuppEapLengthErrorFramesRx;
117	unsigned int dot1xSuppLastEapolFrameVersion;
118	unsigned char dot1xSuppLastEapolFrameSource[6];
119
120	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
121	Boolean changed;
122	struct eap_sm *eap;
123	struct eap_peer_config *config;
124	Boolean initial_req;
125	u8 *last_rx_key;
126	size_t last_rx_key_len;
127	struct wpabuf *eapReqData; /* for EAP */
128	Boolean altAccept; /* for EAP */
129	Boolean altReject; /* for EAP */
130	Boolean replay_counter_valid;
131	u8 last_replay_counter[16];
132	struct eapol_config conf;
133	struct eapol_ctx *ctx;
134	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
135		cb_status;
136	Boolean cached_pmk;
137
138	Boolean unicast_key_received, broadcast_key_received;
139};
140
141
142static void eapol_sm_txLogoff(struct eapol_sm *sm);
143static void eapol_sm_txStart(struct eapol_sm *sm);
144static void eapol_sm_processKey(struct eapol_sm *sm);
145static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
146static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
147static void eapol_sm_abortSupp(struct eapol_sm *sm);
148static void eapol_sm_abort_cached(struct eapol_sm *sm);
149static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
150static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
151static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
152
153
154/* Port Timers state machine - implemented as a function that will be called
155 * once a second as a registered event loop timeout */
156static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
157{
158	struct eapol_sm *sm = timeout_ctx;
159
160	if (sm->authWhile > 0) {
161		sm->authWhile--;
162		if (sm->authWhile == 0)
163			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
164	}
165	if (sm->heldWhile > 0) {
166		sm->heldWhile--;
167		if (sm->heldWhile == 0)
168			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
169	}
170	if (sm->startWhen > 0) {
171		sm->startWhen--;
172		if (sm->startWhen == 0)
173			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
174	}
175	if (sm->idleWhile > 0) {
176		sm->idleWhile--;
177		if (sm->idleWhile == 0)
178			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
179	}
180
181	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
182		eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
183				       sm);
184	} else {
185		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
186		sm->timer_tick_enabled = 0;
187	}
188	eapol_sm_step(sm);
189}
190
191
192static void eapol_enable_timer_tick(struct eapol_sm *sm)
193{
194	if (sm->timer_tick_enabled)
195		return;
196	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
197	sm->timer_tick_enabled = 1;
198	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
199	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
200}
201
202
203SM_STATE(SUPP_PAE, LOGOFF)
204{
205	SM_ENTRY(SUPP_PAE, LOGOFF);
206	eapol_sm_txLogoff(sm);
207	sm->logoffSent = TRUE;
208	sm->suppPortStatus = Unauthorized;
209	eapol_sm_set_port_unauthorized(sm);
210}
211
212
213SM_STATE(SUPP_PAE, DISCONNECTED)
214{
215	SM_ENTRY(SUPP_PAE, DISCONNECTED);
216	sm->sPortMode = Auto;
217	sm->startCount = 0;
218	sm->logoffSent = FALSE;
219	sm->suppPortStatus = Unauthorized;
220	eapol_sm_set_port_unauthorized(sm);
221	sm->suppAbort = TRUE;
222
223	sm->unicast_key_received = FALSE;
224	sm->broadcast_key_received = FALSE;
225
226	/*
227	 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
228	 * allows the timer tick to be stopped more quickly when the port is
229	 * not enabled. Since this variable is used only within HELD state,
230	 * clearing it on initialization does not change actual state machine
231	 * behavior.
232	 */
233	sm->heldWhile = 0;
234}
235
236
237SM_STATE(SUPP_PAE, CONNECTING)
238{
239	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
240	SM_ENTRY(SUPP_PAE, CONNECTING);
241	if (send_start) {
242		sm->startWhen = sm->startPeriod;
243		sm->startCount++;
244	} else {
245		/*
246		 * Do not send EAPOL-Start immediately since in most cases,
247		 * Authenticator is going to start authentication immediately
248		 * after association and an extra EAPOL-Start is just going to
249		 * delay authentication. Use a short timeout to send the first
250		 * EAPOL-Start if Authenticator does not start authentication.
251		 */
252#ifdef CONFIG_WPS
253		/* Reduce latency on starting WPS negotiation. */
254		sm->startWhen = 1;
255#else /* CONFIG_WPS */
256		sm->startWhen = 3;
257#endif /* CONFIG_WPS */
258	}
259	eapol_enable_timer_tick(sm);
260	sm->eapolEap = FALSE;
261	if (send_start)
262		eapol_sm_txStart(sm);
263}
264
265
266SM_STATE(SUPP_PAE, AUTHENTICATING)
267{
268	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
269	sm->startCount = 0;
270	sm->suppSuccess = FALSE;
271	sm->suppFail = FALSE;
272	sm->suppTimeout = FALSE;
273	sm->keyRun = FALSE;
274	sm->keyDone = FALSE;
275	sm->suppStart = TRUE;
276}
277
278
279SM_STATE(SUPP_PAE, HELD)
280{
281	SM_ENTRY(SUPP_PAE, HELD);
282	sm->heldWhile = sm->heldPeriod;
283	eapol_enable_timer_tick(sm);
284	sm->suppPortStatus = Unauthorized;
285	eapol_sm_set_port_unauthorized(sm);
286	sm->cb_status = EAPOL_CB_FAILURE;
287}
288
289
290SM_STATE(SUPP_PAE, AUTHENTICATED)
291{
292	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
293	sm->suppPortStatus = Authorized;
294	eapol_sm_set_port_authorized(sm);
295	sm->cb_status = EAPOL_CB_SUCCESS;
296}
297
298
299SM_STATE(SUPP_PAE, RESTART)
300{
301	SM_ENTRY(SUPP_PAE, RESTART);
302	sm->eapRestart = TRUE;
303}
304
305
306SM_STATE(SUPP_PAE, S_FORCE_AUTH)
307{
308	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
309	sm->suppPortStatus = Authorized;
310	eapol_sm_set_port_authorized(sm);
311	sm->sPortMode = ForceAuthorized;
312}
313
314
315SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
316{
317	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
318	sm->suppPortStatus = Unauthorized;
319	eapol_sm_set_port_unauthorized(sm);
320	sm->sPortMode = ForceUnauthorized;
321	eapol_sm_txLogoff(sm);
322}
323
324
325SM_STEP(SUPP_PAE)
326{
327	if ((sm->userLogoff && !sm->logoffSent) &&
328	    !(sm->initialize || !sm->portEnabled))
329		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
330	else if (((sm->portControl == Auto) &&
331		  (sm->sPortMode != sm->portControl)) ||
332		 sm->initialize || !sm->portEnabled)
333		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
334	else if ((sm->portControl == ForceAuthorized) &&
335		 (sm->sPortMode != sm->portControl) &&
336		 !(sm->initialize || !sm->portEnabled))
337		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
338	else if ((sm->portControl == ForceUnauthorized) &&
339		 (sm->sPortMode != sm->portControl) &&
340		 !(sm->initialize || !sm->portEnabled))
341		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
342	else switch (sm->SUPP_PAE_state) {
343	case SUPP_PAE_UNKNOWN:
344		break;
345	case SUPP_PAE_LOGOFF:
346		if (!sm->userLogoff)
347			SM_ENTER(SUPP_PAE, DISCONNECTED);
348		break;
349	case SUPP_PAE_DISCONNECTED:
350		SM_ENTER(SUPP_PAE, CONNECTING);
351		break;
352	case SUPP_PAE_CONNECTING:
353		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
354			SM_ENTER(SUPP_PAE, CONNECTING);
355		else if (sm->startWhen == 0 &&
356			 sm->startCount >= sm->maxStart &&
357			 sm->portValid)
358			SM_ENTER(SUPP_PAE, AUTHENTICATED);
359		else if (sm->eapSuccess || sm->eapFail)
360			SM_ENTER(SUPP_PAE, AUTHENTICATING);
361		else if (sm->eapolEap)
362			SM_ENTER(SUPP_PAE, RESTART);
363		else if (sm->startWhen == 0 &&
364			 sm->startCount >= sm->maxStart &&
365			 !sm->portValid)
366			SM_ENTER(SUPP_PAE, HELD);
367		break;
368	case SUPP_PAE_AUTHENTICATING:
369		if (sm->eapSuccess && !sm->portValid &&
370		    sm->conf.accept_802_1x_keys &&
371		    sm->conf.required_keys == 0) {
372			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
373				   "plaintext connection; no EAPOL-Key frames "
374				   "required");
375			sm->portValid = TRUE;
376			if (sm->ctx->eapol_done_cb)
377				sm->ctx->eapol_done_cb(sm->ctx->ctx);
378		}
379		if (sm->eapSuccess && sm->portValid)
380			SM_ENTER(SUPP_PAE, AUTHENTICATED);
381		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
382			SM_ENTER(SUPP_PAE, HELD);
383		else if (sm->suppTimeout)
384			SM_ENTER(SUPP_PAE, CONNECTING);
385		break;
386	case SUPP_PAE_HELD:
387		if (sm->heldWhile == 0)
388			SM_ENTER(SUPP_PAE, CONNECTING);
389		else if (sm->eapolEap)
390			SM_ENTER(SUPP_PAE, RESTART);
391		break;
392	case SUPP_PAE_AUTHENTICATED:
393		if (sm->eapolEap && sm->portValid)
394			SM_ENTER(SUPP_PAE, RESTART);
395		else if (!sm->portValid)
396			SM_ENTER(SUPP_PAE, DISCONNECTED);
397		break;
398	case SUPP_PAE_RESTART:
399		if (!sm->eapRestart)
400			SM_ENTER(SUPP_PAE, AUTHENTICATING);
401		break;
402	case SUPP_PAE_S_FORCE_AUTH:
403		break;
404	case SUPP_PAE_S_FORCE_UNAUTH:
405		break;
406	}
407}
408
409
410SM_STATE(KEY_RX, NO_KEY_RECEIVE)
411{
412	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
413}
414
415
416SM_STATE(KEY_RX, KEY_RECEIVE)
417{
418	SM_ENTRY(KEY_RX, KEY_RECEIVE);
419	eapol_sm_processKey(sm);
420	sm->rxKey = FALSE;
421}
422
423
424SM_STEP(KEY_RX)
425{
426	if (sm->initialize || !sm->portEnabled)
427		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
428	switch (sm->KEY_RX_state) {
429	case KEY_RX_UNKNOWN:
430		break;
431	case KEY_RX_NO_KEY_RECEIVE:
432		if (sm->rxKey)
433			SM_ENTER(KEY_RX, KEY_RECEIVE);
434		break;
435	case KEY_RX_KEY_RECEIVE:
436		if (sm->rxKey)
437			SM_ENTER(KEY_RX, KEY_RECEIVE);
438		break;
439	}
440}
441
442
443SM_STATE(SUPP_BE, REQUEST)
444{
445	SM_ENTRY(SUPP_BE, REQUEST);
446	sm->authWhile = 0;
447	sm->eapReq = TRUE;
448	eapol_sm_getSuppRsp(sm);
449}
450
451
452SM_STATE(SUPP_BE, RESPONSE)
453{
454	SM_ENTRY(SUPP_BE, RESPONSE);
455	eapol_sm_txSuppRsp(sm);
456	sm->eapResp = FALSE;
457}
458
459
460SM_STATE(SUPP_BE, SUCCESS)
461{
462	SM_ENTRY(SUPP_BE, SUCCESS);
463	sm->keyRun = TRUE;
464	sm->suppSuccess = TRUE;
465
466	if (eap_key_available(sm->eap)) {
467		/* New key received - clear IEEE 802.1X EAPOL-Key replay
468		 * counter */
469		sm->replay_counter_valid = FALSE;
470	}
471}
472
473
474SM_STATE(SUPP_BE, FAIL)
475{
476	SM_ENTRY(SUPP_BE, FAIL);
477	sm->suppFail = TRUE;
478}
479
480
481SM_STATE(SUPP_BE, TIMEOUT)
482{
483	SM_ENTRY(SUPP_BE, TIMEOUT);
484	sm->suppTimeout = TRUE;
485}
486
487
488SM_STATE(SUPP_BE, IDLE)
489{
490	SM_ENTRY(SUPP_BE, IDLE);
491	sm->suppStart = FALSE;
492	sm->initial_req = TRUE;
493}
494
495
496SM_STATE(SUPP_BE, INITIALIZE)
497{
498	SM_ENTRY(SUPP_BE, INITIALIZE);
499	eapol_sm_abortSupp(sm);
500	sm->suppAbort = FALSE;
501
502	/*
503	 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
504	 * allows the timer tick to be stopped more quickly when the port is
505	 * not enabled. Since this variable is used only within RECEIVE state,
506	 * clearing it on initialization does not change actual state machine
507	 * behavior.
508	 */
509	sm->authWhile = 0;
510}
511
512
513SM_STATE(SUPP_BE, RECEIVE)
514{
515	SM_ENTRY(SUPP_BE, RECEIVE);
516	sm->authWhile = sm->authPeriod;
517	eapol_enable_timer_tick(sm);
518	sm->eapolEap = FALSE;
519	sm->eapNoResp = FALSE;
520	sm->initial_req = FALSE;
521}
522
523
524SM_STEP(SUPP_BE)
525{
526	if (sm->initialize || sm->suppAbort)
527		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
528	else switch (sm->SUPP_BE_state) {
529	case SUPP_BE_UNKNOWN:
530		break;
531	case SUPP_BE_REQUEST:
532		/*
533		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
534		 * and SUCCESS based on eapFail and eapSuccess, respectively.
535		 * However, IEEE Std 802.1X-2004 is also specifying that
536		 * eapNoResp should be set in conjunction with eapSuccess and
537		 * eapFail which would mean that more than one of the
538		 * transitions here would be activated at the same time.
539		 * Skipping RESPONSE and/or RECEIVE states in these cases can
540		 * cause problems and the direct transitions to do not seem
541		 * correct. Because of this, the conditions for these
542		 * transitions are verified only after eapNoResp. They are
543		 * unlikely to be used since eapNoResp should always be set if
544		 * either of eapSuccess or eapFail is set.
545		 */
546		if (sm->eapResp && sm->eapNoResp) {
547			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
548				   "eapResp and eapNoResp set?!");
549		}
550		if (sm->eapResp)
551			SM_ENTER(SUPP_BE, RESPONSE);
552		else if (sm->eapNoResp)
553			SM_ENTER(SUPP_BE, RECEIVE);
554		else if (sm->eapFail)
555			SM_ENTER(SUPP_BE, FAIL);
556		else if (sm->eapSuccess)
557			SM_ENTER(SUPP_BE, SUCCESS);
558		break;
559	case SUPP_BE_RESPONSE:
560		SM_ENTER(SUPP_BE, RECEIVE);
561		break;
562	case SUPP_BE_SUCCESS:
563		SM_ENTER(SUPP_BE, IDLE);
564		break;
565	case SUPP_BE_FAIL:
566		SM_ENTER(SUPP_BE, IDLE);
567		break;
568	case SUPP_BE_TIMEOUT:
569		SM_ENTER(SUPP_BE, IDLE);
570		break;
571	case SUPP_BE_IDLE:
572		if (sm->eapFail && sm->suppStart)
573			SM_ENTER(SUPP_BE, FAIL);
574		else if (sm->eapolEap && sm->suppStart)
575			SM_ENTER(SUPP_BE, REQUEST);
576		else if (sm->eapSuccess && sm->suppStart)
577			SM_ENTER(SUPP_BE, SUCCESS);
578		break;
579	case SUPP_BE_INITIALIZE:
580		SM_ENTER(SUPP_BE, IDLE);
581		break;
582	case SUPP_BE_RECEIVE:
583		if (sm->eapolEap)
584			SM_ENTER(SUPP_BE, REQUEST);
585		else if (sm->eapFail)
586			SM_ENTER(SUPP_BE, FAIL);
587		else if (sm->authWhile == 0)
588			SM_ENTER(SUPP_BE, TIMEOUT);
589		else if (sm->eapSuccess)
590			SM_ENTER(SUPP_BE, SUCCESS);
591		break;
592	}
593}
594
595
596static void eapol_sm_txLogoff(struct eapol_sm *sm)
597{
598	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
599	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
600			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
601	sm->dot1xSuppEapolLogoffFramesTx++;
602	sm->dot1xSuppEapolFramesTx++;
603}
604
605
606static void eapol_sm_txStart(struct eapol_sm *sm)
607{
608	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
609	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
610			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
611	sm->dot1xSuppEapolStartFramesTx++;
612	sm->dot1xSuppEapolFramesTx++;
613}
614
615
616#define IEEE8021X_ENCR_KEY_LEN 32
617#define IEEE8021X_SIGN_KEY_LEN 32
618
619struct eap_key_data {
620	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
621	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
622};
623
624
625static void eapol_sm_processKey(struct eapol_sm *sm)
626{
627#ifndef CONFIG_FIPS
628	struct ieee802_1x_hdr *hdr;
629	struct ieee802_1x_eapol_key *key;
630	struct eap_key_data keydata;
631	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
632	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
633	int key_len, res, sign_key_len, encr_key_len;
634	u16 rx_key_length;
635	size_t plen;
636
637	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
638	if (sm->last_rx_key == NULL)
639		return;
640
641	if (!sm->conf.accept_802_1x_keys) {
642		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
643			   " even though this was not accepted - "
644			   "ignoring this packet");
645		return;
646	}
647
648	if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
649		return;
650	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
651	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
652	plen = be_to_host16(hdr->length);
653	if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
654		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
655		return;
656	}
657	rx_key_length = WPA_GET_BE16(key->key_length);
658	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
659		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
660		   hdr->version, hdr->type, be_to_host16(hdr->length),
661		   key->type, rx_key_length, key->key_index);
662
663	eapol_sm_notify_lower_layer_success(sm, 1);
664	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
665	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
666	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
667	if (res < 0) {
668		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
669			   "decrypting EAPOL-Key keys");
670		return;
671	}
672	if (res == 16) {
673		/* LEAP derives only 16 bytes of keying material. */
674		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
675		if (res) {
676			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
677				   "master key for decrypting EAPOL-Key keys");
678			return;
679		}
680		sign_key_len = 16;
681		encr_key_len = 16;
682		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
683	} else if (res) {
684		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
685			   "data for decrypting EAPOL-Key keys (res=%d)", res);
686		return;
687	}
688
689	/* The key replay_counter must increase when same master key */
690	if (sm->replay_counter_valid &&
691	    os_memcmp(sm->last_replay_counter, key->replay_counter,
692		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
693		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
694			   "not increase - ignoring key");
695		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
696			    sm->last_replay_counter,
697			    IEEE8021X_REPLAY_COUNTER_LEN);
698		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
699			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
700		return;
701	}
702
703	/* Verify key signature (HMAC-MD5) */
704	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
705	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
706	hmac_md5(keydata.sign_key, sign_key_len,
707		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
708		 key->key_signature);
709	if (os_memcmp(orig_key_sign, key->key_signature,
710		      IEEE8021X_KEY_SIGN_LEN) != 0) {
711		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
712			   "EAPOL-Key packet");
713		os_memcpy(key->key_signature, orig_key_sign,
714			  IEEE8021X_KEY_SIGN_LEN);
715		return;
716	}
717	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
718
719	key_len = plen - sizeof(*key);
720	if (key_len > 32 || rx_key_length > 32) {
721		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
722			   key_len ? key_len : rx_key_length);
723		return;
724	}
725	if (key_len == rx_key_length) {
726		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
727		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
728			  encr_key_len);
729		os_memcpy(datakey, key + 1, key_len);
730		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
731			 datakey, key_len);
732		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
733				datakey, key_len);
734	} else if (key_len == 0) {
735		/*
736		 * IEEE 802.1X-2004 specifies that least significant Key Length
737		 * octets from MS-MPPE-Send-Key are used as the key if the key
738		 * data is not present. This seems to be meaning the beginning
739		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
740		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
741		 * Anyway, taking the beginning of the keying material from EAP
742		 * seems to interoperate with Authenticators.
743		 */
744		key_len = rx_key_length;
745		os_memcpy(datakey, keydata.encr_key, key_len);
746		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
747				"material data encryption key",
748				datakey, key_len);
749	} else {
750		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
751			   "(key_length=%d)", key_len, rx_key_length);
752		return;
753	}
754
755	sm->replay_counter_valid = TRUE;
756	os_memcpy(sm->last_replay_counter, key->replay_counter,
757		  IEEE8021X_REPLAY_COUNTER_LEN);
758
759	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
760		   "len %d",
761		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
762		   "unicast" : "broadcast",
763		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
764
765	if (sm->ctx->set_wep_key &&
766	    sm->ctx->set_wep_key(sm->ctx->ctx,
767				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
768				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
769				 datakey, key_len) < 0) {
770		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
771			   " driver.");
772	} else {
773		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
774			sm->unicast_key_received = TRUE;
775		else
776			sm->broadcast_key_received = TRUE;
777
778		if ((sm->unicast_key_received ||
779		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
780		    (sm->broadcast_key_received ||
781		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
782		{
783			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
784				   "frames received");
785			sm->portValid = TRUE;
786			if (sm->ctx->eapol_done_cb)
787				sm->ctx->eapol_done_cb(sm->ctx->ctx);
788		}
789	}
790#endif /* CONFIG_FIPS */
791}
792
793
794static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
795{
796	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
797	/* EAP layer processing; no special code is needed, since Supplicant
798	 * Backend state machine is waiting for eapNoResp or eapResp to be set
799	 * and these are only set in the EAP state machine when the processing
800	 * has finished. */
801}
802
803
804static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
805{
806	struct wpabuf *resp;
807
808	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
809	resp = eap_get_eapRespData(sm->eap);
810	if (resp == NULL) {
811		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
812			   "not available");
813		return;
814	}
815
816	/* Send EAP-Packet from the EAP layer to the Authenticator */
817	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
818			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
819			    wpabuf_len(resp));
820
821	/* eapRespData is not used anymore, so free it here */
822	wpabuf_free(resp);
823
824	if (sm->initial_req)
825		sm->dot1xSuppEapolReqIdFramesRx++;
826	else
827		sm->dot1xSuppEapolReqFramesRx++;
828	sm->dot1xSuppEapolRespFramesTx++;
829	sm->dot1xSuppEapolFramesTx++;
830}
831
832
833static void eapol_sm_abortSupp(struct eapol_sm *sm)
834{
835	/* release system resources that may have been allocated for the
836	 * authentication session */
837	os_free(sm->last_rx_key);
838	sm->last_rx_key = NULL;
839	wpabuf_free(sm->eapReqData);
840	sm->eapReqData = NULL;
841	eap_sm_abort(sm->eap);
842}
843
844
845static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
846{
847	eapol_sm_step(timeout_ctx);
848}
849
850
851static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
852{
853	if (sm->ctx->port_cb)
854		sm->ctx->port_cb(sm->ctx->ctx, 1);
855}
856
857
858static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
859{
860	if (sm->ctx->port_cb)
861		sm->ctx->port_cb(sm->ctx->ctx, 0);
862}
863
864
865/**
866 * eapol_sm_step - EAPOL state machine step function
867 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
868 *
869 * This function is called to notify the state machine about changed external
870 * variables. It will step through the EAPOL state machines in loop to process
871 * all triggered state changes.
872 */
873void eapol_sm_step(struct eapol_sm *sm)
874{
875	int i;
876
877	/* In theory, it should be ok to run this in loop until !changed.
878	 * However, it is better to use a limit on number of iterations to
879	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
880	 * state machine were to generate a busy loop. */
881	for (i = 0; i < 100; i++) {
882		sm->changed = FALSE;
883		SM_STEP_RUN(SUPP_PAE);
884		SM_STEP_RUN(KEY_RX);
885		SM_STEP_RUN(SUPP_BE);
886		if (eap_peer_sm_step(sm->eap))
887			sm->changed = TRUE;
888		if (!sm->changed)
889			break;
890	}
891
892	if (sm->changed) {
893		/* restart EAPOL state machine step from timeout call in order
894		 * to allow other events to be processed. */
895		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
896		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
897	}
898
899	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
900		int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
901		sm->cb_status = EAPOL_CB_IN_PROGRESS;
902		sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
903	}
904}
905
906
907#ifdef CONFIG_CTRL_IFACE
908static const char *eapol_supp_pae_state(int state)
909{
910	switch (state) {
911	case SUPP_PAE_LOGOFF:
912		return "LOGOFF";
913	case SUPP_PAE_DISCONNECTED:
914		return "DISCONNECTED";
915	case SUPP_PAE_CONNECTING:
916		return "CONNECTING";
917	case SUPP_PAE_AUTHENTICATING:
918		return "AUTHENTICATING";
919	case SUPP_PAE_HELD:
920		return "HELD";
921	case SUPP_PAE_AUTHENTICATED:
922		return "AUTHENTICATED";
923	case SUPP_PAE_RESTART:
924		return "RESTART";
925	default:
926		return "UNKNOWN";
927	}
928}
929
930
931static const char *eapol_supp_be_state(int state)
932{
933	switch (state) {
934	case SUPP_BE_REQUEST:
935		return "REQUEST";
936	case SUPP_BE_RESPONSE:
937		return "RESPONSE";
938	case SUPP_BE_SUCCESS:
939		return "SUCCESS";
940	case SUPP_BE_FAIL:
941		return "FAIL";
942	case SUPP_BE_TIMEOUT:
943		return "TIMEOUT";
944	case SUPP_BE_IDLE:
945		return "IDLE";
946	case SUPP_BE_INITIALIZE:
947		return "INITIALIZE";
948	case SUPP_BE_RECEIVE:
949		return "RECEIVE";
950	default:
951		return "UNKNOWN";
952	}
953}
954
955
956static const char * eapol_port_status(PortStatus status)
957{
958	if (status == Authorized)
959		return "Authorized";
960	else
961		return "Unauthorized";
962}
963#endif /* CONFIG_CTRL_IFACE */
964
965
966#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
967static const char * eapol_port_control(PortControl ctrl)
968{
969	switch (ctrl) {
970	case Auto:
971		return "Auto";
972	case ForceUnauthorized:
973		return "ForceUnauthorized";
974	case ForceAuthorized:
975		return "ForceAuthorized";
976	default:
977		return "Unknown";
978	}
979}
980#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
981
982
983/**
984 * eapol_sm_configure - Set EAPOL variables
985 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
986 * @heldPeriod: dot1xSuppHeldPeriod
987 * @authPeriod: dot1xSuppAuthPeriod
988 * @startPeriod: dot1xSuppStartPeriod
989 * @maxStart: dot1xSuppMaxStart
990 *
991 * Set configurable EAPOL state machine variables. Each variable can be set to
992 * the given value or ignored if set to -1 (to set only some of the variables).
993 */
994void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
995			int startPeriod, int maxStart)
996{
997	if (sm == NULL)
998		return;
999	if (heldPeriod >= 0)
1000		sm->heldPeriod = heldPeriod;
1001	if (authPeriod >= 0)
1002		sm->authPeriod = authPeriod;
1003	if (startPeriod >= 0)
1004		sm->startPeriod = startPeriod;
1005	if (maxStart >= 0)
1006		sm->maxStart = maxStart;
1007}
1008
1009
1010/**
1011 * eapol_sm_get_method_name - Get EAPOL method name
1012 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1013 * Returns: Static string containing name of current eap method or NULL
1014 */
1015const char * eapol_sm_get_method_name(struct eapol_sm *sm)
1016{
1017	if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
1018	    sm->suppPortStatus != Authorized)
1019		return NULL;
1020
1021	return eap_sm_get_method_name(sm->eap);
1022}
1023
1024
1025#ifdef CONFIG_CTRL_IFACE
1026/**
1027 * eapol_sm_get_status - Get EAPOL state machine status
1028 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1029 * @buf: Buffer for status information
1030 * @buflen: Maximum buffer length
1031 * @verbose: Whether to include verbose status information
1032 * Returns: Number of bytes written to buf.
1033 *
1034 * Query EAPOL state machine for status information. This function fills in a
1035 * text area with current status information from the EAPOL state machine. If
1036 * the buffer (buf) is not large enough, status information will be truncated
1037 * to fit the buffer.
1038 */
1039int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1040			int verbose)
1041{
1042	int len, ret;
1043	if (sm == NULL)
1044		return 0;
1045
1046	len = os_snprintf(buf, buflen,
1047			  "Supplicant PAE state=%s\n"
1048			  "suppPortStatus=%s\n",
1049			  eapol_supp_pae_state(sm->SUPP_PAE_state),
1050			  eapol_port_status(sm->suppPortStatus));
1051	if (len < 0 || (size_t) len >= buflen)
1052		return 0;
1053
1054	if (verbose) {
1055		ret = os_snprintf(buf + len, buflen - len,
1056				  "heldPeriod=%u\n"
1057				  "authPeriod=%u\n"
1058				  "startPeriod=%u\n"
1059				  "maxStart=%u\n"
1060				  "portControl=%s\n"
1061				  "Supplicant Backend state=%s\n",
1062				  sm->heldPeriod,
1063				  sm->authPeriod,
1064				  sm->startPeriod,
1065				  sm->maxStart,
1066				  eapol_port_control(sm->portControl),
1067				  eapol_supp_be_state(sm->SUPP_BE_state));
1068		if (ret < 0 || (size_t) ret >= buflen - len)
1069			return len;
1070		len += ret;
1071	}
1072
1073	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1074
1075	return len;
1076}
1077
1078
1079/**
1080 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1081 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1082 * @buf: Buffer for MIB information
1083 * @buflen: Maximum buffer length
1084 * Returns: Number of bytes written to buf.
1085 *
1086 * Query EAPOL state machine for MIB information. This function fills in a
1087 * text area with current MIB information from the EAPOL state machine. If
1088 * the buffer (buf) is not large enough, MIB information will be truncated to
1089 * fit the buffer.
1090 */
1091int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1092{
1093	size_t len;
1094	int ret;
1095
1096	if (sm == NULL)
1097		return 0;
1098	ret = os_snprintf(buf, buflen,
1099			  "dot1xSuppPaeState=%d\n"
1100			  "dot1xSuppHeldPeriod=%u\n"
1101			  "dot1xSuppAuthPeriod=%u\n"
1102			  "dot1xSuppStartPeriod=%u\n"
1103			  "dot1xSuppMaxStart=%u\n"
1104			  "dot1xSuppSuppControlledPortStatus=%s\n"
1105			  "dot1xSuppBackendPaeState=%d\n",
1106			  sm->SUPP_PAE_state,
1107			  sm->heldPeriod,
1108			  sm->authPeriod,
1109			  sm->startPeriod,
1110			  sm->maxStart,
1111			  sm->suppPortStatus == Authorized ?
1112			  "Authorized" : "Unauthorized",
1113			  sm->SUPP_BE_state);
1114
1115	if (ret < 0 || (size_t) ret >= buflen)
1116		return 0;
1117	len = ret;
1118
1119	ret = os_snprintf(buf + len, buflen - len,
1120			  "dot1xSuppEapolFramesRx=%u\n"
1121			  "dot1xSuppEapolFramesTx=%u\n"
1122			  "dot1xSuppEapolStartFramesTx=%u\n"
1123			  "dot1xSuppEapolLogoffFramesTx=%u\n"
1124			  "dot1xSuppEapolRespFramesTx=%u\n"
1125			  "dot1xSuppEapolReqIdFramesRx=%u\n"
1126			  "dot1xSuppEapolReqFramesRx=%u\n"
1127			  "dot1xSuppInvalidEapolFramesRx=%u\n"
1128			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
1129			  "dot1xSuppLastEapolFrameVersion=%u\n"
1130			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1131			  sm->dot1xSuppEapolFramesRx,
1132			  sm->dot1xSuppEapolFramesTx,
1133			  sm->dot1xSuppEapolStartFramesTx,
1134			  sm->dot1xSuppEapolLogoffFramesTx,
1135			  sm->dot1xSuppEapolRespFramesTx,
1136			  sm->dot1xSuppEapolReqIdFramesRx,
1137			  sm->dot1xSuppEapolReqFramesRx,
1138			  sm->dot1xSuppInvalidEapolFramesRx,
1139			  sm->dot1xSuppEapLengthErrorFramesRx,
1140			  sm->dot1xSuppLastEapolFrameVersion,
1141			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1142
1143	if (ret < 0 || (size_t) ret >= buflen - len)
1144		return len;
1145	len += ret;
1146
1147	return len;
1148}
1149#endif /* CONFIG_CTRL_IFACE */
1150
1151
1152/**
1153 * eapol_sm_rx_eapol - Process received EAPOL frames
1154 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1155 * @src: Source MAC address of the EAPOL packet
1156 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1157 * @len: Length of the EAPOL frame
1158 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1159 * -1 failure
1160 */
1161int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1162		      size_t len)
1163{
1164	const struct ieee802_1x_hdr *hdr;
1165	const struct ieee802_1x_eapol_key *key;
1166	int data_len;
1167	int res = 1;
1168	size_t plen;
1169
1170	if (sm == NULL)
1171		return 0;
1172	sm->dot1xSuppEapolFramesRx++;
1173	if (len < sizeof(*hdr)) {
1174		sm->dot1xSuppInvalidEapolFramesRx++;
1175		return 0;
1176	}
1177	hdr = (const struct ieee802_1x_hdr *) buf;
1178	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1179	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1180	if (hdr->version < EAPOL_VERSION) {
1181		/* TODO: backwards compatibility */
1182	}
1183	plen = be_to_host16(hdr->length);
1184	if (plen > len - sizeof(*hdr)) {
1185		sm->dot1xSuppEapLengthErrorFramesRx++;
1186		return 0;
1187	}
1188#ifdef CONFIG_WPS
1189	if (sm->conf.workaround &&
1190	    plen < len - sizeof(*hdr) &&
1191	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1192	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1193		const struct eap_hdr *ehdr =
1194			(const struct eap_hdr *) (hdr + 1);
1195		u16 elen;
1196
1197		elen = be_to_host16(ehdr->length);
1198		if (elen > plen && elen <= len - sizeof(*hdr)) {
1199			/*
1200			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1201			 * packets with too short EAPOL header length field
1202			 * (14 octets). This is fixed in firmware Ver.1.49.
1203			 * As a workaround, fix the EAPOL header based on the
1204			 * correct length in the EAP packet.
1205			 */
1206			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1207				   "payload length based on EAP header: "
1208				   "%d -> %d", (int) plen, elen);
1209			plen = elen;
1210		}
1211	}
1212#endif /* CONFIG_WPS */
1213	data_len = plen + sizeof(*hdr);
1214
1215	switch (hdr->type) {
1216	case IEEE802_1X_TYPE_EAP_PACKET:
1217		if (sm->cached_pmk) {
1218			/* Trying to use PMKSA caching, but Authenticator did
1219			 * not seem to have a matching entry. Need to restart
1220			 * EAPOL state machines.
1221			 */
1222			eapol_sm_abort_cached(sm);
1223		}
1224		wpabuf_free(sm->eapReqData);
1225		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1226		if (sm->eapReqData) {
1227			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1228				   "frame");
1229			sm->eapolEap = TRUE;
1230			eapol_sm_step(sm);
1231		}
1232		break;
1233	case IEEE802_1X_TYPE_EAPOL_KEY:
1234		if (plen < sizeof(*key)) {
1235			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1236				   "frame received");
1237			break;
1238		}
1239		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1240		if (key->type == EAPOL_KEY_TYPE_WPA ||
1241		    key->type == EAPOL_KEY_TYPE_RSN) {
1242			/* WPA Supplicant takes care of this frame. */
1243			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1244				   "frame in EAPOL state machines");
1245			res = 0;
1246			break;
1247		}
1248		if (key->type != EAPOL_KEY_TYPE_RC4) {
1249			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1250				   "EAPOL-Key type %d", key->type);
1251			break;
1252		}
1253		os_free(sm->last_rx_key);
1254		sm->last_rx_key = os_malloc(data_len);
1255		if (sm->last_rx_key) {
1256			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1257				   "frame");
1258			os_memcpy(sm->last_rx_key, buf, data_len);
1259			sm->last_rx_key_len = data_len;
1260			sm->rxKey = TRUE;
1261			eapol_sm_step(sm);
1262		}
1263		break;
1264	default:
1265		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1266			   hdr->type);
1267		sm->dot1xSuppInvalidEapolFramesRx++;
1268		break;
1269	}
1270
1271	return res;
1272}
1273
1274
1275/**
1276 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1277 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1278 *
1279 * Notify EAPOL state machine about transmitted EAPOL packet from an external
1280 * component, e.g., WPA. This will update the statistics.
1281 */
1282void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1283{
1284	if (sm)
1285		sm->dot1xSuppEapolFramesTx++;
1286}
1287
1288
1289/**
1290 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1291 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1292 * @enabled: New portEnabled value
1293 *
1294 * Notify EAPOL state machine about new portEnabled value.
1295 */
1296void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1297{
1298	if (sm == NULL)
1299		return;
1300	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1301		   "portEnabled=%d", enabled);
1302	sm->portEnabled = enabled;
1303	eapol_sm_step(sm);
1304}
1305
1306
1307/**
1308 * eapol_sm_notify_portValid - Notification about portValid change
1309 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1310 * @valid: New portValid value
1311 *
1312 * Notify EAPOL state machine about new portValid value.
1313 */
1314void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1315{
1316	if (sm == NULL)
1317		return;
1318	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1319		   "portValid=%d", valid);
1320	sm->portValid = valid;
1321	eapol_sm_step(sm);
1322}
1323
1324
1325/**
1326 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1327 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1328 * @success: %TRUE = set success, %FALSE = clear success
1329 *
1330 * Notify the EAPOL state machine that external event has forced EAP state to
1331 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1332 *
1333 * This function is called to update EAP state when WPA-PSK key handshake has
1334 * been completed successfully since WPA-PSK does not use EAP state machine.
1335 */
1336void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1337{
1338	if (sm == NULL)
1339		return;
1340	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1341		   "EAP success=%d", success);
1342	sm->eapSuccess = success;
1343	sm->altAccept = success;
1344	if (success)
1345		eap_notify_success(sm->eap);
1346	eapol_sm_step(sm);
1347}
1348
1349
1350/**
1351 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1352 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1353 * @fail: %TRUE = set failure, %FALSE = clear failure
1354 *
1355 * Notify EAPOL state machine that external event has forced EAP state to
1356 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1357 */
1358void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1359{
1360	if (sm == NULL)
1361		return;
1362	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1363		   "EAP fail=%d", fail);
1364	sm->eapFail = fail;
1365	sm->altReject = fail;
1366	eapol_sm_step(sm);
1367}
1368
1369
1370/**
1371 * eapol_sm_notify_config - Notification of EAPOL configuration change
1372 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1373 * @config: Pointer to current network EAP configuration
1374 * @conf: Pointer to EAPOL configuration data
1375 *
1376 * Notify EAPOL state machine that configuration has changed. config will be
1377 * stored as a backpointer to network configuration. This can be %NULL to clear
1378 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1379 * data. If conf is %NULL, this part of the configuration change will be
1380 * skipped.
1381 */
1382void eapol_sm_notify_config(struct eapol_sm *sm,
1383			    struct eap_peer_config *config,
1384			    const struct eapol_config *conf)
1385{
1386	if (sm == NULL)
1387		return;
1388
1389	sm->config = config;
1390
1391	if (conf == NULL)
1392		return;
1393
1394	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1395	sm->conf.required_keys = conf->required_keys;
1396	sm->conf.fast_reauth = conf->fast_reauth;
1397	sm->conf.workaround = conf->workaround;
1398	if (sm->eap) {
1399		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1400		eap_set_workaround(sm->eap, conf->workaround);
1401		eap_set_force_disabled(sm->eap, conf->eap_disabled);
1402	}
1403}
1404
1405
1406/**
1407 * eapol_sm_get_key - Get master session key (MSK) from EAP
1408 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1409 * @key: Pointer for key buffer
1410 * @len: Number of bytes to copy to key
1411 * Returns: 0 on success (len of key available), maximum available key len
1412 * (>0) if key is available but it is shorter than len, or -1 on failure.
1413 *
1414 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1415 * is available only after a successful authentication.
1416 */
1417int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1418{
1419	const u8 *eap_key;
1420	size_t eap_len;
1421
1422	if (sm == NULL || !eap_key_available(sm->eap)) {
1423		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1424		return -1;
1425	}
1426	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1427	if (eap_key == NULL) {
1428		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1429		return -1;
1430	}
1431	if (len > eap_len) {
1432		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1433			   "available (len=%lu)",
1434			   (unsigned long) len, (unsigned long) eap_len);
1435		return eap_len;
1436	}
1437	os_memcpy(key, eap_key, len);
1438	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1439		   (unsigned long) len);
1440	return 0;
1441}
1442
1443
1444/**
1445 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1446 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1447 * @logoff: Whether command was logoff
1448 *
1449 * Notify EAPOL state machines that user requested logon/logoff.
1450 */
1451void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1452{
1453	if (sm) {
1454		sm->userLogoff = logoff;
1455		eapol_sm_step(sm);
1456	}
1457}
1458
1459
1460/**
1461 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1462 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1463 *
1464 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1465 * to move EAPOL and EAP state machines into authenticated/successful state.
1466 */
1467void eapol_sm_notify_cached(struct eapol_sm *sm)
1468{
1469	if (sm == NULL)
1470		return;
1471	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1472	sm->eapSuccess = TRUE;
1473	eap_notify_success(sm->eap);
1474	eapol_sm_step(sm);
1475}
1476
1477
1478/**
1479 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1480 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1481 * @attempt: Whether PMKSA caching is tried
1482 *
1483 * Notify EAPOL state machines whether PMKSA caching is used.
1484 */
1485void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1486{
1487	if (sm == NULL)
1488		return;
1489	if (attempt) {
1490		wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1491		sm->cached_pmk = TRUE;
1492	} else {
1493		wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1494		sm->cached_pmk = FALSE;
1495	}
1496}
1497
1498
1499static void eapol_sm_abort_cached(struct eapol_sm *sm)
1500{
1501	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1502		   "doing full EAP authentication");
1503	if (sm == NULL)
1504		return;
1505	sm->cached_pmk = FALSE;
1506	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1507	sm->suppPortStatus = Unauthorized;
1508	eapol_sm_set_port_unauthorized(sm);
1509
1510	/* Make sure we do not start sending EAPOL-Start frames first, but
1511	 * instead move to RESTART state to start EAPOL authentication. */
1512	sm->startWhen = 3;
1513	eapol_enable_timer_tick(sm);
1514
1515	if (sm->ctx->aborted_cached)
1516		sm->ctx->aborted_cached(sm->ctx->ctx);
1517}
1518
1519
1520/**
1521 * eapol_sm_register_scard_ctx - Notification of smart card context
1522 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1523 * @ctx: Context data for smart card operations
1524 *
1525 * Notify EAPOL state machines of context data for smart card operations. This
1526 * context data will be used as a parameter for scard_*() functions.
1527 */
1528void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1529{
1530	if (sm) {
1531		sm->ctx->scard_ctx = ctx;
1532		eap_register_scard_ctx(sm->eap, ctx);
1533	}
1534}
1535
1536
1537/**
1538 * eapol_sm_notify_portControl - Notification of portControl changes
1539 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1540 * @portControl: New value for portControl variable
1541 *
1542 * Notify EAPOL state machines that portControl variable has changed.
1543 */
1544void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1545{
1546	if (sm == NULL)
1547		return;
1548	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1549		   "portControl=%s", eapol_port_control(portControl));
1550	sm->portControl = portControl;
1551	eapol_sm_step(sm);
1552}
1553
1554
1555/**
1556 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1557 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1558 *
1559 * Notify EAPOL state machines that a monitor was attached to the control
1560 * interface to trigger re-sending of pending requests for user input.
1561 */
1562void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1563{
1564	if (sm == NULL)
1565		return;
1566	eap_sm_notify_ctrl_attached(sm->eap);
1567}
1568
1569
1570/**
1571 * eapol_sm_notify_ctrl_response - Notification of received user input
1572 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1573 *
1574 * Notify EAPOL state machines that a control response, i.e., user
1575 * input, was received in order to trigger retrying of a pending EAP request.
1576 */
1577void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1578{
1579	if (sm == NULL)
1580		return;
1581	if (sm->eapReqData && !sm->eapReq) {
1582		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1583			   "input) notification - retrying pending EAP "
1584			   "Request");
1585		sm->eapolEap = TRUE;
1586		sm->eapReq = TRUE;
1587		eapol_sm_step(sm);
1588	}
1589}
1590
1591
1592/**
1593 * eapol_sm_request_reauth - Request reauthentication
1594 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1595 *
1596 * This function can be used to request EAPOL reauthentication, e.g., when the
1597 * current PMKSA entry is nearing expiration.
1598 */
1599void eapol_sm_request_reauth(struct eapol_sm *sm)
1600{
1601	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1602		return;
1603	eapol_sm_txStart(sm);
1604}
1605
1606
1607/**
1608 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1609 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1610 * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1611 * machine loop (eapol_sm_step())
1612 *
1613 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1614 * successful authentication. This is used to recover from dropped EAP-Success
1615 * messages.
1616 */
1617void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1618{
1619	if (sm == NULL)
1620		return;
1621	eap_notify_lower_layer_success(sm->eap);
1622	if (!in_eapol_sm)
1623		eapol_sm_step(sm);
1624}
1625
1626
1627/**
1628 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1629 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1630 */
1631void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1632{
1633	if (sm)
1634		eap_invalidate_cached_session(sm->eap);
1635}
1636
1637
1638static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1639{
1640	struct eapol_sm *sm = ctx;
1641	return sm ? sm->config : NULL;
1642}
1643
1644
1645static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1646{
1647	struct eapol_sm *sm = ctx;
1648	if (sm == NULL || sm->eapReqData == NULL)
1649		return NULL;
1650
1651	return sm->eapReqData;
1652}
1653
1654
1655static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1656{
1657	struct eapol_sm *sm = ctx;
1658	if (sm == NULL)
1659		return FALSE;
1660	switch (variable) {
1661	case EAPOL_eapSuccess:
1662		return sm->eapSuccess;
1663	case EAPOL_eapRestart:
1664		return sm->eapRestart;
1665	case EAPOL_eapFail:
1666		return sm->eapFail;
1667	case EAPOL_eapResp:
1668		return sm->eapResp;
1669	case EAPOL_eapNoResp:
1670		return sm->eapNoResp;
1671	case EAPOL_eapReq:
1672		return sm->eapReq;
1673	case EAPOL_portEnabled:
1674		return sm->portEnabled;
1675	case EAPOL_altAccept:
1676		return sm->altAccept;
1677	case EAPOL_altReject:
1678		return sm->altReject;
1679	}
1680	return FALSE;
1681}
1682
1683
1684static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1685			      Boolean value)
1686{
1687	struct eapol_sm *sm = ctx;
1688	if (sm == NULL)
1689		return;
1690	switch (variable) {
1691	case EAPOL_eapSuccess:
1692		sm->eapSuccess = value;
1693		break;
1694	case EAPOL_eapRestart:
1695		sm->eapRestart = value;
1696		break;
1697	case EAPOL_eapFail:
1698		sm->eapFail = value;
1699		break;
1700	case EAPOL_eapResp:
1701		sm->eapResp = value;
1702		break;
1703	case EAPOL_eapNoResp:
1704		sm->eapNoResp = value;
1705		break;
1706	case EAPOL_eapReq:
1707		sm->eapReq = value;
1708		break;
1709	case EAPOL_portEnabled:
1710		sm->portEnabled = value;
1711		break;
1712	case EAPOL_altAccept:
1713		sm->altAccept = value;
1714		break;
1715	case EAPOL_altReject:
1716		sm->altReject = value;
1717		break;
1718	}
1719}
1720
1721
1722static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1723{
1724	struct eapol_sm *sm = ctx;
1725	if (sm == NULL)
1726		return 0;
1727	switch (variable) {
1728	case EAPOL_idleWhile:
1729		return sm->idleWhile;
1730	}
1731	return 0;
1732}
1733
1734
1735static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1736			     unsigned int value)
1737{
1738	struct eapol_sm *sm = ctx;
1739	if (sm == NULL)
1740		return;
1741	switch (variable) {
1742	case EAPOL_idleWhile:
1743		sm->idleWhile = value;
1744		if (sm->idleWhile > 0)
1745			eapol_enable_timer_tick(sm);
1746		break;
1747	}
1748}
1749
1750
1751static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1752{
1753#ifndef CONFIG_NO_CONFIG_BLOBS
1754	struct eapol_sm *sm = ctx;
1755	if (sm && sm->ctx && sm->ctx->set_config_blob)
1756		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1757#endif /* CONFIG_NO_CONFIG_BLOBS */
1758}
1759
1760
1761static const struct wpa_config_blob *
1762eapol_sm_get_config_blob(void *ctx, const char *name)
1763{
1764#ifndef CONFIG_NO_CONFIG_BLOBS
1765	struct eapol_sm *sm = ctx;
1766	if (sm && sm->ctx && sm->ctx->get_config_blob)
1767		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1768	else
1769		return NULL;
1770#else /* CONFIG_NO_CONFIG_BLOBS */
1771	return NULL;
1772#endif /* CONFIG_NO_CONFIG_BLOBS */
1773}
1774
1775
1776static void eapol_sm_notify_pending(void *ctx)
1777{
1778	struct eapol_sm *sm = ctx;
1779	if (sm == NULL)
1780		return;
1781	if (sm->eapReqData && !sm->eapReq) {
1782		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1783			   "state machine - retrying pending EAP Request");
1784		sm->eapolEap = TRUE;
1785		sm->eapReq = TRUE;
1786		eapol_sm_step(sm);
1787	}
1788}
1789
1790
1791#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1792static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
1793				      const char *txt)
1794{
1795	struct eapol_sm *sm = ctx;
1796	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1797	if (sm->ctx->eap_param_needed)
1798		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1799}
1800#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1801#define eapol_sm_eap_param_needed NULL
1802#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1803
1804static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
1805				 const char *cert_hash,
1806				 const struct wpabuf *cert)
1807{
1808	struct eapol_sm *sm = ctx;
1809	if (sm->ctx->cert_cb)
1810		sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
1811				 cert_hash, cert);
1812}
1813
1814
1815static void eapol_sm_notify_status(void *ctx, const char *status,
1816				   const char *parameter)
1817{
1818	struct eapol_sm *sm = ctx;
1819
1820	if (sm->ctx->status_cb)
1821		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
1822}
1823
1824
1825static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
1826{
1827	struct eapol_sm *sm = ctx;
1828
1829	if (sm->ctx->set_anon_id)
1830		sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
1831}
1832
1833
1834static struct eapol_callbacks eapol_cb =
1835{
1836	eapol_sm_get_config,
1837	eapol_sm_get_bool,
1838	eapol_sm_set_bool,
1839	eapol_sm_get_int,
1840	eapol_sm_set_int,
1841	eapol_sm_get_eapReqData,
1842	eapol_sm_set_config_blob,
1843	eapol_sm_get_config_blob,
1844	eapol_sm_notify_pending,
1845	eapol_sm_eap_param_needed,
1846	eapol_sm_notify_cert,
1847	eapol_sm_notify_status,
1848	eapol_sm_set_anon_id
1849};
1850
1851
1852/**
1853 * eapol_sm_init - Initialize EAPOL state machine
1854 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1855 * and EAPOL state machine will free it in eapol_sm_deinit()
1856 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1857 *
1858 * Allocate and initialize an EAPOL state machine.
1859 */
1860struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1861{
1862	struct eapol_sm *sm;
1863	struct eap_config conf;
1864	sm = os_zalloc(sizeof(*sm));
1865	if (sm == NULL)
1866		return NULL;
1867	sm->ctx = ctx;
1868
1869	sm->portControl = Auto;
1870
1871	/* Supplicant PAE state machine */
1872	sm->heldPeriod = 60;
1873	sm->startPeriod = 30;
1874	sm->maxStart = 3;
1875
1876	/* Supplicant Backend state machine */
1877	sm->authPeriod = 30;
1878
1879	os_memset(&conf, 0, sizeof(conf));
1880	conf.opensc_engine_path = ctx->opensc_engine_path;
1881	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1882	conf.pkcs11_module_path = ctx->pkcs11_module_path;
1883	conf.wps = ctx->wps;
1884	conf.cert_in_cb = ctx->cert_in_cb;
1885
1886	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1887	if (sm->eap == NULL) {
1888		os_free(sm);
1889		return NULL;
1890	}
1891
1892	/* Initialize EAPOL state machines */
1893	sm->initialize = TRUE;
1894	eapol_sm_step(sm);
1895	sm->initialize = FALSE;
1896	eapol_sm_step(sm);
1897
1898	sm->timer_tick_enabled = 1;
1899	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1900
1901	return sm;
1902}
1903
1904
1905/**
1906 * eapol_sm_deinit - Deinitialize EAPOL state machine
1907 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1908 *
1909 * Deinitialize and free EAPOL state machine.
1910 */
1911void eapol_sm_deinit(struct eapol_sm *sm)
1912{
1913	if (sm == NULL)
1914		return;
1915	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1916	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1917	eap_peer_sm_deinit(sm->eap);
1918	os_free(sm->last_rx_key);
1919	wpabuf_free(sm->eapReqData);
1920	os_free(sm->ctx);
1921	os_free(sm);
1922}
1923
1924
1925void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
1926			     struct ext_password_data *ext)
1927{
1928	if (sm && sm->eap)
1929		eap_sm_set_ext_pw_ctx(sm->eap, ext);
1930}
1931
1932
1933int eapol_sm_failed(struct eapol_sm *sm)
1934{
1935	if (sm == NULL)
1936		return 0;
1937	return !sm->eapSuccess && sm->eapFail;
1938}
1939