| /* |
| * IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine |
| * Copyright (c) 2013-2014, Qualcomm Atheros, Inc. |
| * |
| * This software may be distributed under the terms of the BSD license. |
| * See README for more details. |
| */ |
| |
| #include "utils/includes.h" |
| |
| #include "utils/common.h" |
| #include "utils/eloop.h" |
| #include "common/defs.h" |
| #include "common/ieee802_1x_defs.h" |
| #include "utils/state_machine.h" |
| #include "ieee802_1x_kay.h" |
| #include "ieee802_1x_secy_ops.h" |
| #include "pae/ieee802_1x_cp.h" |
| |
| #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm |
| #define STATE_MACHINE_DEBUG_PREFIX "CP" |
| |
| static u8 default_cs_id[] = CS_ID_GCM_AES_128; |
| |
| /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */ |
| enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE }; |
| |
| struct ieee802_1x_cp_sm { |
| enum cp_states { |
| CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED, |
| CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT, |
| CP_TRANSMITTING, CP_ABANDON, CP_RETIRE |
| } CP_state; |
| Boolean changed; |
| |
| /* CP -> Client */ |
| Boolean port_valid; |
| |
| /* Logon -> CP */ |
| enum connect_type connect; |
| u8 *authorization_data; |
| |
| /* KaY -> CP */ |
| Boolean chgd_server; /* clear by CP */ |
| Boolean elected_self; |
| u8 *authorization_data1; |
| enum confidentiality_offset cipher_offset; |
| u8 *cipher_suite; |
| Boolean new_sak; /* clear by CP */ |
| struct ieee802_1x_mka_ki distributed_ki; |
| u8 distributed_an; |
| Boolean using_receive_sas; |
| Boolean all_receiving; |
| Boolean server_transmitting; |
| Boolean using_transmit_sa; |
| |
| /* CP -> KaY */ |
| struct ieee802_1x_mka_ki *lki; |
| u8 lan; |
| Boolean ltx; |
| Boolean lrx; |
| struct ieee802_1x_mka_ki *oki; |
| u8 oan; |
| Boolean otx; |
| Boolean orx; |
| |
| /* CP -> SecY */ |
| Boolean protect_frames; |
| enum validate_frames validate_frames; |
| |
| Boolean replay_protect; |
| u32 replay_window; |
| |
| u8 *current_cipher_suite; |
| enum confidentiality_offset confidentiality_offset; |
| Boolean controlled_port_enabled; |
| |
| /* SecY -> CP */ |
| Boolean port_enabled; /* SecY->CP */ |
| |
| /* private */ |
| u32 transmit_when; |
| u32 transmit_delay; |
| u32 retire_when; |
| u32 retire_delay; |
| |
| /* not defined IEEE Std 802.1X-2010 */ |
| struct ieee802_1x_kay *kay; |
| }; |
| |
| static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, |
| void *timeout_ctx); |
| static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, |
| void *timeout_ctx); |
| |
| |
| static int changed_cipher(struct ieee802_1x_cp_sm *sm) |
| { |
| return sm->confidentiality_offset != sm->cipher_offset || |
| os_memcmp(sm->current_cipher_suite, sm->cipher_suite, |
| CS_ID_LEN) != 0; |
| } |
| |
| |
| static int changed_connect(struct ieee802_1x_cp_sm *sm) |
| { |
| return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm); |
| } |
| |
| |
| SM_STATE(CP, INIT) |
| { |
| SM_ENTRY(CP, INIT); |
| |
| sm->controlled_port_enabled = FALSE; |
| secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); |
| |
| sm->port_valid = FALSE; |
| |
| os_free(sm->lki); |
| sm->lki = NULL; |
| sm->ltx = FALSE; |
| sm->lrx = FALSE; |
| |
| os_free(sm->oki); |
| sm->oki = NULL; |
| sm->otx = FALSE; |
| sm->orx = FALSE; |
| |
| sm->port_enabled = TRUE; |
| sm->chgd_server = FALSE; |
| } |
| |
| |
| SM_STATE(CP, CHANGE) |
| { |
| SM_ENTRY(CP, CHANGE); |
| |
| sm->port_valid = FALSE; |
| sm->controlled_port_enabled = FALSE; |
| secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); |
| |
| if (sm->lki) |
| ieee802_1x_kay_delete_sas(sm->kay, sm->lki); |
| if (sm->oki) |
| ieee802_1x_kay_delete_sas(sm->kay, sm->oki); |
| } |
| |
| |
| SM_STATE(CP, ALLOWED) |
| { |
| SM_ENTRY(CP, ALLOWED); |
| |
| sm->protect_frames = FALSE; |
| sm->replay_protect = FALSE; |
| sm->validate_frames = Checked; |
| |
| sm->port_valid = FALSE; |
| sm->controlled_port_enabled = TRUE; |
| |
| secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); |
| secy_cp_control_protect_frames(sm->kay, sm->protect_frames); |
| secy_cp_control_validate_frames(sm->kay, sm->validate_frames); |
| secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); |
| } |
| |
| |
| SM_STATE(CP, AUTHENTICATED) |
| { |
| SM_ENTRY(CP, AUTHENTICATED); |
| |
| sm->protect_frames = FALSE; |
| sm->replay_protect = FALSE; |
| sm->validate_frames = Checked; |
| |
| sm->port_valid = FALSE; |
| sm->controlled_port_enabled = TRUE; |
| |
| secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); |
| secy_cp_control_protect_frames(sm->kay, sm->protect_frames); |
| secy_cp_control_validate_frames(sm->kay, sm->validate_frames); |
| secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); |
| } |
| |
| |
| SM_STATE(CP, SECURED) |
| { |
| struct ieee802_1x_cp_conf conf; |
| |
| SM_ENTRY(CP, SECURED); |
| |
| sm->chgd_server = FALSE; |
| |
| ieee802_1x_kay_cp_conf(sm->kay, &conf); |
| sm->protect_frames = conf.protect; |
| sm->replay_protect = conf.replay_protect; |
| sm->validate_frames = conf.validate; |
| |
| /* NOTE: now no other than default cipher suiter(AES-GCM-128) */ |
| os_memcpy(sm->current_cipher_suite, sm->cipher_suite, CS_ID_LEN); |
| secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite, |
| CS_ID_LEN); |
| |
| sm->confidentiality_offset = sm->cipher_offset; |
| |
| sm->port_valid = TRUE; |
| |
| secy_cp_control_confidentiality_offset(sm->kay, |
| sm->confidentiality_offset); |
| secy_cp_control_protect_frames(sm->kay, sm->protect_frames); |
| secy_cp_control_validate_frames(sm->kay, sm->validate_frames); |
| secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); |
| } |
| |
| |
| SM_STATE(CP, RECEIVE) |
| { |
| SM_ENTRY(CP, RECEIVE); |
| /* RECEIVE state machine not keep with Figure 12-2 in |
| * IEEE Std 802.1X-2010 */ |
| sm->oki = sm->lki; |
| sm->oan = sm->lan; |
| sm->otx = sm->ltx; |
| sm->orx = sm->lrx; |
| ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, |
| sm->otx, sm->orx); |
| |
| sm->lki = os_malloc(sizeof(*sm->lki)); |
| if (!sm->lki) { |
| wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__); |
| return; |
| } |
| os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki)); |
| sm->lan = sm->distributed_an; |
| sm->ltx = FALSE; |
| sm->lrx = FALSE; |
| ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, |
| sm->ltx, sm->lrx); |
| ieee802_1x_kay_create_sas(sm->kay, sm->lki); |
| ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki); |
| sm->new_sak = FALSE; |
| sm->all_receiving = FALSE; |
| } |
| |
| |
| SM_STATE(CP, RECEIVING) |
| { |
| SM_ENTRY(CP, RECEIVING); |
| |
| sm->lrx = TRUE; |
| ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, |
| sm->ltx, sm->lrx); |
| sm->transmit_when = sm->transmit_delay; |
| eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL); |
| eloop_register_timeout(sm->transmit_when / 1000, 0, |
| ieee802_1x_cp_transmit_when_timeout, sm, NULL); |
| /* the electedSelf have been set before CP entering to RECEIVING |
| * but the CP will transmit from RECEIVING to READY under |
| * the !electedSelf when KaY is not key server */ |
| ieee802_1x_cp_sm_step(sm); |
| sm->using_receive_sas = FALSE; |
| sm->server_transmitting = FALSE; |
| } |
| |
| |
| SM_STATE(CP, READY) |
| { |
| SM_ENTRY(CP, READY); |
| |
| ieee802_1x_kay_enable_new_info(sm->kay); |
| } |
| |
| |
| SM_STATE(CP, TRANSMIT) |
| { |
| SM_ENTRY(CP, TRANSMIT); |
| |
| sm->controlled_port_enabled = TRUE; |
| secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); |
| sm->ltx = TRUE; |
| ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, |
| sm->ltx, sm->lrx); |
| ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki); |
| sm->all_receiving = FALSE; |
| sm->server_transmitting = FALSE; |
| } |
| |
| |
| SM_STATE(CP, TRANSMITTING) |
| { |
| SM_ENTRY(CP, TRANSMITTING); |
| sm->retire_when = sm->orx ? sm->retire_delay : 0; |
| sm->otx = FALSE; |
| ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, |
| sm->otx, sm->orx); |
| ieee802_1x_kay_enable_new_info(sm->kay); |
| eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL); |
| eloop_register_timeout(sm->retire_when / 1000, 0, |
| ieee802_1x_cp_retire_when_timeout, sm, NULL); |
| sm->using_transmit_sa = FALSE; |
| } |
| |
| |
| SM_STATE(CP, ABANDON) |
| { |
| SM_ENTRY(CP, ABANDON); |
| sm->lrx = FALSE; |
| ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, |
| sm->ltx, sm->lrx); |
| ieee802_1x_kay_delete_sas(sm->kay, sm->lki); |
| |
| os_free(sm->lki); |
| sm->lki = NULL; |
| ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan, |
| sm->ltx, sm->lrx); |
| sm->new_sak = FALSE; |
| } |
| |
| |
| SM_STATE(CP, RETIRE) |
| { |
| SM_ENTRY(CP, RETIRE); |
| /* RETIRE state machine not keep with Figure 12-2 in |
| * IEEE Std 802.1X-2010 */ |
| os_free(sm->oki); |
| sm->oki = NULL; |
| sm->orx = FALSE; |
| sm->otx = FALSE; |
| ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan, |
| sm->otx, sm->orx); |
| } |
| |
| |
| /** |
| * CP state machine handler entry |
| */ |
| SM_STEP(CP) |
| { |
| if (!sm->port_enabled) |
| SM_ENTER(CP, INIT); |
| |
| switch (sm->CP_state) { |
| case CP_BEGIN: |
| SM_ENTER(CP, INIT); |
| break; |
| |
| case CP_INIT: |
| SM_ENTER(CP, CHANGE); |
| break; |
| |
| case CP_CHANGE: |
| if (sm->connect == UNAUTHENTICATED) |
| SM_ENTER(CP, ALLOWED); |
| else if (sm->connect == AUTHENTICATED) |
| SM_ENTER(CP, AUTHENTICATED); |
| else if (sm->connect == SECURE) |
| SM_ENTER(CP, SECURED); |
| break; |
| |
| case CP_ALLOWED: |
| if (sm->connect != UNAUTHENTICATED) |
| SM_ENTER(CP, CHANGE); |
| break; |
| |
| case CP_AUTHENTICATED: |
| if (sm->connect != AUTHENTICATED) |
| SM_ENTER(CP, CHANGE); |
| break; |
| |
| case CP_SECURED: |
| if (changed_connect(sm)) |
| SM_ENTER(CP, CHANGE); |
| else if (sm->new_sak) |
| SM_ENTER(CP, RECEIVE); |
| break; |
| |
| case CP_RECEIVE: |
| if (sm->using_receive_sas) |
| SM_ENTER(CP, RECEIVING); |
| break; |
| |
| case CP_RECEIVING: |
| if (sm->new_sak || changed_connect(sm)) |
| SM_ENTER(CP, ABANDON); |
| if (!sm->elected_self) |
| SM_ENTER(CP, READY); |
| if (sm->elected_self && |
| (sm->all_receiving || !sm->transmit_when)) |
| SM_ENTER(CP, TRANSMIT); |
| break; |
| |
| case CP_TRANSMIT: |
| if (sm->using_transmit_sa) |
| SM_ENTER(CP, TRANSMITTING); |
| break; |
| |
| case CP_TRANSMITTING: |
| if (!sm->retire_when || changed_connect(sm)) |
| SM_ENTER(CP, RETIRE); |
| break; |
| |
| case CP_RETIRE: |
| if (changed_connect(sm)) |
| SM_ENTER(CP, CHANGE); |
| else if (sm->new_sak) |
| SM_ENTER(CP, RECEIVE); |
| break; |
| |
| case CP_READY: |
| if (sm->new_sak || changed_connect(sm)) |
| SM_ENTER(CP, RECEIVE); |
| if (sm->server_transmitting) |
| SM_ENTER(CP, TRANSMIT); |
| break; |
| case CP_ABANDON: |
| if (changed_connect(sm)) |
| SM_ENTER(CP, RETIRE); |
| else if (sm->new_sak) |
| SM_ENTER(CP, RECEIVE); |
| break; |
| default: |
| wpa_printf(MSG_ERROR, "CP: the state machine is not defined"); |
| break; |
| } |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_sm_init - |
| */ |
| struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init( |
| struct ieee802_1x_kay *kay, |
| struct ieee802_1x_cp_conf *pcp_conf) |
| { |
| struct ieee802_1x_cp_sm *sm; |
| |
| sm = os_zalloc(sizeof(*sm)); |
| if (sm == NULL) { |
| wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__); |
| return NULL; |
| } |
| |
| sm->kay = kay; |
| |
| sm->port_valid = FALSE; |
| |
| sm->chgd_server = FALSE; |
| |
| sm->protect_frames = pcp_conf->protect; |
| sm->validate_frames = pcp_conf->validate; |
| sm->replay_protect = pcp_conf->replay_protect; |
| sm->replay_window = pcp_conf->replay_window; |
| |
| sm->controlled_port_enabled = FALSE; |
| |
| sm->lki = NULL; |
| sm->lrx = FALSE; |
| sm->ltx = FALSE; |
| sm->oki = NULL; |
| sm->orx = FALSE; |
| sm->otx = FALSE; |
| |
| sm->cipher_suite = os_zalloc(CS_ID_LEN); |
| sm->current_cipher_suite = os_zalloc(CS_ID_LEN); |
| if (!sm->cipher_suite || !sm->current_cipher_suite) { |
| wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__); |
| os_free(sm->cipher_suite); |
| os_free(sm->current_cipher_suite); |
| os_free(sm); |
| return NULL; |
| } |
| os_memcpy(sm->current_cipher_suite, default_cs_id, CS_ID_LEN); |
| os_memcpy(sm->cipher_suite, default_cs_id, CS_ID_LEN); |
| sm->cipher_offset = CONFIDENTIALITY_OFFSET_0; |
| sm->confidentiality_offset = sm->cipher_offset; |
| sm->transmit_delay = MKA_LIFE_TIME; |
| sm->retire_delay = MKA_SAK_RETIRE_TIME; |
| sm->CP_state = CP_BEGIN; |
| sm->changed = FALSE; |
| sm->authorization_data = NULL; |
| |
| wpa_printf(MSG_DEBUG, "CP: state machine created"); |
| |
| secy_cp_control_protect_frames(sm->kay, sm->protect_frames); |
| secy_cp_control_validate_frames(sm->kay, sm->validate_frames); |
| secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window); |
| secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled); |
| secy_cp_control_confidentiality_offset(sm->kay, |
| sm->confidentiality_offset); |
| |
| SM_ENTER(CP, INIT); |
| SM_STEP_RUN(CP); |
| |
| return sm; |
| } |
| |
| |
| static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm) |
| { |
| enum cp_states prev_state; |
| int i; |
| |
| for (i = 0; i < 100; i++) { |
| prev_state = sm->CP_state; |
| SM_STEP_RUN(CP); |
| if (prev_state == sm->CP_state) |
| break; |
| } |
| } |
| |
| |
| static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = eloop_ctx; |
| ieee802_1x_cp_step_run(sm); |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_sm_deinit - |
| */ |
| void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm) |
| { |
| wpa_printf(MSG_DEBUG, "CP: state machine removed"); |
| if (!sm) |
| return; |
| |
| eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL); |
| eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL); |
| eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL); |
| os_free(sm->lki); |
| os_free(sm->oki); |
| os_free(sm->cipher_suite); |
| os_free(sm->current_cipher_suite); |
| os_free(sm->authorization_data); |
| os_free(sm); |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_connect_pending |
| */ |
| void ieee802_1x_cp_connect_pending(void *cp_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| |
| sm->connect = PENDING; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_connect_unauthenticated |
| */ |
| void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx; |
| |
| sm->connect = UNAUTHENTICATED; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_connect_authenticated |
| */ |
| void ieee802_1x_cp_connect_authenticated(void *cp_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| |
| sm->connect = AUTHENTICATED; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_connect_secure |
| */ |
| void ieee802_1x_cp_connect_secure(void *cp_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| |
| sm->connect = SECURE; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_chgdserver - |
| */ |
| void ieee802_1x_cp_signal_chgdserver(void *cp_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| |
| sm->chgd_server = TRUE; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_electedself - |
| */ |
| void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->elected_self = status; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_authorizationdata - |
| */ |
| void ieee802_1x_cp_set_authorizationdata(void *cp_ctx, u8 *pdata, int len) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| os_free(sm->authorization_data); |
| sm->authorization_data = os_zalloc(len); |
| if (sm->authorization_data) |
| os_memcpy(sm->authorization_data, pdata, len); |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_ciphersuite - |
| */ |
| void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, void *pid) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| os_memcpy(sm->cipher_suite, pid, CS_ID_LEN); |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_offset - |
| */ |
| void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->cipher_offset = offset; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_signal_newsak - |
| */ |
| void ieee802_1x_cp_signal_newsak(void *cp_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->new_sak = TRUE; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_distributedki - |
| */ |
| void ieee802_1x_cp_set_distributedki(void *cp_ctx, |
| const struct ieee802_1x_mka_ki *dki) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki)); |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_distributedan - |
| */ |
| void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->distributed_an = an; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_usingreceivesas - |
| */ |
| void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->using_receive_sas = status; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_allreceiving - |
| */ |
| void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->all_receiving = status; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_servertransmitting - |
| */ |
| void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->server_transmitting = status; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_set_usingtransmitsas - |
| */ |
| void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status) |
| { |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| sm->using_transmit_sa = status; |
| } |
| |
| |
| /** |
| * ieee802_1x_cp_sm_step - Advance EAPOL state machines |
| * @sm: EAPOL state machine |
| * |
| * This function is called to advance CP state machines after any change |
| * that could affect their state. |
| */ |
| void ieee802_1x_cp_sm_step(void *cp_ctx) |
| { |
| /* |
| * Run ieee802_1x_cp_step_run from a registered timeout |
| * to make sure that other possible timeouts/events are processed |
| * and to avoid long function call chains. |
| */ |
| struct ieee802_1x_cp_sm *sm = cp_ctx; |
| eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL); |
| eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL); |
| } |
| |
| |
| static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx, |
| void *timeout_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = eloop_ctx; |
| sm->retire_when = 0; |
| ieee802_1x_cp_step_run(sm); |
| } |
| |
| |
| static void |
| ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx) |
| { |
| struct ieee802_1x_cp_sm *sm = eloop_ctx; |
| sm->transmit_when = 0; |
| ieee802_1x_cp_step_run(sm); |
| } |