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