1 /* 2 * IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine 3 * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "utils/eloop.h" 13 #include "common/defs.h" 14 #include "common/ieee802_1x_defs.h" 15 #include "utils/state_machine.h" 16 #include "ieee802_1x_kay.h" 17 #include "ieee802_1x_secy_ops.h" 18 #include "pae/ieee802_1x_cp.h" 19 20 #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm 21 #define STATE_MACHINE_DEBUG_PREFIX "CP" 22 23 static u64 default_cs_id = CS_ID_GCM_AES_128; 24 25 /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */ 26 enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE }; 27 28 struct ieee802_1x_cp_sm { 29 enum cp_states { 30 CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED, 31 CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT, 32 CP_TRANSMITTING, CP_ABANDON, CP_RETIRE 33 } CP_state; 34 Boolean changed; 35 36 /* CP -> Client */ 37 Boolean port_valid; 38 39 /* Logon -> CP */ 40 enum connect_type connect; 41 u8 *authorization_data; 42 43 /* KaY -> CP */ 44 Boolean chgd_server; /* clear by CP */ 45 Boolean elected_self; 46 u8 *authorization_data1; 47 enum confidentiality_offset cipher_offset; 48 u64 cipher_suite; 49 Boolean new_sak; /* clear by CP */ 50 struct ieee802_1x_mka_ki distributed_ki; 51 u8 distributed_an; 52 Boolean using_receive_sas; 53 Boolean all_receiving; 54 Boolean server_transmitting; 55 Boolean using_transmit_sa; 56 57 /* CP -> KaY */ 58 struct ieee802_1x_mka_ki *lki; 59 u8 lan; 60 Boolean ltx; 61 Boolean lrx; 62 struct ieee802_1x_mka_ki *oki; 63 u8 oan; 64 Boolean otx; 65 Boolean orx; 66 67 /* CP -> SecY */ 68 Boolean protect_frames; 69 enum validate_frames validate_frames; 70 71 Boolean replay_protect; 72 u32 replay_window; 73 74 u64 current_cipher_suite; 75 enum confidentiality_offset confidentiality_offset; 76 Boolean controlled_port_enabled; 77 78 /* SecY -> CP */ 79 Boolean port_enabled; /* SecY->CP */ 80 81 /* private */ 82 u32 transmit_when; 83 u32 transmit_delay; 84 u32 retire_when; 85 u32 retire_delay; 86 87 /* not defined IEEE Std 802.1X-2010 */ 88 struct ieee802_1x_kay *kay; 89 }; 90 91 static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, 92 void *timeout_ctx); 93 static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, 94 void *timeout_ctx); 95 96 97 static int changed_cipher(struct ieee802_1x_cp_sm *sm) 98 { 99 return sm->confidentiality_offset != sm->cipher_offset || 100 sm->current_cipher_suite != sm->cipher_suite; 101 } 102 103 104 static int changed_connect(struct ieee802_1x_cp_sm *sm) 105 { 106 return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm); 107 } 108 109 110 SM_STATE(CP, INIT) 111 { 112 SM_ENTRY(CP, INIT); 113 114 sm->controlled_port_enabled = FALSE; 115 secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 116 117 sm->port_valid = FALSE; 118 119 os_free(sm->lki); 120 sm->lki = NULL; 121 sm->ltx = FALSE; 122 sm->lrx = FALSE; 123 124 os_free(sm->oki); 125 sm->oki = NULL; 126 sm->otx = FALSE; 127 sm->orx = FALSE; 128 129 sm->port_enabled = TRUE; 130 sm->chgd_server = FALSE; 131 } 132 133 134 SM_STATE(CP, CHANGE) 135 { 136 SM_ENTRY(CP, CHANGE); 137 138 sm->port_valid = FALSE; 139 sm->controlled_port_enabled = FALSE; 140 secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 141 142 if (sm->lki) 143 ieee802_1x_kay_delete_sas(sm->kay, sm->lki); 144 if (sm->oki) 145 ieee802_1x_kay_delete_sas(sm->kay, sm->oki); 146 } 147 148 149 SM_STATE(CP, ALLOWED) 150 { 151 SM_ENTRY(CP, ALLOWED); 152 153 sm->protect_frames = FALSE; 154 sm->replay_protect = FALSE; 155 sm->validate_frames = Checked; 156 157 sm->port_valid = FALSE; 158 sm->controlled_port_enabled = TRUE; 159 160 secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 161 secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 162 secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 163 secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 164 secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 165 } 166 167 168 SM_STATE(CP, AUTHENTICATED) 169 { 170 SM_ENTRY(CP, AUTHENTICATED); 171 172 sm->protect_frames = FALSE; 173 sm->replay_protect = FALSE; 174 sm->validate_frames = Checked; 175 176 sm->port_valid = FALSE; 177 sm->controlled_port_enabled = TRUE; 178 179 secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 180 secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 181 secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 182 secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 183 secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 184 } 185 186 187 SM_STATE(CP, SECURED) 188 { 189 SM_ENTRY(CP, SECURED); 190 191 sm->chgd_server = FALSE; 192 193 sm->protect_frames = sm->kay->macsec_protect; 194 sm->replay_protect = sm->kay->macsec_replay_protect; 195 sm->validate_frames = sm->kay->macsec_validate; 196 197 /* NOTE: now no other than default cipher suite (AES-GCM-128) */ 198 sm->current_cipher_suite = sm->cipher_suite; 199 secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite); 200 201 sm->confidentiality_offset = sm->cipher_offset; 202 203 sm->port_valid = TRUE; 204 205 secy_cp_control_confidentiality_offset(sm->kay, 206 sm->confidentiality_offset); 207 secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 208 secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 209 secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 210 secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 211 } 212 213 214 SM_STATE(CP, RECEIVE) 215 { 216 SM_ENTRY(CP, RECEIVE); 217 /* RECEIVE state machine not keep with Figure 12-2 in 218 * IEEE Std 802.1X-2010 */ 219 sm->oki = sm->lki; 220 sm->oan = sm->lan; 221 sm->otx = sm->ltx; 222 sm->orx = sm->lrx; 223 ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, 224 sm->otx, sm->orx); 225 226 sm->lki = os_malloc(sizeof(*sm->lki)); 227 if (!sm->lki) { 228 wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__); 229 return; 230 } 231 os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki)); 232 sm->lan = sm->distributed_an; 233 sm->ltx = FALSE; 234 sm->lrx = FALSE; 235 ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 236 sm->ltx, sm->lrx); 237 ieee802_1x_kay_create_sas(sm->kay, sm->lki); 238 ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki); 239 sm->new_sak = FALSE; 240 sm->all_receiving = FALSE; 241 } 242 243 244 SM_STATE(CP, RECEIVING) 245 { 246 SM_ENTRY(CP, RECEIVING); 247 248 sm->lrx = TRUE; 249 ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 250 sm->ltx, sm->lrx); 251 sm->transmit_when = sm->transmit_delay; 252 eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL); 253 eloop_register_timeout(sm->transmit_when / 1000, 0, 254 ieee802_1x_cp_transmit_when_timeout, sm, NULL); 255 /* the electedSelf have been set before CP entering to RECEIVING 256 * but the CP will transmit from RECEIVING to READY under 257 * the !electedSelf when KaY is not key server */ 258 ieee802_1x_cp_sm_step(sm); 259 sm->using_receive_sas = FALSE; 260 sm->server_transmitting = FALSE; 261 } 262 263 264 SM_STATE(CP, READY) 265 { 266 SM_ENTRY(CP, READY); 267 268 ieee802_1x_kay_enable_new_info(sm->kay); 269 } 270 271 272 SM_STATE(CP, TRANSMIT) 273 { 274 SM_ENTRY(CP, TRANSMIT); 275 276 sm->controlled_port_enabled = TRUE; 277 secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 278 sm->ltx = TRUE; 279 ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 280 sm->ltx, sm->lrx); 281 ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki); 282 sm->all_receiving = FALSE; 283 sm->server_transmitting = FALSE; 284 } 285 286 287 SM_STATE(CP, TRANSMITTING) 288 { 289 SM_ENTRY(CP, TRANSMITTING); 290 sm->retire_when = sm->orx ? sm->retire_delay : 0; 291 sm->otx = FALSE; 292 ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, 293 sm->otx, sm->orx); 294 ieee802_1x_kay_enable_new_info(sm->kay); 295 eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL); 296 eloop_register_timeout(sm->retire_when / 1000, 0, 297 ieee802_1x_cp_retire_when_timeout, sm, NULL); 298 sm->using_transmit_sa = FALSE; 299 } 300 301 302 SM_STATE(CP, ABANDON) 303 { 304 SM_ENTRY(CP, ABANDON); 305 sm->lrx = FALSE; 306 ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 307 sm->ltx, sm->lrx); 308 ieee802_1x_kay_delete_sas(sm->kay, sm->lki); 309 310 os_free(sm->lki); 311 sm->lki = NULL; 312 ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, 313 sm->ltx, sm->lrx); 314 sm->new_sak = FALSE; 315 } 316 317 318 SM_STATE(CP, RETIRE) 319 { 320 SM_ENTRY(CP, RETIRE); 321 /* RETIRE state machine not keep with Figure 12-2 in 322 * IEEE Std 802.1X-2010 */ 323 os_free(sm->oki); 324 sm->oki = NULL; 325 sm->orx = FALSE; 326 sm->otx = FALSE; 327 ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, 328 sm->otx, sm->orx); 329 } 330 331 332 /** 333 * CP state machine handler entry 334 */ 335 SM_STEP(CP) 336 { 337 if (!sm->port_enabled) 338 SM_ENTER(CP, INIT); 339 340 switch (sm->CP_state) { 341 case CP_BEGIN: 342 SM_ENTER(CP, INIT); 343 break; 344 345 case CP_INIT: 346 SM_ENTER(CP, CHANGE); 347 break; 348 349 case CP_CHANGE: 350 if (sm->connect == UNAUTHENTICATED) 351 SM_ENTER(CP, ALLOWED); 352 else if (sm->connect == AUTHENTICATED) 353 SM_ENTER(CP, AUTHENTICATED); 354 else if (sm->connect == SECURE) 355 SM_ENTER(CP, SECURED); 356 break; 357 358 case CP_ALLOWED: 359 if (sm->connect != UNAUTHENTICATED) 360 SM_ENTER(CP, CHANGE); 361 break; 362 363 case CP_AUTHENTICATED: 364 if (sm->connect != AUTHENTICATED) 365 SM_ENTER(CP, CHANGE); 366 break; 367 368 case CP_SECURED: 369 if (changed_connect(sm)) 370 SM_ENTER(CP, CHANGE); 371 else if (sm->new_sak) 372 SM_ENTER(CP, RECEIVE); 373 break; 374 375 case CP_RECEIVE: 376 if (sm->using_receive_sas) 377 SM_ENTER(CP, RECEIVING); 378 break; 379 380 case CP_RECEIVING: 381 if (sm->new_sak || changed_connect(sm)) 382 SM_ENTER(CP, ABANDON); 383 if (!sm->elected_self) 384 SM_ENTER(CP, READY); 385 if (sm->elected_self && 386 (sm->all_receiving || !sm->transmit_when)) 387 SM_ENTER(CP, TRANSMIT); 388 break; 389 390 case CP_TRANSMIT: 391 if (sm->using_transmit_sa) 392 SM_ENTER(CP, TRANSMITTING); 393 break; 394 395 case CP_TRANSMITTING: 396 if (!sm->retire_when || changed_connect(sm)) 397 SM_ENTER(CP, RETIRE); 398 break; 399 400 case CP_RETIRE: 401 if (changed_connect(sm)) 402 SM_ENTER(CP, CHANGE); 403 else if (sm->new_sak) 404 SM_ENTER(CP, RECEIVE); 405 break; 406 407 case CP_READY: 408 if (sm->new_sak || changed_connect(sm)) 409 SM_ENTER(CP, RECEIVE); 410 if (sm->server_transmitting) 411 SM_ENTER(CP, TRANSMIT); 412 break; 413 case CP_ABANDON: 414 if (changed_connect(sm)) 415 SM_ENTER(CP, RETIRE); 416 else if (sm->new_sak) 417 SM_ENTER(CP, RECEIVE); 418 break; 419 default: 420 wpa_printf(MSG_ERROR, "CP: the state machine is not defined"); 421 break; 422 } 423 } 424 425 426 /** 427 * ieee802_1x_cp_sm_init - 428 */ 429 struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay) 430 { 431 struct ieee802_1x_cp_sm *sm; 432 433 sm = os_zalloc(sizeof(*sm)); 434 if (sm == NULL) { 435 wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__); 436 return NULL; 437 } 438 439 sm->kay = kay; 440 441 sm->port_valid = FALSE; 442 443 sm->chgd_server = FALSE; 444 445 sm->protect_frames = kay->macsec_protect; 446 sm->validate_frames = kay->macsec_validate; 447 sm->replay_protect = kay->macsec_replay_protect; 448 sm->replay_window = kay->macsec_replay_window; 449 450 sm->controlled_port_enabled = FALSE; 451 452 sm->lki = NULL; 453 sm->lrx = FALSE; 454 sm->ltx = FALSE; 455 sm->oki = NULL; 456 sm->orx = FALSE; 457 sm->otx = FALSE; 458 459 sm->current_cipher_suite = default_cs_id; 460 sm->cipher_suite = default_cs_id; 461 sm->cipher_offset = CONFIDENTIALITY_OFFSET_0; 462 sm->confidentiality_offset = sm->cipher_offset; 463 sm->transmit_delay = MKA_LIFE_TIME; 464 sm->retire_delay = MKA_SAK_RETIRE_TIME; 465 sm->CP_state = CP_BEGIN; 466 sm->changed = FALSE; 467 sm->authorization_data = NULL; 468 469 wpa_printf(MSG_DEBUG, "CP: state machine created"); 470 471 secy_cp_control_protect_frames(sm->kay, sm->protect_frames); 472 secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt); 473 secy_cp_control_validate_frames(sm->kay, sm->validate_frames); 474 secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); 475 secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); 476 secy_cp_control_confidentiality_offset(sm->kay, 477 sm->confidentiality_offset); 478 479 SM_ENTER(CP, INIT); 480 SM_STEP_RUN(CP); 481 482 return sm; 483 } 484 485 486 static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm) 487 { 488 enum cp_states prev_state; 489 int i; 490 491 for (i = 0; i < 100; i++) { 492 prev_state = sm->CP_state; 493 SM_STEP_RUN(CP); 494 if (prev_state == sm->CP_state) 495 break; 496 } 497 } 498 499 500 static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx) 501 { 502 struct ieee802_1x_cp_sm *sm = eloop_ctx; 503 ieee802_1x_cp_step_run(sm); 504 } 505 506 507 /** 508 * ieee802_1x_cp_sm_deinit - 509 */ 510 void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm) 511 { 512 wpa_printf(MSG_DEBUG, "CP: state machine removed"); 513 if (!sm) 514 return; 515 516 eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL); 517 eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL); 518 eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL); 519 os_free(sm->lki); 520 os_free(sm->oki); 521 os_free(sm->authorization_data); 522 os_free(sm); 523 } 524 525 526 /** 527 * ieee802_1x_cp_connect_pending 528 */ 529 void ieee802_1x_cp_connect_pending(void *cp_ctx) 530 { 531 struct ieee802_1x_cp_sm *sm = cp_ctx; 532 533 sm->connect = PENDING; 534 } 535 536 537 /** 538 * ieee802_1x_cp_connect_unauthenticated 539 */ 540 void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx) 541 { 542 struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx; 543 544 sm->connect = UNAUTHENTICATED; 545 } 546 547 548 /** 549 * ieee802_1x_cp_connect_authenticated 550 */ 551 void ieee802_1x_cp_connect_authenticated(void *cp_ctx) 552 { 553 struct ieee802_1x_cp_sm *sm = cp_ctx; 554 555 sm->connect = AUTHENTICATED; 556 } 557 558 559 /** 560 * ieee802_1x_cp_connect_secure 561 */ 562 void ieee802_1x_cp_connect_secure(void *cp_ctx) 563 { 564 struct ieee802_1x_cp_sm *sm = cp_ctx; 565 566 sm->connect = SECURE; 567 } 568 569 570 /** 571 * ieee802_1x_cp_set_chgdserver - 572 */ 573 void ieee802_1x_cp_signal_chgdserver(void *cp_ctx) 574 { 575 struct ieee802_1x_cp_sm *sm = cp_ctx; 576 577 sm->chgd_server = TRUE; 578 } 579 580 581 /** 582 * ieee802_1x_cp_set_electedself - 583 */ 584 void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status) 585 { 586 struct ieee802_1x_cp_sm *sm = cp_ctx; 587 sm->elected_self = status; 588 } 589 590 591 /** 592 * ieee802_1x_cp_set_authorizationdata - 593 */ 594 void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len) 595 { 596 struct ieee802_1x_cp_sm *sm = cp_ctx; 597 os_free(sm->authorization_data); 598 sm->authorization_data = os_zalloc(len); 599 if (sm->authorization_data) 600 os_memcpy(sm->authorization_data, pdata, len); 601 } 602 603 604 /** 605 * ieee802_1x_cp_set_ciphersuite - 606 */ 607 void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs) 608 { 609 struct ieee802_1x_cp_sm *sm = cp_ctx; 610 sm->cipher_suite = cs; 611 } 612 613 614 /** 615 * ieee802_1x_cp_set_offset - 616 */ 617 void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset) 618 { 619 struct ieee802_1x_cp_sm *sm = cp_ctx; 620 sm->cipher_offset = offset; 621 } 622 623 624 /** 625 * ieee802_1x_cp_signal_newsak - 626 */ 627 void ieee802_1x_cp_signal_newsak(void *cp_ctx) 628 { 629 struct ieee802_1x_cp_sm *sm = cp_ctx; 630 sm->new_sak = TRUE; 631 } 632 633 634 /** 635 * ieee802_1x_cp_set_distributedki - 636 */ 637 void ieee802_1x_cp_set_distributedki(void *cp_ctx, 638 const struct ieee802_1x_mka_ki *dki) 639 { 640 struct ieee802_1x_cp_sm *sm = cp_ctx; 641 os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki)); 642 } 643 644 645 /** 646 * ieee802_1x_cp_set_distributedan - 647 */ 648 void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an) 649 { 650 struct ieee802_1x_cp_sm *sm = cp_ctx; 651 sm->distributed_an = an; 652 } 653 654 655 /** 656 * ieee802_1x_cp_set_usingreceivesas - 657 */ 658 void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status) 659 { 660 struct ieee802_1x_cp_sm *sm = cp_ctx; 661 sm->using_receive_sas = status; 662 } 663 664 665 /** 666 * ieee802_1x_cp_set_allreceiving - 667 */ 668 void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status) 669 { 670 struct ieee802_1x_cp_sm *sm = cp_ctx; 671 sm->all_receiving = status; 672 } 673 674 675 /** 676 * ieee802_1x_cp_set_servertransmitting - 677 */ 678 void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status) 679 { 680 struct ieee802_1x_cp_sm *sm = cp_ctx; 681 sm->server_transmitting = status; 682 } 683 684 685 /** 686 * ieee802_1x_cp_set_usingtransmitsas - 687 */ 688 void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status) 689 { 690 struct ieee802_1x_cp_sm *sm = cp_ctx; 691 sm->using_transmit_sa = status; 692 } 693 694 695 /** 696 * ieee802_1x_cp_sm_step - Advance EAPOL state machines 697 * @sm: EAPOL state machine 698 * 699 * This function is called to advance CP state machines after any change 700 * that could affect their state. 701 */ 702 void ieee802_1x_cp_sm_step(void *cp_ctx) 703 { 704 /* 705 * Run ieee802_1x_cp_step_run from a registered timeout 706 * to make sure that other possible timeouts/events are processed 707 * and to avoid long function call chains. 708 */ 709 struct ieee802_1x_cp_sm *sm = cp_ctx; 710 eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL); 711 eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL); 712 } 713 714 715 static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, 716 void *timeout_ctx) 717 { 718 struct ieee802_1x_cp_sm *sm = eloop_ctx; 719 sm->retire_when = 0; 720 ieee802_1x_cp_step_run(sm); 721 } 722 723 724 static void 725 ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx) 726 { 727 struct ieee802_1x_cp_sm *sm = eloop_ctx; 728 sm->transmit_when = 0; 729 ieee802_1x_cp_step_run(sm); 730 } 731