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