2
* WPA Supplicant / EAPOL state machines
3
* Copyright (c) 2004-2007, 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 "eap_peer/eap.h"
24
#include "state_machine.h"
26
#define STATE_MACHINE_DATA struct eapol_sm
27
#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
30
/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
33
* struct eapol_sm - Internal data for EAPOL state machines
37
unsigned int authWhile;
38
unsigned int heldWhile;
39
unsigned int startWhen;
40
unsigned int idleWhile; /* for EAP state machine */
42
/* Global variables */
49
PortControl portControl;
51
PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
59
/* Supplicant PAE state machine */
62
SUPP_PAE_DISCONNECTED = 1,
64
SUPP_PAE_CONNECTING = 3,
65
SUPP_PAE_AUTHENTICATING = 4,
66
SUPP_PAE_AUTHENTICATED = 5,
70
SUPP_PAE_S_FORCE_AUTH = 9,
71
SUPP_PAE_S_FORCE_UNAUTH = 10
72
} SUPP_PAE_state; /* dot1xSuppPaeState */
76
unsigned int startCount;
78
PortControl sPortMode;
80
unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
81
unsigned int startPeriod; /* dot1xSuppStartPeriod */
82
unsigned int maxStart; /* dot1xSuppMaxStart */
84
/* Key Receive state machine */
87
KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
92
/* Supplicant Backend state machine */
95
SUPP_BE_INITIALIZE = 1,
103
} SUPP_BE_state; /* dot1xSuppBackendPaeState */
109
unsigned int authPeriod; /* dot1xSuppAuthPeriod */
112
unsigned int dot1xSuppEapolFramesRx;
113
unsigned int dot1xSuppEapolFramesTx;
114
unsigned int dot1xSuppEapolStartFramesTx;
115
unsigned int dot1xSuppEapolLogoffFramesTx;
116
unsigned int dot1xSuppEapolRespFramesTx;
117
unsigned int dot1xSuppEapolReqIdFramesRx;
118
unsigned int dot1xSuppEapolReqFramesRx;
119
unsigned int dot1xSuppInvalidEapolFramesRx;
120
unsigned int dot1xSuppEapLengthErrorFramesRx;
121
unsigned int dot1xSuppLastEapolFrameVersion;
122
unsigned char dot1xSuppLastEapolFrameSource[6];
124
/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
127
struct wpa_ssid *config;
130
size_t last_rx_key_len;
131
u8 *eapReqData; /* for EAP */
132
size_t eapReqDataLen; /* for EAP */
133
Boolean altAccept; /* for EAP */
134
Boolean altReject; /* for EAP */
135
Boolean replay_counter_valid;
136
u8 last_replay_counter[16];
137
struct eapol_config conf;
138
struct eapol_ctx *ctx;
139
enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
143
Boolean unicast_key_received, broadcast_key_received;
147
#define IEEE8021X_REPLAY_COUNTER_LEN 8
148
#define IEEE8021X_KEY_SIGN_LEN 16
149
#define IEEE8021X_KEY_IV_LEN 16
151
#define IEEE8021X_KEY_INDEX_FLAG 0x80
152
#define IEEE8021X_KEY_INDEX_MASK 0x03
155
#pragma pack(push, 1)
156
#endif /* _MSC_VER */
158
struct ieee802_1x_eapol_key {
160
/* Note: key_length is unaligned */
162
/* does not repeat within the life of the keying material used to
163
* encrypt the Key field; 64-bit NTP timestamp MAY be used here */
164
u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
165
u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
166
u8 key_index; /* key flag in the most significant bit:
167
* 0 = broadcast (default key),
168
* 1 = unicast (key mapping key); key index is in the
169
* 7 least significant bits */
170
/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
172
u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
174
/* followed by key: if packet body length = 44 + key length, then the
175
* key field (of key_length bytes) contains the key in encrypted form;
176
* if packet body length = 44, key field is absent and key_length
177
* represents the number of least significant octets from
178
* MS-MPPE-Send-Key attribute to be used as the keying material;
179
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
184
#endif /* _MSC_VER */
187
static void eapol_sm_txLogoff(struct eapol_sm *sm);
188
static void eapol_sm_txStart(struct eapol_sm *sm);
189
static void eapol_sm_processKey(struct eapol_sm *sm);
190
static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
191
static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
192
static void eapol_sm_abortSupp(struct eapol_sm *sm);
193
static void eapol_sm_abort_cached(struct eapol_sm *sm);
194
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
197
/* Port Timers state machine - implemented as a function that will be called
198
* once a second as a registered event loop timeout */
199
static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
201
struct eapol_sm *sm = timeout_ctx;
203
if (sm->authWhile > 0) {
205
if (sm->authWhile == 0)
206
wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
208
if (sm->heldWhile > 0) {
210
if (sm->heldWhile == 0)
211
wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
213
if (sm->startWhen > 0) {
215
if (sm->startWhen == 0)
216
wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
218
if (sm->idleWhile > 0) {
220
if (sm->idleWhile == 0)
221
wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
224
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
229
SM_STATE(SUPP_PAE, LOGOFF)
231
SM_ENTRY(SUPP_PAE, LOGOFF);
232
eapol_sm_txLogoff(sm);
233
sm->logoffSent = TRUE;
234
sm->suppPortStatus = Unauthorized;
238
SM_STATE(SUPP_PAE, DISCONNECTED)
240
SM_ENTRY(SUPP_PAE, DISCONNECTED);
241
sm->sPortMode = Auto;
243
sm->logoffSent = FALSE;
244
sm->suppPortStatus = Unauthorized;
245
sm->suppAbort = TRUE;
247
sm->unicast_key_received = FALSE;
248
sm->broadcast_key_received = FALSE;
252
SM_STATE(SUPP_PAE, CONNECTING)
254
int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
255
SM_ENTRY(SUPP_PAE, CONNECTING);
257
sm->startWhen = sm->startPeriod;
261
* Do not send EAPOL-Start immediately since in most cases,
262
* Authenticator is going to start authentication immediately
263
* after association and an extra EAPOL-Start is just going to
264
* delay authentication. Use a short timeout to send the first
265
* EAPOL-Start if Authenticator does not start authentication.
269
sm->eapolEap = FALSE;
271
eapol_sm_txStart(sm);
275
SM_STATE(SUPP_PAE, AUTHENTICATING)
277
SM_ENTRY(SUPP_PAE, AUTHENTICATING);
279
sm->suppSuccess = FALSE;
280
sm->suppFail = FALSE;
281
sm->suppTimeout = FALSE;
284
sm->suppStart = TRUE;
288
SM_STATE(SUPP_PAE, HELD)
290
SM_ENTRY(SUPP_PAE, HELD);
291
sm->heldWhile = sm->heldPeriod;
292
sm->suppPortStatus = Unauthorized;
293
sm->cb_status = EAPOL_CB_FAILURE;
297
SM_STATE(SUPP_PAE, AUTHENTICATED)
299
SM_ENTRY(SUPP_PAE, AUTHENTICATED);
300
sm->suppPortStatus = Authorized;
301
sm->cb_status = EAPOL_CB_SUCCESS;
305
SM_STATE(SUPP_PAE, RESTART)
307
SM_ENTRY(SUPP_PAE, RESTART);
308
sm->eapRestart = TRUE;
312
SM_STATE(SUPP_PAE, S_FORCE_AUTH)
314
SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
315
sm->suppPortStatus = Authorized;
316
sm->sPortMode = ForceAuthorized;
320
SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
322
SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
323
sm->suppPortStatus = Unauthorized;
324
sm->sPortMode = ForceUnauthorized;
325
eapol_sm_txLogoff(sm);
331
if ((sm->userLogoff && !sm->logoffSent) &&
332
!(sm->initialize || !sm->portEnabled))
333
SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
334
else if (((sm->portControl == Auto) &&
335
(sm->sPortMode != sm->portControl)) ||
336
sm->initialize || !sm->portEnabled)
337
SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
338
else if ((sm->portControl == ForceAuthorized) &&
339
(sm->sPortMode != sm->portControl) &&
340
!(sm->initialize || !sm->portEnabled))
341
SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
342
else if ((sm->portControl == ForceUnauthorized) &&
343
(sm->sPortMode != sm->portControl) &&
344
!(sm->initialize || !sm->portEnabled))
345
SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
346
else switch (sm->SUPP_PAE_state) {
347
case SUPP_PAE_UNKNOWN:
349
case SUPP_PAE_LOGOFF:
351
SM_ENTER(SUPP_PAE, DISCONNECTED);
353
case SUPP_PAE_DISCONNECTED:
354
SM_ENTER(SUPP_PAE, CONNECTING);
356
case SUPP_PAE_CONNECTING:
357
if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
358
SM_ENTER(SUPP_PAE, CONNECTING);
359
else if (sm->startWhen == 0 &&
360
sm->startCount >= sm->maxStart &&
362
SM_ENTER(SUPP_PAE, AUTHENTICATED);
363
else if (sm->eapSuccess || sm->eapFail)
364
SM_ENTER(SUPP_PAE, AUTHENTICATING);
365
else if (sm->eapolEap)
366
SM_ENTER(SUPP_PAE, RESTART);
367
else if (sm->startWhen == 0 &&
368
sm->startCount >= sm->maxStart &&
370
SM_ENTER(SUPP_PAE, HELD);
372
case SUPP_PAE_AUTHENTICATING:
373
if (sm->eapSuccess && !sm->portValid &&
374
sm->conf.accept_802_1x_keys &&
375
sm->conf.required_keys == 0) {
376
wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
377
"plaintext connection; no EAPOL-Key frames "
379
sm->portValid = TRUE;
380
if (sm->ctx->eapol_done_cb)
381
sm->ctx->eapol_done_cb(sm->ctx->ctx);
383
if (sm->eapSuccess && sm->portValid)
384
SM_ENTER(SUPP_PAE, AUTHENTICATED);
385
else if (sm->eapFail || (sm->keyDone && !sm->portValid))
386
SM_ENTER(SUPP_PAE, HELD);
387
else if (sm->suppTimeout)
388
SM_ENTER(SUPP_PAE, CONNECTING);
391
if (sm->heldWhile == 0)
392
SM_ENTER(SUPP_PAE, CONNECTING);
393
else if (sm->eapolEap)
394
SM_ENTER(SUPP_PAE, RESTART);
396
case SUPP_PAE_AUTHENTICATED:
397
if (sm->eapolEap && sm->portValid)
398
SM_ENTER(SUPP_PAE, RESTART);
399
else if (!sm->portValid)
400
SM_ENTER(SUPP_PAE, DISCONNECTED);
402
case SUPP_PAE_RESTART:
404
SM_ENTER(SUPP_PAE, AUTHENTICATING);
406
case SUPP_PAE_S_FORCE_AUTH:
408
case SUPP_PAE_S_FORCE_UNAUTH:
414
SM_STATE(KEY_RX, NO_KEY_RECEIVE)
416
SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
420
SM_STATE(KEY_RX, KEY_RECEIVE)
422
SM_ENTRY(KEY_RX, KEY_RECEIVE);
423
eapol_sm_processKey(sm);
430
if (sm->initialize || !sm->portEnabled)
431
SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
432
switch (sm->KEY_RX_state) {
435
case KEY_RX_NO_KEY_RECEIVE:
437
SM_ENTER(KEY_RX, KEY_RECEIVE);
439
case KEY_RX_KEY_RECEIVE:
441
SM_ENTER(KEY_RX, KEY_RECEIVE);
447
SM_STATE(SUPP_BE, REQUEST)
449
SM_ENTRY(SUPP_BE, REQUEST);
452
eapol_sm_getSuppRsp(sm);
456
SM_STATE(SUPP_BE, RESPONSE)
458
SM_ENTRY(SUPP_BE, RESPONSE);
459
eapol_sm_txSuppRsp(sm);
464
SM_STATE(SUPP_BE, SUCCESS)
466
SM_ENTRY(SUPP_BE, SUCCESS);
468
sm->suppSuccess = TRUE;
470
if (eap_key_available(sm->eap)) {
471
/* New key received - clear IEEE 802.1X EAPOL-Key replay
473
sm->replay_counter_valid = FALSE;
478
SM_STATE(SUPP_BE, FAIL)
480
SM_ENTRY(SUPP_BE, FAIL);
485
SM_STATE(SUPP_BE, TIMEOUT)
487
SM_ENTRY(SUPP_BE, TIMEOUT);
488
sm->suppTimeout = TRUE;
492
SM_STATE(SUPP_BE, IDLE)
494
SM_ENTRY(SUPP_BE, IDLE);
495
sm->suppStart = FALSE;
496
sm->initial_req = TRUE;
500
SM_STATE(SUPP_BE, INITIALIZE)
502
SM_ENTRY(SUPP_BE, INITIALIZE);
503
eapol_sm_abortSupp(sm);
504
sm->suppAbort = FALSE;
508
SM_STATE(SUPP_BE, RECEIVE)
510
SM_ENTRY(SUPP_BE, RECEIVE);
511
sm->authWhile = sm->authPeriod;
512
sm->eapolEap = FALSE;
513
sm->eapNoResp = FALSE;
514
sm->initial_req = FALSE;
520
if (sm->initialize || sm->suppAbort)
521
SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
522
else switch (sm->SUPP_BE_state) {
523
case SUPP_BE_UNKNOWN:
525
case SUPP_BE_REQUEST:
527
* IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
528
* and SUCCESS based on eapFail and eapSuccess, respectively.
529
* However, IEEE Std 802.1X-2004 is also specifying that
530
* eapNoResp should be set in conjuction with eapSuccess and
531
* eapFail which would mean that more than one of the
532
* transitions here would be activated at the same time.
533
* Skipping RESPONSE and/or RECEIVE states in these cases can
534
* cause problems and the direct transitions to do not seem
535
* correct. Because of this, the conditions for these
536
* transitions are verified only after eapNoResp. They are
537
* unlikely to be used since eapNoResp should always be set if
538
* either of eapSuccess or eapFail is set.
540
if (sm->eapResp && sm->eapNoResp) {
541
wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
542
"eapResp and eapNoResp set?!");
545
SM_ENTER(SUPP_BE, RESPONSE);
546
else if (sm->eapNoResp)
547
SM_ENTER(SUPP_BE, RECEIVE);
548
else if (sm->eapFail)
549
SM_ENTER(SUPP_BE, FAIL);
550
else if (sm->eapSuccess)
551
SM_ENTER(SUPP_BE, SUCCESS);
553
case SUPP_BE_RESPONSE:
554
SM_ENTER(SUPP_BE, RECEIVE);
556
case SUPP_BE_SUCCESS:
557
SM_ENTER(SUPP_BE, IDLE);
560
SM_ENTER(SUPP_BE, IDLE);
562
case SUPP_BE_TIMEOUT:
563
SM_ENTER(SUPP_BE, IDLE);
566
if (sm->eapFail && sm->suppStart)
567
SM_ENTER(SUPP_BE, FAIL);
568
else if (sm->eapolEap && sm->suppStart)
569
SM_ENTER(SUPP_BE, REQUEST);
570
else if (sm->eapSuccess && sm->suppStart)
571
SM_ENTER(SUPP_BE, SUCCESS);
573
case SUPP_BE_INITIALIZE:
574
SM_ENTER(SUPP_BE, IDLE);
576
case SUPP_BE_RECEIVE:
578
SM_ENTER(SUPP_BE, REQUEST);
579
else if (sm->eapFail)
580
SM_ENTER(SUPP_BE, FAIL);
581
else if (sm->authWhile == 0)
582
SM_ENTER(SUPP_BE, TIMEOUT);
583
else if (sm->eapSuccess)
584
SM_ENTER(SUPP_BE, SUCCESS);
590
static void eapol_sm_txLogoff(struct eapol_sm *sm)
592
wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
593
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
594
IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
595
sm->dot1xSuppEapolLogoffFramesTx++;
596
sm->dot1xSuppEapolFramesTx++;
600
static void eapol_sm_txStart(struct eapol_sm *sm)
602
wpa_printf(MSG_DEBUG, "EAPOL: txStart");
603
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
604
IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
605
sm->dot1xSuppEapolStartFramesTx++;
606
sm->dot1xSuppEapolFramesTx++;
610
#define IEEE8021X_ENCR_KEY_LEN 32
611
#define IEEE8021X_SIGN_KEY_LEN 32
613
struct eap_key_data {
614
u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
615
u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
619
static void eapol_sm_processKey(struct eapol_sm *sm)
621
struct ieee802_1x_hdr *hdr;
622
struct ieee802_1x_eapol_key *key;
623
struct eap_key_data keydata;
624
u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
625
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
626
int key_len, res, sign_key_len, encr_key_len;
629
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
630
if (sm->last_rx_key == NULL)
633
if (!sm->conf.accept_802_1x_keys) {
634
wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
635
" even though this was not accepted - "
636
"ignoring this packet");
640
hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
641
key = (struct ieee802_1x_eapol_key *) (hdr + 1);
642
if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
643
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
646
rx_key_length = WPA_GET_BE16(key->key_length);
647
wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
648
"EAPOL-Key: type=%d key_length=%d key_index=0x%x",
649
hdr->version, hdr->type, be_to_host16(hdr->length),
650
key->type, rx_key_length, key->key_index);
652
eapol_sm_notify_lower_layer_success(sm);
653
sign_key_len = IEEE8021X_SIGN_KEY_LEN;
654
encr_key_len = IEEE8021X_ENCR_KEY_LEN;
655
res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
657
wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
658
"decrypting EAPOL-Key keys");
662
/* LEAP derives only 16 bytes of keying material. */
663
res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
665
wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
666
"master key for decrypting EAPOL-Key keys");
671
os_memcpy(keydata.sign_key, keydata.encr_key, 16);
673
wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
674
"data for decrypting EAPOL-Key keys (res=%d)", res);
678
/* The key replay_counter must increase when same master key */
679
if (sm->replay_counter_valid &&
680
os_memcmp(sm->last_replay_counter, key->replay_counter,
681
IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
682
wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
683
"not increase - ignoring key");
684
wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
685
sm->last_replay_counter,
686
IEEE8021X_REPLAY_COUNTER_LEN);
687
wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
688
key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
692
/* Verify key signature (HMAC-MD5) */
693
os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
694
os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
695
hmac_md5(keydata.sign_key, sign_key_len,
696
sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
698
if (os_memcmp(orig_key_sign, key->key_signature,
699
IEEE8021X_KEY_SIGN_LEN) != 0) {
700
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
702
os_memcpy(key->key_signature, orig_key_sign,
703
IEEE8021X_KEY_SIGN_LEN);
706
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
708
key_len = be_to_host16(hdr->length) - sizeof(*key);
709
if (key_len > 32 || rx_key_length > 32) {
710
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
711
key_len ? key_len : rx_key_length);
714
if (key_len == rx_key_length) {
715
os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
716
os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
718
os_memcpy(datakey, key + 1, key_len);
719
rc4(datakey, key_len, ekey,
720
IEEE8021X_KEY_IV_LEN + encr_key_len);
721
wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
723
} else if (key_len == 0) {
725
* IEEE 802.1X-2004 specifies that least significant Key Length
726
* octets from MS-MPPE-Send-Key are used as the key if the key
727
* data is not present. This seems to be meaning the beginning
728
* of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
729
* Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
730
* Anyway, taking the beginning of the keying material from EAP
731
* seems to interoperate with Authenticators.
733
key_len = rx_key_length;
734
os_memcpy(datakey, keydata.encr_key, key_len);
735
wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
736
"material data encryption key",
739
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
740
"(key_length=%d)", key_len, rx_key_length);
744
sm->replay_counter_valid = TRUE;
745
os_memcpy(sm->last_replay_counter, key->replay_counter,
746
IEEE8021X_REPLAY_COUNTER_LEN);
748
wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
750
key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
751
"unicast" : "broadcast",
752
key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
754
if (sm->ctx->set_wep_key &&
755
sm->ctx->set_wep_key(sm->ctx->ctx,
756
key->key_index & IEEE8021X_KEY_INDEX_FLAG,
757
key->key_index & IEEE8021X_KEY_INDEX_MASK,
758
datakey, key_len) < 0) {
759
wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
762
if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
763
sm->unicast_key_received = TRUE;
765
sm->broadcast_key_received = TRUE;
767
if ((sm->unicast_key_received ||
768
!(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
769
(sm->broadcast_key_received ||
770
!(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
772
wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
774
sm->portValid = TRUE;
775
if (sm->ctx->eapol_done_cb)
776
sm->ctx->eapol_done_cb(sm->ctx->ctx);
782
static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
784
wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
785
/* EAP layer processing; no special code is needed, since Supplicant
786
* Backend state machine is waiting for eapNoResp or eapResp to be set
787
* and these are only set in the EAP state machine when the processing
792
static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
797
wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
798
resp = eap_get_eapRespData(sm->eap, &resp_len);
800
wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
805
/* Send EAP-Packet from the EAP layer to the Authenticator */
806
sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
807
IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
809
/* eapRespData is not used anymore, so free it here */
813
sm->dot1xSuppEapolReqIdFramesRx++;
815
sm->dot1xSuppEapolReqFramesRx++;
816
sm->dot1xSuppEapolRespFramesTx++;
817
sm->dot1xSuppEapolFramesTx++;
821
static void eapol_sm_abortSupp(struct eapol_sm *sm)
823
/* release system resources that may have been allocated for the
824
* authentication session */
825
os_free(sm->last_rx_key);
826
sm->last_rx_key = NULL;
827
os_free(sm->eapReqData);
828
sm->eapReqData = NULL;
829
eap_sm_abort(sm->eap);
833
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
835
eapol_sm_step(timeout_ctx);
840
* eapol_sm_step - EAPOL state machine step function
841
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
843
* This function is called to notify the state machine about changed external
844
* variables. It will step through the EAPOL state machines in loop to process
845
* all triggered state changes.
847
void eapol_sm_step(struct eapol_sm *sm)
851
/* In theory, it should be ok to run this in loop until !changed.
852
* However, it is better to use a limit on number of iterations to
853
* allow events (e.g., SIGTERM) to stop the program cleanly if the
854
* state machine were to generate a busy loop. */
855
for (i = 0; i < 100; i++) {
857
SM_STEP_RUN(SUPP_PAE);
859
SM_STEP_RUN(SUPP_BE);
860
if (eap_peer_sm_step(sm->eap))
867
/* restart EAPOL state machine step from timeout call in order
868
* to allow other events to be processed. */
869
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
870
eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
873
if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
874
int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
875
sm->cb_status = EAPOL_CB_IN_PROGRESS;
876
sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
881
#ifdef CONFIG_CTRL_IFACE
882
static const char *eapol_supp_pae_state(int state)
885
case SUPP_PAE_LOGOFF:
887
case SUPP_PAE_DISCONNECTED:
888
return "DISCONNECTED";
889
case SUPP_PAE_CONNECTING:
891
case SUPP_PAE_AUTHENTICATING:
892
return "AUTHENTICATING";
895
case SUPP_PAE_AUTHENTICATED:
896
return "AUTHENTICATED";
897
case SUPP_PAE_RESTART:
905
static const char *eapol_supp_be_state(int state)
908
case SUPP_BE_REQUEST:
910
case SUPP_BE_RESPONSE:
912
case SUPP_BE_SUCCESS:
916
case SUPP_BE_TIMEOUT:
920
case SUPP_BE_INITIALIZE:
922
case SUPP_BE_RECEIVE:
930
static const char * eapol_port_status(PortStatus status)
932
if (status == Authorized)
935
return "Unauthorized";
937
#endif /* CONFIG_CTRL_IFACE */
940
#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
941
static const char * eapol_port_control(PortControl ctrl)
946
case ForceUnauthorized:
947
return "ForceUnauthorized";
948
case ForceAuthorized:
949
return "ForceAuthorized";
954
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
958
* eapol_sm_configure - Set EAPOL variables
959
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
960
* @heldPeriod: dot1xSuppHeldPeriod
961
* @authPeriod: dot1xSuppAuthPeriod
962
* @startPeriod: dot1xSuppStartPeriod
963
* @maxStart: dot1xSuppMaxStart
965
* Set configurable EAPOL state machine variables. Each variable can be set to
966
* the given value or ignored if set to -1 (to set only some of the variables).
968
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
969
int startPeriod, int maxStart)
974
sm->heldPeriod = heldPeriod;
976
sm->authPeriod = authPeriod;
977
if (startPeriod >= 0)
978
sm->startPeriod = startPeriod;
980
sm->maxStart = maxStart;
984
#ifdef CONFIG_CTRL_IFACE
986
* eapol_sm_get_status - Get EAPOL state machine status
987
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
988
* @buf: Buffer for status information
989
* @buflen: Maximum buffer length
990
* @verbose: Whether to include verbose status information
991
* Returns: Number of bytes written to buf.
993
* Query EAPOL state machine for status information. This function fills in a
994
* text area with current status information from the EAPOL state machine. If
995
* the buffer (buf) is not large enough, status information will be truncated
998
int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1005
len = os_snprintf(buf, buflen,
1006
"Supplicant PAE state=%s\n"
1007
"suppPortStatus=%s\n",
1008
eapol_supp_pae_state(sm->SUPP_PAE_state),
1009
eapol_port_status(sm->suppPortStatus));
1010
if (len < 0 || (size_t) len >= buflen)
1014
ret = os_snprintf(buf + len, buflen - len,
1020
"Supplicant Backend state=%s\n",
1025
eapol_port_control(sm->portControl),
1026
eapol_supp_be_state(sm->SUPP_BE_state));
1027
if (ret < 0 || (size_t) ret >= buflen - len)
1032
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1039
* eapol_sm_get_mib - Get EAPOL state machine MIBs
1040
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1041
* @buf: Buffer for MIB information
1042
* @buflen: Maximum buffer length
1043
* Returns: Number of bytes written to buf.
1045
* Query EAPOL state machine for MIB information. This function fills in a
1046
* text area with current MIB information from the EAPOL state machine. If
1047
* the buffer (buf) is not large enough, MIB information will be truncated to
1050
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1057
ret = os_snprintf(buf, buflen,
1058
"dot1xSuppPaeState=%d\n"
1059
"dot1xSuppHeldPeriod=%u\n"
1060
"dot1xSuppAuthPeriod=%u\n"
1061
"dot1xSuppStartPeriod=%u\n"
1062
"dot1xSuppMaxStart=%u\n"
1063
"dot1xSuppSuppControlledPortStatus=%s\n"
1064
"dot1xSuppBackendPaeState=%d\n",
1070
sm->suppPortStatus == Authorized ?
1071
"Authorized" : "Unauthorized",
1074
if (ret < 0 || (size_t) ret >= buflen)
1078
ret = os_snprintf(buf + len, buflen - len,
1079
"dot1xSuppEapolFramesRx=%u\n"
1080
"dot1xSuppEapolFramesTx=%u\n"
1081
"dot1xSuppEapolStartFramesTx=%u\n"
1082
"dot1xSuppEapolLogoffFramesTx=%u\n"
1083
"dot1xSuppEapolRespFramesTx=%u\n"
1084
"dot1xSuppEapolReqIdFramesRx=%u\n"
1085
"dot1xSuppEapolReqFramesRx=%u\n"
1086
"dot1xSuppInvalidEapolFramesRx=%u\n"
1087
"dot1xSuppEapLengthErrorFramesRx=%u\n"
1088
"dot1xSuppLastEapolFrameVersion=%u\n"
1089
"dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1090
sm->dot1xSuppEapolFramesRx,
1091
sm->dot1xSuppEapolFramesTx,
1092
sm->dot1xSuppEapolStartFramesTx,
1093
sm->dot1xSuppEapolLogoffFramesTx,
1094
sm->dot1xSuppEapolRespFramesTx,
1095
sm->dot1xSuppEapolReqIdFramesRx,
1096
sm->dot1xSuppEapolReqFramesRx,
1097
sm->dot1xSuppInvalidEapolFramesRx,
1098
sm->dot1xSuppEapLengthErrorFramesRx,
1099
sm->dot1xSuppLastEapolFrameVersion,
1100
MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1102
if (ret < 0 || (size_t) ret >= buflen - len)
1108
#endif /* CONFIG_CTRL_IFACE */
1112
* eapol_sm_rx_eapol - Process received EAPOL frames
1113
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1114
* @src: Source MAC address of the EAPOL packet
1115
* @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1116
* @len: Length of the EAPOL frame
1117
* Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1120
int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1123
const struct ieee802_1x_hdr *hdr;
1124
const struct ieee802_1x_eapol_key *key;
1131
sm->dot1xSuppEapolFramesRx++;
1132
if (len < sizeof(*hdr)) {
1133
sm->dot1xSuppInvalidEapolFramesRx++;
1136
hdr = (const struct ieee802_1x_hdr *) buf;
1137
sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1138
os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1139
if (hdr->version < EAPOL_VERSION) {
1140
/* TODO: backwards compatibility */
1142
plen = be_to_host16(hdr->length);
1143
if (plen > len - sizeof(*hdr)) {
1144
sm->dot1xSuppEapLengthErrorFramesRx++;
1147
data_len = plen + sizeof(*hdr);
1149
switch (hdr->type) {
1150
case IEEE802_1X_TYPE_EAP_PACKET:
1151
if (sm->cached_pmk) {
1152
/* Trying to use PMKSA caching, but Authenticator did
1153
* not seem to have a matching entry. Need to restart
1154
* EAPOL state machines.
1156
eapol_sm_abort_cached(sm);
1158
os_free(sm->eapReqData);
1159
sm->eapReqDataLen = plen;
1160
sm->eapReqData = os_malloc(sm->eapReqDataLen);
1161
if (sm->eapReqData) {
1162
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1164
os_memcpy(sm->eapReqData, (u8 *) (hdr + 1),
1166
sm->eapolEap = TRUE;
1170
case IEEE802_1X_TYPE_EAPOL_KEY:
1171
if (plen < sizeof(*key)) {
1172
wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1176
key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1177
if (key->type == EAPOL_KEY_TYPE_WPA ||
1178
key->type == EAPOL_KEY_TYPE_RSN) {
1179
/* WPA Supplicant takes care of this frame. */
1180
wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1181
"frame in EAPOL state machines");
1185
if (key->type != EAPOL_KEY_TYPE_RC4) {
1186
wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1187
"EAPOL-Key type %d", key->type);
1190
os_free(sm->last_rx_key);
1191
sm->last_rx_key = os_malloc(data_len);
1192
if (sm->last_rx_key) {
1193
wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1195
os_memcpy(sm->last_rx_key, buf, data_len);
1196
sm->last_rx_key_len = data_len;
1202
wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1204
sm->dot1xSuppInvalidEapolFramesRx++;
1213
* eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1214
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1216
* Notify EAPOL station machine about transmitted EAPOL packet from an external
1217
* component, e.g., WPA. This will update the statistics.
1219
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1222
sm->dot1xSuppEapolFramesTx++;
1227
* eapol_sm_notify_portEnabled - Notification about portEnabled change
1228
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1229
* @enabled: New portEnabled value
1231
* Notify EAPOL station machine about new portEnabled value.
1233
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1237
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1238
"portEnabled=%d", enabled);
1239
sm->portEnabled = enabled;
1245
* eapol_sm_notify_portValid - Notification about portValid change
1246
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1247
* @valid: New portValid value
1249
* Notify EAPOL station machine about new portValid value.
1251
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1255
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1256
"portValid=%d", valid);
1257
sm->portValid = valid;
1263
* eapol_sm_notify_eap_success - Notification of external EAP success trigger
1264
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1265
* @success: %TRUE = set success, %FALSE = clear success
1267
* Notify EAPOL station machine that external event has forced EAP state to
1268
* success (success = %TRUE). This can be cleared by setting success = %FALSE.
1270
* This function is called to update EAP state when WPA-PSK key handshake has
1271
* been completed successfully since WPA-PSK does not use EAP state machine.
1273
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1277
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1278
"EAP success=%d", success);
1279
sm->eapSuccess = success;
1280
sm->altAccept = success;
1282
eap_notify_success(sm->eap);
1288
* eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1289
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1290
* @fail: %TRUE = set failure, %FALSE = clear failure
1292
* Notify EAPOL station machine that external event has forced EAP state to
1293
* failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1295
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1299
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1300
"EAP fail=%d", fail);
1302
sm->altReject = fail;
1308
* eapol_sm_notify_config - Notification of EAPOL configuration change
1309
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1310
* @config: Pointer to current network configuration
1311
* @conf: Pointer to EAPOL configuration data
1313
* Notify EAPOL station machine that configuration has changed. config will be
1314
* stored as a backpointer to network configuration. This can be %NULL to clear
1315
* the stored pointed. conf will be copied to local EAPOL/EAP configuration
1316
* data. If conf is %NULL, this part of the configuration change will be
1319
void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
1320
const struct eapol_config *conf)
1325
sm->config = config;
1330
sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1331
sm->conf.required_keys = conf->required_keys;
1332
sm->conf.fast_reauth = conf->fast_reauth;
1334
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1335
eap_set_workaround(sm->eap, conf->workaround);
1336
eap_set_force_disabled(sm->eap, conf->eap_disabled);
1342
* eapol_sm_get_key - Get master session key (MSK) from EAP
1343
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1344
* @key: Pointer for key buffer
1345
* @len: Number of bytes to copy to key
1346
* Returns: 0 on success (len of key available), maximum available key len
1347
* (>0) if key is available but it is shorter than len, or -1 on failure.
1349
* Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1350
* is available only after a successful authentication.
1352
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1357
if (sm == NULL || !eap_key_available(sm->eap))
1359
eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1360
if (eap_key == NULL)
1364
os_memcpy(key, eap_key, len);
1370
* eapol_sm_notify_logoff - Notification of logon/logoff commands
1371
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1372
* @logoff: Whether command was logoff
1374
* Notify EAPOL state machines that user requested logon/logoff.
1376
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1379
sm->userLogoff = logoff;
1386
* eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1387
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1389
* Notify EAPOL state machines that PMKSA caching was successful. This is used
1390
* to move EAPOL and EAP state machines into authenticated/successful state.
1392
void eapol_sm_notify_cached(struct eapol_sm *sm)
1396
sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1397
sm->suppPortStatus = Authorized;
1398
eap_notify_success(sm->eap);
1403
* eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1404
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1405
* @attempt: Whether PMKSA caching is tried
1407
* Notify EAPOL state machines whether PMKSA caching is used.
1409
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1414
wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1415
sm->cached_pmk = TRUE;
1417
wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1418
sm->cached_pmk = FALSE;
1423
static void eapol_sm_abort_cached(struct eapol_sm *sm)
1425
wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1426
"doing full EAP authentication");
1429
sm->cached_pmk = FALSE;
1430
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1431
sm->suppPortStatus = Unauthorized;
1433
/* Make sure we do not start sending EAPOL-Start frames first, but
1434
* instead move to RESTART state to start EAPOL authentication. */
1437
if (sm->ctx->aborted_cached)
1438
sm->ctx->aborted_cached(sm->ctx->ctx);
1443
* eapol_sm_register_scard_ctx - Notification of smart card context
1444
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1445
* @ctx: Context data for smart card operations
1447
* Notify EAPOL state machines of context data for smart card operations. This
1448
* context data will be used as a parameter for scard_*() functions.
1450
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1453
sm->ctx->scard_ctx = ctx;
1454
eap_register_scard_ctx(sm->eap, ctx);
1460
* eapol_sm_notify_portControl - Notification of portControl changes
1461
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1462
* @portControl: New value for portControl variable
1464
* Notify EAPOL state machines that portControl variable has changed.
1466
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1470
wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1471
"portControl=%s", eapol_port_control(portControl));
1472
sm->portControl = portControl;
1478
* eapol_sm_notify_ctrl_attached - Notification of attached monitor
1479
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1481
* Notify EAPOL state machines that a monitor was attached to the control
1482
* interface to trigger re-sending of pending requests for user input.
1484
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1488
eap_sm_notify_ctrl_attached(sm->eap);
1493
* eapol_sm_notify_ctrl_response - Notification of received user input
1494
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1496
* Notify EAPOL state machines that a control response, i.e., user
1497
* input, was received in order to trigger retrying of a pending EAP request.
1499
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1503
if (sm->eapReqData && !sm->eapReq) {
1504
wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1505
"input) notification - retrying pending EAP "
1507
sm->eapolEap = TRUE;
1515
* eapol_sm_request_reauth - Request reauthentication
1516
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1518
* This function can be used to request EAPOL reauthentication, e.g., when the
1519
* current PMKSA entry is nearing expiration.
1521
void eapol_sm_request_reauth(struct eapol_sm *sm)
1523
if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1525
eapol_sm_txStart(sm);
1530
* eapol_sm_notify_lower_layer_success - Notification of lower layer success
1531
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1533
* Notify EAPOL (and EAP) state machines that a lower layer has detected a
1534
* successful authentication. This is used to recover from dropped EAP-Success
1537
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
1541
eap_notify_lower_layer_success(sm->eap);
1546
* eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1547
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1549
void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1552
eap_invalidate_cached_session(sm->eap);
1556
static struct wpa_ssid * eapol_sm_get_config(void *ctx)
1558
struct eapol_sm *sm = ctx;
1559
return sm ? sm->config : NULL;
1563
static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
1565
struct eapol_sm *sm = ctx;
1566
if (sm == NULL || sm->eapReqData == NULL) {
1571
*len = sm->eapReqDataLen;
1572
return sm->eapReqData;
1576
static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1578
struct eapol_sm *sm = ctx;
1582
case EAPOL_eapSuccess:
1583
return sm->eapSuccess;
1584
case EAPOL_eapRestart:
1585
return sm->eapRestart;
1590
case EAPOL_eapNoResp:
1591
return sm->eapNoResp;
1594
case EAPOL_portEnabled:
1595
return sm->portEnabled;
1596
case EAPOL_altAccept:
1597
return sm->altAccept;
1598
case EAPOL_altReject:
1599
return sm->altReject;
1605
static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1608
struct eapol_sm *sm = ctx;
1612
case EAPOL_eapSuccess:
1613
sm->eapSuccess = value;
1615
case EAPOL_eapRestart:
1616
sm->eapRestart = value;
1619
sm->eapFail = value;
1622
sm->eapResp = value;
1624
case EAPOL_eapNoResp:
1625
sm->eapNoResp = value;
1630
case EAPOL_portEnabled:
1631
sm->portEnabled = value;
1633
case EAPOL_altAccept:
1634
sm->altAccept = value;
1636
case EAPOL_altReject:
1637
sm->altReject = value;
1643
static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1645
struct eapol_sm *sm = ctx;
1649
case EAPOL_idleWhile:
1650
return sm->idleWhile;
1656
static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1659
struct eapol_sm *sm = ctx;
1663
case EAPOL_idleWhile:
1664
sm->idleWhile = value;
1670
static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1672
struct eapol_sm *sm = ctx;
1673
if (sm && sm->ctx && sm->ctx->set_config_blob)
1674
sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1678
static const struct wpa_config_blob *
1679
eapol_sm_get_config_blob(void *ctx, const char *name)
1681
struct eapol_sm *sm = ctx;
1682
if (sm && sm->ctx && sm->ctx->get_config_blob)
1683
return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1689
static void eapol_sm_notify_pending(void *ctx)
1691
struct eapol_sm *sm = ctx;
1694
if (sm->eapReqData && !sm->eapReq) {
1695
wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1696
"state machine - retrying pending EAP Request");
1697
sm->eapolEap = TRUE;
1704
static struct eapol_callbacks eapol_cb =
1706
eapol_sm_get_config,
1711
eapol_sm_get_eapReqData,
1712
eapol_sm_set_config_blob,
1713
eapol_sm_get_config_blob,
1714
eapol_sm_notify_pending
1719
* eapol_sm_init - Initialize EAPOL state machine
1720
* @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1721
* and EAPOL state machine will free it in eapol_sm_deinit()
1722
* Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1724
* Allocate and initialize an EAPOL state machine.
1726
struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1728
struct eapol_sm *sm;
1729
struct eap_config conf;
1730
sm = os_zalloc(sizeof(*sm));
1735
sm->portControl = Auto;
1737
/* Supplicant PAE state machine */
1738
sm->heldPeriod = 60;
1739
sm->startPeriod = 30;
1742
/* Supplicant Backend state machine */
1743
sm->authPeriod = 30;
1745
os_memset(&conf, 0, sizeof(conf));
1746
conf.opensc_engine_path = ctx->opensc_engine_path;
1747
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1748
conf.pkcs11_module_path = ctx->pkcs11_module_path;
1750
sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1751
if (sm->eap == NULL) {
1756
/* Initialize EAPOL state machines */
1757
sm->initialize = TRUE;
1759
sm->initialize = FALSE;
1762
eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1769
* eapol_sm_deinit - Deinitialize EAPOL state machine
1770
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1772
* Deinitialize and free EAPOL state machine.
1774
void eapol_sm_deinit(struct eapol_sm *sm)
1778
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1779
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1780
eap_peer_sm_deinit(sm->eap);
1781
os_free(sm->last_rx_key);
1782
os_free(sm->eapReqData);