]> git.ipfire.org Git - thirdparty/hostap.git/blame - hostapd/eapol_sm.c
Initialize EAPOL authenticator flags during allocation
[thirdparty/hostap.git] / hostapd / eapol_sm.c
CommitLineData
6fc6879b 1/*
2773ca09
JM
2 * IEEE 802.1X-2004 Authenticator - EAPOL state machine
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
6fc6879b
JM
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
11 *
12 * See README and COPYING for more details.
13 */
14
15#include "includes.h"
16
f55802e8 17#include "common.h"
6fc6879b
JM
18#include "eapol_sm.h"
19#include "eloop.h"
fa04fa10 20#include "common/eapol_common.h"
6fc6879b 21#include "wpa.h"
6fc6879b
JM
22#include "sta_info.h"
23#include "eap_server/eap.h"
24#include "state_machine.h"
25#include "eap_common/eap_common.h"
26
27#define STATE_MACHINE_DATA struct eapol_state_machine
28#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
29#define STATE_MACHINE_ADDR sm->addr
30
31static struct eapol_callbacks eapol_cb;
32
33/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
34
35#define setPortAuthorized() \
36sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 1)
37#define setPortUnauthorized() \
38sm->eapol->cb.set_port_authorized(sm->hapd, sm->sta, 0)
39
40/* procedures */
41#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
42#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
43#define txReq() eapol_auth_tx_req(sm)
44#define abortAuth() sm->eapol->cb.abort_auth(sm->hapd, sm->sta)
45#define txKey() sm->eapol->cb.tx_key(sm->hapd, sm->sta)
46#define processKey() do { } while (0)
47
48
49static void eapol_sm_step_run(struct eapol_state_machine *sm);
50static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
51
52
53static void eapol_auth_logger(struct eapol_authenticator *eapol,
fa04fa10 54 const u8 *addr, eapol_logger_level level,
6fc6879b
JM
55 const char *txt)
56{
57 if (eapol->cb.logger == NULL)
58 return;
59 eapol->cb.logger(eapol->conf.hapd, addr, level, txt);
60}
61
62
63static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
fa04fa10 64 const u8 *addr, eapol_logger_level level,
6fc6879b
JM
65 const char *fmt, ...)
66{
67 char *format;
68 int maxlen;
69 va_list ap;
70
71 if (eapol->cb.logger == NULL)
72 return;
73
74 maxlen = os_strlen(fmt) + 100;
75 format = os_malloc(maxlen);
76 if (!format)
77 return;
78
79 va_start(ap, fmt);
80 vsnprintf(format, maxlen, fmt, ap);
81 va_end(ap);
82
83 eapol_auth_logger(eapol, addr, level, format);
84
85 os_free(format);
86}
87
88
89static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
90 int success)
91{
92 struct eap_hdr eap;
93
94 os_memset(&eap, 0, sizeof(eap));
95
96 eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
97 eap.identifier = ++sm->last_eap_id;
98 eap.length = host_to_be16(sizeof(eap));
99
100 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
101 "Sending canned EAP packet %s (identifier %d)",
102 success ? "SUCCESS" : "FAILURE", eap.identifier);
103 sm->eapol->cb.eapol_send(sm->hapd, sm->sta, IEEE802_1X_TYPE_EAP_PACKET,
104 (u8 *) &eap, sizeof(eap));
105 sm->dot1xAuthEapolFramesTx++;
106}
107
108
109static void eapol_auth_tx_req(struct eapol_state_machine *sm)
110{
111 if (sm->eap_if->eapReqData == NULL ||
112 wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
113 eapol_auth_logger(sm->eapol, sm->addr,
114 EAPOL_LOGGER_DEBUG,
115 "TxReq called, but there is no EAP request "
116 "from authentication server");
117 return;
118 }
119
120 if (sm->flags & EAPOL_SM_WAIT_START) {
121 wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
122 " while waiting for EAPOL-Start",
123 MAC2STR(sm->addr));
124 return;
125 }
126
127 sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
128 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
129 "Sending EAP Packet (identifier %d)",
130 sm->last_eap_id);
131 sm->eapol->cb.eapol_send(sm->hapd, sm->sta, IEEE802_1X_TYPE_EAP_PACKET,
132 wpabuf_head(sm->eap_if->eapReqData),
133 wpabuf_len(sm->eap_if->eapReqData));
134 sm->dot1xAuthEapolFramesTx++;
135 if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
136 sm->dot1xAuthEapolReqIdFramesTx++;
137 else
138 sm->dot1xAuthEapolReqFramesTx++;
139}
140
141
1c6e69cc
JM
142/**
143 * eapol_port_timers_tick - Port Timers state machine
144 * @eloop_ctx: struct eapol_state_machine *
145 * @timeout_ctx: Not used
146 *
147 * This statemachine is implemented as a function that will be called
148 * once a second as a registered event loop timeout.
149 */
6fc6879b
JM
150static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
151{
152 struct eapol_state_machine *state = timeout_ctx;
153
154 if (state->aWhile > 0) {
155 state->aWhile--;
156 if (state->aWhile == 0) {
157 wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
158 " - aWhile --> 0",
159 MAC2STR(state->addr));
160 }
161 }
162
163 if (state->quietWhile > 0) {
164 state->quietWhile--;
165 if (state->quietWhile == 0) {
166 wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
167 " - quietWhile --> 0",
168 MAC2STR(state->addr));
169 }
170 }
171
172 if (state->reAuthWhen > 0) {
173 state->reAuthWhen--;
174 if (state->reAuthWhen == 0) {
175 wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
176 " - reAuthWhen --> 0",
177 MAC2STR(state->addr));
178 }
179 }
180
8e09c6d2
JM
181 if (state->eap_if->retransWhile > 0) {
182 state->eap_if->retransWhile--;
183 if (state->eap_if->retransWhile == 0) {
184 wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
185 " - (EAP) retransWhile --> 0",
186 MAC2STR(state->addr));
187 }
188 }
189
6fc6879b
JM
190 eapol_sm_step_run(state);
191
192 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
193}
194
195
196
197/* Authenticator PAE state machine */
198
199SM_STATE(AUTH_PAE, INITIALIZE)
200{
201 SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
202 sm->portMode = Auto;
203}
204
205
206SM_STATE(AUTH_PAE, DISCONNECTED)
207{
208 int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
209
210 if (sm->eapolLogoff) {
211 if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
212 sm->authEapLogoffsWhileConnecting++;
213 else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
214 sm->authAuthEapLogoffWhileAuthenticated++;
215 }
216
217 SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
218
219 sm->authPortStatus = Unauthorized;
220 setPortUnauthorized();
221 sm->reAuthCount = 0;
222 sm->eapolLogoff = FALSE;
223 if (!from_initialize) {
224 sm->eapol->cb.finished(sm->hapd, sm->sta, 0,
225 sm->flags & EAPOL_SM_PREAUTH);
226 }
227}
228
229
230SM_STATE(AUTH_PAE, RESTART)
231{
232 if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
233 if (sm->reAuthenticate)
234 sm->authAuthReauthsWhileAuthenticated++;
235 if (sm->eapolStart)
236 sm->authAuthEapStartsWhileAuthenticated++;
237 if (sm->eapolLogoff)
238 sm->authAuthEapLogoffWhileAuthenticated++;
239 }
240
241 SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
242
243 sm->eap_if->eapRestart = TRUE;
244}
245
246
247SM_STATE(AUTH_PAE, CONNECTING)
248{
249 if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
250 sm->authEntersConnecting++;
251
252 SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
253
254 sm->reAuthenticate = FALSE;
255 sm->reAuthCount++;
256}
257
258
259SM_STATE(AUTH_PAE, HELD)
260{
261 if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
262 sm->authAuthFailWhileAuthenticating++;
263
264 SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
265
266 sm->authPortStatus = Unauthorized;
267 setPortUnauthorized();
268 sm->quietWhile = sm->quietPeriod;
269 sm->eapolLogoff = FALSE;
270
271 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
272 "authentication failed - EAP type: %d (%s)",
273 sm->eap_type_authsrv,
2773ca09 274 eap_server_get_name(0, sm->eap_type_authsrv));
6fc6879b
JM
275 if (sm->eap_type_authsrv != sm->eap_type_supp) {
276 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
277 "Supplicant used different EAP type: "
278 "%d (%s)", sm->eap_type_supp,
2773ca09 279 eap_server_get_name(0, sm->eap_type_supp));
6fc6879b
JM
280 }
281 sm->eapol->cb.finished(sm->hapd, sm->sta, 0,
282 sm->flags & EAPOL_SM_PREAUTH);
283}
284
285
286SM_STATE(AUTH_PAE, AUTHENTICATED)
287{
288 char *extra = "";
289
290 if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
291 sm->authAuthSuccessesWhileAuthenticating++;
292
293 SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
294
295 sm->authPortStatus = Authorized;
296 setPortAuthorized();
297 sm->reAuthCount = 0;
298 if (sm->flags & EAPOL_SM_PREAUTH)
299 extra = " (pre-authentication)";
300 else if (wpa_auth_sta_get_pmksa(sm->sta->wpa_sm))
301 extra = " (PMKSA cache)";
302 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
303 "authenticated - EAP type: %d (%s)%s",
304 sm->eap_type_authsrv,
2773ca09
JM
305 eap_server_get_name(0, sm->eap_type_authsrv),
306 extra);
6fc6879b
JM
307 sm->eapol->cb.finished(sm->hapd, sm->sta, 1,
308 sm->flags & EAPOL_SM_PREAUTH);
309}
310
311
312SM_STATE(AUTH_PAE, AUTHENTICATING)
313{
314 SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
315
316 sm->eapolStart = FALSE;
317 sm->authSuccess = FALSE;
318 sm->authFail = FALSE;
319 sm->authTimeout = FALSE;
320 sm->authStart = TRUE;
321 sm->keyRun = FALSE;
322 sm->keyDone = FALSE;
323}
324
325
326SM_STATE(AUTH_PAE, ABORTING)
327{
328 if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
329 if (sm->authTimeout)
330 sm->authAuthTimeoutsWhileAuthenticating++;
331 if (sm->eapolStart)
332 sm->authAuthEapStartsWhileAuthenticating++;
333 if (sm->eapolLogoff)
334 sm->authAuthEapLogoffWhileAuthenticating++;
335 }
336
337 SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
338
339 sm->authAbort = TRUE;
340 sm->keyRun = FALSE;
341 sm->keyDone = FALSE;
342}
343
344
345SM_STATE(AUTH_PAE, FORCE_AUTH)
346{
347 SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
348
349 sm->authPortStatus = Authorized;
350 setPortAuthorized();
351 sm->portMode = ForceAuthorized;
352 sm->eapolStart = FALSE;
353 txCannedSuccess();
354}
355
356
357SM_STATE(AUTH_PAE, FORCE_UNAUTH)
358{
359 SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
360
361 sm->authPortStatus = Unauthorized;
362 setPortUnauthorized();
363 sm->portMode = ForceUnauthorized;
364 sm->eapolStart = FALSE;
365 txCannedFail();
366}
367
368
369SM_STEP(AUTH_PAE)
370{
371 if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
372 sm->initialize || !sm->eap_if->portEnabled)
74bd7dae 373 SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
6fc6879b
JM
374 else if (sm->portControl == ForceAuthorized &&
375 sm->portMode != sm->portControl &&
376 !(sm->initialize || !sm->eap_if->portEnabled))
74bd7dae 377 SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
6fc6879b
JM
378 else if (sm->portControl == ForceUnauthorized &&
379 sm->portMode != sm->portControl &&
380 !(sm->initialize || !sm->eap_if->portEnabled))
74bd7dae 381 SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
6fc6879b
JM
382 else {
383 switch (sm->auth_pae_state) {
384 case AUTH_PAE_INITIALIZE:
385 SM_ENTER(AUTH_PAE, DISCONNECTED);
386 break;
387 case AUTH_PAE_DISCONNECTED:
388 SM_ENTER(AUTH_PAE, RESTART);
389 break;
390 case AUTH_PAE_RESTART:
391 if (!sm->eap_if->eapRestart)
392 SM_ENTER(AUTH_PAE, CONNECTING);
393 break;
394 case AUTH_PAE_HELD:
395 if (sm->quietWhile == 0)
396 SM_ENTER(AUTH_PAE, RESTART);
397 break;
398 case AUTH_PAE_CONNECTING:
399 if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
400 SM_ENTER(AUTH_PAE, DISCONNECTED);
401 else if ((sm->eap_if->eapReq &&
402 sm->reAuthCount <= sm->reAuthMax) ||
403 sm->eap_if->eapSuccess || sm->eap_if->eapFail)
404 SM_ENTER(AUTH_PAE, AUTHENTICATING);
405 break;
406 case AUTH_PAE_AUTHENTICATED:
407 if (sm->eapolStart || sm->reAuthenticate)
408 SM_ENTER(AUTH_PAE, RESTART);
409 else if (sm->eapolLogoff || !sm->portValid)
410 SM_ENTER(AUTH_PAE, DISCONNECTED);
411 break;
412 case AUTH_PAE_AUTHENTICATING:
413 if (sm->authSuccess && sm->portValid)
414 SM_ENTER(AUTH_PAE, AUTHENTICATED);
415 else if (sm->authFail ||
416 (sm->keyDone && !sm->portValid))
417 SM_ENTER(AUTH_PAE, HELD);
418 else if (sm->eapolStart || sm->eapolLogoff ||
419 sm->authTimeout)
420 SM_ENTER(AUTH_PAE, ABORTING);
421 break;
422 case AUTH_PAE_ABORTING:
423 if (sm->eapolLogoff && !sm->authAbort)
424 SM_ENTER(AUTH_PAE, DISCONNECTED);
425 else if (!sm->eapolLogoff && !sm->authAbort)
426 SM_ENTER(AUTH_PAE, RESTART);
427 break;
428 case AUTH_PAE_FORCE_AUTH:
429 if (sm->eapolStart)
430 SM_ENTER(AUTH_PAE, FORCE_AUTH);
431 break;
432 case AUTH_PAE_FORCE_UNAUTH:
433 if (sm->eapolStart)
434 SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
435 break;
436 }
437 }
438}
439
440
441
442/* Backend Authentication state machine */
443
444SM_STATE(BE_AUTH, INITIALIZE)
445{
446 SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
447
448 abortAuth();
449 sm->eap_if->eapNoReq = FALSE;
450 sm->authAbort = FALSE;
451}
452
453
454SM_STATE(BE_AUTH, REQUEST)
455{
456 SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
457
458 txReq();
459 sm->eap_if->eapReq = FALSE;
460 sm->backendOtherRequestsToSupplicant++;
461
462 /*
463 * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
464 * it looks like this would be logical thing to do there since the old
465 * EAP response would not be valid anymore after the new EAP request
466 * was sent out.
467 *
468 * A race condition has been reported, in which hostapd ended up
469 * sending out EAP-Response/Identity as a response to the first
470 * EAP-Request from the main EAP method. This can be avoided by
471 * clearing eapolEap here.
472 */
473 sm->eapolEap = FALSE;
474}
475
476
477SM_STATE(BE_AUTH, RESPONSE)
478{
479 SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
480
481 sm->authTimeout = FALSE;
482 sm->eapolEap = FALSE;
483 sm->eap_if->eapNoReq = FALSE;
484 sm->aWhile = sm->serverTimeout;
485 sm->eap_if->eapResp = TRUE;
486 /* sendRespToServer(); */
487 sm->backendResponses++;
488}
489
490
491SM_STATE(BE_AUTH, SUCCESS)
492{
493 SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
494
495 txReq();
496 sm->authSuccess = TRUE;
497 sm->keyRun = TRUE;
498}
499
500
501SM_STATE(BE_AUTH, FAIL)
502{
503 SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
504
505 txReq();
506 sm->authFail = TRUE;
507}
508
509
510SM_STATE(BE_AUTH, TIMEOUT)
511{
512 SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
513
514 sm->authTimeout = TRUE;
515}
516
517
518SM_STATE(BE_AUTH, IDLE)
519{
520 SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
521
522 sm->authStart = FALSE;
523}
524
525
526SM_STATE(BE_AUTH, IGNORE)
527{
528 SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
529
530 sm->eap_if->eapNoReq = FALSE;
531}
532
533
534SM_STEP(BE_AUTH)
535{
536 if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
74bd7dae 537 SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
6fc6879b
JM
538 return;
539 }
540
541 switch (sm->be_auth_state) {
542 case BE_AUTH_INITIALIZE:
543 SM_ENTER(BE_AUTH, IDLE);
544 break;
545 case BE_AUTH_REQUEST:
546 if (sm->eapolEap)
547 SM_ENTER(BE_AUTH, RESPONSE);
548 else if (sm->eap_if->eapReq)
549 SM_ENTER(BE_AUTH, REQUEST);
550 else if (sm->eap_if->eapTimeout)
551 SM_ENTER(BE_AUTH, TIMEOUT);
552 break;
553 case BE_AUTH_RESPONSE:
554 if (sm->eap_if->eapNoReq)
555 SM_ENTER(BE_AUTH, IGNORE);
556 if (sm->eap_if->eapReq) {
557 sm->backendAccessChallenges++;
558 SM_ENTER(BE_AUTH, REQUEST);
559 } else if (sm->aWhile == 0)
560 SM_ENTER(BE_AUTH, TIMEOUT);
561 else if (sm->eap_if->eapFail) {
562 sm->backendAuthFails++;
563 SM_ENTER(BE_AUTH, FAIL);
564 } else if (sm->eap_if->eapSuccess) {
565 sm->backendAuthSuccesses++;
566 SM_ENTER(BE_AUTH, SUCCESS);
567 }
568 break;
569 case BE_AUTH_SUCCESS:
570 SM_ENTER(BE_AUTH, IDLE);
571 break;
572 case BE_AUTH_FAIL:
573 SM_ENTER(BE_AUTH, IDLE);
574 break;
575 case BE_AUTH_TIMEOUT:
576 SM_ENTER(BE_AUTH, IDLE);
577 break;
578 case BE_AUTH_IDLE:
579 if (sm->eap_if->eapFail && sm->authStart)
580 SM_ENTER(BE_AUTH, FAIL);
581 else if (sm->eap_if->eapReq && sm->authStart)
582 SM_ENTER(BE_AUTH, REQUEST);
583 else if (sm->eap_if->eapSuccess && sm->authStart)
584 SM_ENTER(BE_AUTH, SUCCESS);
585 break;
586 case BE_AUTH_IGNORE:
587 if (sm->eapolEap)
588 SM_ENTER(BE_AUTH, RESPONSE);
589 else if (sm->eap_if->eapReq)
590 SM_ENTER(BE_AUTH, REQUEST);
591 else if (sm->eap_if->eapTimeout)
592 SM_ENTER(BE_AUTH, TIMEOUT);
593 break;
594 }
595}
596
597
598
599/* Reauthentication Timer state machine */
600
601SM_STATE(REAUTH_TIMER, INITIALIZE)
602{
603 SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
604
605 sm->reAuthWhen = sm->reAuthPeriod;
606}
607
608
609SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
610{
611 SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
612
613 sm->reAuthenticate = TRUE;
614 wpa_auth_sm_event(sm->sta->wpa_sm, WPA_REAUTH_EAPOL);
615}
616
617
618SM_STEP(REAUTH_TIMER)
619{
620 if (sm->portControl != Auto || sm->initialize ||
621 sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
74bd7dae 622 SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
6fc6879b
JM
623 return;
624 }
625
626 switch (sm->reauth_timer_state) {
627 case REAUTH_TIMER_INITIALIZE:
628 if (sm->reAuthWhen == 0)
629 SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
630 break;
631 case REAUTH_TIMER_REAUTHENTICATE:
632 SM_ENTER(REAUTH_TIMER, INITIALIZE);
633 break;
634 }
635}
636
637
638
639/* Authenticator Key Transmit state machine */
640
641SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
642{
643 SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
644}
645
646
647SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
648{
649 SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
650
651 txKey();
652 sm->eap_if->eapKeyAvailable = FALSE;
653 sm->keyDone = TRUE;
654}
655
656
657SM_STEP(AUTH_KEY_TX)
658{
659 if (sm->initialize || sm->portControl != Auto) {
74bd7dae 660 SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
6fc6879b
JM
661 return;
662 }
663
664 switch (sm->auth_key_tx_state) {
665 case AUTH_KEY_TX_NO_KEY_TRANSMIT:
666 if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
5ed1c08f 667 sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
6fc6879b
JM
668 SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
669 break;
670 case AUTH_KEY_TX_KEY_TRANSMIT:
671 if (!sm->keyTxEnabled || !sm->keyRun)
672 SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
673 else if (sm->eap_if->eapKeyAvailable)
674 SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
675 break;
676 }
677}
678
679
680
681/* Key Receive state machine */
682
683SM_STATE(KEY_RX, NO_KEY_RECEIVE)
684{
685 SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
686}
687
688
689SM_STATE(KEY_RX, KEY_RECEIVE)
690{
691 SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
692
693 processKey();
694 sm->rxKey = FALSE;
695}
696
697
698SM_STEP(KEY_RX)
699{
700 if (sm->initialize || !sm->eap_if->portEnabled) {
74bd7dae 701 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
6fc6879b
JM
702 return;
703 }
704
705 switch (sm->key_rx_state) {
706 case KEY_RX_NO_KEY_RECEIVE:
707 if (sm->rxKey)
708 SM_ENTER(KEY_RX, KEY_RECEIVE);
709 break;
710 case KEY_RX_KEY_RECEIVE:
711 if (sm->rxKey)
712 SM_ENTER(KEY_RX, KEY_RECEIVE);
713 break;
714 }
715}
716
717
718
719/* Controlled Directions state machine */
720
721SM_STATE(CTRL_DIR, FORCE_BOTH)
722{
723 SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
724 sm->operControlledDirections = Both;
725}
726
727
728SM_STATE(CTRL_DIR, IN_OR_BOTH)
729{
730 SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
731 sm->operControlledDirections = sm->adminControlledDirections;
732}
733
734
735SM_STEP(CTRL_DIR)
736{
737 if (sm->initialize) {
74bd7dae 738 SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
6fc6879b
JM
739 return;
740 }
741
742 switch (sm->ctrl_dir_state) {
743 case CTRL_DIR_FORCE_BOTH:
744 if (sm->eap_if->portEnabled && sm->operEdge)
745 SM_ENTER(CTRL_DIR, IN_OR_BOTH);
746 break;
747 case CTRL_DIR_IN_OR_BOTH:
748 if (sm->operControlledDirections !=
749 sm->adminControlledDirections)
750 SM_ENTER(CTRL_DIR, IN_OR_BOTH);
751 if (!sm->eap_if->portEnabled || !sm->operEdge)
752 SM_ENTER(CTRL_DIR, FORCE_BOTH);
753 break;
754 }
755}
756
757
758
759struct eapol_state_machine *
760eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
5ed1c08f 761 int flags, struct sta_info *sta)
6fc6879b
JM
762{
763 struct eapol_state_machine *sm;
764 struct hostapd_data *hapd; /* TODO: to be removed */
765 struct eap_config eap_conf;
766
767 if (eapol == NULL)
768 return NULL;
769 hapd = eapol->conf.hapd;
770
771 sm = os_zalloc(sizeof(*sm));
772 if (sm == NULL) {
773 wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
774 "failed");
775 return NULL;
776 }
777 sm->radius_identifier = -1;
778 os_memcpy(sm->addr, addr, ETH_ALEN);
5ed1c08f 779 sm->flags = flags;
6fc6879b
JM
780
781 sm->hapd = hapd;
782 sm->eapol = eapol;
783 sm->sta = sta;
784
785 /* Set default values for state machine constants */
786 sm->auth_pae_state = AUTH_PAE_INITIALIZE;
787 sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
788 sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
789
790 sm->be_auth_state = BE_AUTH_INITIALIZE;
791 sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
792
793 sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
794 sm->reAuthPeriod = eapol->conf.eap_reauth_period;
795 sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
796
797 sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
798
799 sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
800
801 sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
802
803 sm->portControl = Auto;
804
805 if (!eapol->conf.wpa &&
f55802e8 806 (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
6fc6879b
JM
807 sm->keyTxEnabled = TRUE;
808 else
809 sm->keyTxEnabled = FALSE;
810 if (eapol->conf.wpa)
811 sm->portValid = FALSE;
812 else
813 sm->portValid = TRUE;
814
815 os_memset(&eap_conf, 0, sizeof(eap_conf));
816 eap_conf.eap_server = eapol->conf.eap_server;
817 eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
818 eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
819 eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
820 eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
2d867244
JM
821 eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
822 eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
378eae5e 823 eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
a11c90a6
JM
824 eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
825 eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
6fc6879b 826 eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
c3e258ae 827 eap_conf.tnc = eapol->conf.tnc;
ad08c363 828 eap_conf.wps = eapol->conf.wps;
eb76b7e3 829 eap_conf.assoc_wps_ie = sta->wps_ie;
2678509d 830 eap_conf.peer_addr = addr;
6fc6879b
JM
831 sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
832 if (sm->eap == NULL) {
833 eapol_auth_free(sm);
834 return NULL;
835 }
836 sm->eap_if = eap_get_interface(sm->eap);
837
838 eapol_auth_initialize(sm);
839
840 return sm;
841}
842
843
844void eapol_auth_free(struct eapol_state_machine *sm)
845{
846 if (sm == NULL)
847 return;
848
849 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
850 eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
851 if (sm->eap)
852 eap_server_sm_deinit(sm->eap);
853 os_free(sm);
854}
855
856
857static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
858 const u8 *addr)
859{
860 return eapol->cb.sta_entry_alive(eapol->conf.hapd, addr);
861}
862
863
864static void eapol_sm_step_run(struct eapol_state_machine *sm)
865{
866 struct eapol_authenticator *eapol = sm->eapol;
867 u8 addr[ETH_ALEN];
868 unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
869 prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
870 int max_steps = 100;
871
872 os_memcpy(addr, sm->addr, ETH_ALEN);
873
874 /*
875 * Allow EAPOL state machines to run as long as there are state
876 * changes, but exit and return here through event loop if more than
877 * 100 steps is needed as a precaution against infinite loops inside
878 * eloop callback.
879 */
880restart:
881 prev_auth_pae = sm->auth_pae_state;
882 prev_be_auth = sm->be_auth_state;
883 prev_reauth_timer = sm->reauth_timer_state;
884 prev_auth_key_tx = sm->auth_key_tx_state;
885 prev_key_rx = sm->key_rx_state;
886 prev_ctrl_dir = sm->ctrl_dir_state;
887
888 SM_STEP_RUN(AUTH_PAE);
889 if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
890 SM_STEP_RUN(BE_AUTH);
891 if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
892 SM_STEP_RUN(REAUTH_TIMER);
893 if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
894 SM_STEP_RUN(AUTH_KEY_TX);
895 if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
896 SM_STEP_RUN(KEY_RX);
897 if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
898 SM_STEP_RUN(CTRL_DIR);
899
900 if (prev_auth_pae != sm->auth_pae_state ||
901 prev_be_auth != sm->be_auth_state ||
902 prev_reauth_timer != sm->reauth_timer_state ||
903 prev_auth_key_tx != sm->auth_key_tx_state ||
904 prev_key_rx != sm->key_rx_state ||
905 prev_ctrl_dir != sm->ctrl_dir_state) {
906 if (--max_steps > 0)
907 goto restart;
908 /* Re-run from eloop timeout */
909 eapol_auth_step(sm);
910 return;
911 }
912
913 if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
914 if (eap_server_sm_step(sm->eap)) {
915 if (--max_steps > 0)
916 goto restart;
917 /* Re-run from eloop timeout */
918 eapol_auth_step(sm);
919 return;
920 }
921
922 /* TODO: find a better location for this */
923 if (sm->eap_if->aaaEapResp) {
924 sm->eap_if->aaaEapResp = FALSE;
925 if (sm->eap_if->aaaEapRespData == NULL) {
926 wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
927 "but no aaaEapRespData available");
928 return;
929 }
930 sm->eapol->cb.aaa_send(
931 sm->hapd, sm->sta,
932 wpabuf_head(sm->eap_if->aaaEapRespData),
933 wpabuf_len(sm->eap_if->aaaEapRespData));
934 }
935 }
936
937 if (eapol_sm_sta_entry_alive(eapol, addr))
938 wpa_auth_sm_notify(sm->sta->wpa_sm);
939}
940
941
942static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
943{
944 struct eapol_state_machine *sm = eloop_ctx;
945 eapol_sm_step_run(sm);
946}
947
948
1c6e69cc
JM
949/**
950 * eapol_auth_step - Advance EAPOL state machines
951 * @sm: EAPOL state machine
952 *
953 * This function is called to advance EAPOL state machines after any change
954 * that could affect their state.
955 */
6fc6879b
JM
956void eapol_auth_step(struct eapol_state_machine *sm)
957{
958 /*
959 * Run eapol_sm_step_run from a registered timeout to make sure that
960 * other possible timeouts/events are processed and to avoid long
961 * function call chains.
962 */
963
964 eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
965}
966
967
968void eapol_auth_initialize(struct eapol_state_machine *sm)
969{
970 sm->initializing = TRUE;
971 /* Initialize the state machines by asserting initialize and then
972 * deasserting it after one step */
973 sm->initialize = TRUE;
974 eapol_sm_step_run(sm);
975 sm->initialize = FALSE;
976 eapol_sm_step_run(sm);
977 sm->initializing = FALSE;
978
979 /* Start one second tick for port timers state machine */
980 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
981 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
982}
983
984
985#ifdef HOSTAPD_DUMP_STATE
986static inline const char * port_type_txt(PortTypes pt)
987{
988 switch (pt) {
989 case ForceUnauthorized: return "ForceUnauthorized";
990 case ForceAuthorized: return "ForceAuthorized";
991 case Auto: return "Auto";
992 default: return "Unknown";
993 }
994}
995
996
997static inline const char * port_state_txt(PortState ps)
998{
999 switch (ps) {
1000 case Unauthorized: return "Unauthorized";
1001 case Authorized: return "Authorized";
1002 default: return "Unknown";
1003 }
1004}
1005
1006
1007static inline const char * ctrl_dir_txt(ControlledDirection dir)
1008{
1009 switch (dir) {
1010 case Both: return "Both";
1011 case In: return "In";
1012 default: return "Unknown";
1013 }
1014}
1015
1016
1017static inline const char * auth_pae_state_txt(int s)
1018{
1019 switch (s) {
1020 case AUTH_PAE_INITIALIZE: return "INITIALIZE";
1021 case AUTH_PAE_DISCONNECTED: return "DISCONNECTED";
1022 case AUTH_PAE_CONNECTING: return "CONNECTING";
1023 case AUTH_PAE_AUTHENTICATING: return "AUTHENTICATING";
1024 case AUTH_PAE_AUTHENTICATED: return "AUTHENTICATED";
1025 case AUTH_PAE_ABORTING: return "ABORTING";
1026 case AUTH_PAE_HELD: return "HELD";
1027 case AUTH_PAE_FORCE_AUTH: return "FORCE_AUTH";
1028 case AUTH_PAE_FORCE_UNAUTH: return "FORCE_UNAUTH";
1029 case AUTH_PAE_RESTART: return "RESTART";
1030 default: return "Unknown";
1031 }
1032}
1033
1034
1035static inline const char * be_auth_state_txt(int s)
1036{
1037 switch (s) {
1038 case BE_AUTH_REQUEST: return "REQUEST";
1039 case BE_AUTH_RESPONSE: return "RESPONSE";
1040 case BE_AUTH_SUCCESS: return "SUCCESS";
1041 case BE_AUTH_FAIL: return "FAIL";
1042 case BE_AUTH_TIMEOUT: return "TIMEOUT";
1043 case BE_AUTH_IDLE: return "IDLE";
1044 case BE_AUTH_INITIALIZE: return "INITIALIZE";
1045 case BE_AUTH_IGNORE: return "IGNORE";
1046 default: return "Unknown";
1047 }
1048}
1049
1050
1051static inline const char * reauth_timer_state_txt(int s)
1052{
1053 switch (s) {
1054 case REAUTH_TIMER_INITIALIZE: return "INITIALIZE";
1055 case REAUTH_TIMER_REAUTHENTICATE: return "REAUTHENTICATE";
1056 default: return "Unknown";
1057 }
1058}
1059
1060
1061static inline const char * auth_key_tx_state_txt(int s)
1062{
1063 switch (s) {
1064 case AUTH_KEY_TX_NO_KEY_TRANSMIT: return "NO_KEY_TRANSMIT";
1065 case AUTH_KEY_TX_KEY_TRANSMIT: return "KEY_TRANSMIT";
1066 default: return "Unknown";
1067 }
1068}
1069
1070
1071static inline const char * key_rx_state_txt(int s)
1072{
1073 switch (s) {
1074 case KEY_RX_NO_KEY_RECEIVE: return "NO_KEY_RECEIVE";
1075 case KEY_RX_KEY_RECEIVE: return "KEY_RECEIVE";
1076 default: return "Unknown";
1077 }
1078}
1079
1080
1081static inline const char * ctrl_dir_state_txt(int s)
1082{
1083 switch (s) {
1084 case CTRL_DIR_FORCE_BOTH: return "FORCE_BOTH";
1085 case CTRL_DIR_IN_OR_BOTH: return "IN_OR_BOTH";
1086 default: return "Unknown";
1087 }
1088}
1089
1090
1091void eapol_auth_dump_state(FILE *f, const char *prefix,
1092 struct eapol_state_machine *sm)
1093{
1094 fprintf(f, "%sEAPOL state machine:\n", prefix);
1095 fprintf(f, "%s aWhile=%d quietWhile=%d reAuthWhen=%d\n", prefix,
1096 sm->aWhile, sm->quietWhile, sm->reAuthWhen);
1097#define _SB(b) ((b) ? "TRUE" : "FALSE")
1098 fprintf(f,
1099 "%s authAbort=%s authFail=%s authPortStatus=%s authStart=%s\n"
1100 "%s authTimeout=%s authSuccess=%s eapFail=%s eapolEap=%s\n"
1101 "%s eapSuccess=%s eapTimeout=%s initialize=%s "
1102 "keyAvailable=%s\n"
1103 "%s keyDone=%s keyRun=%s keyTxEnabled=%s portControl=%s\n"
1104 "%s portEnabled=%s portValid=%s reAuthenticate=%s\n",
1105 prefix, _SB(sm->authAbort), _SB(sm->authFail),
1106 port_state_txt(sm->authPortStatus), _SB(sm->authStart),
1107 prefix, _SB(sm->authTimeout), _SB(sm->authSuccess),
1108 _SB(sm->eap_if->eapFail), _SB(sm->eapolEap),
1109 prefix, _SB(sm->eap_if->eapSuccess),
1110 _SB(sm->eap_if->eapTimeout),
1111 _SB(sm->initialize), _SB(sm->eap_if->eapKeyAvailable),
1112 prefix, _SB(sm->keyDone), _SB(sm->keyRun),
1113 _SB(sm->keyTxEnabled), port_type_txt(sm->portControl),
1114 prefix, _SB(sm->eap_if->portEnabled), _SB(sm->portValid),
1115 _SB(sm->reAuthenticate));
1116
1117 fprintf(f, "%s Authenticator PAE:\n"
1118 "%s state=%s\n"
1119 "%s eapolLogoff=%s eapolStart=%s eapRestart=%s\n"
1120 "%s portMode=%s reAuthCount=%d\n"
1121 "%s quietPeriod=%d reAuthMax=%d\n"
1122 "%s authEntersConnecting=%d\n"
1123 "%s authEapLogoffsWhileConnecting=%d\n"
1124 "%s authEntersAuthenticating=%d\n"
1125 "%s authAuthSuccessesWhileAuthenticating=%d\n"
1126 "%s authAuthTimeoutsWhileAuthenticating=%d\n"
1127 "%s authAuthFailWhileAuthenticating=%d\n"
1128 "%s authAuthEapStartsWhileAuthenticating=%d\n"
1129 "%s authAuthEapLogoffWhileAuthenticating=%d\n"
1130 "%s authAuthReauthsWhileAuthenticated=%d\n"
1131 "%s authAuthEapStartsWhileAuthenticated=%d\n"
1132 "%s authAuthEapLogoffWhileAuthenticated=%d\n",
1133 prefix, prefix, auth_pae_state_txt(sm->auth_pae_state), prefix,
1134 _SB(sm->eapolLogoff), _SB(sm->eapolStart),
1135 _SB(sm->eap_if->eapRestart),
1136 prefix, port_type_txt(sm->portMode), sm->reAuthCount,
1137 prefix, sm->quietPeriod, sm->reAuthMax,
1138 prefix, sm->authEntersConnecting,
1139 prefix, sm->authEapLogoffsWhileConnecting,
1140 prefix, sm->authEntersAuthenticating,
1141 prefix, sm->authAuthSuccessesWhileAuthenticating,
1142 prefix, sm->authAuthTimeoutsWhileAuthenticating,
1143 prefix, sm->authAuthFailWhileAuthenticating,
1144 prefix, sm->authAuthEapStartsWhileAuthenticating,
1145 prefix, sm->authAuthEapLogoffWhileAuthenticating,
1146 prefix, sm->authAuthReauthsWhileAuthenticated,
1147 prefix, sm->authAuthEapStartsWhileAuthenticated,
1148 prefix, sm->authAuthEapLogoffWhileAuthenticated);
1149
1150 fprintf(f, "%s Backend Authentication:\n"
1151 "%s state=%s\n"
1152 "%s eapNoReq=%s eapReq=%s eapResp=%s\n"
1153 "%s serverTimeout=%d\n"
1154 "%s backendResponses=%d\n"
1155 "%s backendAccessChallenges=%d\n"
1156 "%s backendOtherRequestsToSupplicant=%d\n"
1157 "%s backendAuthSuccesses=%d\n"
1158 "%s backendAuthFails=%d\n",
1159 prefix, prefix,
1160 be_auth_state_txt(sm->be_auth_state),
1161 prefix, _SB(sm->eap_if->eapNoReq), _SB(sm->eap_if->eapReq),
1162 _SB(sm->eap_if->eapResp),
1163 prefix, sm->serverTimeout,
1164 prefix, sm->backendResponses,
1165 prefix, sm->backendAccessChallenges,
1166 prefix, sm->backendOtherRequestsToSupplicant,
1167 prefix, sm->backendAuthSuccesses,
1168 prefix, sm->backendAuthFails);
1169
1170 fprintf(f, "%s Reauthentication Timer:\n"
1171 "%s state=%s\n"
1172 "%s reAuthPeriod=%d reAuthEnabled=%s\n", prefix, prefix,
1173 reauth_timer_state_txt(sm->reauth_timer_state), prefix,
1174 sm->reAuthPeriod, _SB(sm->reAuthEnabled));
1175
1176 fprintf(f, "%s Authenticator Key Transmit:\n"
1177 "%s state=%s\n", prefix, prefix,
1178 auth_key_tx_state_txt(sm->auth_key_tx_state));
1179
1180 fprintf(f, "%s Key Receive:\n"
1181 "%s state=%s\n"
1182 "%s rxKey=%s\n", prefix, prefix,
1183 key_rx_state_txt(sm->key_rx_state), prefix, _SB(sm->rxKey));
1184
1185 fprintf(f, "%s Controlled Directions:\n"
1186 "%s state=%s\n"
1187 "%s adminControlledDirections=%s "
1188 "operControlledDirections=%s\n"
1189 "%s operEdge=%s\n", prefix, prefix,
1190 ctrl_dir_state_txt(sm->ctrl_dir_state),
1191 prefix, ctrl_dir_txt(sm->adminControlledDirections),
1192 ctrl_dir_txt(sm->operControlledDirections),
1193 prefix, _SB(sm->operEdge));
1194#undef _SB
1195}
1196#endif /* HOSTAPD_DUMP_STATE */
1197
1198
1199static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
1200 size_t identity_len, int phase2,
1201 struct eap_user *user)
1202{
1203 struct eapol_state_machine *sm = ctx;
1204 return sm->eapol->cb.get_eap_user(sm->hapd, identity, identity_len,
1205 phase2, user);
1206}
1207
1208
1209static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
1210{
1211 struct eapol_state_machine *sm = ctx;
1212 *len = sm->eapol->conf.eap_req_id_text_len;
1213 return sm->eapol->conf.eap_req_id_text;
1214}
1215
1216
1217static struct eapol_callbacks eapol_cb =
1218{
1219 .get_eap_user = eapol_sm_get_eap_user,
1220 .get_eap_req_id_text = eapol_sm_get_eap_req_id_text,
1221};
1222
1223
1224int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
1225{
1226 if (sm == NULL || ctx != sm->eap)
1227 return -1;
1228
1229 eap_sm_pending_cb(sm->eap);
1230 eapol_auth_step(sm);
1231
1232 return 0;
1233}
1234
1235
1236static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
1237 struct eapol_auth_config *src)
1238{
1239 dst->hapd = src->hapd;
1240 dst->eap_reauth_period = src->eap_reauth_period;
1241 dst->wpa = src->wpa;
1242 dst->individual_wep_key_len = src->individual_wep_key_len;
1243 dst->eap_server = src->eap_server;
1244 dst->ssl_ctx = src->ssl_ctx;
1245 dst->eap_sim_db_priv = src->eap_sim_db_priv;
1246 os_free(dst->eap_req_id_text);
1247 if (src->eap_req_id_text) {
1248 dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
1249 if (dst->eap_req_id_text == NULL)
1250 return -1;
1251 os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
1252 src->eap_req_id_text_len);
1253 dst->eap_req_id_text_len = src->eap_req_id_text_len;
1254 } else {
1255 dst->eap_req_id_text = NULL;
1256 dst->eap_req_id_text_len = 0;
1257 }
1258 if (src->pac_opaque_encr_key) {
1259 dst->pac_opaque_encr_key = os_malloc(16);
1260 os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
1261 16);
1262 } else
1263 dst->pac_opaque_encr_key = NULL;
2d867244
JM
1264 if (src->eap_fast_a_id) {
1265 dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
1266 if (dst->eap_fast_a_id == NULL) {
1267 os_free(dst->eap_req_id_text);
1268 return -1;
1269 }
1270 os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
1271 src->eap_fast_a_id_len);
1272 dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
1273 } else
6fc6879b 1274 dst->eap_fast_a_id = NULL;
2d867244
JM
1275 if (src->eap_fast_a_id_info) {
1276 dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
1277 if (dst->eap_fast_a_id_info == NULL) {
1278 os_free(dst->eap_req_id_text);
1279 os_free(dst->eap_fast_a_id);
1280 return -1;
1281 }
1282 } else
1283 dst->eap_fast_a_id_info = NULL;
378eae5e 1284 dst->eap_fast_prov = src->eap_fast_prov;
a11c90a6
JM
1285 dst->pac_key_lifetime = src->pac_key_lifetime;
1286 dst->pac_key_refresh_time = src->pac_key_refresh_time;
6fc6879b 1287 dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
c3e258ae 1288 dst->tnc = src->tnc;
ad08c363 1289 dst->wps = src->wps;
6fc6879b
JM
1290 return 0;
1291}
1292
1293
1294static void eapol_auth_conf_free(struct eapol_auth_config *conf)
1295{
1296 os_free(conf->eap_req_id_text);
1297 conf->eap_req_id_text = NULL;
1298 os_free(conf->pac_opaque_encr_key);
1299 conf->pac_opaque_encr_key = NULL;
1300 os_free(conf->eap_fast_a_id);
1301 conf->eap_fast_a_id = NULL;
2d867244
JM
1302 os_free(conf->eap_fast_a_id_info);
1303 conf->eap_fast_a_id_info = NULL;
6fc6879b
JM
1304}
1305
1306
1307struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
1308 struct eapol_auth_cb *cb)
1309{
1310 struct eapol_authenticator *eapol;
1311
1312 eapol = os_zalloc(sizeof(*eapol));
1313 if (eapol == NULL)
1314 return NULL;
1315
1316 if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
1317 os_free(eapol);
1318 return NULL;
1319 }
1320
f55802e8
JM
1321 if (conf->individual_wep_key_len > 0) {
1322 /* use key0 in individual key and key1 in broadcast key */
1323 eapol->default_wep_key_idx = 1;
1324 }
1325
6fc6879b
JM
1326 eapol->cb.eapol_send = cb->eapol_send;
1327 eapol->cb.aaa_send = cb->aaa_send;
1328 eapol->cb.finished = cb->finished;
1329 eapol->cb.get_eap_user = cb->get_eap_user;
1330 eapol->cb.sta_entry_alive = cb->sta_entry_alive;
1331 eapol->cb.logger = cb->logger;
1332 eapol->cb.set_port_authorized = cb->set_port_authorized;
1333 eapol->cb.abort_auth = cb->abort_auth;
1334 eapol->cb.tx_key = cb->tx_key;
1335
1336 return eapol;
1337}
1338
1339
1340void eapol_auth_deinit(struct eapol_authenticator *eapol)
1341{
1342 if (eapol == NULL)
1343 return;
1344
1345 eapol_auth_conf_free(&eapol->conf);
f55802e8 1346 os_free(eapol->default_wep_key);
6fc6879b
JM
1347 os_free(eapol);
1348}