1 /* 2 * EAPOL supplicant state machines 3 * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "common.h" 18 #include "eapol_supp_sm.h" 19 #include "eap_peer/eap.h" 20 #include "eloop.h" 21 #include "eapol_common.h" 22 #include "md5.h" 23 #include "rc4.h" 24 #include "state_machine.h" 25 #include "wpabuf.h" 26 27 #define STATE_MACHINE_DATA struct eapol_sm 28 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL" 29 30 31 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */ 32 33 /** 34 * struct eapol_sm - Internal data for EAPOL state machines 35 */ 36 struct eapol_sm { 37 /* Timers */ 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; 43 44 /* Global variables */ 45 Boolean eapFail; 46 Boolean eapolEap; 47 Boolean eapSuccess; 48 Boolean initialize; 49 Boolean keyDone; 50 Boolean keyRun; 51 PortControl portControl; 52 Boolean portEnabled; 53 PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */ 54 Boolean portValid; 55 Boolean suppAbort; 56 Boolean suppFail; 57 Boolean suppStart; 58 Boolean suppSuccess; 59 Boolean suppTimeout; 60 61 /* Supplicant PAE state machine */ 62 enum { 63 SUPP_PAE_UNKNOWN = 0, 64 SUPP_PAE_DISCONNECTED = 1, 65 SUPP_PAE_LOGOFF = 2, 66 SUPP_PAE_CONNECTING = 3, 67 SUPP_PAE_AUTHENTICATING = 4, 68 SUPP_PAE_AUTHENTICATED = 5, 69 /* unused(6) */ 70 SUPP_PAE_HELD = 7, 71 SUPP_PAE_RESTART = 8, 72 SUPP_PAE_S_FORCE_AUTH = 9, 73 SUPP_PAE_S_FORCE_UNAUTH = 10 74 } SUPP_PAE_state; /* dot1xSuppPaeState */ 75 /* Variables */ 76 Boolean userLogoff; 77 Boolean logoffSent; 78 unsigned int startCount; 79 Boolean eapRestart; 80 PortControl sPortMode; 81 /* Constants */ 82 unsigned int heldPeriod; /* dot1xSuppHeldPeriod */ 83 unsigned int startPeriod; /* dot1xSuppStartPeriod */ 84 unsigned int maxStart; /* dot1xSuppMaxStart */ 85 86 /* Key Receive state machine */ 87 enum { 88 KEY_RX_UNKNOWN = 0, 89 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE 90 } KEY_RX_state; 91 /* Variables */ 92 Boolean rxKey; 93 94 /* Supplicant Backend state machine */ 95 enum { 96 SUPP_BE_UNKNOWN = 0, 97 SUPP_BE_INITIALIZE = 1, 98 SUPP_BE_IDLE = 2, 99 SUPP_BE_REQUEST = 3, 100 SUPP_BE_RECEIVE = 4, 101 SUPP_BE_RESPONSE = 5, 102 SUPP_BE_FAIL = 6, 103 SUPP_BE_TIMEOUT = 7, 104 SUPP_BE_SUCCESS = 8 105 } SUPP_BE_state; /* dot1xSuppBackendPaeState */ 106 /* Variables */ 107 Boolean eapNoResp; 108 Boolean eapReq; 109 Boolean eapResp; 110 /* Constants */ 111 unsigned int authPeriod; /* dot1xSuppAuthPeriod */ 112 113 /* Statistics */ 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]; 125 126 /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */ 127 Boolean changed; 128 struct eap_sm *eap; 129 struct eap_peer_config *config; 130 Boolean initial_req; 131 u8 *last_rx_key; 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 } 141 cb_status; 142 Boolean cached_pmk; 143 144 Boolean unicast_key_received, broadcast_key_received; 145 }; 146 147 148 #define IEEE8021X_REPLAY_COUNTER_LEN 8 149 #define IEEE8021X_KEY_SIGN_LEN 16 150 #define IEEE8021X_KEY_IV_LEN 16 151 152 #define IEEE8021X_KEY_INDEX_FLAG 0x80 153 #define IEEE8021X_KEY_INDEX_MASK 0x03 154 155 #ifdef _MSC_VER 156 #pragma pack(push, 1) 157 #endif /* _MSC_VER */ 158 159 struct ieee802_1x_eapol_key { 160 u8 type; 161 /* Note: key_length is unaligned */ 162 u8 key_length[2]; 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 172 * the key */ 173 u8 key_signature[IEEE8021X_KEY_SIGN_LEN]; 174 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 */ 181 } STRUCT_PACKED; 182 183 #ifdef _MSC_VER 184 #pragma pack(pop) 185 #endif /* _MSC_VER */ 186 187 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); 196 197 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) 201 { 202 struct eapol_sm *sm = timeout_ctx; 203 204 if (sm->authWhile > 0) { 205 sm->authWhile--; 206 if (sm->authWhile == 0) 207 wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0"); 208 } 209 if (sm->heldWhile > 0) { 210 sm->heldWhile--; 211 if (sm->heldWhile == 0) 212 wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0"); 213 } 214 if (sm->startWhen > 0) { 215 sm->startWhen--; 216 if (sm->startWhen == 0) 217 wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0"); 218 } 219 if (sm->idleWhile > 0) { 220 sm->idleWhile--; 221 if (sm->idleWhile == 0) 222 wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0"); 223 } 224 225 if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) { 226 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, 227 sm); 228 } else { 229 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick"); 230 sm->timer_tick_enabled = 0; 231 } 232 eapol_sm_step(sm); 233 } 234 235 236 static void eapol_enable_timer_tick(struct eapol_sm *sm) 237 { 238 if (sm->timer_tick_enabled) 239 return; 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); 244 } 245 246 247 SM_STATE(SUPP_PAE, LOGOFF) 248 { 249 SM_ENTRY(SUPP_PAE, LOGOFF); 250 eapol_sm_txLogoff(sm); 251 sm->logoffSent = TRUE; 252 sm->suppPortStatus = Unauthorized; 253 } 254 255 256 SM_STATE(SUPP_PAE, DISCONNECTED) 257 { 258 SM_ENTRY(SUPP_PAE, DISCONNECTED); 259 sm->sPortMode = Auto; 260 sm->startCount = 0; 261 sm->logoffSent = FALSE; 262 sm->suppPortStatus = Unauthorized; 263 sm->suppAbort = TRUE; 264 265 sm->unicast_key_received = FALSE; 266 sm->broadcast_key_received = FALSE; 267 } 268 269 270 SM_STATE(SUPP_PAE, CONNECTING) 271 { 272 int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING; 273 SM_ENTRY(SUPP_PAE, CONNECTING); 274 if (send_start) { 275 sm->startWhen = sm->startPeriod; 276 sm->startCount++; 277 } else { 278 /* 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. 284 */ 285 sm->startWhen = 3; 286 } 287 eapol_enable_timer_tick(sm); 288 sm->eapolEap = FALSE; 289 if (send_start) 290 eapol_sm_txStart(sm); 291 } 292 293 294 SM_STATE(SUPP_PAE, AUTHENTICATING) 295 { 296 SM_ENTRY(SUPP_PAE, AUTHENTICATING); 297 sm->startCount = 0; 298 sm->suppSuccess = FALSE; 299 sm->suppFail = FALSE; 300 sm->suppTimeout = FALSE; 301 sm->keyRun = FALSE; 302 sm->keyDone = FALSE; 303 sm->suppStart = TRUE; 304 } 305 306 307 SM_STATE(SUPP_PAE, HELD) 308 { 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; 314 } 315 316 317 SM_STATE(SUPP_PAE, AUTHENTICATED) 318 { 319 SM_ENTRY(SUPP_PAE, AUTHENTICATED); 320 sm->suppPortStatus = Authorized; 321 sm->cb_status = EAPOL_CB_SUCCESS; 322 } 323 324 325 SM_STATE(SUPP_PAE, RESTART) 326 { 327 SM_ENTRY(SUPP_PAE, RESTART); 328 sm->eapRestart = TRUE; 329 } 330 331 332 SM_STATE(SUPP_PAE, S_FORCE_AUTH) 333 { 334 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); 335 sm->suppPortStatus = Authorized; 336 sm->sPortMode = ForceAuthorized; 337 } 338 339 340 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) 341 { 342 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); 343 sm->suppPortStatus = Unauthorized; 344 sm->sPortMode = ForceUnauthorized; 345 eapol_sm_txLogoff(sm); 346 } 347 348 349 SM_STEP(SUPP_PAE) 350 { 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: 368 break; 369 case SUPP_PAE_LOGOFF: 370 if (!sm->userLogoff) 371 SM_ENTER(SUPP_PAE, DISCONNECTED); 372 break; 373 case SUPP_PAE_DISCONNECTED: 374 SM_ENTER(SUPP_PAE, CONNECTING); 375 break; 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 && 381 sm->portValid) 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 && 389 !sm->portValid) 390 SM_ENTER(SUPP_PAE, HELD); 391 break; 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 " 398 "required"); 399 sm->portValid = TRUE; 400 if (sm->ctx->eapol_done_cb) 401 sm->ctx->eapol_done_cb(sm->ctx->ctx); 402 } 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); 409 break; 410 case SUPP_PAE_HELD: 411 if (sm->heldWhile == 0) 412 SM_ENTER(SUPP_PAE, CONNECTING); 413 else if (sm->eapolEap) 414 SM_ENTER(SUPP_PAE, RESTART); 415 break; 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); 421 break; 422 case SUPP_PAE_RESTART: 423 if (!sm->eapRestart) 424 SM_ENTER(SUPP_PAE, AUTHENTICATING); 425 break; 426 case SUPP_PAE_S_FORCE_AUTH: 427 break; 428 case SUPP_PAE_S_FORCE_UNAUTH: 429 break; 430 } 431 } 432 433 434 SM_STATE(KEY_RX, NO_KEY_RECEIVE) 435 { 436 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE); 437 } 438 439 440 SM_STATE(KEY_RX, KEY_RECEIVE) 441 { 442 SM_ENTRY(KEY_RX, KEY_RECEIVE); 443 eapol_sm_processKey(sm); 444 sm->rxKey = FALSE; 445 } 446 447 448 SM_STEP(KEY_RX) 449 { 450 if (sm->initialize || !sm->portEnabled) 451 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); 452 switch (sm->KEY_RX_state) { 453 case KEY_RX_UNKNOWN: 454 break; 455 case KEY_RX_NO_KEY_RECEIVE: 456 if (sm->rxKey) 457 SM_ENTER(KEY_RX, KEY_RECEIVE); 458 break; 459 case KEY_RX_KEY_RECEIVE: 460 if (sm->rxKey) 461 SM_ENTER(KEY_RX, KEY_RECEIVE); 462 break; 463 } 464 } 465 466 467 SM_STATE(SUPP_BE, REQUEST) 468 { 469 SM_ENTRY(SUPP_BE, REQUEST); 470 sm->authWhile = 0; 471 sm->eapReq = TRUE; 472 eapol_sm_getSuppRsp(sm); 473 } 474 475 476 SM_STATE(SUPP_BE, RESPONSE) 477 { 478 SM_ENTRY(SUPP_BE, RESPONSE); 479 eapol_sm_txSuppRsp(sm); 480 sm->eapResp = FALSE; 481 } 482 483 484 SM_STATE(SUPP_BE, SUCCESS) 485 { 486 SM_ENTRY(SUPP_BE, SUCCESS); 487 sm->keyRun = TRUE; 488 sm->suppSuccess = TRUE; 489 490 if (eap_key_available(sm->eap)) { 491 /* New key received - clear IEEE 802.1X EAPOL-Key replay 492 * counter */ 493 sm->replay_counter_valid = FALSE; 494 } 495 } 496 497 498 SM_STATE(SUPP_BE, FAIL) 499 { 500 SM_ENTRY(SUPP_BE, FAIL); 501 sm->suppFail = TRUE; 502 } 503 504 505 SM_STATE(SUPP_BE, TIMEOUT) 506 { 507 SM_ENTRY(SUPP_BE, TIMEOUT); 508 sm->suppTimeout = TRUE; 509 } 510 511 512 SM_STATE(SUPP_BE, IDLE) 513 { 514 SM_ENTRY(SUPP_BE, IDLE); 515 sm->suppStart = FALSE; 516 sm->initial_req = TRUE; 517 } 518 519 520 SM_STATE(SUPP_BE, INITIALIZE) 521 { 522 SM_ENTRY(SUPP_BE, INITIALIZE); 523 eapol_sm_abortSupp(sm); 524 sm->suppAbort = FALSE; 525 } 526 527 528 SM_STATE(SUPP_BE, RECEIVE) 529 { 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; 536 } 537 538 539 SM_STEP(SUPP_BE) 540 { 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: 545 break; 546 case SUPP_BE_REQUEST: 547 /* 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. 560 */ 561 if (sm->eapResp && sm->eapNoResp) { 562 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both " 563 "eapResp and eapNoResp set?!"); 564 } 565 if (sm->eapResp) 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); 573 break; 574 case SUPP_BE_RESPONSE: 575 SM_ENTER(SUPP_BE, RECEIVE); 576 break; 577 case SUPP_BE_SUCCESS: 578 SM_ENTER(SUPP_BE, IDLE); 579 break; 580 case SUPP_BE_FAIL: 581 SM_ENTER(SUPP_BE, IDLE); 582 break; 583 case SUPP_BE_TIMEOUT: 584 SM_ENTER(SUPP_BE, IDLE); 585 break; 586 case 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); 593 break; 594 case SUPP_BE_INITIALIZE: 595 SM_ENTER(SUPP_BE, IDLE); 596 break; 597 case SUPP_BE_RECEIVE: 598 if (sm->eapolEap) 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); 606 break; 607 } 608 } 609 610 611 static void eapol_sm_txLogoff(struct eapol_sm *sm) 612 { 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++; 618 } 619 620 621 static void eapol_sm_txStart(struct eapol_sm *sm) 622 { 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++; 628 } 629 630 631 #define IEEE8021X_ENCR_KEY_LEN 32 632 #define IEEE8021X_SIGN_KEY_LEN 32 633 634 struct eap_key_data { 635 u8 encr_key[IEEE8021X_ENCR_KEY_LEN]; 636 u8 sign_key[IEEE8021X_SIGN_KEY_LEN]; 637 }; 638 639 640 static void eapol_sm_processKey(struct eapol_sm *sm) 641 { 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; 648 u16 rx_key_length; 649 650 wpa_printf(MSG_DEBUG, "EAPOL: processKey"); 651 if (sm->last_rx_key == NULL) 652 return; 653 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"); 658 return; 659 } 660 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"); 665 return; 666 } 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); 672 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)); 677 if (res < 0) { 678 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " 679 "decrypting EAPOL-Key keys"); 680 return; 681 } 682 if (res == 16) { 683 /* LEAP derives only 16 bytes of keying material. */ 684 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); 685 if (res) { 686 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " 687 "master key for decrypting EAPOL-Key keys"); 688 return; 689 } 690 sign_key_len = 16; 691 encr_key_len = 16; 692 os_memcpy(keydata.sign_key, keydata.encr_key, 16); 693 } else if (res) { 694 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " 695 "data for decrypting EAPOL-Key keys (res=%d)", res); 696 return; 697 } 698 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); 710 return; 711 } 712 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), 718 key->key_signature); 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 " 722 "EAPOL-Key packet"); 723 os_memcpy(key->key_signature, orig_key_sign, 724 IEEE8021X_KEY_SIGN_LEN); 725 return; 726 } 727 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); 728 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); 733 return; 734 } 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, 738 encr_key_len); 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", 743 datakey, key_len); 744 } else if (key_len == 0) { 745 /* 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. 753 */ 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", 758 datakey, key_len); 759 } else { 760 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " 761 "(key_length=%d)", key_len, rx_key_length); 762 return; 763 } 764 765 sm->replay_counter_valid = TRUE; 766 os_memcpy(sm->last_replay_counter, key->replay_counter, 767 IEEE8021X_REPLAY_COUNTER_LEN); 768 769 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " 770 "len %d", 771 key->key_index & IEEE8021X_KEY_INDEX_FLAG ? 772 "unicast" : "broadcast", 773 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); 774 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 " 781 " driver."); 782 } else { 783 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) 784 sm->unicast_key_received = TRUE; 785 else 786 sm->broadcast_key_received = TRUE; 787 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))) 792 { 793 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " 794 "frames received"); 795 sm->portValid = TRUE; 796 if (sm->ctx->eapol_done_cb) 797 sm->ctx->eapol_done_cb(sm->ctx->ctx); 798 } 799 } 800 } 801 802 803 static void eapol_sm_getSuppRsp(struct eapol_sm *sm) 804 { 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 809 * has finished. */ 810 } 811 812 813 static void eapol_sm_txSuppRsp(struct eapol_sm *sm) 814 { 815 struct wpabuf *resp; 816 817 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); 818 resp = eap_get_eapRespData(sm->eap); 819 if (resp == NULL) { 820 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data " 821 "not available"); 822 return; 823 } 824 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), 828 wpabuf_len(resp)); 829 830 /* eapRespData is not used anymore, so free it here */ 831 wpabuf_free(resp); 832 833 if (sm->initial_req) 834 sm->dot1xSuppEapolReqIdFramesRx++; 835 else 836 sm->dot1xSuppEapolReqFramesRx++; 837 sm->dot1xSuppEapolRespFramesTx++; 838 sm->dot1xSuppEapolFramesTx++; 839 } 840 841 842 static void eapol_sm_abortSupp(struct eapol_sm *sm) 843 { 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); 851 } 852 853 854 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) 855 { 856 eapol_sm_step(timeout_ctx); 857 } 858 859 860 /** 861 * eapol_sm_step - EAPOL state machine step function 862 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 863 * 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. 867 */ 868 void eapol_sm_step(struct eapol_sm *sm) 869 { 870 int i; 871 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++) { 877 sm->changed = FALSE; 878 SM_STEP_RUN(SUPP_PAE); 879 SM_STEP_RUN(KEY_RX); 880 SM_STEP_RUN(SUPP_BE); 881 if (eap_peer_sm_step(sm->eap)) 882 sm->changed = TRUE; 883 if (!sm->changed) 884 break; 885 } 886 887 if (sm->changed) { 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); 892 } 893 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); 898 } 899 } 900 901 902 #ifdef CONFIG_CTRL_IFACE 903 static const char *eapol_supp_pae_state(int state) 904 { 905 switch (state) { 906 case SUPP_PAE_LOGOFF: 907 return "LOGOFF"; 908 case SUPP_PAE_DISCONNECTED: 909 return "DISCONNECTED"; 910 case SUPP_PAE_CONNECTING: 911 return "CONNECTING"; 912 case SUPP_PAE_AUTHENTICATING: 913 return "AUTHENTICATING"; 914 case SUPP_PAE_HELD: 915 return "HELD"; 916 case SUPP_PAE_AUTHENTICATED: 917 return "AUTHENTICATED"; 918 case SUPP_PAE_RESTART: 919 return "RESTART"; 920 default: 921 return "UNKNOWN"; 922 } 923 } 924 925 926 static const char *eapol_supp_be_state(int state) 927 { 928 switch (state) { 929 case SUPP_BE_REQUEST: 930 return "REQUEST"; 931 case SUPP_BE_RESPONSE: 932 return "RESPONSE"; 933 case SUPP_BE_SUCCESS: 934 return "SUCCESS"; 935 case SUPP_BE_FAIL: 936 return "FAIL"; 937 case SUPP_BE_TIMEOUT: 938 return "TIMEOUT"; 939 case SUPP_BE_IDLE: 940 return "IDLE"; 941 case SUPP_BE_INITIALIZE: 942 return "INITIALIZE"; 943 case SUPP_BE_RECEIVE: 944 return "RECEIVE"; 945 default: 946 return "UNKNOWN"; 947 } 948 } 949 950 951 static const char * eapol_port_status(PortStatus status) 952 { 953 if (status == Authorized) 954 return "Authorized"; 955 else 956 return "Unauthorized"; 957 } 958 #endif /* CONFIG_CTRL_IFACE */ 959 960 961 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 962 static const char * eapol_port_control(PortControl ctrl) 963 { 964 switch (ctrl) { 965 case Auto: 966 return "Auto"; 967 case ForceUnauthorized: 968 return "ForceUnauthorized"; 969 case ForceAuthorized: 970 return "ForceAuthorized"; 971 default: 972 return "Unknown"; 973 } 974 } 975 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 976 977 978 /** 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 985 * 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). 988 */ 989 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, 990 int startPeriod, int maxStart) 991 { 992 if (sm == NULL) 993 return; 994 if (heldPeriod >= 0) 995 sm->heldPeriod = heldPeriod; 996 if (authPeriod >= 0) 997 sm->authPeriod = authPeriod; 998 if (startPeriod >= 0) 999 sm->startPeriod = startPeriod; 1000 if (maxStart >= 0) 1001 sm->maxStart = maxStart; 1002 } 1003 1004 1005 #ifdef CONFIG_CTRL_IFACE 1006 /** 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. 1013 * 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. 1018 */ 1019 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, 1020 int verbose) 1021 { 1022 int len, ret; 1023 if (sm == NULL) 1024 return 0; 1025 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) 1032 return 0; 1033 1034 if (verbose) { 1035 ret = os_snprintf(buf + len, buflen - len, 1036 "heldPeriod=%u\n" 1037 "authPeriod=%u\n" 1038 "startPeriod=%u\n" 1039 "maxStart=%u\n" 1040 "portControl=%s\n" 1041 "Supplicant Backend state=%s\n", 1042 sm->heldPeriod, 1043 sm->authPeriod, 1044 sm->startPeriod, 1045 sm->maxStart, 1046 eapol_port_control(sm->portControl), 1047 eapol_supp_be_state(sm->SUPP_BE_state)); 1048 if (ret < 0 || (size_t) ret >= buflen - len) 1049 return len; 1050 len += ret; 1051 } 1052 1053 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose); 1054 1055 return len; 1056 } 1057 1058 1059 /** 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. 1065 * 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 1069 * fit the buffer. 1070 */ 1071 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) 1072 { 1073 size_t len; 1074 int ret; 1075 1076 if (sm == NULL) 1077 return 0; 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", 1086 sm->SUPP_PAE_state, 1087 sm->heldPeriod, 1088 sm->authPeriod, 1089 sm->startPeriod, 1090 sm->maxStart, 1091 sm->suppPortStatus == Authorized ? 1092 "Authorized" : "Unauthorized", 1093 sm->SUPP_BE_state); 1094 1095 if (ret < 0 || (size_t) ret >= buflen) 1096 return 0; 1097 len = ret; 1098 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)); 1122 1123 if (ret < 0 || (size_t) ret >= buflen - len) 1124 return len; 1125 len += ret; 1126 1127 return len; 1128 } 1129 #endif /* CONFIG_CTRL_IFACE */ 1130 1131 1132 /** 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, 1139 * -1 failure 1140 */ 1141 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, 1142 size_t len) 1143 { 1144 const struct ieee802_1x_hdr *hdr; 1145 const struct ieee802_1x_eapol_key *key; 1146 int data_len; 1147 int res = 1; 1148 size_t plen; 1149 1150 if (sm == NULL) 1151 return 0; 1152 sm->dot1xSuppEapolFramesRx++; 1153 if (len < sizeof(*hdr)) { 1154 sm->dot1xSuppInvalidEapolFramesRx++; 1155 return 0; 1156 } 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 */ 1162 } 1163 plen = be_to_host16(hdr->length); 1164 if (plen > len - sizeof(*hdr)) { 1165 sm->dot1xSuppEapLengthErrorFramesRx++; 1166 return 0; 1167 } 1168 #ifdef CONFIG_WPS 1169 if (sm->conf.workaround && 1170 plen < len - sizeof(*hdr) && 1171 hdr->type == IEEE802_1X_TYPE_EAP_PACKET && 1172 len - sizeof(*hdr) > sizeof(struct eap_hdr)) { 1173 const struct eap_hdr *ehdr = 1174 (const struct eap_hdr *) (hdr + 1); 1175 u16 elen; 1176 1177 elen = be_to_host16(ehdr->length); 1178 if (elen > plen && elen <= len - sizeof(*hdr)) { 1179 /* 1180 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS 1181 * packets with too short EAPOL header length field 1182 * (14 octets). This is fixed in firmware Ver.1.49. 1183 * As a workaround, fix the EAPOL header based on the 1184 * correct length in the EAP packet. 1185 */ 1186 wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL " 1187 "payload length based on EAP header: " 1188 "%d -> %d", (int) plen, elen); 1189 plen = elen; 1190 } 1191 } 1192 #endif /* CONFIG_WPS */ 1193 data_len = plen + sizeof(*hdr); 1194 1195 switch (hdr->type) { 1196 case IEEE802_1X_TYPE_EAP_PACKET: 1197 if (sm->cached_pmk) { 1198 /* Trying to use PMKSA caching, but Authenticator did 1199 * not seem to have a matching entry. Need to restart 1200 * EAPOL state machines. 1201 */ 1202 eapol_sm_abort_cached(sm); 1203 } 1204 wpabuf_free(sm->eapReqData); 1205 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen); 1206 if (sm->eapReqData) { 1207 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet " 1208 "frame"); 1209 sm->eapolEap = TRUE; 1210 eapol_sm_step(sm); 1211 } 1212 break; 1213 case IEEE802_1X_TYPE_EAPOL_KEY: 1214 if (plen < sizeof(*key)) { 1215 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key " 1216 "frame received"); 1217 break; 1218 } 1219 key = (const struct ieee802_1x_eapol_key *) (hdr + 1); 1220 if (key->type == EAPOL_KEY_TYPE_WPA || 1221 key->type == EAPOL_KEY_TYPE_RSN) { 1222 /* WPA Supplicant takes care of this frame. */ 1223 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key " 1224 "frame in EAPOL state machines"); 1225 res = 0; 1226 break; 1227 } 1228 if (key->type != EAPOL_KEY_TYPE_RC4) { 1229 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown " 1230 "EAPOL-Key type %d", key->type); 1231 break; 1232 } 1233 os_free(sm->last_rx_key); 1234 sm->last_rx_key = os_malloc(data_len); 1235 if (sm->last_rx_key) { 1236 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key " 1237 "frame"); 1238 os_memcpy(sm->last_rx_key, buf, data_len); 1239 sm->last_rx_key_len = data_len; 1240 sm->rxKey = TRUE; 1241 eapol_sm_step(sm); 1242 } 1243 break; 1244 default: 1245 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d", 1246 hdr->type); 1247 sm->dot1xSuppInvalidEapolFramesRx++; 1248 break; 1249 } 1250 1251 return res; 1252 } 1253 1254 1255 /** 1256 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet 1257 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1258 * 1259 * Notify EAPOL state machine about transmitted EAPOL packet from an external 1260 * component, e.g., WPA. This will update the statistics. 1261 */ 1262 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) 1263 { 1264 if (sm) 1265 sm->dot1xSuppEapolFramesTx++; 1266 } 1267 1268 1269 /** 1270 * eapol_sm_notify_portEnabled - Notification about portEnabled change 1271 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1272 * @enabled: New portEnabled value 1273 * 1274 * Notify EAPOL state machine about new portEnabled value. 1275 */ 1276 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) 1277 { 1278 if (sm == NULL) 1279 return; 1280 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1281 "portEnabled=%d", enabled); 1282 sm->portEnabled = enabled; 1283 eapol_sm_step(sm); 1284 } 1285 1286 1287 /** 1288 * eapol_sm_notify_portValid - Notification about portValid change 1289 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1290 * @valid: New portValid value 1291 * 1292 * Notify EAPOL state machine about new portValid value. 1293 */ 1294 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid) 1295 { 1296 if (sm == NULL) 1297 return; 1298 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1299 "portValid=%d", valid); 1300 sm->portValid = valid; 1301 eapol_sm_step(sm); 1302 } 1303 1304 1305 /** 1306 * eapol_sm_notify_eap_success - Notification of external EAP success trigger 1307 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1308 * @success: %TRUE = set success, %FALSE = clear success 1309 * 1310 * Notify the EAPOL state machine that external event has forced EAP state to 1311 * success (success = %TRUE). This can be cleared by setting success = %FALSE. 1312 * 1313 * This function is called to update EAP state when WPA-PSK key handshake has 1314 * been completed successfully since WPA-PSK does not use EAP state machine. 1315 */ 1316 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success) 1317 { 1318 if (sm == NULL) 1319 return; 1320 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1321 "EAP success=%d", success); 1322 sm->eapSuccess = success; 1323 sm->altAccept = success; 1324 if (success) 1325 eap_notify_success(sm->eap); 1326 eapol_sm_step(sm); 1327 } 1328 1329 1330 /** 1331 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger 1332 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1333 * @fail: %TRUE = set failure, %FALSE = clear failure 1334 * 1335 * Notify EAPOL state machine that external event has forced EAP state to 1336 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE. 1337 */ 1338 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) 1339 { 1340 if (sm == NULL) 1341 return; 1342 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1343 "EAP fail=%d", fail); 1344 sm->eapFail = fail; 1345 sm->altReject = fail; 1346 eapol_sm_step(sm); 1347 } 1348 1349 1350 /** 1351 * eapol_sm_notify_config - Notification of EAPOL configuration change 1352 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1353 * @config: Pointer to current network EAP configuration 1354 * @conf: Pointer to EAPOL configuration data 1355 * 1356 * Notify EAPOL state machine that configuration has changed. config will be 1357 * stored as a backpointer to network configuration. This can be %NULL to clear 1358 * the stored pointed. conf will be copied to local EAPOL/EAP configuration 1359 * data. If conf is %NULL, this part of the configuration change will be 1360 * skipped. 1361 */ 1362 void eapol_sm_notify_config(struct eapol_sm *sm, 1363 struct eap_peer_config *config, 1364 const struct eapol_config *conf) 1365 { 1366 if (sm == NULL) 1367 return; 1368 1369 sm->config = config; 1370 1371 if (conf == NULL) 1372 return; 1373 1374 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys; 1375 sm->conf.required_keys = conf->required_keys; 1376 sm->conf.fast_reauth = conf->fast_reauth; 1377 sm->conf.workaround = conf->workaround; 1378 if (sm->eap) { 1379 eap_set_fast_reauth(sm->eap, conf->fast_reauth); 1380 eap_set_workaround(sm->eap, conf->workaround); 1381 eap_set_force_disabled(sm->eap, conf->eap_disabled); 1382 } 1383 } 1384 1385 1386 /** 1387 * eapol_sm_get_key - Get master session key (MSK) from EAP 1388 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1389 * @key: Pointer for key buffer 1390 * @len: Number of bytes to copy to key 1391 * Returns: 0 on success (len of key available), maximum available key len 1392 * (>0) if key is available but it is shorter than len, or -1 on failure. 1393 * 1394 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key 1395 * is available only after a successful authentication. 1396 */ 1397 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) 1398 { 1399 const u8 *eap_key; 1400 size_t eap_len; 1401 1402 if (sm == NULL || !eap_key_available(sm->eap)) { 1403 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); 1404 return -1; 1405 } 1406 eap_key = eap_get_eapKeyData(sm->eap, &eap_len); 1407 if (eap_key == NULL) { 1408 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData"); 1409 return -1; 1410 } 1411 if (len > eap_len) { 1412 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not " 1413 "available (len=%lu)", 1414 (unsigned long) len, (unsigned long) eap_len); 1415 return eap_len; 1416 } 1417 os_memcpy(key, eap_key, len); 1418 wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)", 1419 (unsigned long) len); 1420 return 0; 1421 } 1422 1423 1424 /** 1425 * eapol_sm_notify_logoff - Notification of logon/logoff commands 1426 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1427 * @logoff: Whether command was logoff 1428 * 1429 * Notify EAPOL state machines that user requested logon/logoff. 1430 */ 1431 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) 1432 { 1433 if (sm) { 1434 sm->userLogoff = logoff; 1435 eapol_sm_step(sm); 1436 } 1437 } 1438 1439 1440 /** 1441 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching 1442 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1443 * 1444 * Notify EAPOL state machines that PMKSA caching was successful. This is used 1445 * to move EAPOL and EAP state machines into authenticated/successful state. 1446 */ 1447 void eapol_sm_notify_cached(struct eapol_sm *sm) 1448 { 1449 if (sm == NULL) 1450 return; 1451 wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL"); 1452 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED; 1453 sm->suppPortStatus = Authorized; 1454 sm->portValid = TRUE; 1455 eap_notify_success(sm->eap); 1456 eapol_sm_step(sm); 1457 } 1458 1459 1460 /** 1461 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching 1462 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1463 * @attempt: Whether PMKSA caching is tried 1464 * 1465 * Notify EAPOL state machines whether PMKSA caching is used. 1466 */ 1467 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt) 1468 { 1469 if (sm == NULL) 1470 return; 1471 if (attempt) { 1472 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA"); 1473 sm->cached_pmk = TRUE; 1474 } else { 1475 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA"); 1476 sm->cached_pmk = FALSE; 1477 } 1478 } 1479 1480 1481 static void eapol_sm_abort_cached(struct eapol_sm *sm) 1482 { 1483 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, " 1484 "doing full EAP authentication"); 1485 if (sm == NULL) 1486 return; 1487 sm->cached_pmk = FALSE; 1488 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; 1489 sm->suppPortStatus = Unauthorized; 1490 1491 /* Make sure we do not start sending EAPOL-Start frames first, but 1492 * instead move to RESTART state to start EAPOL authentication. */ 1493 sm->startWhen = 3; 1494 eapol_enable_timer_tick(sm); 1495 1496 if (sm->ctx->aborted_cached) 1497 sm->ctx->aborted_cached(sm->ctx->ctx); 1498 } 1499 1500 1501 /** 1502 * eapol_sm_register_scard_ctx - Notification of smart card context 1503 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1504 * @ctx: Context data for smart card operations 1505 * 1506 * Notify EAPOL state machines of context data for smart card operations. This 1507 * context data will be used as a parameter for scard_*() functions. 1508 */ 1509 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx) 1510 { 1511 if (sm) { 1512 sm->ctx->scard_ctx = ctx; 1513 eap_register_scard_ctx(sm->eap, ctx); 1514 } 1515 } 1516 1517 1518 /** 1519 * eapol_sm_notify_portControl - Notification of portControl changes 1520 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1521 * @portControl: New value for portControl variable 1522 * 1523 * Notify EAPOL state machines that portControl variable has changed. 1524 */ 1525 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl) 1526 { 1527 if (sm == NULL) 1528 return; 1529 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1530 "portControl=%s", eapol_port_control(portControl)); 1531 sm->portControl = portControl; 1532 eapol_sm_step(sm); 1533 } 1534 1535 1536 /** 1537 * eapol_sm_notify_ctrl_attached - Notification of attached monitor 1538 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1539 * 1540 * Notify EAPOL state machines that a monitor was attached to the control 1541 * interface to trigger re-sending of pending requests for user input. 1542 */ 1543 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) 1544 { 1545 if (sm == NULL) 1546 return; 1547 eap_sm_notify_ctrl_attached(sm->eap); 1548 } 1549 1550 1551 /** 1552 * eapol_sm_notify_ctrl_response - Notification of received user input 1553 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1554 * 1555 * Notify EAPOL state machines that a control response, i.e., user 1556 * input, was received in order to trigger retrying of a pending EAP request. 1557 */ 1558 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) 1559 { 1560 if (sm == NULL) 1561 return; 1562 if (sm->eapReqData && !sm->eapReq) { 1563 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user " 1564 "input) notification - retrying pending EAP " 1565 "Request"); 1566 sm->eapolEap = TRUE; 1567 sm->eapReq = TRUE; 1568 eapol_sm_step(sm); 1569 } 1570 } 1571 1572 1573 /** 1574 * eapol_sm_request_reauth - Request reauthentication 1575 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1576 * 1577 * This function can be used to request EAPOL reauthentication, e.g., when the 1578 * current PMKSA entry is nearing expiration. 1579 */ 1580 void eapol_sm_request_reauth(struct eapol_sm *sm) 1581 { 1582 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED) 1583 return; 1584 eapol_sm_txStart(sm); 1585 } 1586 1587 1588 /** 1589 * eapol_sm_notify_lower_layer_success - Notification of lower layer success 1590 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1591 * @in_eapol_sm: Whether the caller is already running inside EAPOL state 1592 * machine loop (eapol_sm_step()) 1593 * 1594 * Notify EAPOL (and EAP) state machines that a lower layer has detected a 1595 * successful authentication. This is used to recover from dropped EAP-Success 1596 * messages. 1597 */ 1598 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm) 1599 { 1600 if (sm == NULL) 1601 return; 1602 eap_notify_lower_layer_success(sm->eap); 1603 if (!in_eapol_sm) 1604 eapol_sm_step(sm); 1605 } 1606 1607 1608 /** 1609 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid 1610 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1611 */ 1612 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) 1613 { 1614 if (sm) 1615 eap_invalidate_cached_session(sm->eap); 1616 } 1617 1618 1619 static struct eap_peer_config * eapol_sm_get_config(void *ctx) 1620 { 1621 struct eapol_sm *sm = ctx; 1622 return sm ? sm->config : NULL; 1623 } 1624 1625 1626 static struct wpabuf * eapol_sm_get_eapReqData(void *ctx) 1627 { 1628 struct eapol_sm *sm = ctx; 1629 if (sm == NULL || sm->eapReqData == NULL) 1630 return NULL; 1631 1632 return sm->eapReqData; 1633 } 1634 1635 1636 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable) 1637 { 1638 struct eapol_sm *sm = ctx; 1639 if (sm == NULL) 1640 return FALSE; 1641 switch (variable) { 1642 case EAPOL_eapSuccess: 1643 return sm->eapSuccess; 1644 case EAPOL_eapRestart: 1645 return sm->eapRestart; 1646 case EAPOL_eapFail: 1647 return sm->eapFail; 1648 case EAPOL_eapResp: 1649 return sm->eapResp; 1650 case EAPOL_eapNoResp: 1651 return sm->eapNoResp; 1652 case EAPOL_eapReq: 1653 return sm->eapReq; 1654 case EAPOL_portEnabled: 1655 return sm->portEnabled; 1656 case EAPOL_altAccept: 1657 return sm->altAccept; 1658 case EAPOL_altReject: 1659 return sm->altReject; 1660 } 1661 return FALSE; 1662 } 1663 1664 1665 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable, 1666 Boolean value) 1667 { 1668 struct eapol_sm *sm = ctx; 1669 if (sm == NULL) 1670 return; 1671 switch (variable) { 1672 case EAPOL_eapSuccess: 1673 sm->eapSuccess = value; 1674 break; 1675 case EAPOL_eapRestart: 1676 sm->eapRestart = value; 1677 break; 1678 case EAPOL_eapFail: 1679 sm->eapFail = value; 1680 break; 1681 case EAPOL_eapResp: 1682 sm->eapResp = value; 1683 break; 1684 case EAPOL_eapNoResp: 1685 sm->eapNoResp = value; 1686 break; 1687 case EAPOL_eapReq: 1688 sm->eapReq = value; 1689 break; 1690 case EAPOL_portEnabled: 1691 sm->portEnabled = value; 1692 break; 1693 case EAPOL_altAccept: 1694 sm->altAccept = value; 1695 break; 1696 case EAPOL_altReject: 1697 sm->altReject = value; 1698 break; 1699 } 1700 } 1701 1702 1703 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable) 1704 { 1705 struct eapol_sm *sm = ctx; 1706 if (sm == NULL) 1707 return 0; 1708 switch (variable) { 1709 case EAPOL_idleWhile: 1710 return sm->idleWhile; 1711 } 1712 return 0; 1713 } 1714 1715 1716 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable, 1717 unsigned int value) 1718 { 1719 struct eapol_sm *sm = ctx; 1720 if (sm == NULL) 1721 return; 1722 switch (variable) { 1723 case EAPOL_idleWhile: 1724 sm->idleWhile = value; 1725 eapol_enable_timer_tick(sm); 1726 break; 1727 } 1728 } 1729 1730 1731 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob) 1732 { 1733 #ifndef CONFIG_NO_CONFIG_BLOBS 1734 struct eapol_sm *sm = ctx; 1735 if (sm && sm->ctx && sm->ctx->set_config_blob) 1736 sm->ctx->set_config_blob(sm->ctx->ctx, blob); 1737 #endif /* CONFIG_NO_CONFIG_BLOBS */ 1738 } 1739 1740 1741 static const struct wpa_config_blob * 1742 eapol_sm_get_config_blob(void *ctx, const char *name) 1743 { 1744 #ifndef CONFIG_NO_CONFIG_BLOBS 1745 struct eapol_sm *sm = ctx; 1746 if (sm && sm->ctx && sm->ctx->get_config_blob) 1747 return sm->ctx->get_config_blob(sm->ctx->ctx, name); 1748 else 1749 return NULL; 1750 #else /* CONFIG_NO_CONFIG_BLOBS */ 1751 return NULL; 1752 #endif /* CONFIG_NO_CONFIG_BLOBS */ 1753 } 1754 1755 1756 static void eapol_sm_notify_pending(void *ctx) 1757 { 1758 struct eapol_sm *sm = ctx; 1759 if (sm == NULL) 1760 return; 1761 if (sm->eapReqData && !sm->eapReq) { 1762 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP " 1763 "state machine - retrying pending EAP Request"); 1764 sm->eapolEap = TRUE; 1765 sm->eapReq = TRUE; 1766 eapol_sm_step(sm); 1767 } 1768 } 1769 1770 1771 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 1772 static void eapol_sm_eap_param_needed(void *ctx, const char *field, 1773 const char *txt) 1774 { 1775 struct eapol_sm *sm = ctx; 1776 wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed"); 1777 if (sm->ctx->eap_param_needed) 1778 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt); 1779 } 1780 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 1781 #define eapol_sm_eap_param_needed NULL 1782 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 1783 1784 1785 static struct eapol_callbacks eapol_cb = 1786 { 1787 eapol_sm_get_config, 1788 eapol_sm_get_bool, 1789 eapol_sm_set_bool, 1790 eapol_sm_get_int, 1791 eapol_sm_set_int, 1792 eapol_sm_get_eapReqData, 1793 eapol_sm_set_config_blob, 1794 eapol_sm_get_config_blob, 1795 eapol_sm_notify_pending, 1796 eapol_sm_eap_param_needed 1797 }; 1798 1799 1800 /** 1801 * eapol_sm_init - Initialize EAPOL state machine 1802 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer 1803 * and EAPOL state machine will free it in eapol_sm_deinit() 1804 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure 1805 * 1806 * Allocate and initialize an EAPOL state machine. 1807 */ 1808 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) 1809 { 1810 struct eapol_sm *sm; 1811 struct eap_config conf; 1812 sm = os_zalloc(sizeof(*sm)); 1813 if (sm == NULL) 1814 return NULL; 1815 sm->ctx = ctx; 1816 1817 sm->portControl = Auto; 1818 1819 /* Supplicant PAE state machine */ 1820 sm->heldPeriod = 60; 1821 sm->startPeriod = 30; 1822 sm->maxStart = 3; 1823 1824 /* Supplicant Backend state machine */ 1825 sm->authPeriod = 30; 1826 1827 os_memset(&conf, 0, sizeof(conf)); 1828 #ifdef EAP_TLS_OPENSSL 1829 conf.opensc_engine_path = ctx->opensc_engine_path; 1830 conf.pkcs11_engine_path = ctx->pkcs11_engine_path; 1831 conf.pkcs11_module_path = ctx->pkcs11_module_path; 1832 #endif /* EAP_TLS_OPENSSL */ 1833 conf.wps = ctx->wps; 1834 1835 sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); 1836 if (sm->eap == NULL) { 1837 os_free(sm); 1838 return NULL; 1839 } 1840 1841 /* Initialize EAPOL state machines */ 1842 sm->initialize = TRUE; 1843 eapol_sm_step(sm); 1844 sm->initialize = FALSE; 1845 eapol_sm_step(sm); 1846 1847 sm->timer_tick_enabled = 1; 1848 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); 1849 1850 return sm; 1851 } 1852 1853 1854 /** 1855 * eapol_sm_deinit - Deinitialize EAPOL state machine 1856 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1857 * 1858 * Deinitialize and free EAPOL state machine. 1859 */ 1860 void eapol_sm_deinit(struct eapol_sm *sm) 1861 { 1862 if (sm == NULL) 1863 return; 1864 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); 1865 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); 1866 eap_peer_sm_deinit(sm->eap); 1867 os_free(sm->last_rx_key); 1868 wpabuf_free(sm->eapReqData); 1869 os_free(sm->ctx); 1870 os_free(sm); 1871 } 1872