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