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 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 91static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, 92 void *timeout_ctx); 93static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, 94 void *timeout_ctx); 95 96 97static 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 104static int changed_connect(struct ieee802_1x_cp_sm *sm) 105{ 106 return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm); 107} 108 109 110SM_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 134SM_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 149SM_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 168SM_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 187SM_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 214SM_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 244SM_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 264SM_STATE(CP, READY) 265{ 266 SM_ENTRY(CP, READY); 267 268 ieee802_1x_kay_enable_new_info(sm->kay); 269} 270 271 272SM_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 287SM_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 302SM_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 318SM_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 */ 335SM_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 */ 429struct 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 486static 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 500static 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 */ 510void 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 */ 529void 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 */ 540void 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 */ 551void 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 */ 562void 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 */ 573void 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 */ 584void 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 */ 594void 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 */ 607void 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 */ 617void 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 */ 627void 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 */ 637void 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 */ 648void 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 */ 658void 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 */ 668void 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 */ 678void 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 */ 688void 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 */ 702void 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 715static 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 724static void 725ieee802_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