/** * eapol_sm_step - EAPOL state machine step function * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init() * * This function is called to notify the state machine about changed external * variables. It will step through the EAPOL state machines in loop to process * all triggered state changes. */ void eapol_sm_step(struct eapol_sm *sm) { int i; /* In theory, it should be ok to run this in loop until !changed. * However, it is better to use a limit on number of iterations to * allow events (e.g., SIGTERM) to stop the program cleanly if the * state machine were to generate a busy loop. */ for (i = 0; i < 100; i++) { sm->changed = FALSE; SM_STEP_RUN(SUPP_PAE); SM_STEP_RUN(KEY_RX); SM_STEP_RUN(SUPP_BE); if (eap_peer_sm_step(sm->eap)) sm->changed = TRUE; if (!sm->changed) break; } if (sm->changed) { /* restart EAPOL state machine step from timeout call in order * to allow other events to be processed. */ eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm); eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm); } if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) { int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0; sm->cb_status = EAPOL_CB_IN_PROGRESS; sm->ctx->cb(sm, success, sm->ctx->cb_ctx); } }
/** * eap_server_sm_step - Step EAP server state machine * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() * Returns: 1 if EAP state was changed or 0 if not * * This function advances EAP state machine to a new state to match with the * current variables. This should be called whenever variables used by the EAP * state machine have changed. */ int eap_server_sm_step(struct eap_sm *sm) { int res = 0; do { sm->changed = FALSE; SM_STEP_RUN(EAP); if (sm->changed) res = 1; } while (sm->changed); return res; }
void eapol_sm_step(struct eapol_state_machine *sm) { int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx; /* FIX: could re-run eapol_sm_step from registered timeout (after * 0 sec) to make sure that other possible timeouts/events are * processed */ do { prev_auth_pae = sm->auth_pae.state; prev_be_auth = sm->be_auth.state; prev_reauth_timer = sm->reauth_timer.state; prev_auth_key_tx = sm->auth_key_tx.state; SM_STEP_RUN(AUTH_PAE); SM_STEP_RUN(BE_AUTH); SM_STEP_RUN(REAUTH_TIMER); SM_STEP_RUN(AUTH_KEY_TX); } while (prev_auth_pae != sm->auth_pae.state || prev_be_auth != sm->be_auth.state || prev_reauth_timer != sm->reauth_timer.state || prev_auth_key_tx != sm->auth_key_tx.state); }
static void eapol_sm_step_run(struct eapol_state_machine *sm) { struct eapol_authenticator *eapol = sm->eapol; u8 addr[ETH_ALEN]; unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx, prev_key_rx, prev_ctrl_dir; int max_steps = 100; os_memcpy(addr, sm->addr, ETH_ALEN); /* * Allow EAPOL state machines to run as long as there are state * changes, but exit and return here through event loop if more than * 100 steps is needed as a precaution against infinite loops inside * eloop callback. */ restart: prev_auth_pae = sm->auth_pae_state; prev_be_auth = sm->be_auth_state; prev_reauth_timer = sm->reauth_timer_state; prev_auth_key_tx = sm->auth_key_tx_state; prev_key_rx = sm->key_rx_state; prev_ctrl_dir = sm->ctrl_dir_state; SM_STEP_RUN(AUTH_PAE); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(BE_AUTH); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(REAUTH_TIMER); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(AUTH_KEY_TX); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(KEY_RX); if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr)) SM_STEP_RUN(CTRL_DIR); if (prev_auth_pae != sm->auth_pae_state || prev_be_auth != sm->be_auth_state || prev_reauth_timer != sm->reauth_timer_state || prev_auth_key_tx != sm->auth_key_tx_state || prev_key_rx != sm->key_rx_state || prev_ctrl_dir != sm->ctrl_dir_state) { if (--max_steps > 0) goto restart; /* Re-run from eloop timeout */ eapol_auth_step(sm); return; } if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) { if (eap_server_sm_step(sm->eap)) { if (--max_steps > 0) goto restart; /* Re-run from eloop timeout */ eapol_auth_step(sm); return; } /* TODO: find a better location for this */ if (sm->eap_if->aaaEapResp) { sm->eap_if->aaaEapResp = FALSE; if (sm->eap_if->aaaEapRespData == NULL) { wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, " "but no aaaEapRespData available"); return; } sm->eapol->cb.aaa_send( sm->eapol->conf.ctx, sm->sta, wpabuf_head(sm->eap_if->aaaEapRespData), wpabuf_len(sm->eap_if->aaaEapRespData)); } } if (eapol_sm_sta_entry_alive(eapol, addr)) sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta, EAPOL_AUTH_SM_CHANGE); }