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