2 * IEEE 802.1X-2004 Authenticator - EAPOL state machine
3 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
19 #include "state_machine.h"
20 #include "common/eapol_common.h"
21 #include "eap_common/eap_defs.h"
22 #include "eap_common/eap_common.h"
23 #include "eap_server/eap.h"
24 #include "eapol_auth_sm.h"
25 #include "eapol_auth_sm_i.h"
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
31 static struct eapol_callbacks eapol_cb
;
33 /* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
35 #define setPortAuthorized() \
36 sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
37 #define setPortUnauthorized() \
38 sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
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->eapol->conf.ctx, sm->sta)
45 #define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
46 #define processKey() do { } while (0)
49 static void eapol_sm_step_run(struct eapol_state_machine
*sm
);
50 static void eapol_sm_step_cb(void *eloop_ctx
, void *timeout_ctx
);
51 static void eapol_auth_initialize(struct eapol_state_machine
*sm
);
54 static void eapol_auth_logger(struct eapol_authenticator
*eapol
,
55 const u8
*addr
, eapol_logger_level level
,
58 if (eapol
->cb
.logger
== NULL
)
60 eapol
->cb
.logger(eapol
->conf
.ctx
, addr
, level
, txt
);
64 static void eapol_auth_vlogger(struct eapol_authenticator
*eapol
,
65 const u8
*addr
, eapol_logger_level level
,
72 if (eapol
->cb
.logger
== NULL
)
75 maxlen
= os_strlen(fmt
) + 100;
76 format
= os_malloc(maxlen
);
81 vsnprintf(format
, maxlen
, fmt
, ap
);
84 eapol_auth_logger(eapol
, addr
, level
, format
);
90 static void eapol_auth_tx_canned_eap(struct eapol_state_machine
*sm
,
95 os_memset(&eap
, 0, sizeof(eap
));
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
));
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
->eapol
->conf
.ctx
, sm
->sta
,
105 IEEE802_1X_TYPE_EAP_PACKET
,
106 (u8
*) &eap
, sizeof(eap
));
107 sm
->dot1xAuthEapolFramesTx
++;
111 static void eapol_auth_tx_req(struct eapol_state_machine
*sm
)
113 if (sm
->eap_if
->eapReqData
== NULL
||
114 wpabuf_len(sm
->eap_if
->eapReqData
) < sizeof(struct eap_hdr
)) {
115 eapol_auth_logger(sm
->eapol
, sm
->addr
,
117 "TxReq called, but there is no EAP request "
118 "from authentication server");
122 if (sm
->flags
& EAPOL_SM_WAIT_START
) {
123 wpa_printf(MSG_DEBUG
, "EAPOL: Drop EAPOL TX to " MACSTR
124 " while waiting for EAPOL-Start",
129 sm
->last_eap_id
= eap_get_id(sm
->eap_if
->eapReqData
);
130 eapol_auth_vlogger(sm
->eapol
, sm
->addr
, EAPOL_LOGGER_DEBUG
,
131 "Sending EAP Packet (identifier %d)",
133 sm
->eapol
->cb
.eapol_send(sm
->eapol
->conf
.ctx
, sm
->sta
,
134 IEEE802_1X_TYPE_EAP_PACKET
,
135 wpabuf_head(sm
->eap_if
->eapReqData
),
136 wpabuf_len(sm
->eap_if
->eapReqData
));
137 sm
->dot1xAuthEapolFramesTx
++;
138 if (eap_get_type(sm
->eap_if
->eapReqData
) == EAP_TYPE_IDENTITY
)
139 sm
->dot1xAuthEapolReqIdFramesTx
++;
141 sm
->dot1xAuthEapolReqFramesTx
++;
146 * eapol_port_timers_tick - Port Timers state machine
147 * @eloop_ctx: struct eapol_state_machine *
148 * @timeout_ctx: Not used
150 * This statemachine is implemented as a function that will be called
151 * once a second as a registered event loop timeout.
153 static void eapol_port_timers_tick(void *eloop_ctx
, void *timeout_ctx
)
155 struct eapol_state_machine
*state
= timeout_ctx
;
157 if (state
->aWhile
> 0) {
159 if (state
->aWhile
== 0) {
160 wpa_printf(MSG_DEBUG
, "IEEE 802.1X: " MACSTR
162 MAC2STR(state
->addr
));
166 if (state
->quietWhile
> 0) {
168 if (state
->quietWhile
== 0) {
169 wpa_printf(MSG_DEBUG
, "IEEE 802.1X: " MACSTR
170 " - quietWhile --> 0",
171 MAC2STR(state
->addr
));
175 if (state
->reAuthWhen
> 0) {
177 if (state
->reAuthWhen
== 0) {
178 wpa_printf(MSG_DEBUG
, "IEEE 802.1X: " MACSTR
179 " - reAuthWhen --> 0",
180 MAC2STR(state
->addr
));
184 if (state
->eap_if
->retransWhile
> 0) {
185 state
->eap_if
->retransWhile
--;
186 if (state
->eap_if
->retransWhile
== 0) {
187 wpa_printf(MSG_DEBUG
, "IEEE 802.1X: " MACSTR
188 " - (EAP) retransWhile --> 0",
189 MAC2STR(state
->addr
));
193 eapol_sm_step_run(state
);
195 eloop_register_timeout(1, 0, eapol_port_timers_tick
, eloop_ctx
, state
);
200 /* Authenticator PAE state machine */
202 SM_STATE(AUTH_PAE
, INITIALIZE
)
204 SM_ENTRY_MA(AUTH_PAE
, INITIALIZE
, auth_pae
);
209 SM_STATE(AUTH_PAE
, DISCONNECTED
)
211 int from_initialize
= sm
->auth_pae_state
== AUTH_PAE_INITIALIZE
;
213 if (sm
->eapolLogoff
) {
214 if (sm
->auth_pae_state
== AUTH_PAE_CONNECTING
)
215 sm
->authEapLogoffsWhileConnecting
++;
216 else if (sm
->auth_pae_state
== AUTH_PAE_AUTHENTICATED
)
217 sm
->authAuthEapLogoffWhileAuthenticated
++;
220 SM_ENTRY_MA(AUTH_PAE
, DISCONNECTED
, auth_pae
);
222 sm
->authPortStatus
= Unauthorized
;
223 setPortUnauthorized();
225 sm
->eapolLogoff
= FALSE
;
226 if (!from_initialize
) {
227 sm
->eapol
->cb
.finished(sm
->eapol
->conf
.ctx
, sm
->sta
, 0,
228 sm
->flags
& EAPOL_SM_PREAUTH
);
233 SM_STATE(AUTH_PAE
, RESTART
)
235 if (sm
->auth_pae_state
== AUTH_PAE_AUTHENTICATED
) {
236 if (sm
->reAuthenticate
)
237 sm
->authAuthReauthsWhileAuthenticated
++;
239 sm
->authAuthEapStartsWhileAuthenticated
++;
241 sm
->authAuthEapLogoffWhileAuthenticated
++;
244 SM_ENTRY_MA(AUTH_PAE
, RESTART
, auth_pae
);
246 sm
->eap_if
->eapRestart
= TRUE
;
250 SM_STATE(AUTH_PAE
, CONNECTING
)
252 if (sm
->auth_pae_state
!= AUTH_PAE_CONNECTING
)
253 sm
->authEntersConnecting
++;
255 SM_ENTRY_MA(AUTH_PAE
, CONNECTING
, auth_pae
);
257 sm
->reAuthenticate
= FALSE
;
262 SM_STATE(AUTH_PAE
, HELD
)
264 if (sm
->auth_pae_state
== AUTH_PAE_AUTHENTICATING
&& sm
->authFail
)
265 sm
->authAuthFailWhileAuthenticating
++;
267 SM_ENTRY_MA(AUTH_PAE
, HELD
, auth_pae
);
269 sm
->authPortStatus
= Unauthorized
;
270 setPortUnauthorized();
271 sm
->quietWhile
= sm
->quietPeriod
;
272 sm
->eapolLogoff
= FALSE
;
274 eapol_auth_vlogger(sm
->eapol
, sm
->addr
, EAPOL_LOGGER_WARNING
,
275 "authentication failed - EAP type: %d (%s)",
276 sm
->eap_type_authsrv
,
277 eap_server_get_name(0, sm
->eap_type_authsrv
));
278 if (sm
->eap_type_authsrv
!= sm
->eap_type_supp
) {
279 eapol_auth_vlogger(sm
->eapol
, sm
->addr
, EAPOL_LOGGER_INFO
,
280 "Supplicant used different EAP type: "
281 "%d (%s)", sm
->eap_type_supp
,
282 eap_server_get_name(0, sm
->eap_type_supp
));
284 sm
->eapol
->cb
.finished(sm
->eapol
->conf
.ctx
, sm
->sta
, 0,
285 sm
->flags
& EAPOL_SM_PREAUTH
);
289 SM_STATE(AUTH_PAE
, AUTHENTICATED
)
293 if (sm
->auth_pae_state
== AUTH_PAE_AUTHENTICATING
&& sm
->authSuccess
)
294 sm
->authAuthSuccessesWhileAuthenticating
++;
296 SM_ENTRY_MA(AUTH_PAE
, AUTHENTICATED
, auth_pae
);
298 sm
->authPortStatus
= Authorized
;
301 if (sm
->flags
& EAPOL_SM_PREAUTH
)
302 extra
= " (pre-authentication)";
303 else if (sm
->flags
& EAPOL_SM_FROM_PMKSA_CACHE
)
304 extra
= " (PMKSA cache)";
305 eapol_auth_vlogger(sm
->eapol
, sm
->addr
, EAPOL_LOGGER_INFO
,
306 "authenticated - EAP type: %d (%s)%s",
307 sm
->eap_type_authsrv
,
308 eap_server_get_name(0, sm
->eap_type_authsrv
),
310 sm
->eapol
->cb
.finished(sm
->eapol
->conf
.ctx
, sm
->sta
, 1,
311 sm
->flags
& EAPOL_SM_PREAUTH
);
315 SM_STATE(AUTH_PAE
, AUTHENTICATING
)
317 SM_ENTRY_MA(AUTH_PAE
, AUTHENTICATING
, auth_pae
);
319 sm
->eapolStart
= FALSE
;
320 sm
->authSuccess
= FALSE
;
321 sm
->authFail
= FALSE
;
322 sm
->authTimeout
= FALSE
;
323 sm
->authStart
= TRUE
;
329 SM_STATE(AUTH_PAE
, ABORTING
)
331 if (sm
->auth_pae_state
== AUTH_PAE_AUTHENTICATING
) {
333 sm
->authAuthTimeoutsWhileAuthenticating
++;
335 sm
->authAuthEapStartsWhileAuthenticating
++;
337 sm
->authAuthEapLogoffWhileAuthenticating
++;
340 SM_ENTRY_MA(AUTH_PAE
, ABORTING
, auth_pae
);
342 sm
->authAbort
= TRUE
;
348 SM_STATE(AUTH_PAE
, FORCE_AUTH
)
350 SM_ENTRY_MA(AUTH_PAE
, FORCE_AUTH
, auth_pae
);
352 sm
->authPortStatus
= Authorized
;
354 sm
->portMode
= ForceAuthorized
;
355 sm
->eapolStart
= FALSE
;
360 SM_STATE(AUTH_PAE
, FORCE_UNAUTH
)
362 SM_ENTRY_MA(AUTH_PAE
, FORCE_UNAUTH
, auth_pae
);
364 sm
->authPortStatus
= Unauthorized
;
365 setPortUnauthorized();
366 sm
->portMode
= ForceUnauthorized
;
367 sm
->eapolStart
= FALSE
;
374 if ((sm
->portControl
== Auto
&& sm
->portMode
!= sm
->portControl
) ||
375 sm
->initialize
|| !sm
->eap_if
->portEnabled
)
376 SM_ENTER_GLOBAL(AUTH_PAE
, INITIALIZE
);
377 else if (sm
->portControl
== ForceAuthorized
&&
378 sm
->portMode
!= sm
->portControl
&&
379 !(sm
->initialize
|| !sm
->eap_if
->portEnabled
))
380 SM_ENTER_GLOBAL(AUTH_PAE
, FORCE_AUTH
);
381 else if (sm
->portControl
== ForceUnauthorized
&&
382 sm
->portMode
!= sm
->portControl
&&
383 !(sm
->initialize
|| !sm
->eap_if
->portEnabled
))
384 SM_ENTER_GLOBAL(AUTH_PAE
, FORCE_UNAUTH
);
386 switch (sm
->auth_pae_state
) {
387 case AUTH_PAE_INITIALIZE
:
388 SM_ENTER(AUTH_PAE
, DISCONNECTED
);
390 case AUTH_PAE_DISCONNECTED
:
391 SM_ENTER(AUTH_PAE
, RESTART
);
393 case AUTH_PAE_RESTART
:
394 if (!sm
->eap_if
->eapRestart
)
395 SM_ENTER(AUTH_PAE
, CONNECTING
);
398 if (sm
->quietWhile
== 0)
399 SM_ENTER(AUTH_PAE
, RESTART
);
401 case AUTH_PAE_CONNECTING
:
402 if (sm
->eapolLogoff
|| sm
->reAuthCount
> sm
->reAuthMax
)
403 SM_ENTER(AUTH_PAE
, DISCONNECTED
);
404 else if ((sm
->eap_if
->eapReq
&&
405 sm
->reAuthCount
<= sm
->reAuthMax
) ||
406 sm
->eap_if
->eapSuccess
|| sm
->eap_if
->eapFail
)
407 SM_ENTER(AUTH_PAE
, AUTHENTICATING
);
409 case AUTH_PAE_AUTHENTICATED
:
410 if (sm
->eapolStart
|| sm
->reAuthenticate
)
411 SM_ENTER(AUTH_PAE
, RESTART
);
412 else if (sm
->eapolLogoff
|| !sm
->portValid
)
413 SM_ENTER(AUTH_PAE
, DISCONNECTED
);
415 case AUTH_PAE_AUTHENTICATING
:
416 if (sm
->authSuccess
&& sm
->portValid
)
417 SM_ENTER(AUTH_PAE
, AUTHENTICATED
);
418 else if (sm
->authFail
||
419 (sm
->keyDone
&& !sm
->portValid
))
420 SM_ENTER(AUTH_PAE
, HELD
);
421 else if (sm
->eapolStart
|| sm
->eapolLogoff
||
423 SM_ENTER(AUTH_PAE
, ABORTING
);
425 case AUTH_PAE_ABORTING
:
426 if (sm
->eapolLogoff
&& !sm
->authAbort
)
427 SM_ENTER(AUTH_PAE
, DISCONNECTED
);
428 else if (!sm
->eapolLogoff
&& !sm
->authAbort
)
429 SM_ENTER(AUTH_PAE
, RESTART
);
431 case AUTH_PAE_FORCE_AUTH
:
433 SM_ENTER(AUTH_PAE
, FORCE_AUTH
);
435 case AUTH_PAE_FORCE_UNAUTH
:
437 SM_ENTER(AUTH_PAE
, FORCE_UNAUTH
);
445 /* Backend Authentication state machine */
447 SM_STATE(BE_AUTH
, INITIALIZE
)
449 SM_ENTRY_MA(BE_AUTH
, INITIALIZE
, be_auth
);
452 sm
->eap_if
->eapNoReq
= FALSE
;
453 sm
->authAbort
= FALSE
;
457 SM_STATE(BE_AUTH
, REQUEST
)
459 SM_ENTRY_MA(BE_AUTH
, REQUEST
, be_auth
);
462 sm
->eap_if
->eapReq
= FALSE
;
463 sm
->backendOtherRequestsToSupplicant
++;
466 * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
467 * it looks like this would be logical thing to do there since the old
468 * EAP response would not be valid anymore after the new EAP request
471 * A race condition has been reported, in which hostapd ended up
472 * sending out EAP-Response/Identity as a response to the first
473 * EAP-Request from the main EAP method. This can be avoided by
474 * clearing eapolEap here.
476 sm
->eapolEap
= FALSE
;
480 SM_STATE(BE_AUTH
, RESPONSE
)
482 SM_ENTRY_MA(BE_AUTH
, RESPONSE
, be_auth
);
484 sm
->authTimeout
= FALSE
;
485 sm
->eapolEap
= FALSE
;
486 sm
->eap_if
->eapNoReq
= FALSE
;
487 sm
->aWhile
= sm
->serverTimeout
;
488 sm
->eap_if
->eapResp
= TRUE
;
489 /* sendRespToServer(); */
490 sm
->backendResponses
++;
494 SM_STATE(BE_AUTH
, SUCCESS
)
496 SM_ENTRY_MA(BE_AUTH
, SUCCESS
, be_auth
);
499 sm
->authSuccess
= TRUE
;
504 SM_STATE(BE_AUTH
, FAIL
)
506 SM_ENTRY_MA(BE_AUTH
, FAIL
, be_auth
);
513 SM_STATE(BE_AUTH
, TIMEOUT
)
515 SM_ENTRY_MA(BE_AUTH
, TIMEOUT
, be_auth
);
517 sm
->authTimeout
= TRUE
;
521 SM_STATE(BE_AUTH
, IDLE
)
523 SM_ENTRY_MA(BE_AUTH
, IDLE
, be_auth
);
525 sm
->authStart
= FALSE
;
529 SM_STATE(BE_AUTH
, IGNORE
)
531 SM_ENTRY_MA(BE_AUTH
, IGNORE
, be_auth
);
533 sm
->eap_if
->eapNoReq
= FALSE
;
539 if (sm
->portControl
!= Auto
|| sm
->initialize
|| sm
->authAbort
) {
540 SM_ENTER_GLOBAL(BE_AUTH
, INITIALIZE
);
544 switch (sm
->be_auth_state
) {
545 case BE_AUTH_INITIALIZE
:
546 SM_ENTER(BE_AUTH
, IDLE
);
548 case BE_AUTH_REQUEST
:
550 SM_ENTER(BE_AUTH
, RESPONSE
);
551 else if (sm
->eap_if
->eapReq
)
552 SM_ENTER(BE_AUTH
, REQUEST
);
553 else if (sm
->eap_if
->eapTimeout
)
554 SM_ENTER(BE_AUTH
, TIMEOUT
);
556 case BE_AUTH_RESPONSE
:
557 if (sm
->eap_if
->eapNoReq
)
558 SM_ENTER(BE_AUTH
, IGNORE
);
559 if (sm
->eap_if
->eapReq
) {
560 sm
->backendAccessChallenges
++;
561 SM_ENTER(BE_AUTH
, REQUEST
);
562 } else if (sm
->aWhile
== 0)
563 SM_ENTER(BE_AUTH
, TIMEOUT
);
564 else if (sm
->eap_if
->eapFail
) {
565 sm
->backendAuthFails
++;
566 SM_ENTER(BE_AUTH
, FAIL
);
567 } else if (sm
->eap_if
->eapSuccess
) {
568 sm
->backendAuthSuccesses
++;
569 SM_ENTER(BE_AUTH
, SUCCESS
);
572 case BE_AUTH_SUCCESS
:
573 SM_ENTER(BE_AUTH
, IDLE
);
576 SM_ENTER(BE_AUTH
, IDLE
);
578 case BE_AUTH_TIMEOUT
:
579 SM_ENTER(BE_AUTH
, IDLE
);
582 if (sm
->eap_if
->eapFail
&& sm
->authStart
)
583 SM_ENTER(BE_AUTH
, FAIL
);
584 else if (sm
->eap_if
->eapReq
&& sm
->authStart
)
585 SM_ENTER(BE_AUTH
, REQUEST
);
586 else if (sm
->eap_if
->eapSuccess
&& sm
->authStart
)
587 SM_ENTER(BE_AUTH
, SUCCESS
);
591 SM_ENTER(BE_AUTH
, RESPONSE
);
592 else if (sm
->eap_if
->eapReq
)
593 SM_ENTER(BE_AUTH
, REQUEST
);
594 else if (sm
->eap_if
->eapTimeout
)
595 SM_ENTER(BE_AUTH
, TIMEOUT
);
602 /* Reauthentication Timer state machine */
604 SM_STATE(REAUTH_TIMER
, INITIALIZE
)
606 SM_ENTRY_MA(REAUTH_TIMER
, INITIALIZE
, reauth_timer
);
608 sm
->reAuthWhen
= sm
->reAuthPeriod
;
612 SM_STATE(REAUTH_TIMER
, REAUTHENTICATE
)
614 SM_ENTRY_MA(REAUTH_TIMER
, REAUTHENTICATE
, reauth_timer
);
616 sm
->reAuthenticate
= TRUE
;
617 sm
->eapol
->cb
.eapol_event(sm
->eapol
->conf
.ctx
, sm
->sta
,
618 EAPOL_AUTH_REAUTHENTICATE
);
622 SM_STEP(REAUTH_TIMER
)
624 if (sm
->portControl
!= Auto
|| sm
->initialize
||
625 sm
->authPortStatus
== Unauthorized
|| !sm
->reAuthEnabled
) {
626 SM_ENTER_GLOBAL(REAUTH_TIMER
, INITIALIZE
);
630 switch (sm
->reauth_timer_state
) {
631 case REAUTH_TIMER_INITIALIZE
:
632 if (sm
->reAuthWhen
== 0)
633 SM_ENTER(REAUTH_TIMER
, REAUTHENTICATE
);
635 case REAUTH_TIMER_REAUTHENTICATE
:
636 SM_ENTER(REAUTH_TIMER
, INITIALIZE
);
643 /* Authenticator Key Transmit state machine */
645 SM_STATE(AUTH_KEY_TX
, NO_KEY_TRANSMIT
)
647 SM_ENTRY_MA(AUTH_KEY_TX
, NO_KEY_TRANSMIT
, auth_key_tx
);
651 SM_STATE(AUTH_KEY_TX
, KEY_TRANSMIT
)
653 SM_ENTRY_MA(AUTH_KEY_TX
, KEY_TRANSMIT
, auth_key_tx
);
656 sm
->eap_if
->eapKeyAvailable
= FALSE
;
663 if (sm
->initialize
|| sm
->portControl
!= Auto
) {
664 SM_ENTER_GLOBAL(AUTH_KEY_TX
, NO_KEY_TRANSMIT
);
668 switch (sm
->auth_key_tx_state
) {
669 case AUTH_KEY_TX_NO_KEY_TRANSMIT
:
670 if (sm
->keyTxEnabled
&& sm
->eap_if
->eapKeyAvailable
&&
671 sm
->keyRun
&& !(sm
->flags
& EAPOL_SM_USES_WPA
))
672 SM_ENTER(AUTH_KEY_TX
, KEY_TRANSMIT
);
674 case AUTH_KEY_TX_KEY_TRANSMIT
:
675 if (!sm
->keyTxEnabled
|| !sm
->keyRun
)
676 SM_ENTER(AUTH_KEY_TX
, NO_KEY_TRANSMIT
);
677 else if (sm
->eap_if
->eapKeyAvailable
)
678 SM_ENTER(AUTH_KEY_TX
, KEY_TRANSMIT
);
685 /* Key Receive state machine */
687 SM_STATE(KEY_RX
, NO_KEY_RECEIVE
)
689 SM_ENTRY_MA(KEY_RX
, NO_KEY_RECEIVE
, key_rx
);
693 SM_STATE(KEY_RX
, KEY_RECEIVE
)
695 SM_ENTRY_MA(KEY_RX
, KEY_RECEIVE
, key_rx
);
704 if (sm
->initialize
|| !sm
->eap_if
->portEnabled
) {
705 SM_ENTER_GLOBAL(KEY_RX
, NO_KEY_RECEIVE
);
709 switch (sm
->key_rx_state
) {
710 case KEY_RX_NO_KEY_RECEIVE
:
712 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
714 case KEY_RX_KEY_RECEIVE
:
716 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
723 /* Controlled Directions state machine */
725 SM_STATE(CTRL_DIR
, FORCE_BOTH
)
727 SM_ENTRY_MA(CTRL_DIR
, FORCE_BOTH
, ctrl_dir
);
728 sm
->operControlledDirections
= Both
;
732 SM_STATE(CTRL_DIR
, IN_OR_BOTH
)
734 SM_ENTRY_MA(CTRL_DIR
, IN_OR_BOTH
, ctrl_dir
);
735 sm
->operControlledDirections
= sm
->adminControlledDirections
;
741 if (sm
->initialize
) {
742 SM_ENTER_GLOBAL(CTRL_DIR
, IN_OR_BOTH
);
746 switch (sm
->ctrl_dir_state
) {
747 case CTRL_DIR_FORCE_BOTH
:
748 if (sm
->eap_if
->portEnabled
&& sm
->operEdge
)
749 SM_ENTER(CTRL_DIR
, IN_OR_BOTH
);
751 case CTRL_DIR_IN_OR_BOTH
:
752 if (sm
->operControlledDirections
!=
753 sm
->adminControlledDirections
)
754 SM_ENTER(CTRL_DIR
, IN_OR_BOTH
);
755 if (!sm
->eap_if
->portEnabled
|| !sm
->operEdge
)
756 SM_ENTER(CTRL_DIR
, FORCE_BOTH
);
763 struct eapol_state_machine
*
764 eapol_auth_alloc(struct eapol_authenticator
*eapol
, const u8
*addr
,
765 int flags
, const struct wpabuf
*assoc_wps_ie
, void *sta_ctx
)
767 struct eapol_state_machine
*sm
;
768 struct eap_config eap_conf
;
773 sm
= os_zalloc(sizeof(*sm
));
775 wpa_printf(MSG_DEBUG
, "IEEE 802.1X state machine allocation "
779 sm
->radius_identifier
= -1;
780 os_memcpy(sm
->addr
, addr
, ETH_ALEN
);
786 /* Set default values for state machine constants */
787 sm
->auth_pae_state
= AUTH_PAE_INITIALIZE
;
788 sm
->quietPeriod
= AUTH_PAE_DEFAULT_quietPeriod
;
789 sm
->reAuthMax
= AUTH_PAE_DEFAULT_reAuthMax
;
791 sm
->be_auth_state
= BE_AUTH_INITIALIZE
;
792 sm
->serverTimeout
= BE_AUTH_DEFAULT_serverTimeout
;
794 sm
->reauth_timer_state
= REAUTH_TIMER_INITIALIZE
;
795 sm
->reAuthPeriod
= eapol
->conf
.eap_reauth_period
;
796 sm
->reAuthEnabled
= eapol
->conf
.eap_reauth_period
> 0 ? TRUE
: FALSE
;
798 sm
->auth_key_tx_state
= AUTH_KEY_TX_NO_KEY_TRANSMIT
;
800 sm
->key_rx_state
= KEY_RX_NO_KEY_RECEIVE
;
802 sm
->ctrl_dir_state
= CTRL_DIR_IN_OR_BOTH
;
804 sm
->portControl
= Auto
;
806 if (!eapol
->conf
.wpa
&&
807 (eapol
->default_wep_key
|| eapol
->conf
.individual_wep_key_len
> 0))
808 sm
->keyTxEnabled
= TRUE
;
810 sm
->keyTxEnabled
= FALSE
;
812 sm
->portValid
= FALSE
;
814 sm
->portValid
= TRUE
;
816 os_memset(&eap_conf
, 0, sizeof(eap_conf
));
817 eap_conf
.eap_server
= eapol
->conf
.eap_server
;
818 eap_conf
.ssl_ctx
= eapol
->conf
.ssl_ctx
;
819 eap_conf
.eap_sim_db_priv
= eapol
->conf
.eap_sim_db_priv
;
820 eap_conf
.pac_opaque_encr_key
= eapol
->conf
.pac_opaque_encr_key
;
821 eap_conf
.eap_fast_a_id
= eapol
->conf
.eap_fast_a_id
;
822 eap_conf
.eap_fast_a_id_len
= eapol
->conf
.eap_fast_a_id_len
;
823 eap_conf
.eap_fast_a_id_info
= eapol
->conf
.eap_fast_a_id_info
;
824 eap_conf
.eap_fast_prov
= eapol
->conf
.eap_fast_prov
;
825 eap_conf
.pac_key_lifetime
= eapol
->conf
.pac_key_lifetime
;
826 eap_conf
.pac_key_refresh_time
= eapol
->conf
.pac_key_refresh_time
;
827 eap_conf
.eap_sim_aka_result_ind
= eapol
->conf
.eap_sim_aka_result_ind
;
828 eap_conf
.tnc
= eapol
->conf
.tnc
;
829 eap_conf
.wps
= eapol
->conf
.wps
;
830 eap_conf
.assoc_wps_ie
= assoc_wps_ie
;
831 eap_conf
.peer_addr
= addr
;
832 sm
->eap
= eap_server_sm_init(sm
, &eapol_cb
, &eap_conf
);
833 if (sm
->eap
== NULL
) {
837 sm
->eap_if
= eap_get_interface(sm
->eap
);
839 eapol_auth_initialize(sm
);
845 void eapol_auth_free(struct eapol_state_machine
*sm
)
850 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
851 eloop_cancel_timeout(eapol_sm_step_cb
, sm
, NULL
);
853 eap_server_sm_deinit(sm
->eap
);
858 static int eapol_sm_sta_entry_alive(struct eapol_authenticator
*eapol
,
861 return eapol
->cb
.sta_entry_alive(eapol
->conf
.ctx
, addr
);
865 static void eapol_sm_step_run(struct eapol_state_machine
*sm
)
867 struct eapol_authenticator
*eapol
= sm
->eapol
;
869 unsigned int prev_auth_pae
, prev_be_auth
, prev_reauth_timer
,
870 prev_auth_key_tx
, prev_key_rx
, prev_ctrl_dir
;
873 os_memcpy(addr
, sm
->addr
, ETH_ALEN
);
876 * Allow EAPOL state machines to run as long as there are state
877 * changes, but exit and return here through event loop if more than
878 * 100 steps is needed as a precaution against infinite loops inside
882 prev_auth_pae
= sm
->auth_pae_state
;
883 prev_be_auth
= sm
->be_auth_state
;
884 prev_reauth_timer
= sm
->reauth_timer_state
;
885 prev_auth_key_tx
= sm
->auth_key_tx_state
;
886 prev_key_rx
= sm
->key_rx_state
;
887 prev_ctrl_dir
= sm
->ctrl_dir_state
;
889 SM_STEP_RUN(AUTH_PAE
);
890 if (sm
->initializing
|| eapol_sm_sta_entry_alive(eapol
, addr
))
891 SM_STEP_RUN(BE_AUTH
);
892 if (sm
->initializing
|| eapol_sm_sta_entry_alive(eapol
, addr
))
893 SM_STEP_RUN(REAUTH_TIMER
);
894 if (sm
->initializing
|| eapol_sm_sta_entry_alive(eapol
, addr
))
895 SM_STEP_RUN(AUTH_KEY_TX
);
896 if (sm
->initializing
|| eapol_sm_sta_entry_alive(eapol
, addr
))
898 if (sm
->initializing
|| eapol_sm_sta_entry_alive(eapol
, addr
))
899 SM_STEP_RUN(CTRL_DIR
);
901 if (prev_auth_pae
!= sm
->auth_pae_state
||
902 prev_be_auth
!= sm
->be_auth_state
||
903 prev_reauth_timer
!= sm
->reauth_timer_state
||
904 prev_auth_key_tx
!= sm
->auth_key_tx_state
||
905 prev_key_rx
!= sm
->key_rx_state
||
906 prev_ctrl_dir
!= sm
->ctrl_dir_state
) {
909 /* Re-run from eloop timeout */
914 if (eapol_sm_sta_entry_alive(eapol
, addr
) && sm
->eap
) {
915 if (eap_server_sm_step(sm
->eap
)) {
918 /* Re-run from eloop timeout */
923 /* TODO: find a better location for this */
924 if (sm
->eap_if
->aaaEapResp
) {
925 sm
->eap_if
->aaaEapResp
= FALSE
;
926 if (sm
->eap_if
->aaaEapRespData
== NULL
) {
927 wpa_printf(MSG_DEBUG
, "EAPOL: aaaEapResp set, "
928 "but no aaaEapRespData available");
931 sm
->eapol
->cb
.aaa_send(
932 sm
->eapol
->conf
.ctx
, sm
->sta
,
933 wpabuf_head(sm
->eap_if
->aaaEapRespData
),
934 wpabuf_len(sm
->eap_if
->aaaEapRespData
));
938 if (eapol_sm_sta_entry_alive(eapol
, addr
))
939 sm
->eapol
->cb
.eapol_event(sm
->eapol
->conf
.ctx
, sm
->sta
,
940 EAPOL_AUTH_SM_CHANGE
);
944 static void eapol_sm_step_cb(void *eloop_ctx
, void *timeout_ctx
)
946 struct eapol_state_machine
*sm
= eloop_ctx
;
947 eapol_sm_step_run(sm
);
952 * eapol_auth_step - Advance EAPOL state machines
953 * @sm: EAPOL state machine
955 * This function is called to advance EAPOL state machines after any change
956 * that could affect their state.
958 void eapol_auth_step(struct eapol_state_machine
*sm
)
961 * Run eapol_sm_step_run from a registered timeout to make sure that
962 * other possible timeouts/events are processed and to avoid long
963 * function call chains.
966 eloop_register_timeout(0, 0, eapol_sm_step_cb
, sm
, NULL
);
970 static void eapol_auth_initialize(struct eapol_state_machine
*sm
)
972 sm
->initializing
= TRUE
;
973 /* Initialize the state machines by asserting initialize and then
974 * deasserting it after one step */
975 sm
->initialize
= TRUE
;
976 eapol_sm_step_run(sm
);
977 sm
->initialize
= FALSE
;
978 eapol_sm_step_run(sm
);
979 sm
->initializing
= FALSE
;
981 /* Start one second tick for port timers state machine */
982 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
983 eloop_register_timeout(1, 0, eapol_port_timers_tick
, NULL
, sm
);
987 static int eapol_sm_get_eap_user(void *ctx
, const u8
*identity
,
988 size_t identity_len
, int phase2
,
989 struct eap_user
*user
)
991 struct eapol_state_machine
*sm
= ctx
;
992 return sm
->eapol
->cb
.get_eap_user(sm
->eapol
->conf
.ctx
, identity
,
993 identity_len
, phase2
, user
);
997 static const char * eapol_sm_get_eap_req_id_text(void *ctx
, size_t *len
)
999 struct eapol_state_machine
*sm
= ctx
;
1000 *len
= sm
->eapol
->conf
.eap_req_id_text_len
;
1001 return sm
->eapol
->conf
.eap_req_id_text
;
1005 static struct eapol_callbacks eapol_cb
=
1007 .get_eap_user
= eapol_sm_get_eap_user
,
1008 .get_eap_req_id_text
= eapol_sm_get_eap_req_id_text
,
1012 int eapol_auth_eap_pending_cb(struct eapol_state_machine
*sm
, void *ctx
)
1014 if (sm
== NULL
|| ctx
!= sm
->eap
)
1017 eap_sm_pending_cb(sm
->eap
);
1018 eapol_auth_step(sm
);
1024 static int eapol_auth_conf_clone(struct eapol_auth_config
*dst
,
1025 struct eapol_auth_config
*src
)
1027 dst
->ctx
= src
->ctx
;
1028 dst
->eap_reauth_period
= src
->eap_reauth_period
;
1029 dst
->wpa
= src
->wpa
;
1030 dst
->individual_wep_key_len
= src
->individual_wep_key_len
;
1031 dst
->eap_server
= src
->eap_server
;
1032 dst
->ssl_ctx
= src
->ssl_ctx
;
1033 dst
->eap_sim_db_priv
= src
->eap_sim_db_priv
;
1034 os_free(dst
->eap_req_id_text
);
1035 if (src
->eap_req_id_text
) {
1036 dst
->eap_req_id_text
= os_malloc(src
->eap_req_id_text_len
);
1037 if (dst
->eap_req_id_text
== NULL
)
1039 os_memcpy(dst
->eap_req_id_text
, src
->eap_req_id_text
,
1040 src
->eap_req_id_text_len
);
1041 dst
->eap_req_id_text_len
= src
->eap_req_id_text_len
;
1043 dst
->eap_req_id_text
= NULL
;
1044 dst
->eap_req_id_text_len
= 0;
1046 if (src
->pac_opaque_encr_key
) {
1047 dst
->pac_opaque_encr_key
= os_malloc(16);
1048 os_memcpy(dst
->pac_opaque_encr_key
, src
->pac_opaque_encr_key
,
1051 dst
->pac_opaque_encr_key
= NULL
;
1052 if (src
->eap_fast_a_id
) {
1053 dst
->eap_fast_a_id
= os_malloc(src
->eap_fast_a_id_len
);
1054 if (dst
->eap_fast_a_id
== NULL
) {
1055 os_free(dst
->eap_req_id_text
);
1058 os_memcpy(dst
->eap_fast_a_id
, src
->eap_fast_a_id
,
1059 src
->eap_fast_a_id_len
);
1060 dst
->eap_fast_a_id_len
= src
->eap_fast_a_id_len
;
1062 dst
->eap_fast_a_id
= NULL
;
1063 if (src
->eap_fast_a_id_info
) {
1064 dst
->eap_fast_a_id_info
= os_strdup(src
->eap_fast_a_id_info
);
1065 if (dst
->eap_fast_a_id_info
== NULL
) {
1066 os_free(dst
->eap_req_id_text
);
1067 os_free(dst
->eap_fast_a_id
);
1071 dst
->eap_fast_a_id_info
= NULL
;
1072 dst
->eap_fast_prov
= src
->eap_fast_prov
;
1073 dst
->pac_key_lifetime
= src
->pac_key_lifetime
;
1074 dst
->pac_key_refresh_time
= src
->pac_key_refresh_time
;
1075 dst
->eap_sim_aka_result_ind
= src
->eap_sim_aka_result_ind
;
1076 dst
->tnc
= src
->tnc
;
1077 dst
->wps
= src
->wps
;
1082 static void eapol_auth_conf_free(struct eapol_auth_config
*conf
)
1084 os_free(conf
->eap_req_id_text
);
1085 conf
->eap_req_id_text
= NULL
;
1086 os_free(conf
->pac_opaque_encr_key
);
1087 conf
->pac_opaque_encr_key
= NULL
;
1088 os_free(conf
->eap_fast_a_id
);
1089 conf
->eap_fast_a_id
= NULL
;
1090 os_free(conf
->eap_fast_a_id_info
);
1091 conf
->eap_fast_a_id_info
= NULL
;
1095 struct eapol_authenticator
* eapol_auth_init(struct eapol_auth_config
*conf
,
1096 struct eapol_auth_cb
*cb
)
1098 struct eapol_authenticator
*eapol
;
1100 eapol
= os_zalloc(sizeof(*eapol
));
1104 if (eapol_auth_conf_clone(&eapol
->conf
, conf
) < 0) {
1109 if (conf
->individual_wep_key_len
> 0) {
1110 /* use key0 in individual key and key1 in broadcast key */
1111 eapol
->default_wep_key_idx
= 1;
1114 eapol
->cb
.eapol_send
= cb
->eapol_send
;
1115 eapol
->cb
.aaa_send
= cb
->aaa_send
;
1116 eapol
->cb
.finished
= cb
->finished
;
1117 eapol
->cb
.get_eap_user
= cb
->get_eap_user
;
1118 eapol
->cb
.sta_entry_alive
= cb
->sta_entry_alive
;
1119 eapol
->cb
.logger
= cb
->logger
;
1120 eapol
->cb
.set_port_authorized
= cb
->set_port_authorized
;
1121 eapol
->cb
.abort_auth
= cb
->abort_auth
;
1122 eapol
->cb
.tx_key
= cb
->tx_key
;
1123 eapol
->cb
.eapol_event
= cb
->eapol_event
;
1129 void eapol_auth_deinit(struct eapol_authenticator
*eapol
)
1134 eapol_auth_conf_free(&eapol
->conf
);
1135 os_free(eapol
->default_wep_key
);