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