15b9c547cSRui Paulo /*
25b9c547cSRui Paulo * IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine
35b9c547cSRui Paulo * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
45b9c547cSRui Paulo *
55b9c547cSRui Paulo * This software may be distributed under the terms of the BSD license.
65b9c547cSRui Paulo * See README for more details.
75b9c547cSRui Paulo */
85b9c547cSRui Paulo
95b9c547cSRui Paulo #include "utils/includes.h"
105b9c547cSRui Paulo
115b9c547cSRui Paulo #include "utils/common.h"
125b9c547cSRui Paulo #include "utils/eloop.h"
135b9c547cSRui Paulo #include "common/defs.h"
145b9c547cSRui Paulo #include "common/ieee802_1x_defs.h"
155b9c547cSRui Paulo #include "utils/state_machine.h"
165b9c547cSRui Paulo #include "ieee802_1x_kay.h"
175b9c547cSRui Paulo #include "ieee802_1x_secy_ops.h"
185b9c547cSRui Paulo #include "pae/ieee802_1x_cp.h"
195b9c547cSRui Paulo
205b9c547cSRui Paulo #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
215b9c547cSRui Paulo #define STATE_MACHINE_DEBUG_PREFIX "CP"
225b9c547cSRui Paulo
23*a90b9d01SCy Schubert static u64 cs_id[] = { CS_ID_GCM_AES_128, CS_ID_GCM_AES_256 };
245b9c547cSRui Paulo
255b9c547cSRui Paulo /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
265b9c547cSRui Paulo enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
275b9c547cSRui Paulo
285b9c547cSRui Paulo struct ieee802_1x_cp_sm {
295b9c547cSRui Paulo enum cp_states {
305b9c547cSRui Paulo CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED,
315b9c547cSRui Paulo CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT,
325b9c547cSRui Paulo CP_TRANSMITTING, CP_ABANDON, CP_RETIRE
335b9c547cSRui Paulo } CP_state;
34c1d255d3SCy Schubert bool changed;
355b9c547cSRui Paulo
365b9c547cSRui Paulo /* CP -> Client */
37c1d255d3SCy Schubert bool port_valid;
385b9c547cSRui Paulo
395b9c547cSRui Paulo /* Logon -> CP */
405b9c547cSRui Paulo enum connect_type connect;
415b9c547cSRui Paulo
425b9c547cSRui Paulo /* KaY -> CP */
43c1d255d3SCy Schubert bool chgd_server; /* clear by CP */
44c1d255d3SCy Schubert bool elected_self;
455b9c547cSRui Paulo enum confidentiality_offset cipher_offset;
46780fb4a2SCy Schubert u64 cipher_suite;
47c1d255d3SCy Schubert bool new_sak; /* clear by CP */
485b9c547cSRui Paulo struct ieee802_1x_mka_ki distributed_ki;
495b9c547cSRui Paulo u8 distributed_an;
50c1d255d3SCy Schubert bool using_receive_sas;
51c1d255d3SCy Schubert bool all_receiving;
52c1d255d3SCy Schubert bool server_transmitting;
53c1d255d3SCy Schubert bool using_transmit_sa;
545b9c547cSRui Paulo
555b9c547cSRui Paulo /* CP -> KaY */
565b9c547cSRui Paulo struct ieee802_1x_mka_ki *lki;
575b9c547cSRui Paulo u8 lan;
58c1d255d3SCy Schubert bool ltx;
59c1d255d3SCy Schubert bool lrx;
605b9c547cSRui Paulo struct ieee802_1x_mka_ki *oki;
615b9c547cSRui Paulo u8 oan;
62c1d255d3SCy Schubert bool otx;
63c1d255d3SCy Schubert bool orx;
645b9c547cSRui Paulo
655b9c547cSRui Paulo /* CP -> SecY */
66c1d255d3SCy Schubert bool protect_frames;
675b9c547cSRui Paulo enum validate_frames validate_frames;
685b9c547cSRui Paulo
69c1d255d3SCy Schubert bool replay_protect;
705b9c547cSRui Paulo u32 replay_window;
715b9c547cSRui Paulo
72780fb4a2SCy Schubert u64 current_cipher_suite;
735b9c547cSRui Paulo enum confidentiality_offset confidentiality_offset;
74c1d255d3SCy Schubert bool controlled_port_enabled;
755b9c547cSRui Paulo
765b9c547cSRui Paulo /* SecY -> CP */
77c1d255d3SCy Schubert bool port_enabled; /* SecY->CP */
785b9c547cSRui Paulo
795b9c547cSRui Paulo /* private */
805b9c547cSRui Paulo u32 transmit_when;
815b9c547cSRui Paulo u32 transmit_delay;
825b9c547cSRui Paulo u32 retire_when;
835b9c547cSRui Paulo u32 retire_delay;
845b9c547cSRui Paulo
855b9c547cSRui Paulo /* not defined IEEE Std 802.1X-2010 */
865b9c547cSRui Paulo struct ieee802_1x_kay *kay;
87*a90b9d01SCy Schubert u8 offload;
885b9c547cSRui Paulo };
895b9c547cSRui Paulo
905b9c547cSRui Paulo static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
915b9c547cSRui Paulo void *timeout_ctx);
925b9c547cSRui Paulo static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx,
935b9c547cSRui Paulo void *timeout_ctx);
945b9c547cSRui Paulo
955b9c547cSRui Paulo
changed_cipher(struct ieee802_1x_cp_sm * sm)965b9c547cSRui Paulo static int changed_cipher(struct ieee802_1x_cp_sm *sm)
975b9c547cSRui Paulo {
985b9c547cSRui Paulo return sm->confidentiality_offset != sm->cipher_offset ||
99780fb4a2SCy Schubert sm->current_cipher_suite != sm->cipher_suite;
1005b9c547cSRui Paulo }
1015b9c547cSRui Paulo
1025b9c547cSRui Paulo
changed_connect(struct ieee802_1x_cp_sm * sm)1035b9c547cSRui Paulo static int changed_connect(struct ieee802_1x_cp_sm *sm)
1045b9c547cSRui Paulo {
1055b9c547cSRui Paulo return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm);
1065b9c547cSRui Paulo }
1075b9c547cSRui Paulo
1085b9c547cSRui Paulo
SM_STATE(CP,INIT)1095b9c547cSRui Paulo SM_STATE(CP, INIT)
1105b9c547cSRui Paulo {
1115b9c547cSRui Paulo SM_ENTRY(CP, INIT);
1125b9c547cSRui Paulo
113c1d255d3SCy Schubert sm->controlled_port_enabled = false;
1145b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
1155b9c547cSRui Paulo
116c1d255d3SCy Schubert sm->port_valid = false;
1175b9c547cSRui Paulo
1185b9c547cSRui Paulo os_free(sm->lki);
1195b9c547cSRui Paulo sm->lki = NULL;
120c1d255d3SCy Schubert sm->ltx = false;
121c1d255d3SCy Schubert sm->lrx = false;
1225b9c547cSRui Paulo
1235b9c547cSRui Paulo os_free(sm->oki);
1245b9c547cSRui Paulo sm->oki = NULL;
125c1d255d3SCy Schubert sm->otx = false;
126c1d255d3SCy Schubert sm->orx = false;
1275b9c547cSRui Paulo
128c1d255d3SCy Schubert sm->port_enabled = true;
129c1d255d3SCy Schubert sm->chgd_server = false;
1305b9c547cSRui Paulo }
1315b9c547cSRui Paulo
1325b9c547cSRui Paulo
SM_STATE(CP,CHANGE)1335b9c547cSRui Paulo SM_STATE(CP, CHANGE)
1345b9c547cSRui Paulo {
1355b9c547cSRui Paulo SM_ENTRY(CP, CHANGE);
1365b9c547cSRui Paulo
137c1d255d3SCy Schubert sm->port_valid = false;
138c1d255d3SCy Schubert sm->controlled_port_enabled = false;
1395b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
1405b9c547cSRui Paulo
1415b9c547cSRui Paulo if (sm->lki)
1425b9c547cSRui Paulo ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
1435b9c547cSRui Paulo if (sm->oki)
1445b9c547cSRui Paulo ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
145c1d255d3SCy Schubert /* The standard doesn't say it but we should clear out the latest
146c1d255d3SCy Schubert * and old key values. Why would we keep advertising them if
147c1d255d3SCy Schubert * they've been deleted and the key server has been changed?
148c1d255d3SCy Schubert */
149c1d255d3SCy Schubert os_free(sm->oki);
150c1d255d3SCy Schubert sm->oki = NULL;
151c1d255d3SCy Schubert sm->otx = false;
152c1d255d3SCy Schubert sm->orx = false;
153c1d255d3SCy Schubert sm->oan = 0;
154c1d255d3SCy Schubert ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
155c1d255d3SCy Schubert sm->otx, sm->orx);
156c1d255d3SCy Schubert os_free(sm->lki);
157c1d255d3SCy Schubert sm->lki = NULL;
158c1d255d3SCy Schubert sm->lrx = false;
159c1d255d3SCy Schubert sm->ltx = false;
160c1d255d3SCy Schubert sm->lan = 0;
161c1d255d3SCy Schubert ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
162c1d255d3SCy Schubert sm->ltx, sm->lrx);
1635b9c547cSRui Paulo }
1645b9c547cSRui Paulo
1655b9c547cSRui Paulo
SM_STATE(CP,ALLOWED)1665b9c547cSRui Paulo SM_STATE(CP, ALLOWED)
1675b9c547cSRui Paulo {
1685b9c547cSRui Paulo SM_ENTRY(CP, ALLOWED);
1695b9c547cSRui Paulo
170c1d255d3SCy Schubert sm->protect_frames = false;
171c1d255d3SCy Schubert sm->replay_protect = false;
1725b9c547cSRui Paulo sm->validate_frames = Checked;
1735b9c547cSRui Paulo
174c1d255d3SCy Schubert sm->port_valid = false;
175c1d255d3SCy Schubert sm->controlled_port_enabled = true;
1765b9c547cSRui Paulo
1775b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
1785b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
17985732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
1805b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
1815b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
1825b9c547cSRui Paulo }
1835b9c547cSRui Paulo
1845b9c547cSRui Paulo
SM_STATE(CP,AUTHENTICATED)1855b9c547cSRui Paulo SM_STATE(CP, AUTHENTICATED)
1865b9c547cSRui Paulo {
1875b9c547cSRui Paulo SM_ENTRY(CP, AUTHENTICATED);
1885b9c547cSRui Paulo
189c1d255d3SCy Schubert sm->protect_frames = false;
190c1d255d3SCy Schubert sm->replay_protect = false;
1915b9c547cSRui Paulo sm->validate_frames = Checked;
192*a90b9d01SCy Schubert sm->offload = sm->kay->macsec_offload;
1935b9c547cSRui Paulo
194c1d255d3SCy Schubert sm->port_valid = false;
195c1d255d3SCy Schubert sm->controlled_port_enabled = true;
1965b9c547cSRui Paulo
1975b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
1985b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
19985732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
2005b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
2015b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
202*a90b9d01SCy Schubert secy_cp_control_offload(sm->kay, sm->offload);
2035b9c547cSRui Paulo }
2045b9c547cSRui Paulo
2055b9c547cSRui Paulo
SM_STATE(CP,SECURED)2065b9c547cSRui Paulo SM_STATE(CP, SECURED)
2075b9c547cSRui Paulo {
2085b9c547cSRui Paulo SM_ENTRY(CP, SECURED);
2095b9c547cSRui Paulo
210c1d255d3SCy Schubert sm->chgd_server = false;
2115b9c547cSRui Paulo
212780fb4a2SCy Schubert sm->protect_frames = sm->kay->macsec_protect;
213780fb4a2SCy Schubert sm->replay_protect = sm->kay->macsec_replay_protect;
214*a90b9d01SCy Schubert sm->offload = sm->kay->macsec_offload;
215780fb4a2SCy Schubert sm->validate_frames = sm->kay->macsec_validate;
2165b9c547cSRui Paulo
217780fb4a2SCy Schubert sm->current_cipher_suite = sm->cipher_suite;
218780fb4a2SCy Schubert secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
2195b9c547cSRui Paulo
2205b9c547cSRui Paulo sm->confidentiality_offset = sm->cipher_offset;
2215b9c547cSRui Paulo
222c1d255d3SCy Schubert sm->port_valid = true;
2235b9c547cSRui Paulo
2245b9c547cSRui Paulo secy_cp_control_confidentiality_offset(sm->kay,
2255b9c547cSRui Paulo sm->confidentiality_offset);
2265b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
22785732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
2285b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
2295b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
230*a90b9d01SCy Schubert secy_cp_control_offload(sm->kay, sm->offload);
2315b9c547cSRui Paulo }
2325b9c547cSRui Paulo
2335b9c547cSRui Paulo
SM_STATE(CP,RECEIVE)2345b9c547cSRui Paulo SM_STATE(CP, RECEIVE)
2355b9c547cSRui Paulo {
2365b9c547cSRui Paulo SM_ENTRY(CP, RECEIVE);
2375b9c547cSRui Paulo
2385b9c547cSRui Paulo sm->lki = os_malloc(sizeof(*sm->lki));
2395b9c547cSRui Paulo if (!sm->lki) {
2405b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__);
2415b9c547cSRui Paulo return;
2425b9c547cSRui Paulo }
2435b9c547cSRui Paulo os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki));
2445b9c547cSRui Paulo sm->lan = sm->distributed_an;
245c1d255d3SCy Schubert sm->ltx = false;
246c1d255d3SCy Schubert sm->lrx = false;
2475b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
2485b9c547cSRui Paulo sm->ltx, sm->lrx);
2495b9c547cSRui Paulo ieee802_1x_kay_create_sas(sm->kay, sm->lki);
2505b9c547cSRui Paulo ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki);
251c1d255d3SCy Schubert sm->new_sak = false;
252c1d255d3SCy Schubert sm->all_receiving = false;
2535b9c547cSRui Paulo }
2545b9c547cSRui Paulo
2555b9c547cSRui Paulo
SM_STATE(CP,RECEIVING)2565b9c547cSRui Paulo SM_STATE(CP, RECEIVING)
2575b9c547cSRui Paulo {
2585b9c547cSRui Paulo SM_ENTRY(CP, RECEIVING);
2595b9c547cSRui Paulo
260c1d255d3SCy Schubert sm->lrx = true;
2615b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
2625b9c547cSRui Paulo sm->ltx, sm->lrx);
2635b9c547cSRui Paulo sm->transmit_when = sm->transmit_delay;
2645b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
2655b9c547cSRui Paulo eloop_register_timeout(sm->transmit_when / 1000, 0,
2665b9c547cSRui Paulo ieee802_1x_cp_transmit_when_timeout, sm, NULL);
2675b9c547cSRui Paulo /* the electedSelf have been set before CP entering to RECEIVING
2685b9c547cSRui Paulo * but the CP will transmit from RECEIVING to READY under
2695b9c547cSRui Paulo * the !electedSelf when KaY is not key server */
2705b9c547cSRui Paulo ieee802_1x_cp_sm_step(sm);
271c1d255d3SCy Schubert sm->using_receive_sas = false;
272c1d255d3SCy Schubert sm->server_transmitting = false;
2735b9c547cSRui Paulo }
2745b9c547cSRui Paulo
2755b9c547cSRui Paulo
SM_STATE(CP,READY)2765b9c547cSRui Paulo SM_STATE(CP, READY)
2775b9c547cSRui Paulo {
2785b9c547cSRui Paulo SM_ENTRY(CP, READY);
2795b9c547cSRui Paulo
2805b9c547cSRui Paulo ieee802_1x_kay_enable_new_info(sm->kay);
2815b9c547cSRui Paulo }
2825b9c547cSRui Paulo
2835b9c547cSRui Paulo
SM_STATE(CP,TRANSMIT)2845b9c547cSRui Paulo SM_STATE(CP, TRANSMIT)
2855b9c547cSRui Paulo {
2865b9c547cSRui Paulo SM_ENTRY(CP, TRANSMIT);
2875b9c547cSRui Paulo
288c1d255d3SCy Schubert sm->controlled_port_enabled = true;
2895b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
290c1d255d3SCy Schubert sm->ltx = true;
2915b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
2925b9c547cSRui Paulo sm->ltx, sm->lrx);
2935b9c547cSRui Paulo ieee802_1x_kay_enable_tx_sas(sm->kay, sm->lki);
294c1d255d3SCy Schubert sm->all_receiving = false;
295c1d255d3SCy Schubert sm->server_transmitting = false;
2965b9c547cSRui Paulo }
2975b9c547cSRui Paulo
2985b9c547cSRui Paulo
SM_STATE(CP,TRANSMITTING)2995b9c547cSRui Paulo SM_STATE(CP, TRANSMITTING)
3005b9c547cSRui Paulo {
3015b9c547cSRui Paulo SM_ENTRY(CP, TRANSMITTING);
3025b9c547cSRui Paulo sm->retire_when = sm->orx ? sm->retire_delay : 0;
303c1d255d3SCy Schubert sm->otx = false;
3045b9c547cSRui Paulo ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
3055b9c547cSRui Paulo sm->otx, sm->orx);
3065b9c547cSRui Paulo ieee802_1x_kay_enable_new_info(sm->kay);
3075b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
3085b9c547cSRui Paulo eloop_register_timeout(sm->retire_when / 1000, 0,
3095b9c547cSRui Paulo ieee802_1x_cp_retire_when_timeout, sm, NULL);
310c1d255d3SCy Schubert sm->using_transmit_sa = false;
3115b9c547cSRui Paulo }
3125b9c547cSRui Paulo
3135b9c547cSRui Paulo
SM_STATE(CP,ABANDON)3145b9c547cSRui Paulo SM_STATE(CP, ABANDON)
3155b9c547cSRui Paulo {
3165b9c547cSRui Paulo SM_ENTRY(CP, ABANDON);
317c1d255d3SCy Schubert sm->lrx = false;
3185b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
3195b9c547cSRui Paulo sm->ltx, sm->lrx);
3205b9c547cSRui Paulo ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
3215b9c547cSRui Paulo
3225b9c547cSRui Paulo os_free(sm->lki);
3235b9c547cSRui Paulo sm->lki = NULL;
3245b9c547cSRui Paulo ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
3255b9c547cSRui Paulo sm->ltx, sm->lrx);
3265b9c547cSRui Paulo }
3275b9c547cSRui Paulo
3285b9c547cSRui Paulo
SM_STATE(CP,RETIRE)3295b9c547cSRui Paulo SM_STATE(CP, RETIRE)
3305b9c547cSRui Paulo {
3315b9c547cSRui Paulo SM_ENTRY(CP, RETIRE);
3324bc52338SCy Schubert if (sm->oki) {
3334bc52338SCy Schubert ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
3345b9c547cSRui Paulo os_free(sm->oki);
3355b9c547cSRui Paulo sm->oki = NULL;
3364bc52338SCy Schubert }
337c1d255d3SCy Schubert sm->oki = sm->lki;
338c1d255d3SCy Schubert sm->otx = sm->ltx;
339c1d255d3SCy Schubert sm->orx = sm->lrx;
340c1d255d3SCy Schubert sm->oan = sm->lan;
3415b9c547cSRui Paulo ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
3425b9c547cSRui Paulo sm->otx, sm->orx);
343c1d255d3SCy Schubert sm->lki = NULL;
344c1d255d3SCy Schubert sm->ltx = false;
345c1d255d3SCy Schubert sm->lrx = false;
346c1d255d3SCy Schubert sm->lan = 0;
347c1d255d3SCy Schubert ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
348c1d255d3SCy Schubert sm->ltx, sm->lrx);
3495b9c547cSRui Paulo }
3505b9c547cSRui Paulo
3515b9c547cSRui Paulo
3525b9c547cSRui Paulo /**
3535b9c547cSRui Paulo * CP state machine handler entry
3545b9c547cSRui Paulo */
SM_STEP(CP)3555b9c547cSRui Paulo SM_STEP(CP)
3565b9c547cSRui Paulo {
3575b9c547cSRui Paulo if (!sm->port_enabled)
3585b9c547cSRui Paulo SM_ENTER(CP, INIT);
3595b9c547cSRui Paulo
3605b9c547cSRui Paulo switch (sm->CP_state) {
3615b9c547cSRui Paulo case CP_BEGIN:
3625b9c547cSRui Paulo SM_ENTER(CP, INIT);
3635b9c547cSRui Paulo break;
3645b9c547cSRui Paulo
3655b9c547cSRui Paulo case CP_INIT:
3665b9c547cSRui Paulo SM_ENTER(CP, CHANGE);
3675b9c547cSRui Paulo break;
3685b9c547cSRui Paulo
3695b9c547cSRui Paulo case CP_CHANGE:
3705b9c547cSRui Paulo if (sm->connect == UNAUTHENTICATED)
3715b9c547cSRui Paulo SM_ENTER(CP, ALLOWED);
3725b9c547cSRui Paulo else if (sm->connect == AUTHENTICATED)
3735b9c547cSRui Paulo SM_ENTER(CP, AUTHENTICATED);
3745b9c547cSRui Paulo else if (sm->connect == SECURE)
3755b9c547cSRui Paulo SM_ENTER(CP, SECURED);
3765b9c547cSRui Paulo break;
3775b9c547cSRui Paulo
3785b9c547cSRui Paulo case CP_ALLOWED:
3795b9c547cSRui Paulo if (sm->connect != UNAUTHENTICATED)
3805b9c547cSRui Paulo SM_ENTER(CP, CHANGE);
3815b9c547cSRui Paulo break;
3825b9c547cSRui Paulo
3835b9c547cSRui Paulo case CP_AUTHENTICATED:
3845b9c547cSRui Paulo if (sm->connect != AUTHENTICATED)
3855b9c547cSRui Paulo SM_ENTER(CP, CHANGE);
3865b9c547cSRui Paulo break;
3875b9c547cSRui Paulo
3885b9c547cSRui Paulo case CP_SECURED:
3895b9c547cSRui Paulo if (changed_connect(sm))
3905b9c547cSRui Paulo SM_ENTER(CP, CHANGE);
3915b9c547cSRui Paulo else if (sm->new_sak)
3925b9c547cSRui Paulo SM_ENTER(CP, RECEIVE);
3935b9c547cSRui Paulo break;
3945b9c547cSRui Paulo
3955b9c547cSRui Paulo case CP_RECEIVE:
3965b9c547cSRui Paulo if (sm->using_receive_sas)
3975b9c547cSRui Paulo SM_ENTER(CP, RECEIVING);
3985b9c547cSRui Paulo break;
3995b9c547cSRui Paulo
4005b9c547cSRui Paulo case CP_RECEIVING:
4015b9c547cSRui Paulo if (sm->new_sak || changed_connect(sm))
4025b9c547cSRui Paulo SM_ENTER(CP, ABANDON);
4035b9c547cSRui Paulo if (!sm->elected_self)
4045b9c547cSRui Paulo SM_ENTER(CP, READY);
4055b9c547cSRui Paulo if (sm->elected_self &&
4064bc52338SCy Schubert (sm->all_receiving || !sm->controlled_port_enabled ||
4074bc52338SCy Schubert !sm->transmit_when))
4085b9c547cSRui Paulo SM_ENTER(CP, TRANSMIT);
4095b9c547cSRui Paulo break;
4105b9c547cSRui Paulo
4115b9c547cSRui Paulo case CP_TRANSMIT:
4125b9c547cSRui Paulo if (sm->using_transmit_sa)
4135b9c547cSRui Paulo SM_ENTER(CP, TRANSMITTING);
4145b9c547cSRui Paulo break;
4155b9c547cSRui Paulo
4165b9c547cSRui Paulo case CP_TRANSMITTING:
4175b9c547cSRui Paulo if (!sm->retire_when || changed_connect(sm))
4185b9c547cSRui Paulo SM_ENTER(CP, RETIRE);
4195b9c547cSRui Paulo break;
4205b9c547cSRui Paulo
4215b9c547cSRui Paulo case CP_RETIRE:
4225b9c547cSRui Paulo if (changed_connect(sm))
4235b9c547cSRui Paulo SM_ENTER(CP, CHANGE);
4245b9c547cSRui Paulo else if (sm->new_sak)
4255b9c547cSRui Paulo SM_ENTER(CP, RECEIVE);
4265b9c547cSRui Paulo break;
4275b9c547cSRui Paulo
4285b9c547cSRui Paulo case CP_READY:
4295b9c547cSRui Paulo if (sm->new_sak || changed_connect(sm))
4304bc52338SCy Schubert SM_ENTER(CP, ABANDON);
4314bc52338SCy Schubert if (sm->server_transmitting || !sm->controlled_port_enabled)
4325b9c547cSRui Paulo SM_ENTER(CP, TRANSMIT);
4335b9c547cSRui Paulo break;
4345b9c547cSRui Paulo case CP_ABANDON:
4355b9c547cSRui Paulo if (changed_connect(sm))
4365b9c547cSRui Paulo SM_ENTER(CP, RETIRE);
4375b9c547cSRui Paulo else if (sm->new_sak)
4385b9c547cSRui Paulo SM_ENTER(CP, RECEIVE);
4395b9c547cSRui Paulo break;
4405b9c547cSRui Paulo default:
4415b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CP: the state machine is not defined");
4425b9c547cSRui Paulo break;
4435b9c547cSRui Paulo }
4445b9c547cSRui Paulo }
4455b9c547cSRui Paulo
4465b9c547cSRui Paulo
4475b9c547cSRui Paulo /**
4485b9c547cSRui Paulo * ieee802_1x_cp_sm_init -
4495b9c547cSRui Paulo */
ieee802_1x_cp_sm_init(struct ieee802_1x_kay * kay)450780fb4a2SCy Schubert struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
4515b9c547cSRui Paulo {
4525b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm;
4535b9c547cSRui Paulo
4545b9c547cSRui Paulo sm = os_zalloc(sizeof(*sm));
4555b9c547cSRui Paulo if (sm == NULL) {
4565b9c547cSRui Paulo wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
4575b9c547cSRui Paulo return NULL;
4585b9c547cSRui Paulo }
4595b9c547cSRui Paulo
4605b9c547cSRui Paulo sm->kay = kay;
4615b9c547cSRui Paulo
462c1d255d3SCy Schubert sm->port_valid = false;
4635b9c547cSRui Paulo
464c1d255d3SCy Schubert sm->chgd_server = false;
4655b9c547cSRui Paulo
466780fb4a2SCy Schubert sm->protect_frames = kay->macsec_protect;
467780fb4a2SCy Schubert sm->validate_frames = kay->macsec_validate;
468780fb4a2SCy Schubert sm->replay_protect = kay->macsec_replay_protect;
469780fb4a2SCy Schubert sm->replay_window = kay->macsec_replay_window;
470*a90b9d01SCy Schubert sm->offload = kay->macsec_offload;
4715b9c547cSRui Paulo
472c1d255d3SCy Schubert sm->controlled_port_enabled = false;
4735b9c547cSRui Paulo
4745b9c547cSRui Paulo sm->lki = NULL;
475c1d255d3SCy Schubert sm->lrx = false;
476c1d255d3SCy Schubert sm->ltx = false;
4775b9c547cSRui Paulo sm->oki = NULL;
478c1d255d3SCy Schubert sm->orx = false;
479c1d255d3SCy Schubert sm->otx = false;
4805b9c547cSRui Paulo
481*a90b9d01SCy Schubert sm->current_cipher_suite = cs_id[kay->macsec_csindex];
482*a90b9d01SCy Schubert sm->cipher_suite = cs_id[kay->macsec_csindex];
4835b9c547cSRui Paulo sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
4845b9c547cSRui Paulo sm->confidentiality_offset = sm->cipher_offset;
4855b9c547cSRui Paulo sm->transmit_delay = MKA_LIFE_TIME;
4865b9c547cSRui Paulo sm->retire_delay = MKA_SAK_RETIRE_TIME;
4875b9c547cSRui Paulo sm->CP_state = CP_BEGIN;
488c1d255d3SCy Schubert sm->changed = false;
4895b9c547cSRui Paulo
4905b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CP: state machine created");
4915b9c547cSRui Paulo
4925b9c547cSRui Paulo secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
49385732ac8SCy Schubert secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
4945b9c547cSRui Paulo secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
4955b9c547cSRui Paulo secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
4965b9c547cSRui Paulo secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
4975b9c547cSRui Paulo secy_cp_control_confidentiality_offset(sm->kay,
4985b9c547cSRui Paulo sm->confidentiality_offset);
499*a90b9d01SCy Schubert secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
500*a90b9d01SCy Schubert secy_cp_control_offload(sm->kay, sm->offload);
5015b9c547cSRui Paulo
5025b9c547cSRui Paulo SM_STEP_RUN(CP);
5035b9c547cSRui Paulo
5045b9c547cSRui Paulo return sm;
5055b9c547cSRui Paulo }
5065b9c547cSRui Paulo
5075b9c547cSRui Paulo
ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm * sm)5085b9c547cSRui Paulo static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm)
5095b9c547cSRui Paulo {
5105b9c547cSRui Paulo enum cp_states prev_state;
5115b9c547cSRui Paulo int i;
5125b9c547cSRui Paulo
5135b9c547cSRui Paulo for (i = 0; i < 100; i++) {
5145b9c547cSRui Paulo prev_state = sm->CP_state;
5155b9c547cSRui Paulo SM_STEP_RUN(CP);
5165b9c547cSRui Paulo if (prev_state == sm->CP_state)
5175b9c547cSRui Paulo break;
5185b9c547cSRui Paulo }
5195b9c547cSRui Paulo }
5205b9c547cSRui Paulo
5215b9c547cSRui Paulo
ieee802_1x_cp_step_cb(void * eloop_ctx,void * timeout_ctx)5225b9c547cSRui Paulo static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx)
5235b9c547cSRui Paulo {
5245b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = eloop_ctx;
5255b9c547cSRui Paulo ieee802_1x_cp_step_run(sm);
5265b9c547cSRui Paulo }
5275b9c547cSRui Paulo
5285b9c547cSRui Paulo
5295b9c547cSRui Paulo /**
5305b9c547cSRui Paulo * ieee802_1x_cp_sm_deinit -
5315b9c547cSRui Paulo */
ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm * sm)5325b9c547cSRui Paulo void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm)
5335b9c547cSRui Paulo {
5345b9c547cSRui Paulo wpa_printf(MSG_DEBUG, "CP: state machine removed");
5355b9c547cSRui Paulo if (!sm)
5365b9c547cSRui Paulo return;
5375b9c547cSRui Paulo
5385b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
5395b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
5405b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
5415b9c547cSRui Paulo os_free(sm->lki);
5425b9c547cSRui Paulo os_free(sm->oki);
5435b9c547cSRui Paulo os_free(sm);
5445b9c547cSRui Paulo }
5455b9c547cSRui Paulo
5465b9c547cSRui Paulo
5475b9c547cSRui Paulo /**
5485b9c547cSRui Paulo * ieee802_1x_cp_connect_pending
5495b9c547cSRui Paulo */
ieee802_1x_cp_connect_pending(void * cp_ctx)5505b9c547cSRui Paulo void ieee802_1x_cp_connect_pending(void *cp_ctx)
5515b9c547cSRui Paulo {
5525b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
5535b9c547cSRui Paulo
5545b9c547cSRui Paulo sm->connect = PENDING;
5555b9c547cSRui Paulo }
5565b9c547cSRui Paulo
5575b9c547cSRui Paulo
5585b9c547cSRui Paulo /**
5595b9c547cSRui Paulo * ieee802_1x_cp_connect_unauthenticated
5605b9c547cSRui Paulo */
ieee802_1x_cp_connect_unauthenticated(void * cp_ctx)5615b9c547cSRui Paulo void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx)
5625b9c547cSRui Paulo {
5635b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx;
5645b9c547cSRui Paulo
5655b9c547cSRui Paulo sm->connect = UNAUTHENTICATED;
5665b9c547cSRui Paulo }
5675b9c547cSRui Paulo
5685b9c547cSRui Paulo
5695b9c547cSRui Paulo /**
5705b9c547cSRui Paulo * ieee802_1x_cp_connect_authenticated
5715b9c547cSRui Paulo */
ieee802_1x_cp_connect_authenticated(void * cp_ctx)5725b9c547cSRui Paulo void ieee802_1x_cp_connect_authenticated(void *cp_ctx)
5735b9c547cSRui Paulo {
5745b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
5755b9c547cSRui Paulo
5765b9c547cSRui Paulo sm->connect = AUTHENTICATED;
5775b9c547cSRui Paulo }
5785b9c547cSRui Paulo
5795b9c547cSRui Paulo
5805b9c547cSRui Paulo /**
5815b9c547cSRui Paulo * ieee802_1x_cp_connect_secure
5825b9c547cSRui Paulo */
ieee802_1x_cp_connect_secure(void * cp_ctx)5835b9c547cSRui Paulo void ieee802_1x_cp_connect_secure(void *cp_ctx)
5845b9c547cSRui Paulo {
5855b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
5865b9c547cSRui Paulo
5875b9c547cSRui Paulo sm->connect = SECURE;
5885b9c547cSRui Paulo }
5895b9c547cSRui Paulo
5905b9c547cSRui Paulo
5915b9c547cSRui Paulo /**
5925b9c547cSRui Paulo * ieee802_1x_cp_set_chgdserver -
5935b9c547cSRui Paulo */
ieee802_1x_cp_signal_chgdserver(void * cp_ctx)5945b9c547cSRui Paulo void ieee802_1x_cp_signal_chgdserver(void *cp_ctx)
5955b9c547cSRui Paulo {
5965b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
5975b9c547cSRui Paulo
598c1d255d3SCy Schubert sm->chgd_server = true;
5995b9c547cSRui Paulo }
6005b9c547cSRui Paulo
6015b9c547cSRui Paulo
6025b9c547cSRui Paulo /**
6035b9c547cSRui Paulo * ieee802_1x_cp_set_electedself -
6045b9c547cSRui Paulo */
ieee802_1x_cp_set_electedself(void * cp_ctx,bool status)605c1d255d3SCy Schubert void ieee802_1x_cp_set_electedself(void *cp_ctx, bool status)
6065b9c547cSRui Paulo {
6075b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6085b9c547cSRui Paulo sm->elected_self = status;
6095b9c547cSRui Paulo }
6105b9c547cSRui Paulo
6115b9c547cSRui Paulo
6125b9c547cSRui Paulo /**
6135b9c547cSRui Paulo * ieee802_1x_cp_set_ciphersuite -
6145b9c547cSRui Paulo */
ieee802_1x_cp_set_ciphersuite(void * cp_ctx,u64 cs)615780fb4a2SCy Schubert void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
6165b9c547cSRui Paulo {
6175b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
618780fb4a2SCy Schubert sm->cipher_suite = cs;
6195b9c547cSRui Paulo }
6205b9c547cSRui Paulo
6215b9c547cSRui Paulo
6225b9c547cSRui Paulo /**
6235b9c547cSRui Paulo * ieee802_1x_cp_set_offset -
6245b9c547cSRui Paulo */
ieee802_1x_cp_set_offset(void * cp_ctx,enum confidentiality_offset offset)6255b9c547cSRui Paulo void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset)
6265b9c547cSRui Paulo {
6275b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6285b9c547cSRui Paulo sm->cipher_offset = offset;
6295b9c547cSRui Paulo }
6305b9c547cSRui Paulo
6315b9c547cSRui Paulo
6325b9c547cSRui Paulo /**
6335b9c547cSRui Paulo * ieee802_1x_cp_signal_newsak -
6345b9c547cSRui Paulo */
ieee802_1x_cp_signal_newsak(void * cp_ctx)6355b9c547cSRui Paulo void ieee802_1x_cp_signal_newsak(void *cp_ctx)
6365b9c547cSRui Paulo {
6375b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
638c1d255d3SCy Schubert sm->new_sak = true;
6395b9c547cSRui Paulo }
6405b9c547cSRui Paulo
6415b9c547cSRui Paulo
6425b9c547cSRui Paulo /**
6435b9c547cSRui Paulo * ieee802_1x_cp_set_distributedki -
6445b9c547cSRui Paulo */
ieee802_1x_cp_set_distributedki(void * cp_ctx,const struct ieee802_1x_mka_ki * dki)6455b9c547cSRui Paulo void ieee802_1x_cp_set_distributedki(void *cp_ctx,
6465b9c547cSRui Paulo const struct ieee802_1x_mka_ki *dki)
6475b9c547cSRui Paulo {
6485b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6495b9c547cSRui Paulo os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki));
6505b9c547cSRui Paulo }
6515b9c547cSRui Paulo
6525b9c547cSRui Paulo
6535b9c547cSRui Paulo /**
6545b9c547cSRui Paulo * ieee802_1x_cp_set_distributedan -
6555b9c547cSRui Paulo */
ieee802_1x_cp_set_distributedan(void * cp_ctx,u8 an)6565b9c547cSRui Paulo void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an)
6575b9c547cSRui Paulo {
6585b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6595b9c547cSRui Paulo sm->distributed_an = an;
6605b9c547cSRui Paulo }
6615b9c547cSRui Paulo
6625b9c547cSRui Paulo
6635b9c547cSRui Paulo /**
6645b9c547cSRui Paulo * ieee802_1x_cp_set_usingreceivesas -
6655b9c547cSRui Paulo */
ieee802_1x_cp_set_usingreceivesas(void * cp_ctx,bool status)666c1d255d3SCy Schubert void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, bool status)
6675b9c547cSRui Paulo {
6685b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6695b9c547cSRui Paulo sm->using_receive_sas = status;
6705b9c547cSRui Paulo }
6715b9c547cSRui Paulo
6725b9c547cSRui Paulo
6735b9c547cSRui Paulo /**
6745b9c547cSRui Paulo * ieee802_1x_cp_set_allreceiving -
6755b9c547cSRui Paulo */
ieee802_1x_cp_set_allreceiving(void * cp_ctx,bool status)676c1d255d3SCy Schubert void ieee802_1x_cp_set_allreceiving(void *cp_ctx, bool status)
6775b9c547cSRui Paulo {
6785b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6795b9c547cSRui Paulo sm->all_receiving = status;
6805b9c547cSRui Paulo }
6815b9c547cSRui Paulo
6825b9c547cSRui Paulo
6835b9c547cSRui Paulo /**
6845b9c547cSRui Paulo * ieee802_1x_cp_set_servertransmitting -
6855b9c547cSRui Paulo */
ieee802_1x_cp_set_servertransmitting(void * cp_ctx,bool status)686c1d255d3SCy Schubert void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, bool status)
6875b9c547cSRui Paulo {
6885b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6895b9c547cSRui Paulo sm->server_transmitting = status;
6905b9c547cSRui Paulo }
6915b9c547cSRui Paulo
6925b9c547cSRui Paulo
6935b9c547cSRui Paulo /**
6945b9c547cSRui Paulo * ieee802_1x_cp_set_usingtransmitsas -
6955b9c547cSRui Paulo */
ieee802_1x_cp_set_usingtransmitas(void * cp_ctx,bool status)696c1d255d3SCy Schubert void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, bool status)
6975b9c547cSRui Paulo {
6985b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
6995b9c547cSRui Paulo sm->using_transmit_sa = status;
7005b9c547cSRui Paulo }
7015b9c547cSRui Paulo
7025b9c547cSRui Paulo
7035b9c547cSRui Paulo /**
7045b9c547cSRui Paulo * ieee802_1x_cp_sm_step - Advance EAPOL state machines
7055b9c547cSRui Paulo * @sm: EAPOL state machine
7065b9c547cSRui Paulo *
7075b9c547cSRui Paulo * This function is called to advance CP state machines after any change
7085b9c547cSRui Paulo * that could affect their state.
7095b9c547cSRui Paulo */
ieee802_1x_cp_sm_step(void * cp_ctx)7105b9c547cSRui Paulo void ieee802_1x_cp_sm_step(void *cp_ctx)
7115b9c547cSRui Paulo {
7125b9c547cSRui Paulo /*
7135b9c547cSRui Paulo * Run ieee802_1x_cp_step_run from a registered timeout
7145b9c547cSRui Paulo * to make sure that other possible timeouts/events are processed
7155b9c547cSRui Paulo * and to avoid long function call chains.
7165b9c547cSRui Paulo */
7175b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = cp_ctx;
7185b9c547cSRui Paulo eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
7195b9c547cSRui Paulo eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL);
7205b9c547cSRui Paulo }
7215b9c547cSRui Paulo
7225b9c547cSRui Paulo
ieee802_1x_cp_retire_when_timeout(void * eloop_ctx,void * timeout_ctx)7235b9c547cSRui Paulo static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
7245b9c547cSRui Paulo void *timeout_ctx)
7255b9c547cSRui Paulo {
7265b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = eloop_ctx;
7275b9c547cSRui Paulo sm->retire_when = 0;
7285b9c547cSRui Paulo ieee802_1x_cp_step_run(sm);
7295b9c547cSRui Paulo }
7305b9c547cSRui Paulo
7315b9c547cSRui Paulo
7325b9c547cSRui Paulo static void
ieee802_1x_cp_transmit_when_timeout(void * eloop_ctx,void * timeout_ctx)7335b9c547cSRui Paulo ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx)
7345b9c547cSRui Paulo {
7355b9c547cSRui Paulo struct ieee802_1x_cp_sm *sm = eloop_ctx;
7365b9c547cSRui Paulo sm->transmit_when = 0;
7375b9c547cSRui Paulo ieee802_1x_cp_step_run(sm);
7385b9c547cSRui Paulo }
739