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#ifdef CONFIG_CTRL_IFACE
1033/**
1034 * eapol_sm_get_status - Get EAPOL state machine status
1035 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1036 * @buf: Buffer for status information
1037 * @buflen: Maximum buffer length
1038 * @verbose: Whether to include verbose status information
1039 * Returns: Number of bytes written to buf.
1040 *
1041 * Query EAPOL state machine for status information. This function fills in a
1042 * text area with current status information from the EAPOL state machine. If
1043 * the buffer (buf) is not large enough, status information will be truncated
1044 * to fit the buffer.
1045 */
1046int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1047			int verbose)
1048{
1049	int len, ret;
1050	if (sm == NULL)
1051		return 0;
1052
1053	len = os_snprintf(buf, buflen,
1054			  "Supplicant PAE state=%s\n"
1055			  "suppPortStatus=%s\n",
1056			  eapol_supp_pae_state(sm->SUPP_PAE_state),
1057			  eapol_port_status(sm->suppPortStatus));
1058	if (len < 0 || (size_t) len >= buflen)
1059		return 0;
1060
1061	if (verbose) {
1062		ret = os_snprintf(buf + len, buflen - len,
1063				  "heldPeriod=%u\n"
1064				  "authPeriod=%u\n"
1065				  "startPeriod=%u\n"
1066				  "maxStart=%u\n"
1067				  "portControl=%s\n"
1068				  "Supplicant Backend state=%s\n",
1069				  sm->heldPeriod,
1070				  sm->authPeriod,
1071				  sm->startPeriod,
1072				  sm->maxStart,
1073				  eapol_port_control(sm->portControl),
1074				  eapol_supp_be_state(sm->SUPP_BE_state));
1075		if (ret < 0 || (size_t) ret >= buflen - len)
1076			return len;
1077		len += ret;
1078	}
1079
1080	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1081
1082	return len;
1083}
1084
1085
1086/**
1087 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1088 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1089 * @buf: Buffer for MIB information
1090 * @buflen: Maximum buffer length
1091 * Returns: Number of bytes written to buf.
1092 *
1093 * Query EAPOL state machine for MIB information. This function fills in a
1094 * text area with current MIB information from the EAPOL state machine. If
1095 * the buffer (buf) is not large enough, MIB information will be truncated to
1096 * fit the buffer.
1097 */
1098int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1099{
1100	size_t len;
1101	int ret;
1102
1103	if (sm == NULL)
1104		return 0;
1105	ret = os_snprintf(buf, buflen,
1106			  "dot1xSuppPaeState=%d\n"
1107			  "dot1xSuppHeldPeriod=%u\n"
1108			  "dot1xSuppAuthPeriod=%u\n"
1109			  "dot1xSuppStartPeriod=%u\n"
1110			  "dot1xSuppMaxStart=%u\n"
1111			  "dot1xSuppSuppControlledPortStatus=%s\n"
1112			  "dot1xSuppBackendPaeState=%d\n",
1113			  sm->SUPP_PAE_state,
1114			  sm->heldPeriod,
1115			  sm->authPeriod,
1116			  sm->startPeriod,
1117			  sm->maxStart,
1118			  sm->suppPortStatus == Authorized ?
1119			  "Authorized" : "Unauthorized",
1120			  sm->SUPP_BE_state);
1121
1122	if (ret < 0 || (size_t) ret >= buflen)
1123		return 0;
1124	len = ret;
1125
1126	ret = os_snprintf(buf + len, buflen - len,
1127			  "dot1xSuppEapolFramesRx=%u\n"
1128			  "dot1xSuppEapolFramesTx=%u\n"
1129			  "dot1xSuppEapolStartFramesTx=%u\n"
1130			  "dot1xSuppEapolLogoffFramesTx=%u\n"
1131			  "dot1xSuppEapolRespFramesTx=%u\n"
1132			  "dot1xSuppEapolReqIdFramesRx=%u\n"
1133			  "dot1xSuppEapolReqFramesRx=%u\n"
1134			  "dot1xSuppInvalidEapolFramesRx=%u\n"
1135			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
1136			  "dot1xSuppLastEapolFrameVersion=%u\n"
1137			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1138			  sm->dot1xSuppEapolFramesRx,
1139			  sm->dot1xSuppEapolFramesTx,
1140			  sm->dot1xSuppEapolStartFramesTx,
1141			  sm->dot1xSuppEapolLogoffFramesTx,
1142			  sm->dot1xSuppEapolRespFramesTx,
1143			  sm->dot1xSuppEapolReqIdFramesRx,
1144			  sm->dot1xSuppEapolReqFramesRx,
1145			  sm->dot1xSuppInvalidEapolFramesRx,
1146			  sm->dot1xSuppEapLengthErrorFramesRx,
1147			  sm->dot1xSuppLastEapolFrameVersion,
1148			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1149
1150	if (ret < 0 || (size_t) ret >= buflen - len)
1151		return len;
1152	len += ret;
1153
1154	return len;
1155}
1156#endif /* CONFIG_CTRL_IFACE */
1157
1158
1159/**
1160 * eapol_sm_rx_eapol - Process received EAPOL frames
1161 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1162 * @src: Source MAC address of the EAPOL packet
1163 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1164 * @len: Length of the EAPOL frame
1165 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1166 * -1 failure
1167 */
1168int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1169		      size_t len)
1170{
1171	const struct ieee802_1x_hdr *hdr;
1172	const struct ieee802_1x_eapol_key *key;
1173	int data_len;
1174	int res = 1;
1175	size_t plen;
1176
1177	if (sm == NULL)
1178		return 0;
1179	sm->dot1xSuppEapolFramesRx++;
1180	if (len < sizeof(*hdr)) {
1181		sm->dot1xSuppInvalidEapolFramesRx++;
1182		return 0;
1183	}
1184	hdr = (const struct ieee802_1x_hdr *) buf;
1185	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1186	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1187	if (hdr->version < EAPOL_VERSION) {
1188		/* TODO: backwards compatibility */
1189	}
1190	plen = be_to_host16(hdr->length);
1191	if (plen > len - sizeof(*hdr)) {
1192		sm->dot1xSuppEapLengthErrorFramesRx++;
1193		return 0;
1194	}
1195#ifdef CONFIG_WPS
1196	if (sm->conf.workaround &&
1197	    plen < len - sizeof(*hdr) &&
1198	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1199	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1200		const struct eap_hdr *ehdr =
1201			(const struct eap_hdr *) (hdr + 1);
1202		u16 elen;
1203
1204		elen = be_to_host16(ehdr->length);
1205		if (elen > plen && elen <= len - sizeof(*hdr)) {
1206			/*
1207			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1208			 * packets with too short EAPOL header length field
1209			 * (14 octets). This is fixed in firmware Ver.1.49.
1210			 * As a workaround, fix the EAPOL header based on the
1211			 * correct length in the EAP packet.
1212			 */
1213			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1214				   "payload length based on EAP header: "
1215				   "%d -> %d", (int) plen, elen);
1216			plen = elen;
1217		}
1218	}
1219#endif /* CONFIG_WPS */
1220	data_len = plen + sizeof(*hdr);
1221
1222	switch (hdr->type) {
1223	case IEEE802_1X_TYPE_EAP_PACKET:
1224		if (sm->cached_pmk) {
1225			/* Trying to use PMKSA caching, but Authenticator did
1226			 * not seem to have a matching entry. Need to restart
1227			 * EAPOL state machines.
1228			 */
1229			eapol_sm_abort_cached(sm);
1230		}
1231		wpabuf_free(sm->eapReqData);
1232		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1233		if (sm->eapReqData) {
1234			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1235				   "frame");
1236			sm->eapolEap = TRUE;
1237			eapol_sm_step(sm);
1238		}
1239		break;
1240	case IEEE802_1X_TYPE_EAPOL_KEY:
1241		if (plen < sizeof(*key)) {
1242			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1243				   "frame received");
1244			break;
1245		}
1246		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1247		if (key->type == EAPOL_KEY_TYPE_WPA ||
1248		    key->type == EAPOL_KEY_TYPE_RSN) {
1249			/* WPA Supplicant takes care of this frame. */
1250			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1251				   "frame in EAPOL state machines");
1252			res = 0;
1253			break;
1254		}
1255		if (key->type != EAPOL_KEY_TYPE_RC4) {
1256			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1257				   "EAPOL-Key type %d", key->type);
1258			break;
1259		}
1260		os_free(sm->last_rx_key);
1261		sm->last_rx_key = os_malloc(data_len);
1262		if (sm->last_rx_key) {
1263			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1264				   "frame");
1265			os_memcpy(sm->last_rx_key, buf, data_len);
1266			sm->last_rx_key_len = data_len;
1267			sm->rxKey = TRUE;
1268			eapol_sm_step(sm);
1269		}
1270		break;
1271	default:
1272		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1273			   hdr->type);
1274		sm->dot1xSuppInvalidEapolFramesRx++;
1275		break;
1276	}
1277
1278	return res;
1279}
1280
1281
1282/**
1283 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1284 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1285 *
1286 * Notify EAPOL state machine about transmitted EAPOL packet from an external
1287 * component, e.g., WPA. This will update the statistics.
1288 */
1289void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1290{
1291	if (sm)
1292		sm->dot1xSuppEapolFramesTx++;
1293}
1294
1295
1296/**
1297 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1298 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1299 * @enabled: New portEnabled value
1300 *
1301 * Notify EAPOL state machine about new portEnabled value.
1302 */
1303void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1304{
1305	if (sm == NULL)
1306		return;
1307	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1308		   "portEnabled=%d", enabled);
1309	sm->portEnabled = enabled;
1310	eapol_sm_step(sm);
1311}
1312
1313
1314/**
1315 * eapol_sm_notify_portValid - Notification about portValid change
1316 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1317 * @valid: New portValid value
1318 *
1319 * Notify EAPOL state machine about new portValid value.
1320 */
1321void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1322{
1323	if (sm == NULL)
1324		return;
1325	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1326		   "portValid=%d", valid);
1327	sm->portValid = valid;
1328	eapol_sm_step(sm);
1329}
1330
1331
1332/**
1333 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1334 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1335 * @success: %TRUE = set success, %FALSE = clear success
1336 *
1337 * Notify the EAPOL state machine that external event has forced EAP state to
1338 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1339 *
1340 * This function is called to update EAP state when WPA-PSK key handshake has
1341 * been completed successfully since WPA-PSK does not use EAP state machine.
1342 */
1343void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1344{
1345	if (sm == NULL)
1346		return;
1347	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1348		   "EAP success=%d", success);
1349	sm->eapSuccess = success;
1350	sm->altAccept = success;
1351	if (success)
1352		eap_notify_success(sm->eap);
1353	eapol_sm_step(sm);
1354}
1355
1356
1357/**
1358 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1359 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1360 * @fail: %TRUE = set failure, %FALSE = clear failure
1361 *
1362 * Notify EAPOL state machine that external event has forced EAP state to
1363 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1364 */
1365void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1366{
1367	if (sm == NULL)
1368		return;
1369	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1370		   "EAP fail=%d", fail);
1371	sm->eapFail = fail;
1372	sm->altReject = fail;
1373	eapol_sm_step(sm);
1374}
1375
1376
1377/**
1378 * eapol_sm_notify_config - Notification of EAPOL configuration change
1379 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1380 * @config: Pointer to current network EAP configuration
1381 * @conf: Pointer to EAPOL configuration data
1382 *
1383 * Notify EAPOL state machine that configuration has changed. config will be
1384 * stored as a backpointer to network configuration. This can be %NULL to clear
1385 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1386 * data. If conf is %NULL, this part of the configuration change will be
1387 * skipped.
1388 */
1389void eapol_sm_notify_config(struct eapol_sm *sm,
1390			    struct eap_peer_config *config,
1391			    const struct eapol_config *conf)
1392{
1393	if (sm == NULL)
1394		return;
1395
1396	sm->config = config;
1397
1398	if (conf == NULL)
1399		return;
1400
1401	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1402	sm->conf.required_keys = conf->required_keys;
1403	sm->conf.fast_reauth = conf->fast_reauth;
1404	sm->conf.workaround = conf->workaround;
1405	if (sm->eap) {
1406		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1407		eap_set_workaround(sm->eap, conf->workaround);
1408		eap_set_force_disabled(sm->eap, conf->eap_disabled);
1409	}
1410}
1411
1412
1413/**
1414 * eapol_sm_get_key - Get master session key (MSK) from EAP
1415 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1416 * @key: Pointer for key buffer
1417 * @len: Number of bytes to copy to key
1418 * Returns: 0 on success (len of key available), maximum available key len
1419 * (>0) if key is available but it is shorter than len, or -1 on failure.
1420 *
1421 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1422 * is available only after a successful authentication.
1423 */
1424int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1425{
1426	const u8 *eap_key;
1427	size_t eap_len;
1428
1429	if (sm == NULL || !eap_key_available(sm->eap)) {
1430		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1431		return -1;
1432	}
1433	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1434	if (eap_key == NULL) {
1435		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1436		return -1;
1437	}
1438	if (len > eap_len) {
1439		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1440			   "available (len=%lu)",
1441			   (unsigned long) len, (unsigned long) eap_len);
1442		return eap_len;
1443	}
1444	os_memcpy(key, eap_key, len);
1445	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1446		   (unsigned long) len);
1447	return 0;
1448}
1449
1450
1451/**
1452 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1453 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1454 * @logoff: Whether command was logoff
1455 *
1456 * Notify EAPOL state machines that user requested logon/logoff.
1457 */
1458void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1459{
1460	if (sm) {
1461		sm->userLogoff = logoff;
1462		eapol_sm_step(sm);
1463	}
1464}
1465
1466
1467/**
1468 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1469 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1470 *
1471 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1472 * to move EAPOL and EAP state machines into authenticated/successful state.
1473 */
1474void eapol_sm_notify_cached(struct eapol_sm *sm)
1475{
1476	if (sm == NULL)
1477		return;
1478	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1479	sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1480	sm->suppPortStatus = Authorized;
1481	eapol_sm_set_port_authorized(sm);
1482	sm->portValid = TRUE;
1483	eap_notify_success(sm->eap);
1484	eapol_sm_step(sm);
1485}
1486
1487
1488/**
1489 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1490 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1491 * @attempt: Whether PMKSA caching is tried
1492 *
1493 * Notify EAPOL state machines whether PMKSA caching is used.
1494 */
1495void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1496{
1497	if (sm == NULL)
1498		return;
1499	if (attempt) {
1500		wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1501		sm->cached_pmk = TRUE;
1502	} else {
1503		wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1504		sm->cached_pmk = FALSE;
1505	}
1506}
1507
1508
1509static void eapol_sm_abort_cached(struct eapol_sm *sm)
1510{
1511	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1512		   "doing full EAP authentication");
1513	if (sm == NULL)
1514		return;
1515	sm->cached_pmk = FALSE;
1516	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1517	sm->suppPortStatus = Unauthorized;
1518	eapol_sm_set_port_unauthorized(sm);
1519
1520	/* Make sure we do not start sending EAPOL-Start frames first, but
1521	 * instead move to RESTART state to start EAPOL authentication. */
1522	sm->startWhen = 3;
1523	eapol_enable_timer_tick(sm);
1524
1525	if (sm->ctx->aborted_cached)
1526		sm->ctx->aborted_cached(sm->ctx->ctx);
1527}
1528
1529
1530/**
1531 * eapol_sm_register_scard_ctx - Notification of smart card context
1532 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1533 * @ctx: Context data for smart card operations
1534 *
1535 * Notify EAPOL state machines of context data for smart card operations. This
1536 * context data will be used as a parameter for scard_*() functions.
1537 */
1538void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1539{
1540	if (sm) {
1541		sm->ctx->scard_ctx = ctx;
1542		eap_register_scard_ctx(sm->eap, ctx);
1543	}
1544}
1545
1546
1547/**
1548 * eapol_sm_notify_portControl - Notification of portControl changes
1549 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1550 * @portControl: New value for portControl variable
1551 *
1552 * Notify EAPOL state machines that portControl variable has changed.
1553 */
1554void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1555{
1556	if (sm == NULL)
1557		return;
1558	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1559		   "portControl=%s", eapol_port_control(portControl));
1560	sm->portControl = portControl;
1561	eapol_sm_step(sm);
1562}
1563
1564
1565/**
1566 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1567 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1568 *
1569 * Notify EAPOL state machines that a monitor was attached to the control
1570 * interface to trigger re-sending of pending requests for user input.
1571 */
1572void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1573{
1574	if (sm == NULL)
1575		return;
1576	eap_sm_notify_ctrl_attached(sm->eap);
1577}
1578
1579
1580/**
1581 * eapol_sm_notify_ctrl_response - Notification of received user input
1582 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1583 *
1584 * Notify EAPOL state machines that a control response, i.e., user
1585 * input, was received in order to trigger retrying of a pending EAP request.
1586 */
1587void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1588{
1589	if (sm == NULL)
1590		return;
1591	if (sm->eapReqData && !sm->eapReq) {
1592		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1593			   "input) notification - retrying pending EAP "
1594			   "Request");
1595		sm->eapolEap = TRUE;
1596		sm->eapReq = TRUE;
1597		eapol_sm_step(sm);
1598	}
1599}
1600
1601
1602/**
1603 * eapol_sm_request_reauth - Request reauthentication
1604 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1605 *
1606 * This function can be used to request EAPOL reauthentication, e.g., when the
1607 * current PMKSA entry is nearing expiration.
1608 */
1609void eapol_sm_request_reauth(struct eapol_sm *sm)
1610{
1611	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1612		return;
1613	eapol_sm_txStart(sm);
1614}
1615
1616
1617/**
1618 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1619 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1620 * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1621 * machine loop (eapol_sm_step())
1622 *
1623 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1624 * successful authentication. This is used to recover from dropped EAP-Success
1625 * messages.
1626 */
1627void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1628{
1629	if (sm == NULL)
1630		return;
1631	eap_notify_lower_layer_success(sm->eap);
1632	if (!in_eapol_sm)
1633		eapol_sm_step(sm);
1634}
1635
1636
1637/**
1638 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1639 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1640 */
1641void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1642{
1643	if (sm)
1644		eap_invalidate_cached_session(sm->eap);
1645}
1646
1647
1648static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1649{
1650	struct eapol_sm *sm = ctx;
1651	return sm ? sm->config : NULL;
1652}
1653
1654
1655static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1656{
1657	struct eapol_sm *sm = ctx;
1658	if (sm == NULL || sm->eapReqData == NULL)
1659		return NULL;
1660
1661	return sm->eapReqData;
1662}
1663
1664
1665static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1666{
1667	struct eapol_sm *sm = ctx;
1668	if (sm == NULL)
1669		return FALSE;
1670	switch (variable) {
1671	case EAPOL_eapSuccess:
1672		return sm->eapSuccess;
1673	case EAPOL_eapRestart:
1674		return sm->eapRestart;
1675	case EAPOL_eapFail:
1676		return sm->eapFail;
1677	case EAPOL_eapResp:
1678		return sm->eapResp;
1679	case EAPOL_eapNoResp:
1680		return sm->eapNoResp;
1681	case EAPOL_eapReq:
1682		return sm->eapReq;
1683	case EAPOL_portEnabled:
1684		return sm->portEnabled;
1685	case EAPOL_altAccept:
1686		return sm->altAccept;
1687	case EAPOL_altReject:
1688		return sm->altReject;
1689	}
1690	return FALSE;
1691}
1692
1693
1694static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1695			      Boolean value)
1696{
1697	struct eapol_sm *sm = ctx;
1698	if (sm == NULL)
1699		return;
1700	switch (variable) {
1701	case EAPOL_eapSuccess:
1702		sm->eapSuccess = value;
1703		break;
1704	case EAPOL_eapRestart:
1705		sm->eapRestart = value;
1706		break;
1707	case EAPOL_eapFail:
1708		sm->eapFail = value;
1709		break;
1710	case EAPOL_eapResp:
1711		sm->eapResp = value;
1712		break;
1713	case EAPOL_eapNoResp:
1714		sm->eapNoResp = value;
1715		break;
1716	case EAPOL_eapReq:
1717		sm->eapReq = value;
1718		break;
1719	case EAPOL_portEnabled:
1720		sm->portEnabled = value;
1721		break;
1722	case EAPOL_altAccept:
1723		sm->altAccept = value;
1724		break;
1725	case EAPOL_altReject:
1726		sm->altReject = value;
1727		break;
1728	}
1729}
1730
1731
1732static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1733{
1734	struct eapol_sm *sm = ctx;
1735	if (sm == NULL)
1736		return 0;
1737	switch (variable) {
1738	case EAPOL_idleWhile:
1739		return sm->idleWhile;
1740	}
1741	return 0;
1742}
1743
1744
1745static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1746			     unsigned int value)
1747{
1748	struct eapol_sm *sm = ctx;
1749	if (sm == NULL)
1750		return;
1751	switch (variable) {
1752	case EAPOL_idleWhile:
1753		sm->idleWhile = value;
1754		eapol_enable_timer_tick(sm);
1755		break;
1756	}
1757}
1758
1759
1760static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1761{
1762#ifndef CONFIG_NO_CONFIG_BLOBS
1763	struct eapol_sm *sm = ctx;
1764	if (sm && sm->ctx && sm->ctx->set_config_blob)
1765		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1766#endif /* CONFIG_NO_CONFIG_BLOBS */
1767}
1768
1769
1770static const struct wpa_config_blob *
1771eapol_sm_get_config_blob(void *ctx, const char *name)
1772{
1773#ifndef CONFIG_NO_CONFIG_BLOBS
1774	struct eapol_sm *sm = ctx;
1775	if (sm && sm->ctx && sm->ctx->get_config_blob)
1776		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1777	else
1778		return NULL;
1779#else /* CONFIG_NO_CONFIG_BLOBS */
1780	return NULL;
1781#endif /* CONFIG_NO_CONFIG_BLOBS */
1782}
1783
1784
1785static void eapol_sm_notify_pending(void *ctx)
1786{
1787	struct eapol_sm *sm = ctx;
1788	if (sm == NULL)
1789		return;
1790	if (sm->eapReqData && !sm->eapReq) {
1791		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1792			   "state machine - retrying pending EAP Request");
1793		sm->eapolEap = TRUE;
1794		sm->eapReq = TRUE;
1795		eapol_sm_step(sm);
1796	}
1797}
1798
1799
1800#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1801static void eapol_sm_eap_param_needed(void *ctx, const char *field,
1802				      const char *txt)
1803{
1804	struct eapol_sm *sm = ctx;
1805	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1806	if (sm->ctx->eap_param_needed)
1807		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1808}
1809#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1810#define eapol_sm_eap_param_needed NULL
1811#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1812
1813
1814static struct eapol_callbacks eapol_cb =
1815{
1816	eapol_sm_get_config,
1817	eapol_sm_get_bool,
1818	eapol_sm_set_bool,
1819	eapol_sm_get_int,
1820	eapol_sm_set_int,
1821	eapol_sm_get_eapReqData,
1822	eapol_sm_set_config_blob,
1823	eapol_sm_get_config_blob,
1824	eapol_sm_notify_pending,
1825	eapol_sm_eap_param_needed
1826};
1827
1828
1829/**
1830 * eapol_sm_init - Initialize EAPOL state machine
1831 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1832 * and EAPOL state machine will free it in eapol_sm_deinit()
1833 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1834 *
1835 * Allocate and initialize an EAPOL state machine.
1836 */
1837struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1838{
1839	struct eapol_sm *sm;
1840	struct eap_config conf;
1841	sm = os_zalloc(sizeof(*sm));
1842	if (sm == NULL)
1843		return NULL;
1844	sm->ctx = ctx;
1845
1846	sm->portControl = Auto;
1847
1848	/* Supplicant PAE state machine */
1849	sm->heldPeriod = 60;
1850	sm->startPeriod = 30;
1851	sm->maxStart = 3;
1852
1853	/* Supplicant Backend state machine */
1854	sm->authPeriod = 30;
1855
1856	os_memset(&conf, 0, sizeof(conf));
1857	conf.opensc_engine_path = ctx->opensc_engine_path;
1858	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1859	conf.pkcs11_module_path = ctx->pkcs11_module_path;
1860	conf.wps = ctx->wps;
1861
1862	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1863	if (sm->eap == NULL) {
1864		os_free(sm);
1865		return NULL;
1866	}
1867
1868	/* Initialize EAPOL state machines */
1869	sm->initialize = TRUE;
1870	eapol_sm_step(sm);
1871	sm->initialize = FALSE;
1872	eapol_sm_step(sm);
1873
1874	sm->timer_tick_enabled = 1;
1875	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1876
1877	return sm;
1878}
1879
1880
1881/**
1882 * eapol_sm_deinit - Deinitialize EAPOL state machine
1883 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1884 *
1885 * Deinitialize and free EAPOL state machine.
1886 */
1887void eapol_sm_deinit(struct eapol_sm *sm)
1888{
1889	if (sm == NULL)
1890		return;
1891	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1892	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1893	eap_peer_sm_deinit(sm->eap);
1894	os_free(sm->last_rx_key);
1895	wpabuf_free(sm->eapReqData);
1896	os_free(sm->ctx);
1897	os_free(sm);
1898}
1899