2 * EAPOL supplicant state machines
3 * Copyright (c) 2004-2008, 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.
18 #include "eapol_supp_sm.h"
19 #include "eap_peer/eap.h"
21 #include "eapol_common.h"
24 #include "state_machine.h"
27 #define STATE_MACHINE_DATA struct eapol_sm
28 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
31 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
34 * struct eapol_sm - Internal data for EAPOL state machines
38 unsigned int authWhile
;
39 unsigned int heldWhile
;
40 unsigned int startWhen
;
41 unsigned int idleWhile
; /* for EAP state machine */
42 int timer_tick_enabled
;
44 /* Global variables */
51 PortControl portControl
;
53 PortStatus suppPortStatus
; /* dot1xSuppControlledPortStatus */
61 /* Supplicant PAE state machine */
64 SUPP_PAE_DISCONNECTED
= 1,
66 SUPP_PAE_CONNECTING
= 3,
67 SUPP_PAE_AUTHENTICATING
= 4,
68 SUPP_PAE_AUTHENTICATED
= 5,
72 SUPP_PAE_S_FORCE_AUTH
= 9,
73 SUPP_PAE_S_FORCE_UNAUTH
= 10
74 } SUPP_PAE_state
; /* dot1xSuppPaeState */
78 unsigned int startCount
;
80 PortControl sPortMode
;
82 unsigned int heldPeriod
; /* dot1xSuppHeldPeriod */
83 unsigned int startPeriod
; /* dot1xSuppStartPeriod */
84 unsigned int maxStart
; /* dot1xSuppMaxStart */
86 /* Key Receive state machine */
89 KEY_RX_NO_KEY_RECEIVE
, KEY_RX_KEY_RECEIVE
94 /* Supplicant Backend state machine */
97 SUPP_BE_INITIALIZE
= 1,
101 SUPP_BE_RESPONSE
= 5,
105 } SUPP_BE_state
; /* dot1xSuppBackendPaeState */
111 unsigned int authPeriod
; /* dot1xSuppAuthPeriod */
114 unsigned int dot1xSuppEapolFramesRx
;
115 unsigned int dot1xSuppEapolFramesTx
;
116 unsigned int dot1xSuppEapolStartFramesTx
;
117 unsigned int dot1xSuppEapolLogoffFramesTx
;
118 unsigned int dot1xSuppEapolRespFramesTx
;
119 unsigned int dot1xSuppEapolReqIdFramesRx
;
120 unsigned int dot1xSuppEapolReqFramesRx
;
121 unsigned int dot1xSuppInvalidEapolFramesRx
;
122 unsigned int dot1xSuppEapLengthErrorFramesRx
;
123 unsigned int dot1xSuppLastEapolFrameVersion
;
124 unsigned char dot1xSuppLastEapolFrameSource
[6];
126 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
129 struct eap_peer_config
*config
;
132 size_t last_rx_key_len
;
133 struct wpabuf
*eapReqData
; /* for EAP */
134 Boolean altAccept
; /* for EAP */
135 Boolean altReject
; /* for EAP */
136 Boolean replay_counter_valid
;
137 u8 last_replay_counter
[16];
138 struct eapol_config conf
;
139 struct eapol_ctx
*ctx
;
140 enum { EAPOL_CB_IN_PROGRESS
= 0, EAPOL_CB_SUCCESS
, EAPOL_CB_FAILURE
}
144 Boolean unicast_key_received
, broadcast_key_received
;
148 #define IEEE8021X_REPLAY_COUNTER_LEN 8
149 #define IEEE8021X_KEY_SIGN_LEN 16
150 #define IEEE8021X_KEY_IV_LEN 16
152 #define IEEE8021X_KEY_INDEX_FLAG 0x80
153 #define IEEE8021X_KEY_INDEX_MASK 0x03
156 #pragma pack(push, 1)
157 #endif /* _MSC_VER */
159 struct ieee802_1x_eapol_key
{
161 /* Note: key_length is unaligned */
163 /* does not repeat within the life of the keying material used to
164 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
165 u8 replay_counter
[IEEE8021X_REPLAY_COUNTER_LEN
];
166 u8 key_iv
[IEEE8021X_KEY_IV_LEN
]; /* cryptographically random number */
167 u8 key_index
; /* key flag in the most significant bit:
168 * 0 = broadcast (default key),
169 * 1 = unicast (key mapping key); key index is in the
170 * 7 least significant bits */
171 /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
173 u8 key_signature
[IEEE8021X_KEY_SIGN_LEN
];
175 /* followed by key: if packet body length = 44 + key length, then the
176 * key field (of key_length bytes) contains the key in encrypted form;
177 * if packet body length = 44, key field is absent and key_length
178 * represents the number of least significant octets from
179 * MS-MPPE-Send-Key attribute to be used as the keying material;
180 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
185 #endif /* _MSC_VER */
188 static void eapol_sm_txLogoff(struct eapol_sm
*sm
);
189 static void eapol_sm_txStart(struct eapol_sm
*sm
);
190 static void eapol_sm_processKey(struct eapol_sm
*sm
);
191 static void eapol_sm_getSuppRsp(struct eapol_sm
*sm
);
192 static void eapol_sm_txSuppRsp(struct eapol_sm
*sm
);
193 static void eapol_sm_abortSupp(struct eapol_sm
*sm
);
194 static void eapol_sm_abort_cached(struct eapol_sm
*sm
);
195 static void eapol_sm_step_timeout(void *eloop_ctx
, void *timeout_ctx
);
198 /* Port Timers state machine - implemented as a function that will be called
199 * once a second as a registered event loop timeout */
200 static void eapol_port_timers_tick(void *eloop_ctx
, void *timeout_ctx
)
202 struct eapol_sm
*sm
= timeout_ctx
;
204 if (sm
->authWhile
> 0) {
206 if (sm
->authWhile
== 0)
207 wpa_printf(MSG_DEBUG
, "EAPOL: authWhile --> 0");
209 if (sm
->heldWhile
> 0) {
211 if (sm
->heldWhile
== 0)
212 wpa_printf(MSG_DEBUG
, "EAPOL: heldWhile --> 0");
214 if (sm
->startWhen
> 0) {
216 if (sm
->startWhen
== 0)
217 wpa_printf(MSG_DEBUG
, "EAPOL: startWhen --> 0");
219 if (sm
->idleWhile
> 0) {
221 if (sm
->idleWhile
== 0)
222 wpa_printf(MSG_DEBUG
, "EAPOL: idleWhile --> 0");
225 if (sm
->authWhile
| sm
->heldWhile
| sm
->startWhen
| sm
->idleWhile
) {
226 eloop_register_timeout(1, 0, eapol_port_timers_tick
, eloop_ctx
,
229 wpa_printf(MSG_DEBUG
, "EAPOL: disable timer tick");
230 sm
->timer_tick_enabled
= 0;
236 static void eapol_enable_timer_tick(struct eapol_sm
*sm
)
238 if (sm
->timer_tick_enabled
)
240 wpa_printf(MSG_DEBUG
, "EAPOL: enable timer tick");
241 sm
->timer_tick_enabled
= 1;
242 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
243 eloop_register_timeout(1, 0, eapol_port_timers_tick
, NULL
, sm
);
247 SM_STATE(SUPP_PAE
, LOGOFF
)
249 SM_ENTRY(SUPP_PAE
, LOGOFF
);
250 eapol_sm_txLogoff(sm
);
251 sm
->logoffSent
= TRUE
;
252 sm
->suppPortStatus
= Unauthorized
;
256 SM_STATE(SUPP_PAE
, DISCONNECTED
)
258 SM_ENTRY(SUPP_PAE
, DISCONNECTED
);
259 sm
->sPortMode
= Auto
;
261 sm
->logoffSent
= FALSE
;
262 sm
->suppPortStatus
= Unauthorized
;
263 sm
->suppAbort
= TRUE
;
265 sm
->unicast_key_received
= FALSE
;
266 sm
->broadcast_key_received
= FALSE
;
270 SM_STATE(SUPP_PAE
, CONNECTING
)
272 int send_start
= sm
->SUPP_PAE_state
== SUPP_PAE_CONNECTING
;
273 SM_ENTRY(SUPP_PAE
, CONNECTING
);
275 sm
->startWhen
= sm
->startPeriod
;
279 * Do not send EAPOL-Start immediately since in most cases,
280 * Authenticator is going to start authentication immediately
281 * after association and an extra EAPOL-Start is just going to
282 * delay authentication. Use a short timeout to send the first
283 * EAPOL-Start if Authenticator does not start authentication.
287 eapol_enable_timer_tick(sm
);
288 sm
->eapolEap
= FALSE
;
290 eapol_sm_txStart(sm
);
294 SM_STATE(SUPP_PAE
, AUTHENTICATING
)
296 SM_ENTRY(SUPP_PAE
, AUTHENTICATING
);
298 sm
->suppSuccess
= FALSE
;
299 sm
->suppFail
= FALSE
;
300 sm
->suppTimeout
= FALSE
;
303 sm
->suppStart
= TRUE
;
307 SM_STATE(SUPP_PAE
, HELD
)
309 SM_ENTRY(SUPP_PAE
, HELD
);
310 sm
->heldWhile
= sm
->heldPeriod
;
311 eapol_enable_timer_tick(sm
);
312 sm
->suppPortStatus
= Unauthorized
;
313 sm
->cb_status
= EAPOL_CB_FAILURE
;
317 SM_STATE(SUPP_PAE
, AUTHENTICATED
)
319 SM_ENTRY(SUPP_PAE
, AUTHENTICATED
);
320 sm
->suppPortStatus
= Authorized
;
321 sm
->cb_status
= EAPOL_CB_SUCCESS
;
325 SM_STATE(SUPP_PAE
, RESTART
)
327 SM_ENTRY(SUPP_PAE
, RESTART
);
328 sm
->eapRestart
= TRUE
;
332 SM_STATE(SUPP_PAE
, S_FORCE_AUTH
)
334 SM_ENTRY(SUPP_PAE
, S_FORCE_AUTH
);
335 sm
->suppPortStatus
= Authorized
;
336 sm
->sPortMode
= ForceAuthorized
;
340 SM_STATE(SUPP_PAE
, S_FORCE_UNAUTH
)
342 SM_ENTRY(SUPP_PAE
, S_FORCE_UNAUTH
);
343 sm
->suppPortStatus
= Unauthorized
;
344 sm
->sPortMode
= ForceUnauthorized
;
345 eapol_sm_txLogoff(sm
);
351 if ((sm
->userLogoff
&& !sm
->logoffSent
) &&
352 !(sm
->initialize
|| !sm
->portEnabled
))
353 SM_ENTER_GLOBAL(SUPP_PAE
, LOGOFF
);
354 else if (((sm
->portControl
== Auto
) &&
355 (sm
->sPortMode
!= sm
->portControl
)) ||
356 sm
->initialize
|| !sm
->portEnabled
)
357 SM_ENTER_GLOBAL(SUPP_PAE
, DISCONNECTED
);
358 else if ((sm
->portControl
== ForceAuthorized
) &&
359 (sm
->sPortMode
!= sm
->portControl
) &&
360 !(sm
->initialize
|| !sm
->portEnabled
))
361 SM_ENTER_GLOBAL(SUPP_PAE
, S_FORCE_AUTH
);
362 else if ((sm
->portControl
== ForceUnauthorized
) &&
363 (sm
->sPortMode
!= sm
->portControl
) &&
364 !(sm
->initialize
|| !sm
->portEnabled
))
365 SM_ENTER_GLOBAL(SUPP_PAE
, S_FORCE_UNAUTH
);
366 else switch (sm
->SUPP_PAE_state
) {
367 case SUPP_PAE_UNKNOWN
:
369 case SUPP_PAE_LOGOFF
:
371 SM_ENTER(SUPP_PAE
, DISCONNECTED
);
373 case SUPP_PAE_DISCONNECTED
:
374 SM_ENTER(SUPP_PAE
, CONNECTING
);
376 case SUPP_PAE_CONNECTING
:
377 if (sm
->startWhen
== 0 && sm
->startCount
< sm
->maxStart
)
378 SM_ENTER(SUPP_PAE
, CONNECTING
);
379 else if (sm
->startWhen
== 0 &&
380 sm
->startCount
>= sm
->maxStart
&&
382 SM_ENTER(SUPP_PAE
, AUTHENTICATED
);
383 else if (sm
->eapSuccess
|| sm
->eapFail
)
384 SM_ENTER(SUPP_PAE
, AUTHENTICATING
);
385 else if (sm
->eapolEap
)
386 SM_ENTER(SUPP_PAE
, RESTART
);
387 else if (sm
->startWhen
== 0 &&
388 sm
->startCount
>= sm
->maxStart
&&
390 SM_ENTER(SUPP_PAE
, HELD
);
392 case SUPP_PAE_AUTHENTICATING
:
393 if (sm
->eapSuccess
&& !sm
->portValid
&&
394 sm
->conf
.accept_802_1x_keys
&&
395 sm
->conf
.required_keys
== 0) {
396 wpa_printf(MSG_DEBUG
, "EAPOL: IEEE 802.1X for "
397 "plaintext connection; no EAPOL-Key frames "
399 sm
->portValid
= TRUE
;
400 if (sm
->ctx
->eapol_done_cb
)
401 sm
->ctx
->eapol_done_cb(sm
->ctx
->ctx
);
403 if (sm
->eapSuccess
&& sm
->portValid
)
404 SM_ENTER(SUPP_PAE
, AUTHENTICATED
);
405 else if (sm
->eapFail
|| (sm
->keyDone
&& !sm
->portValid
))
406 SM_ENTER(SUPP_PAE
, HELD
);
407 else if (sm
->suppTimeout
)
408 SM_ENTER(SUPP_PAE
, CONNECTING
);
411 if (sm
->heldWhile
== 0)
412 SM_ENTER(SUPP_PAE
, CONNECTING
);
413 else if (sm
->eapolEap
)
414 SM_ENTER(SUPP_PAE
, RESTART
);
416 case SUPP_PAE_AUTHENTICATED
:
417 if (sm
->eapolEap
&& sm
->portValid
)
418 SM_ENTER(SUPP_PAE
, RESTART
);
419 else if (!sm
->portValid
)
420 SM_ENTER(SUPP_PAE
, DISCONNECTED
);
422 case SUPP_PAE_RESTART
:
424 SM_ENTER(SUPP_PAE
, AUTHENTICATING
);
426 case SUPP_PAE_S_FORCE_AUTH
:
428 case SUPP_PAE_S_FORCE_UNAUTH
:
434 SM_STATE(KEY_RX
, NO_KEY_RECEIVE
)
436 SM_ENTRY(KEY_RX
, NO_KEY_RECEIVE
);
440 SM_STATE(KEY_RX
, KEY_RECEIVE
)
442 SM_ENTRY(KEY_RX
, KEY_RECEIVE
);
443 eapol_sm_processKey(sm
);
450 if (sm
->initialize
|| !sm
->portEnabled
)
451 SM_ENTER_GLOBAL(KEY_RX
, NO_KEY_RECEIVE
);
452 switch (sm
->KEY_RX_state
) {
455 case KEY_RX_NO_KEY_RECEIVE
:
457 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
459 case KEY_RX_KEY_RECEIVE
:
461 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
467 SM_STATE(SUPP_BE
, REQUEST
)
469 SM_ENTRY(SUPP_BE
, REQUEST
);
472 eapol_sm_getSuppRsp(sm
);
476 SM_STATE(SUPP_BE
, RESPONSE
)
478 SM_ENTRY(SUPP_BE
, RESPONSE
);
479 eapol_sm_txSuppRsp(sm
);
484 SM_STATE(SUPP_BE
, SUCCESS
)
486 SM_ENTRY(SUPP_BE
, SUCCESS
);
488 sm
->suppSuccess
= TRUE
;
490 if (eap_key_available(sm
->eap
)) {
491 /* New key received - clear IEEE 802.1X EAPOL-Key replay
493 sm
->replay_counter_valid
= FALSE
;
498 SM_STATE(SUPP_BE
, FAIL
)
500 SM_ENTRY(SUPP_BE
, FAIL
);
505 SM_STATE(SUPP_BE
, TIMEOUT
)
507 SM_ENTRY(SUPP_BE
, TIMEOUT
);
508 sm
->suppTimeout
= TRUE
;
512 SM_STATE(SUPP_BE
, IDLE
)
514 SM_ENTRY(SUPP_BE
, IDLE
);
515 sm
->suppStart
= FALSE
;
516 sm
->initial_req
= TRUE
;
520 SM_STATE(SUPP_BE
, INITIALIZE
)
522 SM_ENTRY(SUPP_BE
, INITIALIZE
);
523 eapol_sm_abortSupp(sm
);
524 sm
->suppAbort
= FALSE
;
528 SM_STATE(SUPP_BE
, RECEIVE
)
530 SM_ENTRY(SUPP_BE
, RECEIVE
);
531 sm
->authWhile
= sm
->authPeriod
;
532 eapol_enable_timer_tick(sm
);
533 sm
->eapolEap
= FALSE
;
534 sm
->eapNoResp
= FALSE
;
535 sm
->initial_req
= FALSE
;
541 if (sm
->initialize
|| sm
->suppAbort
)
542 SM_ENTER_GLOBAL(SUPP_BE
, INITIALIZE
);
543 else switch (sm
->SUPP_BE_state
) {
544 case SUPP_BE_UNKNOWN
:
546 case SUPP_BE_REQUEST
:
548 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
549 * and SUCCESS based on eapFail and eapSuccess, respectively.
550 * However, IEEE Std 802.1X-2004 is also specifying that
551 * eapNoResp should be set in conjuction with eapSuccess and
552 * eapFail which would mean that more than one of the
553 * transitions here would be activated at the same time.
554 * Skipping RESPONSE and/or RECEIVE states in these cases can
555 * cause problems and the direct transitions to do not seem
556 * correct. Because of this, the conditions for these
557 * transitions are verified only after eapNoResp. They are
558 * unlikely to be used since eapNoResp should always be set if
559 * either of eapSuccess or eapFail is set.
561 if (sm
->eapResp
&& sm
->eapNoResp
) {
562 wpa_printf(MSG_DEBUG
, "EAPOL: SUPP_BE REQUEST: both "
563 "eapResp and eapNoResp set?!");
566 SM_ENTER(SUPP_BE
, RESPONSE
);
567 else if (sm
->eapNoResp
)
568 SM_ENTER(SUPP_BE
, RECEIVE
);
569 else if (sm
->eapFail
)
570 SM_ENTER(SUPP_BE
, FAIL
);
571 else if (sm
->eapSuccess
)
572 SM_ENTER(SUPP_BE
, SUCCESS
);
574 case SUPP_BE_RESPONSE
:
575 SM_ENTER(SUPP_BE
, RECEIVE
);
577 case SUPP_BE_SUCCESS
:
578 SM_ENTER(SUPP_BE
, IDLE
);
581 SM_ENTER(SUPP_BE
, IDLE
);
583 case SUPP_BE_TIMEOUT
:
584 SM_ENTER(SUPP_BE
, IDLE
);
587 if (sm
->eapFail
&& sm
->suppStart
)
588 SM_ENTER(SUPP_BE
, FAIL
);
589 else if (sm
->eapolEap
&& sm
->suppStart
)
590 SM_ENTER(SUPP_BE
, REQUEST
);
591 else if (sm
->eapSuccess
&& sm
->suppStart
)
592 SM_ENTER(SUPP_BE
, SUCCESS
);
594 case SUPP_BE_INITIALIZE
:
595 SM_ENTER(SUPP_BE
, IDLE
);
597 case SUPP_BE_RECEIVE
:
599 SM_ENTER(SUPP_BE
, REQUEST
);
600 else if (sm
->eapFail
)
601 SM_ENTER(SUPP_BE
, FAIL
);
602 else if (sm
->authWhile
== 0)
603 SM_ENTER(SUPP_BE
, TIMEOUT
);
604 else if (sm
->eapSuccess
)
605 SM_ENTER(SUPP_BE
, SUCCESS
);
611 static void eapol_sm_txLogoff(struct eapol_sm
*sm
)
613 wpa_printf(MSG_DEBUG
, "EAPOL: txLogoff");
614 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
615 IEEE802_1X_TYPE_EAPOL_LOGOFF
, (u8
*) "", 0);
616 sm
->dot1xSuppEapolLogoffFramesTx
++;
617 sm
->dot1xSuppEapolFramesTx
++;
621 static void eapol_sm_txStart(struct eapol_sm
*sm
)
623 wpa_printf(MSG_DEBUG
, "EAPOL: txStart");
624 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
625 IEEE802_1X_TYPE_EAPOL_START
, (u8
*) "", 0);
626 sm
->dot1xSuppEapolStartFramesTx
++;
627 sm
->dot1xSuppEapolFramesTx
++;
631 #define IEEE8021X_ENCR_KEY_LEN 32
632 #define IEEE8021X_SIGN_KEY_LEN 32
634 struct eap_key_data
{
635 u8 encr_key
[IEEE8021X_ENCR_KEY_LEN
];
636 u8 sign_key
[IEEE8021X_SIGN_KEY_LEN
];
640 static void eapol_sm_processKey(struct eapol_sm
*sm
)
642 struct ieee802_1x_hdr
*hdr
;
643 struct ieee802_1x_eapol_key
*key
;
644 struct eap_key_data keydata
;
645 u8 orig_key_sign
[IEEE8021X_KEY_SIGN_LEN
], datakey
[32];
646 u8 ekey
[IEEE8021X_KEY_IV_LEN
+ IEEE8021X_ENCR_KEY_LEN
];
647 int key_len
, res
, sign_key_len
, encr_key_len
;
650 wpa_printf(MSG_DEBUG
, "EAPOL: processKey");
651 if (sm
->last_rx_key
== NULL
)
654 if (!sm
->conf
.accept_802_1x_keys
) {
655 wpa_printf(MSG_WARNING
, "EAPOL: Received IEEE 802.1X EAPOL-Key"
656 " even though this was not accepted - "
657 "ignoring this packet");
661 hdr
= (struct ieee802_1x_hdr
*) sm
->last_rx_key
;
662 key
= (struct ieee802_1x_eapol_key
*) (hdr
+ 1);
663 if (sizeof(*hdr
) + be_to_host16(hdr
->length
) > sm
->last_rx_key_len
) {
664 wpa_printf(MSG_WARNING
, "EAPOL: Too short EAPOL-Key frame");
667 rx_key_length
= WPA_GET_BE16(key
->key_length
);
668 wpa_printf(MSG_DEBUG
, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
669 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
670 hdr
->version
, hdr
->type
, be_to_host16(hdr
->length
),
671 key
->type
, rx_key_length
, key
->key_index
);
673 eapol_sm_notify_lower_layer_success(sm
, 1);
674 sign_key_len
= IEEE8021X_SIGN_KEY_LEN
;
675 encr_key_len
= IEEE8021X_ENCR_KEY_LEN
;
676 res
= eapol_sm_get_key(sm
, (u8
*) &keydata
, sizeof(keydata
));
678 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get master key for "
679 "decrypting EAPOL-Key keys");
683 /* LEAP derives only 16 bytes of keying material. */
684 res
= eapol_sm_get_key(sm
, (u8
*) &keydata
, 16);
686 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get LEAP "
687 "master key for decrypting EAPOL-Key keys");
692 os_memcpy(keydata
.sign_key
, keydata
.encr_key
, 16);
694 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get enough master key "
695 "data for decrypting EAPOL-Key keys (res=%d)", res
);
699 /* The key replay_counter must increase when same master key */
700 if (sm
->replay_counter_valid
&&
701 os_memcmp(sm
->last_replay_counter
, key
->replay_counter
,
702 IEEE8021X_REPLAY_COUNTER_LEN
) >= 0) {
703 wpa_printf(MSG_WARNING
, "EAPOL: EAPOL-Key replay counter did "
704 "not increase - ignoring key");
705 wpa_hexdump(MSG_DEBUG
, "EAPOL: last replay counter",
706 sm
->last_replay_counter
,
707 IEEE8021X_REPLAY_COUNTER_LEN
);
708 wpa_hexdump(MSG_DEBUG
, "EAPOL: received replay counter",
709 key
->replay_counter
, IEEE8021X_REPLAY_COUNTER_LEN
);
713 /* Verify key signature (HMAC-MD5) */
714 os_memcpy(orig_key_sign
, key
->key_signature
, IEEE8021X_KEY_SIGN_LEN
);
715 os_memset(key
->key_signature
, 0, IEEE8021X_KEY_SIGN_LEN
);
716 hmac_md5(keydata
.sign_key
, sign_key_len
,
717 sm
->last_rx_key
, sizeof(*hdr
) + be_to_host16(hdr
->length
),
719 if (os_memcmp(orig_key_sign
, key
->key_signature
,
720 IEEE8021X_KEY_SIGN_LEN
) != 0) {
721 wpa_printf(MSG_DEBUG
, "EAPOL: Invalid key signature in "
723 os_memcpy(key
->key_signature
, orig_key_sign
,
724 IEEE8021X_KEY_SIGN_LEN
);
727 wpa_printf(MSG_DEBUG
, "EAPOL: EAPOL-Key key signature verified");
729 key_len
= be_to_host16(hdr
->length
) - sizeof(*key
);
730 if (key_len
> 32 || rx_key_length
> 32) {
731 wpa_printf(MSG_WARNING
, "EAPOL: Too long key data length %d",
732 key_len
? key_len
: rx_key_length
);
735 if (key_len
== rx_key_length
) {
736 os_memcpy(ekey
, key
->key_iv
, IEEE8021X_KEY_IV_LEN
);
737 os_memcpy(ekey
+ IEEE8021X_KEY_IV_LEN
, keydata
.encr_key
,
739 os_memcpy(datakey
, key
+ 1, key_len
);
740 rc4(datakey
, key_len
, ekey
,
741 IEEE8021X_KEY_IV_LEN
+ encr_key_len
);
742 wpa_hexdump_key(MSG_DEBUG
, "EAPOL: Decrypted(RC4) key",
744 } else if (key_len
== 0) {
746 * IEEE 802.1X-2004 specifies that least significant Key Length
747 * octets from MS-MPPE-Send-Key are used as the key if the key
748 * data is not present. This seems to be meaning the beginning
749 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
750 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
751 * Anyway, taking the beginning of the keying material from EAP
752 * seems to interoperate with Authenticators.
754 key_len
= rx_key_length
;
755 os_memcpy(datakey
, keydata
.encr_key
, key_len
);
756 wpa_hexdump_key(MSG_DEBUG
, "EAPOL: using part of EAP keying "
757 "material data encryption key",
760 wpa_printf(MSG_DEBUG
, "EAPOL: Invalid key data length %d "
761 "(key_length=%d)", key_len
, rx_key_length
);
765 sm
->replay_counter_valid
= TRUE
;
766 os_memcpy(sm
->last_replay_counter
, key
->replay_counter
,
767 IEEE8021X_REPLAY_COUNTER_LEN
);
769 wpa_printf(MSG_DEBUG
, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
771 key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
?
772 "unicast" : "broadcast",
773 key
->key_index
& IEEE8021X_KEY_INDEX_MASK
, key_len
);
775 if (sm
->ctx
->set_wep_key
&&
776 sm
->ctx
->set_wep_key(sm
->ctx
->ctx
,
777 key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
,
778 key
->key_index
& IEEE8021X_KEY_INDEX_MASK
,
779 datakey
, key_len
) < 0) {
780 wpa_printf(MSG_WARNING
, "EAPOL: Failed to set WEP key to the "
783 if (key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
)
784 sm
->unicast_key_received
= TRUE
;
786 sm
->broadcast_key_received
= TRUE
;
788 if ((sm
->unicast_key_received
||
789 !(sm
->conf
.required_keys
& EAPOL_REQUIRE_KEY_UNICAST
)) &&
790 (sm
->broadcast_key_received
||
791 !(sm
->conf
.required_keys
& EAPOL_REQUIRE_KEY_BROADCAST
)))
793 wpa_printf(MSG_DEBUG
, "EAPOL: all required EAPOL-Key "
795 sm
->portValid
= TRUE
;
796 if (sm
->ctx
->eapol_done_cb
)
797 sm
->ctx
->eapol_done_cb(sm
->ctx
->ctx
);
803 static void eapol_sm_getSuppRsp(struct eapol_sm
*sm
)
805 wpa_printf(MSG_DEBUG
, "EAPOL: getSuppRsp");
806 /* EAP layer processing; no special code is needed, since Supplicant
807 * Backend state machine is waiting for eapNoResp or eapResp to be set
808 * and these are only set in the EAP state machine when the processing
813 static void eapol_sm_txSuppRsp(struct eapol_sm
*sm
)
817 wpa_printf(MSG_DEBUG
, "EAPOL: txSuppRsp");
818 resp
= eap_get_eapRespData(sm
->eap
);
820 wpa_printf(MSG_WARNING
, "EAPOL: txSuppRsp - EAP response data "
825 /* Send EAP-Packet from the EAP layer to the Authenticator */
826 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
827 IEEE802_1X_TYPE_EAP_PACKET
, wpabuf_head(resp
),
830 /* eapRespData is not used anymore, so free it here */
834 sm
->dot1xSuppEapolReqIdFramesRx
++;
836 sm
->dot1xSuppEapolReqFramesRx
++;
837 sm
->dot1xSuppEapolRespFramesTx
++;
838 sm
->dot1xSuppEapolFramesTx
++;
842 static void eapol_sm_abortSupp(struct eapol_sm
*sm
)
844 /* release system resources that may have been allocated for the
845 * authentication session */
846 os_free(sm
->last_rx_key
);
847 sm
->last_rx_key
= NULL
;
848 wpabuf_free(sm
->eapReqData
);
849 sm
->eapReqData
= NULL
;
850 eap_sm_abort(sm
->eap
);
854 static void eapol_sm_step_timeout(void *eloop_ctx
, void *timeout_ctx
)
856 eapol_sm_step(timeout_ctx
);
861 * eapol_sm_step - EAPOL state machine step function
862 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
864 * This function is called to notify the state machine about changed external
865 * variables. It will step through the EAPOL state machines in loop to process
866 * all triggered state changes.
868 void eapol_sm_step(struct eapol_sm
*sm
)
872 /* In theory, it should be ok to run this in loop until !changed.
873 * However, it is better to use a limit on number of iterations to
874 * allow events (e.g., SIGTERM) to stop the program cleanly if the
875 * state machine were to generate a busy loop. */
876 for (i
= 0; i
< 100; i
++) {
878 SM_STEP_RUN(SUPP_PAE
);
880 SM_STEP_RUN(SUPP_BE
);
881 if (eap_peer_sm_step(sm
->eap
))
888 /* restart EAPOL state machine step from timeout call in order
889 * to allow other events to be processed. */
890 eloop_cancel_timeout(eapol_sm_step_timeout
, NULL
, sm
);
891 eloop_register_timeout(0, 0, eapol_sm_step_timeout
, NULL
, sm
);
894 if (sm
->ctx
->cb
&& sm
->cb_status
!= EAPOL_CB_IN_PROGRESS
) {
895 int success
= sm
->cb_status
== EAPOL_CB_SUCCESS
? 1 : 0;
896 sm
->cb_status
= EAPOL_CB_IN_PROGRESS
;
897 sm
->ctx
->cb(sm
, success
, sm
->ctx
->cb_ctx
);
902 #ifdef CONFIG_CTRL_IFACE
903 static const char *eapol_supp_pae_state(int state
)
906 case SUPP_PAE_LOGOFF
:
908 case SUPP_PAE_DISCONNECTED
:
909 return "DISCONNECTED";
910 case SUPP_PAE_CONNECTING
:
912 case SUPP_PAE_AUTHENTICATING
:
913 return "AUTHENTICATING";
916 case SUPP_PAE_AUTHENTICATED
:
917 return "AUTHENTICATED";
918 case SUPP_PAE_RESTART
:
926 static const char *eapol_supp_be_state(int state
)
929 case SUPP_BE_REQUEST
:
931 case SUPP_BE_RESPONSE
:
933 case SUPP_BE_SUCCESS
:
937 case SUPP_BE_TIMEOUT
:
941 case SUPP_BE_INITIALIZE
:
943 case SUPP_BE_RECEIVE
:
951 static const char * eapol_port_status(PortStatus status
)
953 if (status
== Authorized
)
956 return "Unauthorized";
958 #endif /* CONFIG_CTRL_IFACE */
961 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
962 static const char * eapol_port_control(PortControl ctrl
)
967 case ForceUnauthorized
:
968 return "ForceUnauthorized";
969 case ForceAuthorized
:
970 return "ForceAuthorized";
975 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
979 * eapol_sm_configure - Set EAPOL variables
980 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
981 * @heldPeriod: dot1xSuppHeldPeriod
982 * @authPeriod: dot1xSuppAuthPeriod
983 * @startPeriod: dot1xSuppStartPeriod
984 * @maxStart: dot1xSuppMaxStart
986 * Set configurable EAPOL state machine variables. Each variable can be set to
987 * the given value or ignored if set to -1 (to set only some of the variables).
989 void eapol_sm_configure(struct eapol_sm
*sm
, int heldPeriod
, int authPeriod
,
990 int startPeriod
, int maxStart
)
995 sm
->heldPeriod
= heldPeriod
;
997 sm
->authPeriod
= authPeriod
;
998 if (startPeriod
>= 0)
999 sm
->startPeriod
= startPeriod
;
1001 sm
->maxStart
= maxStart
;
1005 #ifdef CONFIG_CTRL_IFACE
1007 * eapol_sm_get_status - Get EAPOL state machine status
1008 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1009 * @buf: Buffer for status information
1010 * @buflen: Maximum buffer length
1011 * @verbose: Whether to include verbose status information
1012 * Returns: Number of bytes written to buf.
1014 * Query EAPOL state machine for status information. This function fills in a
1015 * text area with current status information from the EAPOL state machine. If
1016 * the buffer (buf) is not large enough, status information will be truncated
1017 * to fit the buffer.
1019 int eapol_sm_get_status(struct eapol_sm
*sm
, char *buf
, size_t buflen
,
1026 len
= os_snprintf(buf
, buflen
,
1027 "Supplicant PAE state=%s\n"
1028 "suppPortStatus=%s\n",
1029 eapol_supp_pae_state(sm
->SUPP_PAE_state
),
1030 eapol_port_status(sm
->suppPortStatus
));
1031 if (len
< 0 || (size_t) len
>= buflen
)
1035 ret
= os_snprintf(buf
+ len
, buflen
- len
,
1041 "Supplicant Backend state=%s\n",
1046 eapol_port_control(sm
->portControl
),
1047 eapol_supp_be_state(sm
->SUPP_BE_state
));
1048 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
1053 len
+= eap_sm_get_status(sm
->eap
, buf
+ len
, buflen
- len
, verbose
);
1060 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1061 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1062 * @buf: Buffer for MIB information
1063 * @buflen: Maximum buffer length
1064 * Returns: Number of bytes written to buf.
1066 * Query EAPOL state machine for MIB information. This function fills in a
1067 * text area with current MIB information from the EAPOL state machine. If
1068 * the buffer (buf) is not large enough, MIB information will be truncated to
1071 int eapol_sm_get_mib(struct eapol_sm
*sm
, char *buf
, size_t buflen
)
1078 ret
= os_snprintf(buf
, buflen
,
1079 "dot1xSuppPaeState=%d\n"
1080 "dot1xSuppHeldPeriod=%u\n"
1081 "dot1xSuppAuthPeriod=%u\n"
1082 "dot1xSuppStartPeriod=%u\n"
1083 "dot1xSuppMaxStart=%u\n"
1084 "dot1xSuppSuppControlledPortStatus=%s\n"
1085 "dot1xSuppBackendPaeState=%d\n",
1091 sm
->suppPortStatus
== Authorized
?
1092 "Authorized" : "Unauthorized",
1095 if (ret
< 0 || (size_t) ret
>= buflen
)
1099 ret
= os_snprintf(buf
+ len
, buflen
- len
,
1100 "dot1xSuppEapolFramesRx=%u\n"
1101 "dot1xSuppEapolFramesTx=%u\n"
1102 "dot1xSuppEapolStartFramesTx=%u\n"
1103 "dot1xSuppEapolLogoffFramesTx=%u\n"
1104 "dot1xSuppEapolRespFramesTx=%u\n"
1105 "dot1xSuppEapolReqIdFramesRx=%u\n"
1106 "dot1xSuppEapolReqFramesRx=%u\n"
1107 "dot1xSuppInvalidEapolFramesRx=%u\n"
1108 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1109 "dot1xSuppLastEapolFrameVersion=%u\n"
1110 "dot1xSuppLastEapolFrameSource=" MACSTR
"\n",
1111 sm
->dot1xSuppEapolFramesRx
,
1112 sm
->dot1xSuppEapolFramesTx
,
1113 sm
->dot1xSuppEapolStartFramesTx
,
1114 sm
->dot1xSuppEapolLogoffFramesTx
,
1115 sm
->dot1xSuppEapolRespFramesTx
,
1116 sm
->dot1xSuppEapolReqIdFramesRx
,
1117 sm
->dot1xSuppEapolReqFramesRx
,
1118 sm
->dot1xSuppInvalidEapolFramesRx
,
1119 sm
->dot1xSuppEapLengthErrorFramesRx
,
1120 sm
->dot1xSuppLastEapolFrameVersion
,
1121 MAC2STR(sm
->dot1xSuppLastEapolFrameSource
));
1123 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
1129 #endif /* CONFIG_CTRL_IFACE */
1133 * eapol_sm_rx_eapol - Process received EAPOL frames
1134 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1135 * @src: Source MAC address of the EAPOL packet
1136 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1137 * @len: Length of the EAPOL frame
1138 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1141 int eapol_sm_rx_eapol(struct eapol_sm
*sm
, const u8
*src
, const u8
*buf
,
1144 const struct ieee802_1x_hdr
*hdr
;
1145 const struct ieee802_1x_eapol_key
*key
;
1152 sm
->dot1xSuppEapolFramesRx
++;
1153 if (len
< sizeof(*hdr
)) {
1154 sm
->dot1xSuppInvalidEapolFramesRx
++;
1157 hdr
= (const struct ieee802_1x_hdr
*) buf
;
1158 sm
->dot1xSuppLastEapolFrameVersion
= hdr
->version
;
1159 os_memcpy(sm
->dot1xSuppLastEapolFrameSource
, src
, ETH_ALEN
);
1160 if (hdr
->version
< EAPOL_VERSION
) {
1161 /* TODO: backwards compatibility */
1163 plen
= be_to_host16(hdr
->length
);
1164 if (plen
> len
- sizeof(*hdr
)) {
1165 sm
->dot1xSuppEapLengthErrorFramesRx
++;
1168 data_len
= plen
+ sizeof(*hdr
);
1170 switch (hdr
->type
) {
1171 case IEEE802_1X_TYPE_EAP_PACKET
:
1172 if (sm
->cached_pmk
) {
1173 /* Trying to use PMKSA caching, but Authenticator did
1174 * not seem to have a matching entry. Need to restart
1175 * EAPOL state machines.
1177 eapol_sm_abort_cached(sm
);
1179 wpabuf_free(sm
->eapReqData
);
1180 sm
->eapReqData
= wpabuf_alloc_copy(hdr
+ 1, plen
);
1181 if (sm
->eapReqData
) {
1182 wpa_printf(MSG_DEBUG
, "EAPOL: Received EAP-Packet "
1184 sm
->eapolEap
= TRUE
;
1188 case IEEE802_1X_TYPE_EAPOL_KEY
:
1189 if (plen
< sizeof(*key
)) {
1190 wpa_printf(MSG_DEBUG
, "EAPOL: Too short EAPOL-Key "
1194 key
= (const struct ieee802_1x_eapol_key
*) (hdr
+ 1);
1195 if (key
->type
== EAPOL_KEY_TYPE_WPA
||
1196 key
->type
== EAPOL_KEY_TYPE_RSN
) {
1197 /* WPA Supplicant takes care of this frame. */
1198 wpa_printf(MSG_DEBUG
, "EAPOL: Ignoring WPA EAPOL-Key "
1199 "frame in EAPOL state machines");
1203 if (key
->type
!= EAPOL_KEY_TYPE_RC4
) {
1204 wpa_printf(MSG_DEBUG
, "EAPOL: Ignored unknown "
1205 "EAPOL-Key type %d", key
->type
);
1208 os_free(sm
->last_rx_key
);
1209 sm
->last_rx_key
= os_malloc(data_len
);
1210 if (sm
->last_rx_key
) {
1211 wpa_printf(MSG_DEBUG
, "EAPOL: Received EAPOL-Key "
1213 os_memcpy(sm
->last_rx_key
, buf
, data_len
);
1214 sm
->last_rx_key_len
= data_len
;
1220 wpa_printf(MSG_DEBUG
, "EAPOL: Received unknown EAPOL type %d",
1222 sm
->dot1xSuppInvalidEapolFramesRx
++;
1231 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1232 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1234 * Notify EAPOL state machine about transmitted EAPOL packet from an external
1235 * component, e.g., WPA. This will update the statistics.
1237 void eapol_sm_notify_tx_eapol_key(struct eapol_sm
*sm
)
1240 sm
->dot1xSuppEapolFramesTx
++;
1245 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1246 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1247 * @enabled: New portEnabled value
1249 * Notify EAPOL state machine about new portEnabled value.
1251 void eapol_sm_notify_portEnabled(struct eapol_sm
*sm
, Boolean enabled
)
1255 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1256 "portEnabled=%d", enabled
);
1257 sm
->portEnabled
= enabled
;
1263 * eapol_sm_notify_portValid - Notification about portValid change
1264 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1265 * @valid: New portValid value
1267 * Notify EAPOL state machine about new portValid value.
1269 void eapol_sm_notify_portValid(struct eapol_sm
*sm
, Boolean valid
)
1273 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1274 "portValid=%d", valid
);
1275 sm
->portValid
= valid
;
1281 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1282 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1283 * @success: %TRUE = set success, %FALSE = clear success
1285 * Notify the EAPOL state machine that external event has forced EAP state to
1286 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1288 * This function is called to update EAP state when WPA-PSK key handshake has
1289 * been completed successfully since WPA-PSK does not use EAP state machine.
1291 void eapol_sm_notify_eap_success(struct eapol_sm
*sm
, Boolean success
)
1295 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1296 "EAP success=%d", success
);
1297 sm
->eapSuccess
= success
;
1298 sm
->altAccept
= success
;
1300 eap_notify_success(sm
->eap
);
1306 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1307 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1308 * @fail: %TRUE = set failure, %FALSE = clear failure
1310 * Notify EAPOL state machine that external event has forced EAP state to
1311 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1313 void eapol_sm_notify_eap_fail(struct eapol_sm
*sm
, Boolean fail
)
1317 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1318 "EAP fail=%d", fail
);
1320 sm
->altReject
= fail
;
1326 * eapol_sm_notify_config - Notification of EAPOL configuration change
1327 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1328 * @config: Pointer to current network EAP configuration
1329 * @conf: Pointer to EAPOL configuration data
1331 * Notify EAPOL state machine that configuration has changed. config will be
1332 * stored as a backpointer to network configuration. This can be %NULL to clear
1333 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1334 * data. If conf is %NULL, this part of the configuration change will be
1337 void eapol_sm_notify_config(struct eapol_sm
*sm
,
1338 struct eap_peer_config
*config
,
1339 const struct eapol_config
*conf
)
1344 sm
->config
= config
;
1349 sm
->conf
.accept_802_1x_keys
= conf
->accept_802_1x_keys
;
1350 sm
->conf
.required_keys
= conf
->required_keys
;
1351 sm
->conf
.fast_reauth
= conf
->fast_reauth
;
1353 eap_set_fast_reauth(sm
->eap
, conf
->fast_reauth
);
1354 eap_set_workaround(sm
->eap
, conf
->workaround
);
1355 eap_set_force_disabled(sm
->eap
, conf
->eap_disabled
);
1361 * eapol_sm_get_key - Get master session key (MSK) from EAP
1362 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1363 * @key: Pointer for key buffer
1364 * @len: Number of bytes to copy to key
1365 * Returns: 0 on success (len of key available), maximum available key len
1366 * (>0) if key is available but it is shorter than len, or -1 on failure.
1368 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1369 * is available only after a successful authentication.
1371 int eapol_sm_get_key(struct eapol_sm
*sm
, u8
*key
, size_t len
)
1376 if (sm
== NULL
|| !eap_key_available(sm
->eap
)) {
1377 wpa_printf(MSG_DEBUG
, "EAPOL: EAP key not available");
1380 eap_key
= eap_get_eapKeyData(sm
->eap
, &eap_len
);
1381 if (eap_key
== NULL
) {
1382 wpa_printf(MSG_DEBUG
, "EAPOL: Failed to get eapKeyData");
1385 if (len
> eap_len
) {
1386 wpa_printf(MSG_DEBUG
, "EAPOL: Requested key length (%lu) not "
1387 "available (len=%lu)",
1388 (unsigned long) len
, (unsigned long) eap_len
);
1391 os_memcpy(key
, eap_key
, len
);
1392 wpa_printf(MSG_DEBUG
, "EAPOL: Successfully fetched key (len=%lu)",
1393 (unsigned long) len
);
1399 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1400 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1401 * @logoff: Whether command was logoff
1403 * Notify EAPOL state machines that user requested logon/logoff.
1405 void eapol_sm_notify_logoff(struct eapol_sm
*sm
, Boolean logoff
)
1408 sm
->userLogoff
= logoff
;
1415 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1416 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1418 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1419 * to move EAPOL and EAP state machines into authenticated/successful state.
1421 void eapol_sm_notify_cached(struct eapol_sm
*sm
)
1425 sm
->SUPP_PAE_state
= SUPP_PAE_AUTHENTICATED
;
1426 sm
->suppPortStatus
= Authorized
;
1427 eap_notify_success(sm
->eap
);
1433 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1434 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1435 * @attempt: Whether PMKSA caching is tried
1437 * Notify EAPOL state machines whether PMKSA caching is used.
1439 void eapol_sm_notify_pmkid_attempt(struct eapol_sm
*sm
, int attempt
)
1444 wpa_printf(MSG_DEBUG
, "RSN: Trying to use cached PMKSA");
1445 sm
->cached_pmk
= TRUE
;
1447 wpa_printf(MSG_DEBUG
, "RSN: Do not try to use cached PMKSA");
1448 sm
->cached_pmk
= FALSE
;
1453 static void eapol_sm_abort_cached(struct eapol_sm
*sm
)
1455 wpa_printf(MSG_DEBUG
, "RSN: Authenticator did not accept PMKID, "
1456 "doing full EAP authentication");
1459 sm
->cached_pmk
= FALSE
;
1460 sm
->SUPP_PAE_state
= SUPP_PAE_CONNECTING
;
1461 sm
->suppPortStatus
= Unauthorized
;
1463 /* Make sure we do not start sending EAPOL-Start frames first, but
1464 * instead move to RESTART state to start EAPOL authentication. */
1466 eapol_enable_timer_tick(sm
);
1468 if (sm
->ctx
->aborted_cached
)
1469 sm
->ctx
->aborted_cached(sm
->ctx
->ctx
);
1474 * eapol_sm_register_scard_ctx - Notification of smart card context
1475 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1476 * @ctx: Context data for smart card operations
1478 * Notify EAPOL state machines of context data for smart card operations. This
1479 * context data will be used as a parameter for scard_*() functions.
1481 void eapol_sm_register_scard_ctx(struct eapol_sm
*sm
, void *ctx
)
1484 sm
->ctx
->scard_ctx
= ctx
;
1485 eap_register_scard_ctx(sm
->eap
, ctx
);
1491 * eapol_sm_notify_portControl - Notification of portControl changes
1492 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1493 * @portControl: New value for portControl variable
1495 * Notify EAPOL state machines that portControl variable has changed.
1497 void eapol_sm_notify_portControl(struct eapol_sm
*sm
, PortControl portControl
)
1501 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1502 "portControl=%s", eapol_port_control(portControl
));
1503 sm
->portControl
= portControl
;
1509 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1510 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1512 * Notify EAPOL state machines that a monitor was attached to the control
1513 * interface to trigger re-sending of pending requests for user input.
1515 void eapol_sm_notify_ctrl_attached(struct eapol_sm
*sm
)
1519 eap_sm_notify_ctrl_attached(sm
->eap
);
1524 * eapol_sm_notify_ctrl_response - Notification of received user input
1525 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1527 * Notify EAPOL state machines that a control response, i.e., user
1528 * input, was received in order to trigger retrying of a pending EAP request.
1530 void eapol_sm_notify_ctrl_response(struct eapol_sm
*sm
)
1534 if (sm
->eapReqData
&& !sm
->eapReq
) {
1535 wpa_printf(MSG_DEBUG
, "EAPOL: received control response (user "
1536 "input) notification - retrying pending EAP "
1538 sm
->eapolEap
= TRUE
;
1546 * eapol_sm_request_reauth - Request reauthentication
1547 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1549 * This function can be used to request EAPOL reauthentication, e.g., when the
1550 * current PMKSA entry is nearing expiration.
1552 void eapol_sm_request_reauth(struct eapol_sm
*sm
)
1554 if (sm
== NULL
|| sm
->SUPP_PAE_state
!= SUPP_PAE_AUTHENTICATED
)
1556 eapol_sm_txStart(sm
);
1561 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1562 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1563 * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1564 * machine loop (eapol_sm_step())
1566 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1567 * successful authentication. This is used to recover from dropped EAP-Success
1570 void eapol_sm_notify_lower_layer_success(struct eapol_sm
*sm
, int in_eapol_sm
)
1574 eap_notify_lower_layer_success(sm
->eap
);
1581 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1582 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1584 void eapol_sm_invalidate_cached_session(struct eapol_sm
*sm
)
1587 eap_invalidate_cached_session(sm
->eap
);
1591 static struct eap_peer_config
* eapol_sm_get_config(void *ctx
)
1593 struct eapol_sm
*sm
= ctx
;
1594 return sm
? sm
->config
: NULL
;
1598 static struct wpabuf
* eapol_sm_get_eapReqData(void *ctx
)
1600 struct eapol_sm
*sm
= ctx
;
1601 if (sm
== NULL
|| sm
->eapReqData
== NULL
)
1604 return sm
->eapReqData
;
1608 static Boolean
eapol_sm_get_bool(void *ctx
, enum eapol_bool_var variable
)
1610 struct eapol_sm
*sm
= ctx
;
1614 case EAPOL_eapSuccess
:
1615 return sm
->eapSuccess
;
1616 case EAPOL_eapRestart
:
1617 return sm
->eapRestart
;
1622 case EAPOL_eapNoResp
:
1623 return sm
->eapNoResp
;
1626 case EAPOL_portEnabled
:
1627 return sm
->portEnabled
;
1628 case EAPOL_altAccept
:
1629 return sm
->altAccept
;
1630 case EAPOL_altReject
:
1631 return sm
->altReject
;
1637 static void eapol_sm_set_bool(void *ctx
, enum eapol_bool_var variable
,
1640 struct eapol_sm
*sm
= ctx
;
1644 case EAPOL_eapSuccess
:
1645 sm
->eapSuccess
= value
;
1647 case EAPOL_eapRestart
:
1648 sm
->eapRestart
= value
;
1651 sm
->eapFail
= value
;
1654 sm
->eapResp
= value
;
1656 case EAPOL_eapNoResp
:
1657 sm
->eapNoResp
= value
;
1662 case EAPOL_portEnabled
:
1663 sm
->portEnabled
= value
;
1665 case EAPOL_altAccept
:
1666 sm
->altAccept
= value
;
1668 case EAPOL_altReject
:
1669 sm
->altReject
= value
;
1675 static unsigned int eapol_sm_get_int(void *ctx
, enum eapol_int_var variable
)
1677 struct eapol_sm
*sm
= ctx
;
1681 case EAPOL_idleWhile
:
1682 return sm
->idleWhile
;
1688 static void eapol_sm_set_int(void *ctx
, enum eapol_int_var variable
,
1691 struct eapol_sm
*sm
= ctx
;
1695 case EAPOL_idleWhile
:
1696 sm
->idleWhile
= value
;
1697 eapol_enable_timer_tick(sm
);
1703 static void eapol_sm_set_config_blob(void *ctx
, struct wpa_config_blob
*blob
)
1705 #ifndef CONFIG_NO_CONFIG_BLOBS
1706 struct eapol_sm
*sm
= ctx
;
1707 if (sm
&& sm
->ctx
&& sm
->ctx
->set_config_blob
)
1708 sm
->ctx
->set_config_blob(sm
->ctx
->ctx
, blob
);
1709 #endif /* CONFIG_NO_CONFIG_BLOBS */
1713 static const struct wpa_config_blob
*
1714 eapol_sm_get_config_blob(void *ctx
, const char *name
)
1716 #ifndef CONFIG_NO_CONFIG_BLOBS
1717 struct eapol_sm
*sm
= ctx
;
1718 if (sm
&& sm
->ctx
&& sm
->ctx
->get_config_blob
)
1719 return sm
->ctx
->get_config_blob(sm
->ctx
->ctx
, name
);
1722 #else /* CONFIG_NO_CONFIG_BLOBS */
1724 #endif /* CONFIG_NO_CONFIG_BLOBS */
1728 static void eapol_sm_notify_pending(void *ctx
)
1730 struct eapol_sm
*sm
= ctx
;
1733 if (sm
->eapReqData
&& !sm
->eapReq
) {
1734 wpa_printf(MSG_DEBUG
, "EAPOL: received notification from EAP "
1735 "state machine - retrying pending EAP Request");
1736 sm
->eapolEap
= TRUE
;
1743 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1744 static void eapol_sm_eap_param_needed(void *ctx
, const char *field
,
1747 struct eapol_sm
*sm
= ctx
;
1748 wpa_printf(MSG_DEBUG
, "EAPOL: EAP parameter needed");
1749 if (sm
->ctx
->eap_param_needed
)
1750 sm
->ctx
->eap_param_needed(sm
->ctx
->ctx
, field
, txt
);
1752 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1753 #define eapol_sm_eap_param_needed NULL
1754 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1757 static struct eapol_callbacks eapol_cb
=
1759 eapol_sm_get_config
,
1764 eapol_sm_get_eapReqData
,
1765 eapol_sm_set_config_blob
,
1766 eapol_sm_get_config_blob
,
1767 eapol_sm_notify_pending
,
1768 eapol_sm_eap_param_needed
1773 * eapol_sm_init - Initialize EAPOL state machine
1774 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1775 * and EAPOL state machine will free it in eapol_sm_deinit()
1776 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1778 * Allocate and initialize an EAPOL state machine.
1780 struct eapol_sm
*eapol_sm_init(struct eapol_ctx
*ctx
)
1782 struct eapol_sm
*sm
;
1783 struct eap_config conf
;
1784 sm
= os_zalloc(sizeof(*sm
));
1789 sm
->portControl
= Auto
;
1791 /* Supplicant PAE state machine */
1792 sm
->heldPeriod
= 60;
1793 sm
->startPeriod
= 30;
1796 /* Supplicant Backend state machine */
1797 sm
->authPeriod
= 30;
1799 os_memset(&conf
, 0, sizeof(conf
));
1800 #ifdef EAP_TLS_OPENSSL
1801 conf
.opensc_engine_path
= ctx
->opensc_engine_path
;
1802 conf
.pkcs11_engine_path
= ctx
->pkcs11_engine_path
;
1803 conf
.pkcs11_module_path
= ctx
->pkcs11_module_path
;
1804 #endif /* EAP_TLS_OPENSSL */
1806 sm
->eap
= eap_peer_sm_init(sm
, &eapol_cb
, sm
->ctx
->msg_ctx
, &conf
);
1807 if (sm
->eap
== NULL
) {
1812 /* Initialize EAPOL state machines */
1813 sm
->initialize
= TRUE
;
1815 sm
->initialize
= FALSE
;
1818 sm
->timer_tick_enabled
= 1;
1819 eloop_register_timeout(1, 0, eapol_port_timers_tick
, NULL
, sm
);
1826 * eapol_sm_deinit - Deinitialize EAPOL state machine
1827 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1829 * Deinitialize and free EAPOL state machine.
1831 void eapol_sm_deinit(struct eapol_sm
*sm
)
1835 eloop_cancel_timeout(eapol_sm_step_timeout
, NULL
, sm
);
1836 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
1837 eap_peer_sm_deinit(sm
->eap
);
1838 os_free(sm
->last_rx_key
);
1839 wpabuf_free(sm
->eapReqData
);