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 "crypto/md5.h" 23#include "crypto/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 */ 36struct 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 159struct 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 188static void eapol_sm_txLogoff(struct eapol_sm *sm); 189static void eapol_sm_txStart(struct eapol_sm *sm); 190static void eapol_sm_processKey(struct eapol_sm *sm); 191static void eapol_sm_getSuppRsp(struct eapol_sm *sm); 192static void eapol_sm_txSuppRsp(struct eapol_sm *sm); 193static void eapol_sm_abortSupp(struct eapol_sm *sm); 194static void eapol_sm_abort_cached(struct eapol_sm *sm); 195static 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 */ 200static 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 236static 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 247SM_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 256SM_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 270SM_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#ifdef CONFIG_WPS 286 /* Reduce latency on starting WPS negotiation. */ 287 sm->startWhen = 1; 288#else /* CONFIG_WPS */ 289 sm->startWhen = 3; 290#endif /* CONFIG_WPS */ 291 } 292 eapol_enable_timer_tick(sm); 293 sm->eapolEap = FALSE; 294 if (send_start) 295 eapol_sm_txStart(sm); 296} 297 298 299SM_STATE(SUPP_PAE, AUTHENTICATING) 300{ 301 SM_ENTRY(SUPP_PAE, AUTHENTICATING); 302 sm->startCount = 0; 303 sm->suppSuccess = FALSE; 304 sm->suppFail = FALSE; 305 sm->suppTimeout = FALSE; 306 sm->keyRun = FALSE; 307 sm->keyDone = FALSE; 308 sm->suppStart = TRUE; 309} 310 311 312SM_STATE(SUPP_PAE, HELD) 313{ 314 SM_ENTRY(SUPP_PAE, HELD); 315 sm->heldWhile = sm->heldPeriod; 316 eapol_enable_timer_tick(sm); 317 sm->suppPortStatus = Unauthorized; 318 sm->cb_status = EAPOL_CB_FAILURE; 319} 320 321 322SM_STATE(SUPP_PAE, AUTHENTICATED) 323{ 324 SM_ENTRY(SUPP_PAE, AUTHENTICATED); 325 sm->suppPortStatus = Authorized; 326 sm->cb_status = EAPOL_CB_SUCCESS; 327} 328 329 330SM_STATE(SUPP_PAE, RESTART) 331{ 332 SM_ENTRY(SUPP_PAE, RESTART); 333 sm->eapRestart = TRUE; 334} 335 336 337SM_STATE(SUPP_PAE, S_FORCE_AUTH) 338{ 339 SM_ENTRY(SUPP_PAE, S_FORCE_AUTH); 340 sm->suppPortStatus = Authorized; 341 sm->sPortMode = ForceAuthorized; 342} 343 344 345SM_STATE(SUPP_PAE, S_FORCE_UNAUTH) 346{ 347 SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH); 348 sm->suppPortStatus = Unauthorized; 349 sm->sPortMode = ForceUnauthorized; 350 eapol_sm_txLogoff(sm); 351} 352 353 354SM_STEP(SUPP_PAE) 355{ 356 if ((sm->userLogoff && !sm->logoffSent) && 357 !(sm->initialize || !sm->portEnabled)) 358 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF); 359 else if (((sm->portControl == Auto) && 360 (sm->sPortMode != sm->portControl)) || 361 sm->initialize || !sm->portEnabled) 362 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED); 363 else if ((sm->portControl == ForceAuthorized) && 364 (sm->sPortMode != sm->portControl) && 365 !(sm->initialize || !sm->portEnabled)) 366 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH); 367 else if ((sm->portControl == ForceUnauthorized) && 368 (sm->sPortMode != sm->portControl) && 369 !(sm->initialize || !sm->portEnabled)) 370 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH); 371 else switch (sm->SUPP_PAE_state) { 372 case SUPP_PAE_UNKNOWN: 373 break; 374 case SUPP_PAE_LOGOFF: 375 if (!sm->userLogoff) 376 SM_ENTER(SUPP_PAE, DISCONNECTED); 377 break; 378 case SUPP_PAE_DISCONNECTED: 379 SM_ENTER(SUPP_PAE, CONNECTING); 380 break; 381 case SUPP_PAE_CONNECTING: 382 if (sm->startWhen == 0 && sm->startCount < sm->maxStart) 383 SM_ENTER(SUPP_PAE, CONNECTING); 384 else if (sm->startWhen == 0 && 385 sm->startCount >= sm->maxStart && 386 sm->portValid) 387 SM_ENTER(SUPP_PAE, AUTHENTICATED); 388 else if (sm->eapSuccess || sm->eapFail) 389 SM_ENTER(SUPP_PAE, AUTHENTICATING); 390 else if (sm->eapolEap) 391 SM_ENTER(SUPP_PAE, RESTART); 392 else if (sm->startWhen == 0 && 393 sm->startCount >= sm->maxStart && 394 !sm->portValid) 395 SM_ENTER(SUPP_PAE, HELD); 396 break; 397 case SUPP_PAE_AUTHENTICATING: 398 if (sm->eapSuccess && !sm->portValid && 399 sm->conf.accept_802_1x_keys && 400 sm->conf.required_keys == 0) { 401 wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for " 402 "plaintext connection; no EAPOL-Key frames " 403 "required"); 404 sm->portValid = TRUE; 405 if (sm->ctx->eapol_done_cb) 406 sm->ctx->eapol_done_cb(sm->ctx->ctx); 407 } 408 if (sm->eapSuccess && sm->portValid) 409 SM_ENTER(SUPP_PAE, AUTHENTICATED); 410 else if (sm->eapFail || (sm->keyDone && !sm->portValid)) 411 SM_ENTER(SUPP_PAE, HELD); 412 else if (sm->suppTimeout) 413 SM_ENTER(SUPP_PAE, CONNECTING); 414 break; 415 case SUPP_PAE_HELD: 416 if (sm->heldWhile == 0) 417 SM_ENTER(SUPP_PAE, CONNECTING); 418 else if (sm->eapolEap) 419 SM_ENTER(SUPP_PAE, RESTART); 420 break; 421 case SUPP_PAE_AUTHENTICATED: 422 if (sm->eapolEap && sm->portValid) 423 SM_ENTER(SUPP_PAE, RESTART); 424 else if (!sm->portValid) 425 SM_ENTER(SUPP_PAE, DISCONNECTED); 426 break; 427 case SUPP_PAE_RESTART: 428 if (!sm->eapRestart) 429 SM_ENTER(SUPP_PAE, AUTHENTICATING); 430 break; 431 case SUPP_PAE_S_FORCE_AUTH: 432 break; 433 case SUPP_PAE_S_FORCE_UNAUTH: 434 break; 435 } 436} 437 438 439SM_STATE(KEY_RX, NO_KEY_RECEIVE) 440{ 441 SM_ENTRY(KEY_RX, NO_KEY_RECEIVE); 442} 443 444 445SM_STATE(KEY_RX, KEY_RECEIVE) 446{ 447 SM_ENTRY(KEY_RX, KEY_RECEIVE); 448 eapol_sm_processKey(sm); 449 sm->rxKey = FALSE; 450} 451 452 453SM_STEP(KEY_RX) 454{ 455 if (sm->initialize || !sm->portEnabled) 456 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE); 457 switch (sm->KEY_RX_state) { 458 case KEY_RX_UNKNOWN: 459 break; 460 case KEY_RX_NO_KEY_RECEIVE: 461 if (sm->rxKey) 462 SM_ENTER(KEY_RX, KEY_RECEIVE); 463 break; 464 case KEY_RX_KEY_RECEIVE: 465 if (sm->rxKey) 466 SM_ENTER(KEY_RX, KEY_RECEIVE); 467 break; 468 } 469} 470 471 472SM_STATE(SUPP_BE, REQUEST) 473{ 474 SM_ENTRY(SUPP_BE, REQUEST); 475 sm->authWhile = 0; 476 sm->eapReq = TRUE; 477 eapol_sm_getSuppRsp(sm); 478} 479 480 481SM_STATE(SUPP_BE, RESPONSE) 482{ 483 SM_ENTRY(SUPP_BE, RESPONSE); 484 eapol_sm_txSuppRsp(sm); 485 sm->eapResp = FALSE; 486} 487 488 489SM_STATE(SUPP_BE, SUCCESS) 490{ 491 SM_ENTRY(SUPP_BE, SUCCESS); 492 sm->keyRun = TRUE; 493 sm->suppSuccess = TRUE; 494 495 if (eap_key_available(sm->eap)) { 496 /* New key received - clear IEEE 802.1X EAPOL-Key replay 497 * counter */ 498 sm->replay_counter_valid = FALSE; 499 } 500} 501 502 503SM_STATE(SUPP_BE, FAIL) 504{ 505 SM_ENTRY(SUPP_BE, FAIL); 506 sm->suppFail = TRUE; 507} 508 509 510SM_STATE(SUPP_BE, TIMEOUT) 511{ 512 SM_ENTRY(SUPP_BE, TIMEOUT); 513 sm->suppTimeout = TRUE; 514} 515 516 517SM_STATE(SUPP_BE, IDLE) 518{ 519 SM_ENTRY(SUPP_BE, IDLE); 520 sm->suppStart = FALSE; 521 sm->initial_req = TRUE; 522} 523 524 525SM_STATE(SUPP_BE, INITIALIZE) 526{ 527 SM_ENTRY(SUPP_BE, INITIALIZE); 528 eapol_sm_abortSupp(sm); 529 sm->suppAbort = FALSE; 530} 531 532 533SM_STATE(SUPP_BE, RECEIVE) 534{ 535 SM_ENTRY(SUPP_BE, RECEIVE); 536 sm->authWhile = sm->authPeriod; 537 eapol_enable_timer_tick(sm); 538 sm->eapolEap = FALSE; 539 sm->eapNoResp = FALSE; 540 sm->initial_req = FALSE; 541} 542 543 544SM_STEP(SUPP_BE) 545{ 546 if (sm->initialize || sm->suppAbort) 547 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE); 548 else switch (sm->SUPP_BE_state) { 549 case SUPP_BE_UNKNOWN: 550 break; 551 case SUPP_BE_REQUEST: 552 /* 553 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL 554 * and SUCCESS based on eapFail and eapSuccess, respectively. 555 * However, IEEE Std 802.1X-2004 is also specifying that 556 * eapNoResp should be set in conjuction with eapSuccess and 557 * eapFail which would mean that more than one of the 558 * transitions here would be activated at the same time. 559 * Skipping RESPONSE and/or RECEIVE states in these cases can 560 * cause problems and the direct transitions to do not seem 561 * correct. Because of this, the conditions for these 562 * transitions are verified only after eapNoResp. They are 563 * unlikely to be used since eapNoResp should always be set if 564 * either of eapSuccess or eapFail is set. 565 */ 566 if (sm->eapResp && sm->eapNoResp) { 567 wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both " 568 "eapResp and eapNoResp set?!"); 569 } 570 if (sm->eapResp) 571 SM_ENTER(SUPP_BE, RESPONSE); 572 else if (sm->eapNoResp) 573 SM_ENTER(SUPP_BE, RECEIVE); 574 else if (sm->eapFail) 575 SM_ENTER(SUPP_BE, FAIL); 576 else if (sm->eapSuccess) 577 SM_ENTER(SUPP_BE, SUCCESS); 578 break; 579 case SUPP_BE_RESPONSE: 580 SM_ENTER(SUPP_BE, RECEIVE); 581 break; 582 case SUPP_BE_SUCCESS: 583 SM_ENTER(SUPP_BE, IDLE); 584 break; 585 case SUPP_BE_FAIL: 586 SM_ENTER(SUPP_BE, IDLE); 587 break; 588 case SUPP_BE_TIMEOUT: 589 SM_ENTER(SUPP_BE, IDLE); 590 break; 591 case SUPP_BE_IDLE: 592 if (sm->eapFail && sm->suppStart) 593 SM_ENTER(SUPP_BE, FAIL); 594 else if (sm->eapolEap && sm->suppStart) 595 SM_ENTER(SUPP_BE, REQUEST); 596 else if (sm->eapSuccess && sm->suppStart) 597 SM_ENTER(SUPP_BE, SUCCESS); 598 break; 599 case SUPP_BE_INITIALIZE: 600 SM_ENTER(SUPP_BE, IDLE); 601 break; 602 case SUPP_BE_RECEIVE: 603 if (sm->eapolEap) 604 SM_ENTER(SUPP_BE, REQUEST); 605 else if (sm->eapFail) 606 SM_ENTER(SUPP_BE, FAIL); 607 else if (sm->authWhile == 0) 608 SM_ENTER(SUPP_BE, TIMEOUT); 609 else if (sm->eapSuccess) 610 SM_ENTER(SUPP_BE, SUCCESS); 611 break; 612 } 613} 614 615 616static void eapol_sm_txLogoff(struct eapol_sm *sm) 617{ 618 wpa_printf(MSG_DEBUG, "EAPOL: txLogoff"); 619 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, 620 IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0); 621 sm->dot1xSuppEapolLogoffFramesTx++; 622 sm->dot1xSuppEapolFramesTx++; 623} 624 625 626static void eapol_sm_txStart(struct eapol_sm *sm) 627{ 628 wpa_printf(MSG_DEBUG, "EAPOL: txStart"); 629 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, 630 IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0); 631 sm->dot1xSuppEapolStartFramesTx++; 632 sm->dot1xSuppEapolFramesTx++; 633} 634 635 636#define IEEE8021X_ENCR_KEY_LEN 32 637#define IEEE8021X_SIGN_KEY_LEN 32 638 639struct eap_key_data { 640 u8 encr_key[IEEE8021X_ENCR_KEY_LEN]; 641 u8 sign_key[IEEE8021X_SIGN_KEY_LEN]; 642}; 643 644 645static void eapol_sm_processKey(struct eapol_sm *sm) 646{ 647 struct ieee802_1x_hdr *hdr; 648 struct ieee802_1x_eapol_key *key; 649 struct eap_key_data keydata; 650 u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32]; 651 u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN]; 652 int key_len, res, sign_key_len, encr_key_len; 653 u16 rx_key_length; 654 655 wpa_printf(MSG_DEBUG, "EAPOL: processKey"); 656 if (sm->last_rx_key == NULL) 657 return; 658 659 if (!sm->conf.accept_802_1x_keys) { 660 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key" 661 " even though this was not accepted - " 662 "ignoring this packet"); 663 return; 664 } 665 666 hdr = (struct ieee802_1x_hdr *) sm->last_rx_key; 667 key = (struct ieee802_1x_eapol_key *) (hdr + 1); 668 if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) { 669 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame"); 670 return; 671 } 672 rx_key_length = WPA_GET_BE16(key->key_length); 673 wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d " 674 "EAPOL-Key: type=%d key_length=%d key_index=0x%x", 675 hdr->version, hdr->type, be_to_host16(hdr->length), 676 key->type, rx_key_length, key->key_index); 677 678 eapol_sm_notify_lower_layer_success(sm, 1); 679 sign_key_len = IEEE8021X_SIGN_KEY_LEN; 680 encr_key_len = IEEE8021X_ENCR_KEY_LEN; 681 res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata)); 682 if (res < 0) { 683 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for " 684 "decrypting EAPOL-Key keys"); 685 return; 686 } 687 if (res == 16) { 688 /* LEAP derives only 16 bytes of keying material. */ 689 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16); 690 if (res) { 691 wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP " 692 "master key for decrypting EAPOL-Key keys"); 693 return; 694 } 695 sign_key_len = 16; 696 encr_key_len = 16; 697 os_memcpy(keydata.sign_key, keydata.encr_key, 16); 698 } else if (res) { 699 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key " 700 "data for decrypting EAPOL-Key keys (res=%d)", res); 701 return; 702 } 703 704 /* The key replay_counter must increase when same master key */ 705 if (sm->replay_counter_valid && 706 os_memcmp(sm->last_replay_counter, key->replay_counter, 707 IEEE8021X_REPLAY_COUNTER_LEN) >= 0) { 708 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did " 709 "not increase - ignoring key"); 710 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter", 711 sm->last_replay_counter, 712 IEEE8021X_REPLAY_COUNTER_LEN); 713 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter", 714 key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN); 715 return; 716 } 717 718 /* Verify key signature (HMAC-MD5) */ 719 os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN); 720 os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN); 721 hmac_md5(keydata.sign_key, sign_key_len, 722 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length), 723 key->key_signature); 724 if (os_memcmp(orig_key_sign, key->key_signature, 725 IEEE8021X_KEY_SIGN_LEN) != 0) { 726 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in " 727 "EAPOL-Key packet"); 728 os_memcpy(key->key_signature, orig_key_sign, 729 IEEE8021X_KEY_SIGN_LEN); 730 return; 731 } 732 wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified"); 733 734 key_len = be_to_host16(hdr->length) - sizeof(*key); 735 if (key_len > 32 || rx_key_length > 32) { 736 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d", 737 key_len ? key_len : rx_key_length); 738 return; 739 } 740 if (key_len == rx_key_length) { 741 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN); 742 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key, 743 encr_key_len); 744 os_memcpy(datakey, key + 1, key_len); 745 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0, 746 datakey, key_len); 747 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key", 748 datakey, key_len); 749 } else if (key_len == 0) { 750 /* 751 * IEEE 802.1X-2004 specifies that least significant Key Length 752 * octets from MS-MPPE-Send-Key are used as the key if the key 753 * data is not present. This seems to be meaning the beginning 754 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in 755 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator. 756 * Anyway, taking the beginning of the keying material from EAP 757 * seems to interoperate with Authenticators. 758 */ 759 key_len = rx_key_length; 760 os_memcpy(datakey, keydata.encr_key, key_len); 761 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying " 762 "material data encryption key", 763 datakey, key_len); 764 } else { 765 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d " 766 "(key_length=%d)", key_len, rx_key_length); 767 return; 768 } 769 770 sm->replay_counter_valid = TRUE; 771 os_memcpy(sm->last_replay_counter, key->replay_counter, 772 IEEE8021X_REPLAY_COUNTER_LEN); 773 774 wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d " 775 "len %d", 776 key->key_index & IEEE8021X_KEY_INDEX_FLAG ? 777 "unicast" : "broadcast", 778 key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len); 779 780 if (sm->ctx->set_wep_key && 781 sm->ctx->set_wep_key(sm->ctx->ctx, 782 key->key_index & IEEE8021X_KEY_INDEX_FLAG, 783 key->key_index & IEEE8021X_KEY_INDEX_MASK, 784 datakey, key_len) < 0) { 785 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the " 786 " driver."); 787 } else { 788 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG) 789 sm->unicast_key_received = TRUE; 790 else 791 sm->broadcast_key_received = TRUE; 792 793 if ((sm->unicast_key_received || 794 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) && 795 (sm->broadcast_key_received || 796 !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST))) 797 { 798 wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key " 799 "frames received"); 800 sm->portValid = TRUE; 801 if (sm->ctx->eapol_done_cb) 802 sm->ctx->eapol_done_cb(sm->ctx->ctx); 803 } 804 } 805} 806 807 808static void eapol_sm_getSuppRsp(struct eapol_sm *sm) 809{ 810 wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp"); 811 /* EAP layer processing; no special code is needed, since Supplicant 812 * Backend state machine is waiting for eapNoResp or eapResp to be set 813 * and these are only set in the EAP state machine when the processing 814 * has finished. */ 815} 816 817 818static void eapol_sm_txSuppRsp(struct eapol_sm *sm) 819{ 820 struct wpabuf *resp; 821 822 wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp"); 823 resp = eap_get_eapRespData(sm->eap); 824 if (resp == NULL) { 825 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data " 826 "not available"); 827 return; 828 } 829 830 /* Send EAP-Packet from the EAP layer to the Authenticator */ 831 sm->ctx->eapol_send(sm->ctx->eapol_send_ctx, 832 IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp), 833 wpabuf_len(resp)); 834 835 /* eapRespData is not used anymore, so free it here */ 836 wpabuf_free(resp); 837 838 if (sm->initial_req) 839 sm->dot1xSuppEapolReqIdFramesRx++; 840 else 841 sm->dot1xSuppEapolReqFramesRx++; 842 sm->dot1xSuppEapolRespFramesTx++; 843 sm->dot1xSuppEapolFramesTx++; 844} 845 846 847static void eapol_sm_abortSupp(struct eapol_sm *sm) 848{ 849 /* release system resources that may have been allocated for the 850 * authentication session */ 851 os_free(sm->last_rx_key); 852 sm->last_rx_key = NULL; 853 wpabuf_free(sm->eapReqData); 854 sm->eapReqData = NULL; 855 eap_sm_abort(sm->eap); 856} 857 858 859static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx) 860{ 861 eapol_sm_step(timeout_ctx); 862} 863 864 865/** 866 * eapol_sm_step - EAPOL state machine step function 867 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 868 * 869 * This function is called to notify the state machine about changed external 870 * variables. It will step through the EAPOL state machines in loop to process 871 * all triggered state changes. 872 */ 873void eapol_sm_step(struct eapol_sm *sm) 874{ 875 int i; 876 877 /* In theory, it should be ok to run this in loop until !changed. 878 * However, it is better to use a limit on number of iterations to 879 * allow events (e.g., SIGTERM) to stop the program cleanly if the 880 * state machine were to generate a busy loop. */ 881 for (i = 0; i < 100; i++) { 882 sm->changed = FALSE; 883 SM_STEP_RUN(SUPP_PAE); 884 SM_STEP_RUN(KEY_RX); 885 SM_STEP_RUN(SUPP_BE); 886 if (eap_peer_sm_step(sm->eap)) 887 sm->changed = TRUE; 888 if (!sm->changed) 889 break; 890 } 891 892 if (sm->changed) { 893 /* restart EAPOL state machine step from timeout call in order 894 * to allow other events to be processed. */ 895 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); 896 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm); 897 } 898 899 if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) { 900 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0; 901 sm->cb_status = EAPOL_CB_IN_PROGRESS; 902 sm->ctx->cb(sm, success, sm->ctx->cb_ctx); 903 } 904} 905 906 907#ifdef CONFIG_CTRL_IFACE 908static const char *eapol_supp_pae_state(int state) 909{ 910 switch (state) { 911 case SUPP_PAE_LOGOFF: 912 return "LOGOFF"; 913 case SUPP_PAE_DISCONNECTED: 914 return "DISCONNECTED"; 915 case SUPP_PAE_CONNECTING: 916 return "CONNECTING"; 917 case SUPP_PAE_AUTHENTICATING: 918 return "AUTHENTICATING"; 919 case SUPP_PAE_HELD: 920 return "HELD"; 921 case SUPP_PAE_AUTHENTICATED: 922 return "AUTHENTICATED"; 923 case SUPP_PAE_RESTART: 924 return "RESTART"; 925 default: 926 return "UNKNOWN"; 927 } 928} 929 930 931static const char *eapol_supp_be_state(int state) 932{ 933 switch (state) { 934 case SUPP_BE_REQUEST: 935 return "REQUEST"; 936 case SUPP_BE_RESPONSE: 937 return "RESPONSE"; 938 case SUPP_BE_SUCCESS: 939 return "SUCCESS"; 940 case SUPP_BE_FAIL: 941 return "FAIL"; 942 case SUPP_BE_TIMEOUT: 943 return "TIMEOUT"; 944 case SUPP_BE_IDLE: 945 return "IDLE"; 946 case SUPP_BE_INITIALIZE: 947 return "INITIALIZE"; 948 case SUPP_BE_RECEIVE: 949 return "RECEIVE"; 950 default: 951 return "UNKNOWN"; 952 } 953} 954 955 956static const char * eapol_port_status(PortStatus status) 957{ 958 if (status == Authorized) 959 return "Authorized"; 960 else 961 return "Unauthorized"; 962} 963#endif /* CONFIG_CTRL_IFACE */ 964 965 966#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 967static const char * eapol_port_control(PortControl ctrl) 968{ 969 switch (ctrl) { 970 case Auto: 971 return "Auto"; 972 case ForceUnauthorized: 973 return "ForceUnauthorized"; 974 case ForceAuthorized: 975 return "ForceAuthorized"; 976 default: 977 return "Unknown"; 978 } 979} 980#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 981 982 983/** 984 * eapol_sm_configure - Set EAPOL variables 985 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 986 * @heldPeriod: dot1xSuppHeldPeriod 987 * @authPeriod: dot1xSuppAuthPeriod 988 * @startPeriod: dot1xSuppStartPeriod 989 * @maxStart: dot1xSuppMaxStart 990 * 991 * Set configurable EAPOL state machine variables. Each variable can be set to 992 * the given value or ignored if set to -1 (to set only some of the variables). 993 */ 994void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod, 995 int startPeriod, int maxStart) 996{ 997 if (sm == NULL) 998 return; 999 if (heldPeriod >= 0) 1000 sm->heldPeriod = heldPeriod; 1001 if (authPeriod >= 0) 1002 sm->authPeriod = authPeriod; 1003 if (startPeriod >= 0) 1004 sm->startPeriod = startPeriod; 1005 if (maxStart >= 0) 1006 sm->maxStart = maxStart; 1007} 1008 1009 1010#ifdef CONFIG_CTRL_IFACE 1011/** 1012 * eapol_sm_get_status - Get EAPOL state machine status 1013 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1014 * @buf: Buffer for status information 1015 * @buflen: Maximum buffer length 1016 * @verbose: Whether to include verbose status information 1017 * Returns: Number of bytes written to buf. 1018 * 1019 * Query EAPOL state machine for status information. This function fills in a 1020 * text area with current status information from the EAPOL state machine. If 1021 * the buffer (buf) is not large enough, status information will be truncated 1022 * to fit the buffer. 1023 */ 1024int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen, 1025 int verbose) 1026{ 1027 int len, ret; 1028 if (sm == NULL) 1029 return 0; 1030 1031 len = os_snprintf(buf, buflen, 1032 "Supplicant PAE state=%s\n" 1033 "suppPortStatus=%s\n", 1034 eapol_supp_pae_state(sm->SUPP_PAE_state), 1035 eapol_port_status(sm->suppPortStatus)); 1036 if (len < 0 || (size_t) len >= buflen) 1037 return 0; 1038 1039 if (verbose) { 1040 ret = os_snprintf(buf + len, buflen - len, 1041 "heldPeriod=%u\n" 1042 "authPeriod=%u\n" 1043 "startPeriod=%u\n" 1044 "maxStart=%u\n" 1045 "portControl=%s\n" 1046 "Supplicant Backend state=%s\n", 1047 sm->heldPeriod, 1048 sm->authPeriod, 1049 sm->startPeriod, 1050 sm->maxStart, 1051 eapol_port_control(sm->portControl), 1052 eapol_supp_be_state(sm->SUPP_BE_state)); 1053 if (ret < 0 || (size_t) ret >= buflen - len) 1054 return len; 1055 len += ret; 1056 } 1057 1058 len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose); 1059 1060 return len; 1061} 1062 1063 1064/** 1065 * eapol_sm_get_mib - Get EAPOL state machine MIBs 1066 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1067 * @buf: Buffer for MIB information 1068 * @buflen: Maximum buffer length 1069 * Returns: Number of bytes written to buf. 1070 * 1071 * Query EAPOL state machine for MIB information. This function fills in a 1072 * text area with current MIB information from the EAPOL state machine. If 1073 * the buffer (buf) is not large enough, MIB information will be truncated to 1074 * fit the buffer. 1075 */ 1076int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen) 1077{ 1078 size_t len; 1079 int ret; 1080 1081 if (sm == NULL) 1082 return 0; 1083 ret = os_snprintf(buf, buflen, 1084 "dot1xSuppPaeState=%d\n" 1085 "dot1xSuppHeldPeriod=%u\n" 1086 "dot1xSuppAuthPeriod=%u\n" 1087 "dot1xSuppStartPeriod=%u\n" 1088 "dot1xSuppMaxStart=%u\n" 1089 "dot1xSuppSuppControlledPortStatus=%s\n" 1090 "dot1xSuppBackendPaeState=%d\n", 1091 sm->SUPP_PAE_state, 1092 sm->heldPeriod, 1093 sm->authPeriod, 1094 sm->startPeriod, 1095 sm->maxStart, 1096 sm->suppPortStatus == Authorized ? 1097 "Authorized" : "Unauthorized", 1098 sm->SUPP_BE_state); 1099 1100 if (ret < 0 || (size_t) ret >= buflen) 1101 return 0; 1102 len = ret; 1103 1104 ret = os_snprintf(buf + len, buflen - len, 1105 "dot1xSuppEapolFramesRx=%u\n" 1106 "dot1xSuppEapolFramesTx=%u\n" 1107 "dot1xSuppEapolStartFramesTx=%u\n" 1108 "dot1xSuppEapolLogoffFramesTx=%u\n" 1109 "dot1xSuppEapolRespFramesTx=%u\n" 1110 "dot1xSuppEapolReqIdFramesRx=%u\n" 1111 "dot1xSuppEapolReqFramesRx=%u\n" 1112 "dot1xSuppInvalidEapolFramesRx=%u\n" 1113 "dot1xSuppEapLengthErrorFramesRx=%u\n" 1114 "dot1xSuppLastEapolFrameVersion=%u\n" 1115 "dot1xSuppLastEapolFrameSource=" MACSTR "\n", 1116 sm->dot1xSuppEapolFramesRx, 1117 sm->dot1xSuppEapolFramesTx, 1118 sm->dot1xSuppEapolStartFramesTx, 1119 sm->dot1xSuppEapolLogoffFramesTx, 1120 sm->dot1xSuppEapolRespFramesTx, 1121 sm->dot1xSuppEapolReqIdFramesRx, 1122 sm->dot1xSuppEapolReqFramesRx, 1123 sm->dot1xSuppInvalidEapolFramesRx, 1124 sm->dot1xSuppEapLengthErrorFramesRx, 1125 sm->dot1xSuppLastEapolFrameVersion, 1126 MAC2STR(sm->dot1xSuppLastEapolFrameSource)); 1127 1128 if (ret < 0 || (size_t) ret >= buflen - len) 1129 return len; 1130 len += ret; 1131 1132 return len; 1133} 1134#endif /* CONFIG_CTRL_IFACE */ 1135 1136 1137/** 1138 * eapol_sm_rx_eapol - Process received EAPOL frames 1139 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1140 * @src: Source MAC address of the EAPOL packet 1141 * @buf: Pointer to the beginning of the EAPOL data (EAPOL header) 1142 * @len: Length of the EAPOL frame 1143 * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine, 1144 * -1 failure 1145 */ 1146int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf, 1147 size_t len) 1148{ 1149 const struct ieee802_1x_hdr *hdr; 1150 const struct ieee802_1x_eapol_key *key; 1151 int data_len; 1152 int res = 1; 1153 size_t plen; 1154 1155 if (sm == NULL) 1156 return 0; 1157 sm->dot1xSuppEapolFramesRx++; 1158 if (len < sizeof(*hdr)) { 1159 sm->dot1xSuppInvalidEapolFramesRx++; 1160 return 0; 1161 } 1162 hdr = (const struct ieee802_1x_hdr *) buf; 1163 sm->dot1xSuppLastEapolFrameVersion = hdr->version; 1164 os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN); 1165 if (hdr->version < EAPOL_VERSION) { 1166 /* TODO: backwards compatibility */ 1167 } 1168 plen = be_to_host16(hdr->length); 1169 if (plen > len - sizeof(*hdr)) { 1170 sm->dot1xSuppEapLengthErrorFramesRx++; 1171 return 0; 1172 } 1173#ifdef CONFIG_WPS 1174 if (sm->conf.workaround && 1175 plen < len - sizeof(*hdr) && 1176 hdr->type == IEEE802_1X_TYPE_EAP_PACKET && 1177 len - sizeof(*hdr) > sizeof(struct eap_hdr)) { 1178 const struct eap_hdr *ehdr = 1179 (const struct eap_hdr *) (hdr + 1); 1180 u16 elen; 1181 1182 elen = be_to_host16(ehdr->length); 1183 if (elen > plen && elen <= len - sizeof(*hdr)) { 1184 /* 1185 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS 1186 * packets with too short EAPOL header length field 1187 * (14 octets). This is fixed in firmware Ver.1.49. 1188 * As a workaround, fix the EAPOL header based on the 1189 * correct length in the EAP packet. 1190 */ 1191 wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL " 1192 "payload length based on EAP header: " 1193 "%d -> %d", (int) plen, elen); 1194 plen = elen; 1195 } 1196 } 1197#endif /* CONFIG_WPS */ 1198 data_len = plen + sizeof(*hdr); 1199 1200 switch (hdr->type) { 1201 case IEEE802_1X_TYPE_EAP_PACKET: 1202 if (sm->cached_pmk) { 1203 /* Trying to use PMKSA caching, but Authenticator did 1204 * not seem to have a matching entry. Need to restart 1205 * EAPOL state machines. 1206 */ 1207 eapol_sm_abort_cached(sm); 1208 } 1209 wpabuf_free(sm->eapReqData); 1210 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen); 1211 if (sm->eapReqData) { 1212 wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet " 1213 "frame"); 1214 sm->eapolEap = TRUE; 1215 eapol_sm_step(sm); 1216 } 1217 break; 1218 case IEEE802_1X_TYPE_EAPOL_KEY: 1219 if (plen < sizeof(*key)) { 1220 wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key " 1221 "frame received"); 1222 break; 1223 } 1224 key = (const struct ieee802_1x_eapol_key *) (hdr + 1); 1225 if (key->type == EAPOL_KEY_TYPE_WPA || 1226 key->type == EAPOL_KEY_TYPE_RSN) { 1227 /* WPA Supplicant takes care of this frame. */ 1228 wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key " 1229 "frame in EAPOL state machines"); 1230 res = 0; 1231 break; 1232 } 1233 if (key->type != EAPOL_KEY_TYPE_RC4) { 1234 wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown " 1235 "EAPOL-Key type %d", key->type); 1236 break; 1237 } 1238 os_free(sm->last_rx_key); 1239 sm->last_rx_key = os_malloc(data_len); 1240 if (sm->last_rx_key) { 1241 wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key " 1242 "frame"); 1243 os_memcpy(sm->last_rx_key, buf, data_len); 1244 sm->last_rx_key_len = data_len; 1245 sm->rxKey = TRUE; 1246 eapol_sm_step(sm); 1247 } 1248 break; 1249 default: 1250 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d", 1251 hdr->type); 1252 sm->dot1xSuppInvalidEapolFramesRx++; 1253 break; 1254 } 1255 1256 return res; 1257} 1258 1259 1260/** 1261 * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet 1262 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1263 * 1264 * Notify EAPOL state machine about transmitted EAPOL packet from an external 1265 * component, e.g., WPA. This will update the statistics. 1266 */ 1267void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm) 1268{ 1269 if (sm) 1270 sm->dot1xSuppEapolFramesTx++; 1271} 1272 1273 1274/** 1275 * eapol_sm_notify_portEnabled - Notification about portEnabled change 1276 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1277 * @enabled: New portEnabled value 1278 * 1279 * Notify EAPOL state machine about new portEnabled value. 1280 */ 1281void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled) 1282{ 1283 if (sm == NULL) 1284 return; 1285 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1286 "portEnabled=%d", enabled); 1287 sm->portEnabled = enabled; 1288 eapol_sm_step(sm); 1289} 1290 1291 1292/** 1293 * eapol_sm_notify_portValid - Notification about portValid change 1294 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1295 * @valid: New portValid value 1296 * 1297 * Notify EAPOL state machine about new portValid value. 1298 */ 1299void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid) 1300{ 1301 if (sm == NULL) 1302 return; 1303 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1304 "portValid=%d", valid); 1305 sm->portValid = valid; 1306 eapol_sm_step(sm); 1307} 1308 1309 1310/** 1311 * eapol_sm_notify_eap_success - Notification of external EAP success trigger 1312 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1313 * @success: %TRUE = set success, %FALSE = clear success 1314 * 1315 * Notify the EAPOL state machine that external event has forced EAP state to 1316 * success (success = %TRUE). This can be cleared by setting success = %FALSE. 1317 * 1318 * This function is called to update EAP state when WPA-PSK key handshake has 1319 * been completed successfully since WPA-PSK does not use EAP state machine. 1320 */ 1321void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success) 1322{ 1323 if (sm == NULL) 1324 return; 1325 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1326 "EAP success=%d", success); 1327 sm->eapSuccess = success; 1328 sm->altAccept = success; 1329 if (success) 1330 eap_notify_success(sm->eap); 1331 eapol_sm_step(sm); 1332} 1333 1334 1335/** 1336 * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger 1337 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1338 * @fail: %TRUE = set failure, %FALSE = clear failure 1339 * 1340 * Notify EAPOL state machine that external event has forced EAP state to 1341 * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE. 1342 */ 1343void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail) 1344{ 1345 if (sm == NULL) 1346 return; 1347 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1348 "EAP fail=%d", fail); 1349 sm->eapFail = fail; 1350 sm->altReject = fail; 1351 eapol_sm_step(sm); 1352} 1353 1354 1355/** 1356 * eapol_sm_notify_config - Notification of EAPOL configuration change 1357 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1358 * @config: Pointer to current network EAP configuration 1359 * @conf: Pointer to EAPOL configuration data 1360 * 1361 * Notify EAPOL state machine that configuration has changed. config will be 1362 * stored as a backpointer to network configuration. This can be %NULL to clear 1363 * the stored pointed. conf will be copied to local EAPOL/EAP configuration 1364 * data. If conf is %NULL, this part of the configuration change will be 1365 * skipped. 1366 */ 1367void eapol_sm_notify_config(struct eapol_sm *sm, 1368 struct eap_peer_config *config, 1369 const struct eapol_config *conf) 1370{ 1371 if (sm == NULL) 1372 return; 1373 1374 sm->config = config; 1375 1376 if (conf == NULL) 1377 return; 1378 1379 sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys; 1380 sm->conf.required_keys = conf->required_keys; 1381 sm->conf.fast_reauth = conf->fast_reauth; 1382 sm->conf.workaround = conf->workaround; 1383 if (sm->eap) { 1384 eap_set_fast_reauth(sm->eap, conf->fast_reauth); 1385 eap_set_workaround(sm->eap, conf->workaround); 1386 eap_set_force_disabled(sm->eap, conf->eap_disabled); 1387 } 1388} 1389 1390 1391/** 1392 * eapol_sm_get_key - Get master session key (MSK) from EAP 1393 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1394 * @key: Pointer for key buffer 1395 * @len: Number of bytes to copy to key 1396 * Returns: 0 on success (len of key available), maximum available key len 1397 * (>0) if key is available but it is shorter than len, or -1 on failure. 1398 * 1399 * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key 1400 * is available only after a successful authentication. 1401 */ 1402int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len) 1403{ 1404 const u8 *eap_key; 1405 size_t eap_len; 1406 1407 if (sm == NULL || !eap_key_available(sm->eap)) { 1408 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available"); 1409 return -1; 1410 } 1411 eap_key = eap_get_eapKeyData(sm->eap, &eap_len); 1412 if (eap_key == NULL) { 1413 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData"); 1414 return -1; 1415 } 1416 if (len > eap_len) { 1417 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not " 1418 "available (len=%lu)", 1419 (unsigned long) len, (unsigned long) eap_len); 1420 return eap_len; 1421 } 1422 os_memcpy(key, eap_key, len); 1423 wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)", 1424 (unsigned long) len); 1425 return 0; 1426} 1427 1428 1429/** 1430 * eapol_sm_notify_logoff - Notification of logon/logoff commands 1431 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1432 * @logoff: Whether command was logoff 1433 * 1434 * Notify EAPOL state machines that user requested logon/logoff. 1435 */ 1436void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff) 1437{ 1438 if (sm) { 1439 sm->userLogoff = logoff; 1440 eapol_sm_step(sm); 1441 } 1442} 1443 1444 1445/** 1446 * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching 1447 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1448 * 1449 * Notify EAPOL state machines that PMKSA caching was successful. This is used 1450 * to move EAPOL and EAP state machines into authenticated/successful state. 1451 */ 1452void eapol_sm_notify_cached(struct eapol_sm *sm) 1453{ 1454 if (sm == NULL) 1455 return; 1456 wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL"); 1457 sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED; 1458 sm->suppPortStatus = Authorized; 1459 sm->portValid = TRUE; 1460 eap_notify_success(sm->eap); 1461 eapol_sm_step(sm); 1462} 1463 1464 1465/** 1466 * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching 1467 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1468 * @attempt: Whether PMKSA caching is tried 1469 * 1470 * Notify EAPOL state machines whether PMKSA caching is used. 1471 */ 1472void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt) 1473{ 1474 if (sm == NULL) 1475 return; 1476 if (attempt) { 1477 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA"); 1478 sm->cached_pmk = TRUE; 1479 } else { 1480 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA"); 1481 sm->cached_pmk = FALSE; 1482 } 1483} 1484 1485 1486static void eapol_sm_abort_cached(struct eapol_sm *sm) 1487{ 1488 wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, " 1489 "doing full EAP authentication"); 1490 if (sm == NULL) 1491 return; 1492 sm->cached_pmk = FALSE; 1493 sm->SUPP_PAE_state = SUPP_PAE_CONNECTING; 1494 sm->suppPortStatus = Unauthorized; 1495 1496 /* Make sure we do not start sending EAPOL-Start frames first, but 1497 * instead move to RESTART state to start EAPOL authentication. */ 1498 sm->startWhen = 3; 1499 eapol_enable_timer_tick(sm); 1500 1501 if (sm->ctx->aborted_cached) 1502 sm->ctx->aborted_cached(sm->ctx->ctx); 1503} 1504 1505 1506/** 1507 * eapol_sm_register_scard_ctx - Notification of smart card context 1508 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1509 * @ctx: Context data for smart card operations 1510 * 1511 * Notify EAPOL state machines of context data for smart card operations. This 1512 * context data will be used as a parameter for scard_*() functions. 1513 */ 1514void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx) 1515{ 1516 if (sm) { 1517 sm->ctx->scard_ctx = ctx; 1518 eap_register_scard_ctx(sm->eap, ctx); 1519 } 1520} 1521 1522 1523/** 1524 * eapol_sm_notify_portControl - Notification of portControl changes 1525 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1526 * @portControl: New value for portControl variable 1527 * 1528 * Notify EAPOL state machines that portControl variable has changed. 1529 */ 1530void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl) 1531{ 1532 if (sm == NULL) 1533 return; 1534 wpa_printf(MSG_DEBUG, "EAPOL: External notification - " 1535 "portControl=%s", eapol_port_control(portControl)); 1536 sm->portControl = portControl; 1537 eapol_sm_step(sm); 1538} 1539 1540 1541/** 1542 * eapol_sm_notify_ctrl_attached - Notification of attached monitor 1543 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1544 * 1545 * Notify EAPOL state machines that a monitor was attached to the control 1546 * interface to trigger re-sending of pending requests for user input. 1547 */ 1548void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm) 1549{ 1550 if (sm == NULL) 1551 return; 1552 eap_sm_notify_ctrl_attached(sm->eap); 1553} 1554 1555 1556/** 1557 * eapol_sm_notify_ctrl_response - Notification of received user input 1558 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1559 * 1560 * Notify EAPOL state machines that a control response, i.e., user 1561 * input, was received in order to trigger retrying of a pending EAP request. 1562 */ 1563void eapol_sm_notify_ctrl_response(struct eapol_sm *sm) 1564{ 1565 if (sm == NULL) 1566 return; 1567 if (sm->eapReqData && !sm->eapReq) { 1568 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user " 1569 "input) notification - retrying pending EAP " 1570 "Request"); 1571 sm->eapolEap = TRUE; 1572 sm->eapReq = TRUE; 1573 eapol_sm_step(sm); 1574 } 1575} 1576 1577 1578/** 1579 * eapol_sm_request_reauth - Request reauthentication 1580 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1581 * 1582 * This function can be used to request EAPOL reauthentication, e.g., when the 1583 * current PMKSA entry is nearing expiration. 1584 */ 1585void eapol_sm_request_reauth(struct eapol_sm *sm) 1586{ 1587 if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED) 1588 return; 1589 eapol_sm_txStart(sm); 1590} 1591 1592 1593/** 1594 * eapol_sm_notify_lower_layer_success - Notification of lower layer success 1595 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1596 * @in_eapol_sm: Whether the caller is already running inside EAPOL state 1597 * machine loop (eapol_sm_step()) 1598 * 1599 * Notify EAPOL (and EAP) state machines that a lower layer has detected a 1600 * successful authentication. This is used to recover from dropped EAP-Success 1601 * messages. 1602 */ 1603void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm) 1604{ 1605 if (sm == NULL) 1606 return; 1607 eap_notify_lower_layer_success(sm->eap); 1608 if (!in_eapol_sm) 1609 eapol_sm_step(sm); 1610} 1611 1612 1613/** 1614 * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid 1615 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1616 */ 1617void eapol_sm_invalidate_cached_session(struct eapol_sm *sm) 1618{ 1619 if (sm) 1620 eap_invalidate_cached_session(sm->eap); 1621} 1622 1623 1624static struct eap_peer_config * eapol_sm_get_config(void *ctx) 1625{ 1626 struct eapol_sm *sm = ctx; 1627 return sm ? sm->config : NULL; 1628} 1629 1630 1631static struct wpabuf * eapol_sm_get_eapReqData(void *ctx) 1632{ 1633 struct eapol_sm *sm = ctx; 1634 if (sm == NULL || sm->eapReqData == NULL) 1635 return NULL; 1636 1637 return sm->eapReqData; 1638} 1639 1640 1641static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable) 1642{ 1643 struct eapol_sm *sm = ctx; 1644 if (sm == NULL) 1645 return FALSE; 1646 switch (variable) { 1647 case EAPOL_eapSuccess: 1648 return sm->eapSuccess; 1649 case EAPOL_eapRestart: 1650 return sm->eapRestart; 1651 case EAPOL_eapFail: 1652 return sm->eapFail; 1653 case EAPOL_eapResp: 1654 return sm->eapResp; 1655 case EAPOL_eapNoResp: 1656 return sm->eapNoResp; 1657 case EAPOL_eapReq: 1658 return sm->eapReq; 1659 case EAPOL_portEnabled: 1660 return sm->portEnabled; 1661 case EAPOL_altAccept: 1662 return sm->altAccept; 1663 case EAPOL_altReject: 1664 return sm->altReject; 1665 } 1666 return FALSE; 1667} 1668 1669 1670static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable, 1671 Boolean value) 1672{ 1673 struct eapol_sm *sm = ctx; 1674 if (sm == NULL) 1675 return; 1676 switch (variable) { 1677 case EAPOL_eapSuccess: 1678 sm->eapSuccess = value; 1679 break; 1680 case EAPOL_eapRestart: 1681 sm->eapRestart = value; 1682 break; 1683 case EAPOL_eapFail: 1684 sm->eapFail = value; 1685 break; 1686 case EAPOL_eapResp: 1687 sm->eapResp = value; 1688 break; 1689 case EAPOL_eapNoResp: 1690 sm->eapNoResp = value; 1691 break; 1692 case EAPOL_eapReq: 1693 sm->eapReq = value; 1694 break; 1695 case EAPOL_portEnabled: 1696 sm->portEnabled = value; 1697 break; 1698 case EAPOL_altAccept: 1699 sm->altAccept = value; 1700 break; 1701 case EAPOL_altReject: 1702 sm->altReject = value; 1703 break; 1704 } 1705} 1706 1707 1708static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable) 1709{ 1710 struct eapol_sm *sm = ctx; 1711 if (sm == NULL) 1712 return 0; 1713 switch (variable) { 1714 case EAPOL_idleWhile: 1715 return sm->idleWhile; 1716 } 1717 return 0; 1718} 1719 1720 1721static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable, 1722 unsigned int value) 1723{ 1724 struct eapol_sm *sm = ctx; 1725 if (sm == NULL) 1726 return; 1727 switch (variable) { 1728 case EAPOL_idleWhile: 1729 sm->idleWhile = value; 1730 eapol_enable_timer_tick(sm); 1731 break; 1732 } 1733} 1734 1735 1736static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob) 1737{ 1738#ifndef CONFIG_NO_CONFIG_BLOBS 1739 struct eapol_sm *sm = ctx; 1740 if (sm && sm->ctx && sm->ctx->set_config_blob) 1741 sm->ctx->set_config_blob(sm->ctx->ctx, blob); 1742#endif /* CONFIG_NO_CONFIG_BLOBS */ 1743} 1744 1745 1746static const struct wpa_config_blob * 1747eapol_sm_get_config_blob(void *ctx, const char *name) 1748{ 1749#ifndef CONFIG_NO_CONFIG_BLOBS 1750 struct eapol_sm *sm = ctx; 1751 if (sm && sm->ctx && sm->ctx->get_config_blob) 1752 return sm->ctx->get_config_blob(sm->ctx->ctx, name); 1753 else 1754 return NULL; 1755#else /* CONFIG_NO_CONFIG_BLOBS */ 1756 return NULL; 1757#endif /* CONFIG_NO_CONFIG_BLOBS */ 1758} 1759 1760 1761static void eapol_sm_notify_pending(void *ctx) 1762{ 1763 struct eapol_sm *sm = ctx; 1764 if (sm == NULL) 1765 return; 1766 if (sm->eapReqData && !sm->eapReq) { 1767 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP " 1768 "state machine - retrying pending EAP Request"); 1769 sm->eapolEap = TRUE; 1770 sm->eapReq = TRUE; 1771 eapol_sm_step(sm); 1772 } 1773} 1774 1775 1776#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG) 1777static void eapol_sm_eap_param_needed(void *ctx, const char *field, 1778 const char *txt) 1779{ 1780 struct eapol_sm *sm = ctx; 1781 wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed"); 1782 if (sm->ctx->eap_param_needed) 1783 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt); 1784} 1785#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 1786#define eapol_sm_eap_param_needed NULL 1787#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */ 1788 1789 1790static struct eapol_callbacks eapol_cb = 1791{ 1792 eapol_sm_get_config, 1793 eapol_sm_get_bool, 1794 eapol_sm_set_bool, 1795 eapol_sm_get_int, 1796 eapol_sm_set_int, 1797 eapol_sm_get_eapReqData, 1798 eapol_sm_set_config_blob, 1799 eapol_sm_get_config_blob, 1800 eapol_sm_notify_pending, 1801 eapol_sm_eap_param_needed 1802}; 1803 1804 1805/** 1806 * eapol_sm_init - Initialize EAPOL state machine 1807 * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer 1808 * and EAPOL state machine will free it in eapol_sm_deinit() 1809 * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure 1810 * 1811 * Allocate and initialize an EAPOL state machine. 1812 */ 1813struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx) 1814{ 1815 struct eapol_sm *sm; 1816 struct eap_config conf; 1817 sm = os_zalloc(sizeof(*sm)); 1818 if (sm == NULL) 1819 return NULL; 1820 sm->ctx = ctx; 1821 1822 sm->portControl = Auto; 1823 1824 /* Supplicant PAE state machine */ 1825 sm->heldPeriod = 60; 1826 sm->startPeriod = 30; 1827 sm->maxStart = 3; 1828 1829 /* Supplicant Backend state machine */ 1830 sm->authPeriod = 30; 1831 1832 os_memset(&conf, 0, sizeof(conf)); 1833#ifdef EAP_TLS_OPENSSL 1834 conf.opensc_engine_path = ctx->opensc_engine_path; 1835 conf.pkcs11_engine_path = ctx->pkcs11_engine_path; 1836 conf.pkcs11_module_path = ctx->pkcs11_module_path; 1837#endif /* EAP_TLS_OPENSSL */ 1838 conf.wps = ctx->wps; 1839 1840 sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf); 1841 if (sm->eap == NULL) { 1842 os_free(sm); 1843 return NULL; 1844 } 1845 1846 /* Initialize EAPOL state machines */ 1847 sm->initialize = TRUE; 1848 eapol_sm_step(sm); 1849 sm->initialize = FALSE; 1850 eapol_sm_step(sm); 1851 1852 sm->timer_tick_enabled = 1; 1853 eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm); 1854 1855 return sm; 1856} 1857 1858 1859/** 1860 * eapol_sm_deinit - Deinitialize EAPOL state machine 1861 * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() 1862 * 1863 * Deinitialize and free EAPOL state machine. 1864 */ 1865void eapol_sm_deinit(struct eapol_sm *sm) 1866{ 1867 if (sm == NULL) 1868 return; 1869 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); 1870 eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm); 1871 eap_peer_sm_deinit(sm->eap); 1872 os_free(sm->last_rx_key); 1873 wpabuf_free(sm->eapReqData); 1874 os_free(sm->ctx); 1875 os_free(sm); 1876} 1877