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