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 23static u64 default_cs_id = CS_ID_GCM_AES_128; 24 25/* The variable defined in clause 12 in IEEE Std 802.1X-2010 */ 26enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE }; 27 28struct 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 89static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, 90 void *timeout_ctx); 91static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, 92 void *timeout_ctx); 93 94 95static 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 102static int changed_connect(struct ieee802_1x_cp_sm *sm) 103{ 104 return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm); 105} 106 107 108SM_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 132SM_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 147SM_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 166SM_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 185SM_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 212SM_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 246SM_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 266SM_STATE(CP, READY) 267{ 268 SM_ENTRY(CP, READY); 269 270 ieee802_1x_kay_enable_new_info(sm->kay); 271} 272 273 274SM_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 289SM_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 304SM_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 320SM_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 */ 340SM_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 */ 435struct 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 490static 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 504static 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 */ 514void 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 */ 532void 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 */ 543void 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 */ 554void 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 */ 565void 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 */ 576void 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 */ 587void 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 */ 597void 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 */ 607void 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 */ 617void 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 */ 627void 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 */ 638void 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 */ 648void 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 */ 658void 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 */ 668void 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 */ 678void 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 */ 692void 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 705static 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 714static void 715ieee802_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