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