745 lines
16 KiB
C
745 lines
16 KiB
C
|
/*
|
||
|
* 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);
|
||
|
}
|