2 * WPA Supplicant / EAPOL state machines
3 * Copyright (c) 2004-2005, 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.
21 #include "l2_packet.h"
25 #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 */
43 /* Global variables */
50 PortControl portControl
;
52 PortStatus suppPortStatus
; /* dot1xSuppControlledPortStatus */
60 /* Supplicant PAE state machine */
63 SUPP_PAE_DISCONNECTED
= 1,
65 SUPP_PAE_CONNECTING
= 3,
66 SUPP_PAE_AUTHENTICATING
= 4,
67 SUPP_PAE_AUTHENTICATED
= 5,
71 SUPP_PAE_S_FORCE_AUTH
= 9,
72 SUPP_PAE_S_FORCE_UNAUTH
= 10
73 } SUPP_PAE_state
; /* dot1xSuppPaeState */
77 unsigned int startCount
;
79 PortControl sPortMode
;
81 unsigned int heldPeriod
; /* dot1xSuppHeldPeriod */
82 unsigned int startPeriod
; /* dot1xSuppStartPeriod */
83 unsigned int maxStart
; /* dot1xSuppMaxStart */
85 /* Key Receive state machine */
88 KEY_RX_NO_KEY_RECEIVE
, KEY_RX_KEY_RECEIVE
93 /* Supplicant Backend state machine */
96 SUPP_BE_INITIALIZE
= 1,
100 SUPP_BE_RESPONSE
= 5,
104 } SUPP_BE_state
; /* dot1xSuppBackendPaeState */
110 unsigned int authPeriod
; /* dot1xSuppAuthPeriod */
113 unsigned int dot1xSuppEapolFramesRx
;
114 unsigned int dot1xSuppEapolFramesTx
;
115 unsigned int dot1xSuppEapolStartFramesTx
;
116 unsigned int dot1xSuppEapolLogoffFramesTx
;
117 unsigned int dot1xSuppEapolRespFramesTx
;
118 unsigned int dot1xSuppEapolReqIdFramesRx
;
119 unsigned int dot1xSuppEapolReqFramesRx
;
120 unsigned int dot1xSuppInvalidEapolFramesRx
;
121 unsigned int dot1xSuppEapLengthErrorFramesRx
;
122 unsigned int dot1xSuppLastEapolFrameVersion
;
123 unsigned char dot1xSuppLastEapolFrameSource
[6];
125 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
128 struct wpa_ssid
*config
;
131 size_t last_rx_key_len
;
132 u8
*eapReqData
; /* for EAP */
133 size_t eapReqDataLen
; /* 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 eloop_register_timeout(1, 0, eapol_port_timers_tick
, eloop_ctx
, sm
);
230 SM_STATE(SUPP_PAE
, LOGOFF
)
232 SM_ENTRY(SUPP_PAE
, LOGOFF
);
233 eapol_sm_txLogoff(sm
);
234 sm
->logoffSent
= TRUE
;
235 sm
->suppPortStatus
= Unauthorized
;
239 SM_STATE(SUPP_PAE
, DISCONNECTED
)
241 SM_ENTRY(SUPP_PAE
, DISCONNECTED
);
242 sm
->sPortMode
= Auto
;
244 sm
->logoffSent
= FALSE
;
245 sm
->suppPortStatus
= Unauthorized
;
246 sm
->suppAbort
= TRUE
;
248 sm
->unicast_key_received
= FALSE
;
249 sm
->broadcast_key_received
= FALSE
;
253 SM_STATE(SUPP_PAE
, CONNECTING
)
255 int send_start
= sm
->SUPP_PAE_state
== SUPP_PAE_CONNECTING
;
256 SM_ENTRY(SUPP_PAE
, CONNECTING
);
258 sm
->startWhen
= sm
->startPeriod
;
262 * Do not send EAPOL-Start immediately since in most cases,
263 * Authenticator is going to start authentication immediately
264 * after association and an extra EAPOL-Start is just going to
265 * delay authentication. Use a short timeout to send the first
266 * EAPOL-Start if Authenticator does not start authentication.
270 sm
->eapolEap
= FALSE
;
272 eapol_sm_txStart(sm
);
276 SM_STATE(SUPP_PAE
, AUTHENTICATING
)
278 SM_ENTRY(SUPP_PAE
, AUTHENTICATING
);
280 sm
->suppSuccess
= FALSE
;
281 sm
->suppFail
= FALSE
;
282 sm
->suppTimeout
= FALSE
;
285 sm
->suppStart
= TRUE
;
289 SM_STATE(SUPP_PAE
, HELD
)
291 SM_ENTRY(SUPP_PAE
, HELD
);
292 sm
->heldWhile
= sm
->heldPeriod
;
293 sm
->suppPortStatus
= Unauthorized
;
294 sm
->cb_status
= EAPOL_CB_FAILURE
;
298 SM_STATE(SUPP_PAE
, AUTHENTICATED
)
300 SM_ENTRY(SUPP_PAE
, AUTHENTICATED
);
301 sm
->suppPortStatus
= Authorized
;
302 sm
->cb_status
= EAPOL_CB_SUCCESS
;
306 SM_STATE(SUPP_PAE
, RESTART
)
308 SM_ENTRY(SUPP_PAE
, RESTART
);
309 sm
->eapRestart
= TRUE
;
313 SM_STATE(SUPP_PAE
, S_FORCE_AUTH
)
315 SM_ENTRY(SUPP_PAE
, S_FORCE_AUTH
);
316 sm
->suppPortStatus
= Authorized
;
317 sm
->sPortMode
= ForceAuthorized
;
321 SM_STATE(SUPP_PAE
, S_FORCE_UNAUTH
)
323 SM_ENTRY(SUPP_PAE
, S_FORCE_UNAUTH
);
324 sm
->suppPortStatus
= Unauthorized
;
325 sm
->sPortMode
= ForceUnauthorized
;
326 eapol_sm_txLogoff(sm
);
332 if ((sm
->userLogoff
&& !sm
->logoffSent
) &&
333 !(sm
->initialize
|| !sm
->portEnabled
))
334 SM_ENTER_GLOBAL(SUPP_PAE
, LOGOFF
);
335 else if (((sm
->portControl
== Auto
) &&
336 (sm
->sPortMode
!= sm
->portControl
)) ||
337 sm
->initialize
|| !sm
->portEnabled
)
338 SM_ENTER_GLOBAL(SUPP_PAE
, DISCONNECTED
);
339 else if ((sm
->portControl
== ForceAuthorized
) &&
340 (sm
->sPortMode
!= sm
->portControl
) &&
341 !(sm
->initialize
|| !sm
->portEnabled
))
342 SM_ENTER_GLOBAL(SUPP_PAE
, S_FORCE_AUTH
);
343 else if ((sm
->portControl
== ForceUnauthorized
) &&
344 (sm
->sPortMode
!= sm
->portControl
) &&
345 !(sm
->initialize
|| !sm
->portEnabled
))
346 SM_ENTER_GLOBAL(SUPP_PAE
, S_FORCE_UNAUTH
);
347 else switch (sm
->SUPP_PAE_state
) {
348 case SUPP_PAE_UNKNOWN
:
350 case SUPP_PAE_LOGOFF
:
352 SM_ENTER(SUPP_PAE
, DISCONNECTED
);
354 case SUPP_PAE_DISCONNECTED
:
355 SM_ENTER(SUPP_PAE
, CONNECTING
);
357 case SUPP_PAE_CONNECTING
:
358 if (sm
->startWhen
== 0 && sm
->startCount
< sm
->maxStart
)
359 SM_ENTER(SUPP_PAE
, CONNECTING
);
360 else if (sm
->startWhen
== 0 &&
361 sm
->startCount
>= sm
->maxStart
&&
363 SM_ENTER(SUPP_PAE
, AUTHENTICATED
);
364 else if (sm
->eapSuccess
|| sm
->eapFail
)
365 SM_ENTER(SUPP_PAE
, AUTHENTICATING
);
366 else if (sm
->eapolEap
)
367 SM_ENTER(SUPP_PAE
, RESTART
);
368 else if (sm
->startWhen
== 0 &&
369 sm
->startCount
>= sm
->maxStart
&&
371 SM_ENTER(SUPP_PAE
, HELD
);
373 case SUPP_PAE_AUTHENTICATING
:
374 if (sm
->eapSuccess
&& !sm
->portValid
&&
375 sm
->conf
.accept_802_1x_keys
&&
376 sm
->conf
.required_keys
== 0) {
377 wpa_printf(MSG_DEBUG
, "EAPOL: IEEE 802.1X for "
378 "plaintext connection; no EAPOL-Key frames "
380 sm
->portValid
= TRUE
;
381 if (sm
->ctx
->eapol_done_cb
)
382 sm
->ctx
->eapol_done_cb(sm
->ctx
->ctx
);
384 if (sm
->eapSuccess
&& sm
->portValid
)
385 SM_ENTER(SUPP_PAE
, AUTHENTICATED
);
386 else if (sm
->eapFail
|| (sm
->keyDone
&& !sm
->portValid
))
387 SM_ENTER(SUPP_PAE
, HELD
);
388 else if (sm
->suppTimeout
)
389 SM_ENTER(SUPP_PAE
, CONNECTING
);
392 if (sm
->heldWhile
== 0)
393 SM_ENTER(SUPP_PAE
, CONNECTING
);
394 else if (sm
->eapolEap
)
395 SM_ENTER(SUPP_PAE
, RESTART
);
397 case SUPP_PAE_AUTHENTICATED
:
398 if (sm
->eapolEap
&& sm
->portValid
)
399 SM_ENTER(SUPP_PAE
, RESTART
);
400 else if (!sm
->portValid
)
401 SM_ENTER(SUPP_PAE
, DISCONNECTED
);
403 case SUPP_PAE_RESTART
:
405 SM_ENTER(SUPP_PAE
, AUTHENTICATING
);
407 case SUPP_PAE_S_FORCE_AUTH
:
409 case SUPP_PAE_S_FORCE_UNAUTH
:
415 SM_STATE(KEY_RX
, NO_KEY_RECEIVE
)
417 SM_ENTRY(KEY_RX
, NO_KEY_RECEIVE
);
421 SM_STATE(KEY_RX
, KEY_RECEIVE
)
423 SM_ENTRY(KEY_RX
, KEY_RECEIVE
);
424 eapol_sm_processKey(sm
);
431 if (sm
->initialize
|| !sm
->portEnabled
)
432 SM_ENTER_GLOBAL(KEY_RX
, NO_KEY_RECEIVE
);
433 switch (sm
->KEY_RX_state
) {
436 case KEY_RX_NO_KEY_RECEIVE
:
438 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
440 case KEY_RX_KEY_RECEIVE
:
442 SM_ENTER(KEY_RX
, KEY_RECEIVE
);
448 SM_STATE(SUPP_BE
, REQUEST
)
450 SM_ENTRY(SUPP_BE
, REQUEST
);
453 eapol_sm_getSuppRsp(sm
);
457 SM_STATE(SUPP_BE
, RESPONSE
)
459 SM_ENTRY(SUPP_BE
, RESPONSE
);
460 eapol_sm_txSuppRsp(sm
);
465 SM_STATE(SUPP_BE
, SUCCESS
)
467 SM_ENTRY(SUPP_BE
, SUCCESS
);
469 sm
->suppSuccess
= TRUE
;
471 if (eap_key_available(sm
->eap
)) {
472 /* New key received - clear IEEE 802.1X EAPOL-Key replay
474 sm
->replay_counter_valid
= FALSE
;
479 SM_STATE(SUPP_BE
, FAIL
)
481 SM_ENTRY(SUPP_BE
, FAIL
);
486 SM_STATE(SUPP_BE
, TIMEOUT
)
488 SM_ENTRY(SUPP_BE
, TIMEOUT
);
489 sm
->suppTimeout
= TRUE
;
493 SM_STATE(SUPP_BE
, IDLE
)
495 SM_ENTRY(SUPP_BE
, IDLE
);
496 sm
->suppStart
= FALSE
;
497 sm
->initial_req
= TRUE
;
501 SM_STATE(SUPP_BE
, INITIALIZE
)
503 SM_ENTRY(SUPP_BE
, INITIALIZE
);
504 eapol_sm_abortSupp(sm
);
505 sm
->suppAbort
= FALSE
;
509 SM_STATE(SUPP_BE
, RECEIVE
)
511 SM_ENTRY(SUPP_BE
, RECEIVE
);
512 sm
->authWhile
= sm
->authPeriod
;
513 sm
->eapolEap
= FALSE
;
514 sm
->eapNoResp
= FALSE
;
515 sm
->initial_req
= FALSE
;
521 if (sm
->initialize
|| sm
->suppAbort
)
522 SM_ENTER_GLOBAL(SUPP_BE
, INITIALIZE
);
523 else switch (sm
->SUPP_BE_state
) {
524 case SUPP_BE_UNKNOWN
:
526 case SUPP_BE_REQUEST
:
528 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
529 * and SUCCESS based on eapFail and eapSuccess, respectively.
530 * However, IEEE Std 802.1X-2004 is also specifying that
531 * eapNoResp should be set in conjuction with eapSuccess and
532 * eapFail which would mean that more than one of the
533 * transitions here would be activated at the same time.
534 * Skipping RESPONSE and/or RECEIVE states in these cases can
535 * cause problems and the direct transitions to do not seem
536 * correct. Because of this, the conditions for these
537 * transitions are verified only after eapNoResp. They are
538 * unlikely to be used since eapNoResp should always be set if
539 * either of eapSuccess or eapFail is set.
541 if (sm
->eapResp
&& sm
->eapNoResp
) {
542 wpa_printf(MSG_DEBUG
, "EAPOL: SUPP_BE REQUEST: both "
543 "eapResp and eapNoResp set?!");
546 SM_ENTER(SUPP_BE
, RESPONSE
);
547 else if (sm
->eapNoResp
)
548 SM_ENTER(SUPP_BE
, RECEIVE
);
549 else if (sm
->eapFail
)
550 SM_ENTER(SUPP_BE
, FAIL
);
551 else if (sm
->eapSuccess
)
552 SM_ENTER(SUPP_BE
, SUCCESS
);
554 case SUPP_BE_RESPONSE
:
555 SM_ENTER(SUPP_BE
, RECEIVE
);
557 case SUPP_BE_SUCCESS
:
558 SM_ENTER(SUPP_BE
, IDLE
);
561 SM_ENTER(SUPP_BE
, IDLE
);
563 case SUPP_BE_TIMEOUT
:
564 SM_ENTER(SUPP_BE
, IDLE
);
567 if (sm
->eapFail
&& sm
->suppStart
)
568 SM_ENTER(SUPP_BE
, FAIL
);
569 else if (sm
->eapolEap
&& sm
->suppStart
)
570 SM_ENTER(SUPP_BE
, REQUEST
);
571 else if (sm
->eapSuccess
&& sm
->suppStart
)
572 SM_ENTER(SUPP_BE
, SUCCESS
);
574 case SUPP_BE_INITIALIZE
:
575 SM_ENTER(SUPP_BE
, IDLE
);
577 case SUPP_BE_RECEIVE
:
579 SM_ENTER(SUPP_BE
, REQUEST
);
580 else if (sm
->eapFail
)
581 SM_ENTER(SUPP_BE
, FAIL
);
582 else if (sm
->authWhile
== 0)
583 SM_ENTER(SUPP_BE
, TIMEOUT
);
584 else if (sm
->eapSuccess
)
585 SM_ENTER(SUPP_BE
, SUCCESS
);
591 static void eapol_sm_txLogoff(struct eapol_sm
*sm
)
593 wpa_printf(MSG_DEBUG
, "EAPOL: txLogoff");
594 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
595 IEEE802_1X_TYPE_EAPOL_LOGOFF
, (u8
*) "", 0);
596 sm
->dot1xSuppEapolLogoffFramesTx
++;
597 sm
->dot1xSuppEapolFramesTx
++;
601 static void eapol_sm_txStart(struct eapol_sm
*sm
)
603 wpa_printf(MSG_DEBUG
, "EAPOL: txStart");
604 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
605 IEEE802_1X_TYPE_EAPOL_START
, (u8
*) "", 0);
606 sm
->dot1xSuppEapolStartFramesTx
++;
607 sm
->dot1xSuppEapolFramesTx
++;
611 #define IEEE8021X_ENCR_KEY_LEN 32
612 #define IEEE8021X_SIGN_KEY_LEN 32
614 struct eap_key_data
{
615 u8 encr_key
[IEEE8021X_ENCR_KEY_LEN
];
616 u8 sign_key
[IEEE8021X_SIGN_KEY_LEN
];
620 static void eapol_sm_processKey(struct eapol_sm
*sm
)
622 struct ieee802_1x_hdr
*hdr
;
623 struct ieee802_1x_eapol_key
*key
;
624 struct eap_key_data keydata
;
625 u8 orig_key_sign
[IEEE8021X_KEY_SIGN_LEN
], datakey
[32];
626 u8 ekey
[IEEE8021X_KEY_IV_LEN
+ IEEE8021X_ENCR_KEY_LEN
];
627 int key_len
, res
, sign_key_len
, encr_key_len
;
630 wpa_printf(MSG_DEBUG
, "EAPOL: processKey");
631 if (sm
->last_rx_key
== NULL
)
634 if (!sm
->conf
.accept_802_1x_keys
) {
635 wpa_printf(MSG_WARNING
, "EAPOL: Received IEEE 802.1X EAPOL-Key"
636 " even though this was not accepted - "
637 "ignoring this packet");
641 hdr
= (struct ieee802_1x_hdr
*) sm
->last_rx_key
;
642 key
= (struct ieee802_1x_eapol_key
*) (hdr
+ 1);
643 if (sizeof(*hdr
) + be_to_host16(hdr
->length
) > sm
->last_rx_key_len
) {
644 wpa_printf(MSG_WARNING
, "EAPOL: Too short EAPOL-Key frame");
647 rx_key_length
= WPA_GET_BE16(key
->key_length
);
648 wpa_printf(MSG_DEBUG
, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
649 "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
650 hdr
->version
, hdr
->type
, be_to_host16(hdr
->length
),
651 key
->type
, rx_key_length
, key
->key_index
);
653 eapol_sm_notify_lower_layer_success(sm
);
654 sign_key_len
= IEEE8021X_SIGN_KEY_LEN
;
655 encr_key_len
= IEEE8021X_ENCR_KEY_LEN
;
656 res
= eapol_sm_get_key(sm
, (u8
*) &keydata
, sizeof(keydata
));
658 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get master key for "
659 "decrypting EAPOL-Key keys");
663 /* LEAP derives only 16 bytes of keying material. */
664 res
= eapol_sm_get_key(sm
, (u8
*) &keydata
, 16);
666 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get LEAP "
667 "master key for decrypting EAPOL-Key keys");
672 os_memcpy(keydata
.sign_key
, keydata
.encr_key
, 16);
674 wpa_printf(MSG_DEBUG
, "EAPOL: Could not get enough master key "
675 "data for decrypting EAPOL-Key keys (res=%d)", res
);
679 /* The key replay_counter must increase when same master key */
680 if (sm
->replay_counter_valid
&&
681 os_memcmp(sm
->last_replay_counter
, key
->replay_counter
,
682 IEEE8021X_REPLAY_COUNTER_LEN
) >= 0) {
683 wpa_printf(MSG_WARNING
, "EAPOL: EAPOL-Key replay counter did "
684 "not increase - ignoring key");
685 wpa_hexdump(MSG_DEBUG
, "EAPOL: last replay counter",
686 sm
->last_replay_counter
,
687 IEEE8021X_REPLAY_COUNTER_LEN
);
688 wpa_hexdump(MSG_DEBUG
, "EAPOL: received replay counter",
689 key
->replay_counter
, IEEE8021X_REPLAY_COUNTER_LEN
);
693 /* Verify key signature (HMAC-MD5) */
694 os_memcpy(orig_key_sign
, key
->key_signature
, IEEE8021X_KEY_SIGN_LEN
);
695 os_memset(key
->key_signature
, 0, IEEE8021X_KEY_SIGN_LEN
);
696 hmac_md5(keydata
.sign_key
, sign_key_len
,
697 sm
->last_rx_key
, sizeof(*hdr
) + be_to_host16(hdr
->length
),
699 if (os_memcmp(orig_key_sign
, key
->key_signature
,
700 IEEE8021X_KEY_SIGN_LEN
) != 0) {
701 wpa_printf(MSG_DEBUG
, "EAPOL: Invalid key signature in "
703 os_memcpy(key
->key_signature
, orig_key_sign
,
704 IEEE8021X_KEY_SIGN_LEN
);
707 wpa_printf(MSG_DEBUG
, "EAPOL: EAPOL-Key key signature verified");
709 key_len
= be_to_host16(hdr
->length
) - sizeof(*key
);
710 if (key_len
> 32 || rx_key_length
> 32) {
711 wpa_printf(MSG_WARNING
, "EAPOL: Too long key data length %d",
712 key_len
? key_len
: rx_key_length
);
715 if (key_len
== rx_key_length
) {
716 os_memcpy(ekey
, key
->key_iv
, IEEE8021X_KEY_IV_LEN
);
717 os_memcpy(ekey
+ IEEE8021X_KEY_IV_LEN
, keydata
.encr_key
,
719 os_memcpy(datakey
, key
+ 1, key_len
);
720 rc4(datakey
, key_len
, ekey
,
721 IEEE8021X_KEY_IV_LEN
+ encr_key_len
);
722 wpa_hexdump_key(MSG_DEBUG
, "EAPOL: Decrypted(RC4) key",
724 } else if (key_len
== 0) {
726 * IEEE 802.1X-2004 specifies that least significant Key Length
727 * octets from MS-MPPE-Send-Key are used as the key if the key
728 * data is not present. This seems to be meaning the beginning
729 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
730 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
731 * Anyway, taking the beginning of the keying material from EAP
732 * seems to interoperate with Authenticators.
734 key_len
= rx_key_length
;
735 os_memcpy(datakey
, keydata
.encr_key
, key_len
);
736 wpa_hexdump_key(MSG_DEBUG
, "EAPOL: using part of EAP keying "
737 "material data encryption key",
740 wpa_printf(MSG_DEBUG
, "EAPOL: Invalid key data length %d "
741 "(key_length=%d)", key_len
, rx_key_length
);
745 sm
->replay_counter_valid
= TRUE
;
746 os_memcpy(sm
->last_replay_counter
, key
->replay_counter
,
747 IEEE8021X_REPLAY_COUNTER_LEN
);
749 wpa_printf(MSG_DEBUG
, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
751 key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
?
752 "unicast" : "broadcast",
753 key
->key_index
& IEEE8021X_KEY_INDEX_MASK
, key_len
);
755 if (sm
->ctx
->set_wep_key
&&
756 sm
->ctx
->set_wep_key(sm
->ctx
->ctx
,
757 key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
,
758 key
->key_index
& IEEE8021X_KEY_INDEX_MASK
,
759 datakey
, key_len
) < 0) {
760 wpa_printf(MSG_WARNING
, "EAPOL: Failed to set WEP key to the "
763 if (key
->key_index
& IEEE8021X_KEY_INDEX_FLAG
)
764 sm
->unicast_key_received
= TRUE
;
766 sm
->broadcast_key_received
= TRUE
;
768 if ((sm
->unicast_key_received
||
769 !(sm
->conf
.required_keys
& EAPOL_REQUIRE_KEY_UNICAST
)) &&
770 (sm
->broadcast_key_received
||
771 !(sm
->conf
.required_keys
& EAPOL_REQUIRE_KEY_BROADCAST
)))
773 wpa_printf(MSG_DEBUG
, "EAPOL: all required EAPOL-Key "
775 sm
->portValid
= TRUE
;
776 if (sm
->ctx
->eapol_done_cb
)
777 sm
->ctx
->eapol_done_cb(sm
->ctx
->ctx
);
783 static void eapol_sm_getSuppRsp(struct eapol_sm
*sm
)
785 wpa_printf(MSG_DEBUG
, "EAPOL: getSuppRsp");
786 /* EAP layer processing; no special code is needed, since Supplicant
787 * Backend state machine is waiting for eapNoResp or eapResp to be set
788 * and these are only set in the EAP state machine when the processing
793 static void eapol_sm_txSuppRsp(struct eapol_sm
*sm
)
798 wpa_printf(MSG_DEBUG
, "EAPOL: txSuppRsp");
799 resp
= eap_get_eapRespData(sm
->eap
, &resp_len
);
801 wpa_printf(MSG_WARNING
, "EAPOL: txSuppRsp - EAP response data "
806 /* Send EAP-Packet from the EAP layer to the Authenticator */
807 sm
->ctx
->eapol_send(sm
->ctx
->eapol_send_ctx
,
808 IEEE802_1X_TYPE_EAP_PACKET
, resp
, resp_len
);
810 /* eapRespData is not used anymore, so free it here */
814 sm
->dot1xSuppEapolReqIdFramesRx
++;
816 sm
->dot1xSuppEapolReqFramesRx
++;
817 sm
->dot1xSuppEapolRespFramesTx
++;
818 sm
->dot1xSuppEapolFramesTx
++;
822 static void eapol_sm_abortSupp(struct eapol_sm
*sm
)
824 /* release system resources that may have been allocated for the
825 * authentication session */
826 os_free(sm
->last_rx_key
);
827 sm
->last_rx_key
= NULL
;
828 os_free(sm
->eapReqData
);
829 sm
->eapReqData
= NULL
;
830 eap_sm_abort(sm
->eap
);
834 static void eapol_sm_step_timeout(void *eloop_ctx
, void *timeout_ctx
)
836 eapol_sm_step(timeout_ctx
);
841 * eapol_sm_step - EAPOL state machine step function
842 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
844 * This function is called to notify the state machine about changed external
845 * variables. It will step through the EAPOL state machines in loop to process
846 * all triggered state changes.
848 void eapol_sm_step(struct eapol_sm
*sm
)
852 /* In theory, it should be ok to run this in loop until !changed.
853 * However, it is better to use a limit on number of iterations to
854 * allow events (e.g., SIGTERM) to stop the program cleanly if the
855 * state machine were to generate a busy loop. */
856 for (i
= 0; i
< 100; i
++) {
858 SM_STEP_RUN(SUPP_PAE
);
860 SM_STEP_RUN(SUPP_BE
);
861 if (eap_sm_step(sm
->eap
))
868 /* restart EAPOL state machine step from timeout call in order
869 * to allow other events to be processed. */
870 eloop_cancel_timeout(eapol_sm_step_timeout
, NULL
, sm
);
871 eloop_register_timeout(0, 0, eapol_sm_step_timeout
, NULL
, sm
);
874 if (sm
->ctx
->cb
&& sm
->cb_status
!= EAPOL_CB_IN_PROGRESS
) {
875 int success
= sm
->cb_status
== EAPOL_CB_SUCCESS
? 1 : 0;
876 sm
->cb_status
= EAPOL_CB_IN_PROGRESS
;
877 sm
->ctx
->cb(sm
, success
, sm
->ctx
->cb_ctx
);
882 #ifdef CONFIG_CTRL_IFACE
883 static const char *eapol_supp_pae_state(int state
)
886 case SUPP_PAE_LOGOFF
:
888 case SUPP_PAE_DISCONNECTED
:
889 return "DISCONNECTED";
890 case SUPP_PAE_CONNECTING
:
892 case SUPP_PAE_AUTHENTICATING
:
893 return "AUTHENTICATING";
896 case SUPP_PAE_AUTHENTICATED
:
897 return "AUTHENTICATED";
898 case SUPP_PAE_RESTART
:
906 static const char *eapol_supp_be_state(int state
)
909 case SUPP_BE_REQUEST
:
911 case SUPP_BE_RESPONSE
:
913 case SUPP_BE_SUCCESS
:
917 case SUPP_BE_TIMEOUT
:
921 case SUPP_BE_INITIALIZE
:
923 case SUPP_BE_RECEIVE
:
931 static const char * eapol_port_status(PortStatus status
)
933 if (status
== Authorized
)
936 return "Unauthorized";
938 #endif /* CONFIG_CTRL_IFACE */
941 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
942 static const char * eapol_port_control(PortControl ctrl
)
947 case ForceUnauthorized
:
948 return "ForceUnauthorized";
949 case ForceAuthorized
:
950 return "ForceAuthorized";
955 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
959 * eapol_sm_configure - Set EAPOL variables
960 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
961 * @heldPeriod: dot1xSuppHeldPeriod
962 * @authPeriod: dot1xSuppAuthPeriod
963 * @startPeriod: dot1xSuppStartPeriod
964 * @maxStart: dot1xSuppMaxStart
966 * Set configurable EAPOL state machine variables. Each variable can be set to
967 * the given value or ignored if set to -1 (to set only some of the variables).
969 void eapol_sm_configure(struct eapol_sm
*sm
, int heldPeriod
, int authPeriod
,
970 int startPeriod
, int maxStart
)
975 sm
->heldPeriod
= heldPeriod
;
977 sm
->authPeriod
= authPeriod
;
978 if (startPeriod
>= 0)
979 sm
->startPeriod
= startPeriod
;
981 sm
->maxStart
= maxStart
;
985 #ifdef CONFIG_CTRL_IFACE
987 * eapol_sm_get_status - Get EAPOL state machine status
988 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
989 * @buf: Buffer for status information
990 * @buflen: Maximum buffer length
991 * @verbose: Whether to include verbose status information
992 * Returns: Number of bytes written to buf.
994 * Query EAPOL state machine for status information. This function fills in a
995 * text area with current status information from the EAPOL state machine. If
996 * the buffer (buf) is not large enough, status information will be truncated
999 int eapol_sm_get_status(struct eapol_sm
*sm
, char *buf
, size_t buflen
,
1006 len
= os_snprintf(buf
, buflen
,
1007 "Supplicant PAE state=%s\n"
1008 "suppPortStatus=%s\n",
1009 eapol_supp_pae_state(sm
->SUPP_PAE_state
),
1010 eapol_port_status(sm
->suppPortStatus
));
1011 if (len
< 0 || (size_t) len
>= buflen
)
1015 ret
= os_snprintf(buf
+ len
, buflen
- len
,
1021 "Supplicant Backend state=%s\n",
1026 eapol_port_control(sm
->portControl
),
1027 eapol_supp_be_state(sm
->SUPP_BE_state
));
1028 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
1033 len
+= eap_sm_get_status(sm
->eap
, buf
+ len
, buflen
- len
, verbose
);
1040 * eapol_sm_get_mib - Get EAPOL state machine MIBs
1041 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1042 * @buf: Buffer for MIB information
1043 * @buflen: Maximum buffer length
1044 * Returns: Number of bytes written to buf.
1046 * Query EAPOL state machine for MIB information. This function fills in a
1047 * text area with current MIB information from the EAPOL state machine. If
1048 * the buffer (buf) is not large enough, MIB information will be truncated to
1051 int eapol_sm_get_mib(struct eapol_sm
*sm
, char *buf
, size_t buflen
)
1058 ret
= os_snprintf(buf
, buflen
,
1059 "dot1xSuppPaeState=%d\n"
1060 "dot1xSuppHeldPeriod=%u\n"
1061 "dot1xSuppAuthPeriod=%u\n"
1062 "dot1xSuppStartPeriod=%u\n"
1063 "dot1xSuppMaxStart=%u\n"
1064 "dot1xSuppSuppControlledPortStatus=%s\n"
1065 "dot1xSuppBackendPaeState=%d\n",
1071 sm
->suppPortStatus
== Authorized
?
1072 "Authorized" : "Unauthorized",
1075 if (ret
< 0 || (size_t) ret
>= buflen
)
1079 ret
= os_snprintf(buf
+ len
, buflen
- len
,
1080 "dot1xSuppEapolFramesRx=%u\n"
1081 "dot1xSuppEapolFramesTx=%u\n"
1082 "dot1xSuppEapolStartFramesTx=%u\n"
1083 "dot1xSuppEapolLogoffFramesTx=%u\n"
1084 "dot1xSuppEapolRespFramesTx=%u\n"
1085 "dot1xSuppEapolReqIdFramesRx=%u\n"
1086 "dot1xSuppEapolReqFramesRx=%u\n"
1087 "dot1xSuppInvalidEapolFramesRx=%u\n"
1088 "dot1xSuppEapLengthErrorFramesRx=%u\n"
1089 "dot1xSuppLastEapolFrameVersion=%u\n"
1090 "dot1xSuppLastEapolFrameSource=" MACSTR
"\n",
1091 sm
->dot1xSuppEapolFramesRx
,
1092 sm
->dot1xSuppEapolFramesTx
,
1093 sm
->dot1xSuppEapolStartFramesTx
,
1094 sm
->dot1xSuppEapolLogoffFramesTx
,
1095 sm
->dot1xSuppEapolRespFramesTx
,
1096 sm
->dot1xSuppEapolReqIdFramesRx
,
1097 sm
->dot1xSuppEapolReqFramesRx
,
1098 sm
->dot1xSuppInvalidEapolFramesRx
,
1099 sm
->dot1xSuppEapLengthErrorFramesRx
,
1100 sm
->dot1xSuppLastEapolFrameVersion
,
1101 MAC2STR(sm
->dot1xSuppLastEapolFrameSource
));
1103 if (ret
< 0 || (size_t) ret
>= buflen
- len
)
1109 #endif /* CONFIG_CTRL_IFACE */
1113 * eapol_sm_rx_eapol - Process received EAPOL frames
1114 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1115 * @src: Source MAC address of the EAPOL packet
1116 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1117 * @len: Length of the EAPOL frame
1118 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1121 int eapol_sm_rx_eapol(struct eapol_sm
*sm
, const u8
*src
, const u8
*buf
,
1124 const struct ieee802_1x_hdr
*hdr
;
1125 const struct ieee802_1x_eapol_key
*key
;
1132 sm
->dot1xSuppEapolFramesRx
++;
1133 if (len
< sizeof(*hdr
)) {
1134 sm
->dot1xSuppInvalidEapolFramesRx
++;
1137 hdr
= (const struct ieee802_1x_hdr
*) buf
;
1138 sm
->dot1xSuppLastEapolFrameVersion
= hdr
->version
;
1139 os_memcpy(sm
->dot1xSuppLastEapolFrameSource
, src
, ETH_ALEN
);
1140 if (hdr
->version
< EAPOL_VERSION
) {
1141 /* TODO: backwards compatibility */
1143 plen
= be_to_host16(hdr
->length
);
1144 if (plen
> len
- sizeof(*hdr
)) {
1145 sm
->dot1xSuppEapLengthErrorFramesRx
++;
1148 data_len
= plen
+ sizeof(*hdr
);
1150 switch (hdr
->type
) {
1151 case IEEE802_1X_TYPE_EAP_PACKET
:
1152 if (sm
->cached_pmk
) {
1153 /* Trying to use PMKSA caching, but Authenticator did
1154 * not seem to have a matching entry. Need to restart
1155 * EAPOL state machines.
1157 eapol_sm_abort_cached(sm
);
1159 os_free(sm
->eapReqData
);
1160 sm
->eapReqDataLen
= plen
;
1161 sm
->eapReqData
= os_malloc(sm
->eapReqDataLen
);
1162 if (sm
->eapReqData
) {
1163 wpa_printf(MSG_DEBUG
, "EAPOL: Received EAP-Packet "
1165 os_memcpy(sm
->eapReqData
, (u8
*) (hdr
+ 1),
1167 sm
->eapolEap
= TRUE
;
1171 case IEEE802_1X_TYPE_EAPOL_KEY
:
1172 if (plen
< sizeof(*key
)) {
1173 wpa_printf(MSG_DEBUG
, "EAPOL: Too short EAPOL-Key "
1177 key
= (const struct ieee802_1x_eapol_key
*) (hdr
+ 1);
1178 if (key
->type
== EAPOL_KEY_TYPE_WPA
||
1179 key
->type
== EAPOL_KEY_TYPE_RSN
) {
1180 /* WPA Supplicant takes care of this frame. */
1181 wpa_printf(MSG_DEBUG
, "EAPOL: Ignoring WPA EAPOL-Key "
1182 "frame in EAPOL state machines");
1186 if (key
->type
!= EAPOL_KEY_TYPE_RC4
) {
1187 wpa_printf(MSG_DEBUG
, "EAPOL: Ignored unknown "
1188 "EAPOL-Key type %d", key
->type
);
1191 os_free(sm
->last_rx_key
);
1192 sm
->last_rx_key
= os_malloc(data_len
);
1193 if (sm
->last_rx_key
) {
1194 wpa_printf(MSG_DEBUG
, "EAPOL: Received EAPOL-Key "
1196 os_memcpy(sm
->last_rx_key
, buf
, data_len
);
1197 sm
->last_rx_key_len
= data_len
;
1203 wpa_printf(MSG_DEBUG
, "EAPOL: Received unknown EAPOL type %d",
1205 sm
->dot1xSuppInvalidEapolFramesRx
++;
1214 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1215 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1217 * Notify EAPOL station machine about transmitted EAPOL packet from an external
1218 * component, e.g., WPA. This will update the statistics.
1220 void eapol_sm_notify_tx_eapol_key(struct eapol_sm
*sm
)
1223 sm
->dot1xSuppEapolFramesTx
++;
1228 * eapol_sm_notify_portEnabled - Notification about portEnabled change
1229 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1230 * @enabled: New portEnabled value
1232 * Notify EAPOL station machine about new portEnabled value.
1234 void eapol_sm_notify_portEnabled(struct eapol_sm
*sm
, Boolean enabled
)
1238 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1239 "portEnabled=%d", enabled
);
1240 sm
->portEnabled
= enabled
;
1246 * eapol_sm_notify_portValid - Notification about portValid change
1247 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1248 * @valid: New portValid value
1250 * Notify EAPOL station machine about new portValid value.
1252 void eapol_sm_notify_portValid(struct eapol_sm
*sm
, Boolean valid
)
1256 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1257 "portValid=%d", valid
);
1258 sm
->portValid
= valid
;
1264 * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1265 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1266 * @success: %TRUE = set success, %FALSE = clear success
1268 * Notify EAPOL station machine that external event has forced EAP state to
1269 * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1271 * This function is called to update EAP state when WPA-PSK key handshake has
1272 * been completed successfully since WPA-PSK does not use EAP state machine.
1274 void eapol_sm_notify_eap_success(struct eapol_sm
*sm
, Boolean success
)
1278 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1279 "EAP success=%d", success
);
1280 sm
->eapSuccess
= success
;
1281 sm
->altAccept
= success
;
1283 eap_notify_success(sm
->eap
);
1289 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1290 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1291 * @fail: %TRUE = set failure, %FALSE = clear failure
1293 * Notify EAPOL station machine that external event has forced EAP state to
1294 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1296 void eapol_sm_notify_eap_fail(struct eapol_sm
*sm
, Boolean fail
)
1300 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1301 "EAP fail=%d", fail
);
1303 sm
->altReject
= fail
;
1309 * eapol_sm_notify_config - Notification of EAPOL configuration change
1310 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1311 * @config: Pointer to current network configuration
1312 * @conf: Pointer to EAPOL configuration data
1314 * Notify EAPOL station machine that configuration has changed. config will be
1315 * stored as a backpointer to network configuration. This can be %NULL to clear
1316 * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1317 * data. If conf is %NULL, this part of the configuration change will be
1320 void eapol_sm_notify_config(struct eapol_sm
*sm
, struct wpa_ssid
*config
,
1321 const struct eapol_config
*conf
)
1326 sm
->config
= config
;
1331 sm
->conf
.accept_802_1x_keys
= conf
->accept_802_1x_keys
;
1332 sm
->conf
.required_keys
= conf
->required_keys
;
1333 sm
->conf
.fast_reauth
= conf
->fast_reauth
;
1335 eap_set_fast_reauth(sm
->eap
, conf
->fast_reauth
);
1336 eap_set_workaround(sm
->eap
, conf
->workaround
);
1337 eap_set_force_disabled(sm
->eap
, conf
->eap_disabled
);
1343 * eapol_sm_get_key - Get master session key (MSK) from EAP
1344 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1345 * @key: Pointer for key buffer
1346 * @len: Number of bytes to copy to key
1347 * Returns: 0 on success (len of key available), maximum available key len
1348 * (>0) if key is available but it is shorter than len, or -1 on failure.
1350 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1351 * is available only after a successful authentication.
1353 int eapol_sm_get_key(struct eapol_sm
*sm
, u8
*key
, size_t len
)
1358 if (sm
== NULL
|| !eap_key_available(sm
->eap
))
1360 eap_key
= eap_get_eapKeyData(sm
->eap
, &eap_len
);
1361 if (eap_key
== NULL
)
1365 os_memcpy(key
, eap_key
, len
);
1371 * eapol_sm_notify_logoff - Notification of logon/logoff commands
1372 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1373 * @logoff: Whether command was logoff
1375 * Notify EAPOL state machines that user requested logon/logoff.
1377 void eapol_sm_notify_logoff(struct eapol_sm
*sm
, Boolean logoff
)
1380 sm
->userLogoff
= logoff
;
1387 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1388 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1390 * Notify EAPOL state machines that PMKSA caching was successful. This is used
1391 * to move EAPOL and EAP state machines into authenticated/successful state.
1393 void eapol_sm_notify_cached(struct eapol_sm
*sm
)
1397 sm
->SUPP_PAE_state
= SUPP_PAE_AUTHENTICATED
;
1398 sm
->suppPortStatus
= Authorized
;
1399 eap_notify_success(sm
->eap
);
1404 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1405 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1406 * @attempt: Whether PMKSA caching is tried
1408 * Notify EAPOL state machines whether PMKSA caching is used.
1410 void eapol_sm_notify_pmkid_attempt(struct eapol_sm
*sm
, int attempt
)
1415 wpa_printf(MSG_DEBUG
, "RSN: Trying to use cached PMKSA");
1416 sm
->cached_pmk
= TRUE
;
1418 wpa_printf(MSG_DEBUG
, "RSN: Do not try to use cached PMKSA");
1419 sm
->cached_pmk
= FALSE
;
1424 static void eapol_sm_abort_cached(struct eapol_sm
*sm
)
1426 wpa_printf(MSG_DEBUG
, "RSN: Authenticator did not accept PMKID, "
1427 "doing full EAP authentication");
1430 sm
->cached_pmk
= FALSE
;
1431 sm
->SUPP_PAE_state
= SUPP_PAE_CONNECTING
;
1432 sm
->suppPortStatus
= Unauthorized
;
1434 /* Make sure we do not start sending EAPOL-Start frames first, but
1435 * instead move to RESTART state to start EAPOL authentication. */
1438 if (sm
->ctx
->aborted_cached
)
1439 sm
->ctx
->aborted_cached(sm
->ctx
->ctx
);
1444 * eapol_sm_register_scard_ctx - Notification of smart card context
1445 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1446 * @ctx: Context data for smart card operations
1448 * Notify EAPOL state machines of context data for smart card operations. This
1449 * context data will be used as a parameter for scard_*() functions.
1451 void eapol_sm_register_scard_ctx(struct eapol_sm
*sm
, void *ctx
)
1454 sm
->ctx
->scard_ctx
= ctx
;
1455 eap_register_scard_ctx(sm
->eap
, ctx
);
1461 * eapol_sm_notify_portControl - Notification of portControl changes
1462 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1463 * @portControl: New value for portControl variable
1465 * Notify EAPOL state machines that portControl variable has changed.
1467 void eapol_sm_notify_portControl(struct eapol_sm
*sm
, PortControl portControl
)
1471 wpa_printf(MSG_DEBUG
, "EAPOL: External notification - "
1472 "portControl=%s", eapol_port_control(portControl
));
1473 sm
->portControl
= portControl
;
1479 * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1480 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1482 * Notify EAPOL state machines that a monitor was attached to the control
1483 * interface to trigger re-sending of pending requests for user input.
1485 void eapol_sm_notify_ctrl_attached(struct eapol_sm
*sm
)
1489 eap_sm_notify_ctrl_attached(sm
->eap
);
1494 * eapol_sm_notify_ctrl_response - Notification of received user input
1495 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1497 * Notify EAPOL state machines that a control response, i.e., user
1498 * input, was received in order to trigger retrying of a pending EAP request.
1500 void eapol_sm_notify_ctrl_response(struct eapol_sm
*sm
)
1504 if (sm
->eapReqData
&& !sm
->eapReq
) {
1505 wpa_printf(MSG_DEBUG
, "EAPOL: received control response (user "
1506 "input) notification - retrying pending EAP "
1508 sm
->eapolEap
= TRUE
;
1516 * eapol_sm_request_reauth - Request reauthentication
1517 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1519 * This function can be used to request EAPOL reauthentication, e.g., when the
1520 * current PMKSA entry is nearing expiration.
1522 void eapol_sm_request_reauth(struct eapol_sm
*sm
)
1524 if (sm
== NULL
|| sm
->SUPP_PAE_state
!= SUPP_PAE_AUTHENTICATED
)
1526 eapol_sm_txStart(sm
);
1531 * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1532 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1534 * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1535 * successful authentication. This is used to recover from dropped EAP-Success
1538 void eapol_sm_notify_lower_layer_success(struct eapol_sm
*sm
)
1542 eap_notify_lower_layer_success(sm
->eap
);
1547 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1548 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1550 void eapol_sm_invalidate_cached_session(struct eapol_sm
*sm
)
1553 eap_invalidate_cached_session(sm
->eap
);
1557 static struct wpa_ssid
* eapol_sm_get_config(void *ctx
)
1559 struct eapol_sm
*sm
= ctx
;
1560 return sm
? sm
->config
: NULL
;
1564 static u8
* eapol_sm_get_eapReqData(void *ctx
, size_t *len
)
1566 struct eapol_sm
*sm
= ctx
;
1567 if (sm
== NULL
|| sm
->eapReqData
== NULL
) {
1572 *len
= sm
->eapReqDataLen
;
1573 return sm
->eapReqData
;
1577 static Boolean
eapol_sm_get_bool(void *ctx
, enum eapol_bool_var variable
)
1579 struct eapol_sm
*sm
= ctx
;
1583 case EAPOL_eapSuccess
:
1584 return sm
->eapSuccess
;
1585 case EAPOL_eapRestart
:
1586 return sm
->eapRestart
;
1591 case EAPOL_eapNoResp
:
1592 return sm
->eapNoResp
;
1595 case EAPOL_portEnabled
:
1596 return sm
->portEnabled
;
1597 case EAPOL_altAccept
:
1598 return sm
->altAccept
;
1599 case EAPOL_altReject
:
1600 return sm
->altReject
;
1606 static void eapol_sm_set_bool(void *ctx
, enum eapol_bool_var variable
,
1609 struct eapol_sm
*sm
= ctx
;
1613 case EAPOL_eapSuccess
:
1614 sm
->eapSuccess
= value
;
1616 case EAPOL_eapRestart
:
1617 sm
->eapRestart
= value
;
1620 sm
->eapFail
= value
;
1623 sm
->eapResp
= value
;
1625 case EAPOL_eapNoResp
:
1626 sm
->eapNoResp
= value
;
1631 case EAPOL_portEnabled
:
1632 sm
->portEnabled
= value
;
1634 case EAPOL_altAccept
:
1635 sm
->altAccept
= value
;
1637 case EAPOL_altReject
:
1638 sm
->altReject
= value
;
1644 static unsigned int eapol_sm_get_int(void *ctx
, enum eapol_int_var variable
)
1646 struct eapol_sm
*sm
= ctx
;
1650 case EAPOL_idleWhile
:
1651 return sm
->idleWhile
;
1657 static void eapol_sm_set_int(void *ctx
, enum eapol_int_var variable
,
1660 struct eapol_sm
*sm
= ctx
;
1664 case EAPOL_idleWhile
:
1665 sm
->idleWhile
= value
;
1671 static void eapol_sm_set_config_blob(void *ctx
, struct wpa_config_blob
*blob
)
1673 struct eapol_sm
*sm
= ctx
;
1674 if (sm
&& sm
->ctx
&& sm
->ctx
->set_config_blob
)
1675 sm
->ctx
->set_config_blob(sm
->ctx
->ctx
, blob
);
1679 static const struct wpa_config_blob
*
1680 eapol_sm_get_config_blob(void *ctx
, const char *name
)
1682 struct eapol_sm
*sm
= ctx
;
1683 if (sm
&& sm
->ctx
&& sm
->ctx
->get_config_blob
)
1684 return sm
->ctx
->get_config_blob(sm
->ctx
->ctx
, name
);
1690 static void eapol_sm_notify_pending(void *ctx
)
1692 struct eapol_sm
*sm
= ctx
;
1695 if (sm
->eapReqData
&& !sm
->eapReq
) {
1696 wpa_printf(MSG_DEBUG
, "EAPOL: received notification from EAP "
1697 "state machine - retrying pending EAP Request");
1698 sm
->eapolEap
= TRUE
;
1705 static struct eapol_callbacks eapol_cb
=
1707 eapol_sm_get_config
,
1712 eapol_sm_get_eapReqData
,
1713 eapol_sm_set_config_blob
,
1714 eapol_sm_get_config_blob
,
1715 eapol_sm_notify_pending
1720 * eapol_sm_init - Initialize EAPOL state machine
1721 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1722 * and EAPOL state machine will free it in eapol_sm_deinit()
1723 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1725 * Allocate and initialize an EAPOL state machine.
1727 struct eapol_sm
*eapol_sm_init(struct eapol_ctx
*ctx
)
1729 struct eapol_sm
*sm
;
1730 struct eap_config conf
;
1731 sm
= os_zalloc(sizeof(*sm
));
1736 sm
->portControl
= Auto
;
1738 /* Supplicant PAE state machine */
1739 sm
->heldPeriod
= 60;
1740 sm
->startPeriod
= 30;
1743 /* Supplicant Backend state machine */
1744 sm
->authPeriod
= 30;
1746 os_memset(&conf
, 0, sizeof(conf
));
1747 conf
.opensc_engine_path
= ctx
->opensc_engine_path
;
1748 conf
.pkcs11_engine_path
= ctx
->pkcs11_engine_path
;
1749 conf
.pkcs11_module_path
= ctx
->pkcs11_module_path
;
1751 sm
->eap
= eap_sm_init(sm
, &eapol_cb
, sm
->ctx
->msg_ctx
, &conf
);
1752 if (sm
->eap
== NULL
) {
1757 /* Initialize EAPOL state machines */
1758 sm
->initialize
= TRUE
;
1760 sm
->initialize
= FALSE
;
1763 eloop_register_timeout(1, 0, eapol_port_timers_tick
, NULL
, sm
);
1770 * eapol_sm_deinit - Deinitialize EAPOL state machine
1771 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1773 * Deinitialize and free EAPOL state machine.
1775 void eapol_sm_deinit(struct eapol_sm
*sm
)
1779 eloop_cancel_timeout(eapol_sm_step_timeout
, NULL
, sm
);
1780 eloop_cancel_timeout(eapol_port_timers_tick
, NULL
, sm
);
1781 eap_sm_deinit(sm
->eap
);
1782 os_free(sm
->last_rx_key
);
1783 os_free(sm
->eapReqData
);