1*a1157835SDaniel Fojt /*
2*a1157835SDaniel Fojt  * IEEE 802.1X-2010 Controlled Port of PAE state machine - CP state machine
3*a1157835SDaniel Fojt  * Copyright (c) 2013-2014, Qualcomm Atheros, Inc.
4*a1157835SDaniel Fojt  *
5*a1157835SDaniel Fojt  * This software may be distributed under the terms of the BSD license.
6*a1157835SDaniel Fojt  * See README for more details.
7*a1157835SDaniel Fojt  */
8*a1157835SDaniel Fojt 
9*a1157835SDaniel Fojt #include "utils/includes.h"
10*a1157835SDaniel Fojt 
11*a1157835SDaniel Fojt #include "utils/common.h"
12*a1157835SDaniel Fojt #include "utils/eloop.h"
13*a1157835SDaniel Fojt #include "common/defs.h"
14*a1157835SDaniel Fojt #include "common/ieee802_1x_defs.h"
15*a1157835SDaniel Fojt #include "utils/state_machine.h"
16*a1157835SDaniel Fojt #include "ieee802_1x_kay.h"
17*a1157835SDaniel Fojt #include "ieee802_1x_secy_ops.h"
18*a1157835SDaniel Fojt #include "pae/ieee802_1x_cp.h"
19*a1157835SDaniel Fojt 
20*a1157835SDaniel Fojt #define STATE_MACHINE_DATA struct ieee802_1x_cp_sm
21*a1157835SDaniel Fojt #define STATE_MACHINE_DEBUG_PREFIX "CP"
22*a1157835SDaniel Fojt 
23*a1157835SDaniel Fojt static u64 default_cs_id = CS_ID_GCM_AES_128;
24*a1157835SDaniel Fojt 
25*a1157835SDaniel Fojt /* The variable defined in clause 12 in IEEE Std 802.1X-2010 */
26*a1157835SDaniel Fojt enum connect_type { PENDING, UNAUTHENTICATED, AUTHENTICATED, SECURE };
27*a1157835SDaniel Fojt 
28*a1157835SDaniel Fojt struct ieee802_1x_cp_sm {
29*a1157835SDaniel Fojt 	enum cp_states {
30*a1157835SDaniel Fojt 		CP_BEGIN, CP_INIT, CP_CHANGE, CP_ALLOWED, CP_AUTHENTICATED,
31*a1157835SDaniel Fojt 		CP_SECURED, CP_RECEIVE, CP_RECEIVING, CP_READY, CP_TRANSMIT,
32*a1157835SDaniel Fojt 		CP_TRANSMITTING, CP_ABANDON, CP_RETIRE
33*a1157835SDaniel Fojt 	} CP_state;
34*a1157835SDaniel Fojt 	Boolean changed;
35*a1157835SDaniel Fojt 
36*a1157835SDaniel Fojt 	/* CP -> Client */
37*a1157835SDaniel Fojt 	Boolean port_valid;
38*a1157835SDaniel Fojt 
39*a1157835SDaniel Fojt 	/* Logon -> CP */
40*a1157835SDaniel Fojt 	enum connect_type connect;
41*a1157835SDaniel Fojt 
42*a1157835SDaniel Fojt 	/* KaY -> CP */
43*a1157835SDaniel Fojt 	Boolean chgd_server; /* clear by CP */
44*a1157835SDaniel Fojt 	Boolean elected_self;
45*a1157835SDaniel Fojt 	enum confidentiality_offset cipher_offset;
46*a1157835SDaniel Fojt 	u64 cipher_suite;
47*a1157835SDaniel Fojt 	Boolean new_sak; /* clear by CP */
48*a1157835SDaniel Fojt 	struct ieee802_1x_mka_ki distributed_ki;
49*a1157835SDaniel Fojt 	u8 distributed_an;
50*a1157835SDaniel Fojt 	Boolean using_receive_sas;
51*a1157835SDaniel Fojt 	Boolean all_receiving;
52*a1157835SDaniel Fojt 	Boolean server_transmitting;
53*a1157835SDaniel Fojt 	Boolean using_transmit_sa;
54*a1157835SDaniel Fojt 
55*a1157835SDaniel Fojt 	/* CP -> KaY */
56*a1157835SDaniel Fojt 	struct ieee802_1x_mka_ki *lki;
57*a1157835SDaniel Fojt 	u8 lan;
58*a1157835SDaniel Fojt 	Boolean ltx;
59*a1157835SDaniel Fojt 	Boolean lrx;
60*a1157835SDaniel Fojt 	struct ieee802_1x_mka_ki *oki;
61*a1157835SDaniel Fojt 	u8 oan;
62*a1157835SDaniel Fojt 	Boolean otx;
63*a1157835SDaniel Fojt 	Boolean orx;
64*a1157835SDaniel Fojt 
65*a1157835SDaniel Fojt 	/* CP -> SecY */
66*a1157835SDaniel Fojt 	Boolean protect_frames;
67*a1157835SDaniel Fojt 	enum validate_frames validate_frames;
68*a1157835SDaniel Fojt 
69*a1157835SDaniel Fojt 	Boolean replay_protect;
70*a1157835SDaniel Fojt 	u32 replay_window;
71*a1157835SDaniel Fojt 
72*a1157835SDaniel Fojt 	u64 current_cipher_suite;
73*a1157835SDaniel Fojt 	enum confidentiality_offset confidentiality_offset;
74*a1157835SDaniel Fojt 	Boolean controlled_port_enabled;
75*a1157835SDaniel Fojt 
76*a1157835SDaniel Fojt 	/* SecY -> CP */
77*a1157835SDaniel Fojt 	Boolean port_enabled; /* SecY->CP */
78*a1157835SDaniel Fojt 
79*a1157835SDaniel Fojt 	/* private */
80*a1157835SDaniel Fojt 	u32 transmit_when;
81*a1157835SDaniel Fojt 	u32 transmit_delay;
82*a1157835SDaniel Fojt 	u32 retire_when;
83*a1157835SDaniel Fojt 	u32 retire_delay;
84*a1157835SDaniel Fojt 
85*a1157835SDaniel Fojt 	/* not defined IEEE Std 802.1X-2010 */
86*a1157835SDaniel Fojt 	struct ieee802_1x_kay *kay;
87*a1157835SDaniel Fojt };
88*a1157835SDaniel Fojt 
89*a1157835SDaniel Fojt static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
90*a1157835SDaniel Fojt 					      void *timeout_ctx);
91*a1157835SDaniel Fojt static void ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx,
92*a1157835SDaniel Fojt 						void *timeout_ctx);
93*a1157835SDaniel Fojt 
94*a1157835SDaniel Fojt 
changed_cipher(struct ieee802_1x_cp_sm * sm)95*a1157835SDaniel Fojt static int changed_cipher(struct ieee802_1x_cp_sm *sm)
96*a1157835SDaniel Fojt {
97*a1157835SDaniel Fojt 	return sm->confidentiality_offset != sm->cipher_offset ||
98*a1157835SDaniel Fojt 		sm->current_cipher_suite != sm->cipher_suite;
99*a1157835SDaniel Fojt }
100*a1157835SDaniel Fojt 
101*a1157835SDaniel Fojt 
changed_connect(struct ieee802_1x_cp_sm * sm)102*a1157835SDaniel Fojt static int changed_connect(struct ieee802_1x_cp_sm *sm)
103*a1157835SDaniel Fojt {
104*a1157835SDaniel Fojt 	return sm->connect != SECURE || sm->chgd_server || changed_cipher(sm);
105*a1157835SDaniel Fojt }
106*a1157835SDaniel Fojt 
107*a1157835SDaniel Fojt 
SM_STATE(CP,INIT)108*a1157835SDaniel Fojt SM_STATE(CP, INIT)
109*a1157835SDaniel Fojt {
110*a1157835SDaniel Fojt 	SM_ENTRY(CP, INIT);
111*a1157835SDaniel Fojt 
112*a1157835SDaniel Fojt 	sm->controlled_port_enabled = FALSE;
113*a1157835SDaniel Fojt 	secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
114*a1157835SDaniel Fojt 
115*a1157835SDaniel Fojt 	sm->port_valid = FALSE;
116*a1157835SDaniel Fojt 
117*a1157835SDaniel Fojt 	os_free(sm->lki);
118*a1157835SDaniel Fojt 	sm->lki = NULL;
119*a1157835SDaniel Fojt 	sm->ltx = FALSE;
120*a1157835SDaniel Fojt 	sm->lrx = FALSE;
121*a1157835SDaniel Fojt 
122*a1157835SDaniel Fojt 	os_free(sm->oki);
123*a1157835SDaniel Fojt 	sm->oki = NULL;
124*a1157835SDaniel Fojt 	sm->otx = FALSE;
125*a1157835SDaniel Fojt 	sm->orx = FALSE;
126*a1157835SDaniel Fojt 
127*a1157835SDaniel Fojt 	sm->port_enabled = TRUE;
128*a1157835SDaniel Fojt 	sm->chgd_server = FALSE;
129*a1157835SDaniel Fojt }
130*a1157835SDaniel Fojt 
131*a1157835SDaniel Fojt 
SM_STATE(CP,CHANGE)132*a1157835SDaniel Fojt SM_STATE(CP, CHANGE)
133*a1157835SDaniel Fojt {
134*a1157835SDaniel Fojt 	SM_ENTRY(CP, CHANGE);
135*a1157835SDaniel Fojt 
136*a1157835SDaniel Fojt 	sm->port_valid = FALSE;
137*a1157835SDaniel Fojt 	sm->controlled_port_enabled = FALSE;
138*a1157835SDaniel Fojt 	secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
139*a1157835SDaniel Fojt 
140*a1157835SDaniel Fojt 	if (sm->lki)
141*a1157835SDaniel Fojt 		ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
142*a1157835SDaniel Fojt 	if (sm->oki)
143*a1157835SDaniel Fojt 		ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
144*a1157835SDaniel Fojt }
145*a1157835SDaniel Fojt 
146*a1157835SDaniel Fojt 
SM_STATE(CP,ALLOWED)147*a1157835SDaniel Fojt SM_STATE(CP, ALLOWED)
148*a1157835SDaniel Fojt {
149*a1157835SDaniel Fojt 	SM_ENTRY(CP, ALLOWED);
150*a1157835SDaniel Fojt 
151*a1157835SDaniel Fojt 	sm->protect_frames = FALSE;
152*a1157835SDaniel Fojt 	sm->replay_protect = FALSE;
153*a1157835SDaniel Fojt 	sm->validate_frames = Checked;
154*a1157835SDaniel Fojt 
155*a1157835SDaniel Fojt 	sm->port_valid = FALSE;
156*a1157835SDaniel Fojt 	sm->controlled_port_enabled = TRUE;
157*a1157835SDaniel Fojt 
158*a1157835SDaniel Fojt 	secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
159*a1157835SDaniel Fojt 	secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
160*a1157835SDaniel Fojt 	secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
161*a1157835SDaniel Fojt 	secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
162*a1157835SDaniel Fojt 	secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
163*a1157835SDaniel Fojt }
164*a1157835SDaniel Fojt 
165*a1157835SDaniel Fojt 
SM_STATE(CP,AUTHENTICATED)166*a1157835SDaniel Fojt SM_STATE(CP, AUTHENTICATED)
167*a1157835SDaniel Fojt {
168*a1157835SDaniel Fojt 	SM_ENTRY(CP, AUTHENTICATED);
169*a1157835SDaniel Fojt 
170*a1157835SDaniel Fojt 	sm->protect_frames = FALSE;
171*a1157835SDaniel Fojt 	sm->replay_protect = FALSE;
172*a1157835SDaniel Fojt 	sm->validate_frames = Checked;
173*a1157835SDaniel Fojt 
174*a1157835SDaniel Fojt 	sm->port_valid = FALSE;
175*a1157835SDaniel Fojt 	sm->controlled_port_enabled = TRUE;
176*a1157835SDaniel Fojt 
177*a1157835SDaniel Fojt 	secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
178*a1157835SDaniel Fojt 	secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
179*a1157835SDaniel Fojt 	secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
180*a1157835SDaniel Fojt 	secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
181*a1157835SDaniel Fojt 	secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
182*a1157835SDaniel Fojt }
183*a1157835SDaniel Fojt 
184*a1157835SDaniel Fojt 
SM_STATE(CP,SECURED)185*a1157835SDaniel Fojt SM_STATE(CP, SECURED)
186*a1157835SDaniel Fojt {
187*a1157835SDaniel Fojt 	SM_ENTRY(CP, SECURED);
188*a1157835SDaniel Fojt 
189*a1157835SDaniel Fojt 	sm->chgd_server = FALSE;
190*a1157835SDaniel Fojt 
191*a1157835SDaniel Fojt 	sm->protect_frames = sm->kay->macsec_protect;
192*a1157835SDaniel Fojt 	sm->replay_protect = sm->kay->macsec_replay_protect;
193*a1157835SDaniel Fojt 	sm->validate_frames = sm->kay->macsec_validate;
194*a1157835SDaniel Fojt 
195*a1157835SDaniel Fojt 	/* NOTE: now no other than default cipher suite (AES-GCM-128) */
196*a1157835SDaniel Fojt 	sm->current_cipher_suite = sm->cipher_suite;
197*a1157835SDaniel Fojt 	secy_cp_control_current_cipher_suite(sm->kay, sm->current_cipher_suite);
198*a1157835SDaniel Fojt 
199*a1157835SDaniel Fojt 	sm->confidentiality_offset = sm->cipher_offset;
200*a1157835SDaniel Fojt 
201*a1157835SDaniel Fojt 	sm->port_valid = TRUE;
202*a1157835SDaniel Fojt 
203*a1157835SDaniel Fojt 	secy_cp_control_confidentiality_offset(sm->kay,
204*a1157835SDaniel Fojt 					       sm->confidentiality_offset);
205*a1157835SDaniel Fojt 	secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
206*a1157835SDaniel Fojt 	secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
207*a1157835SDaniel Fojt 	secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
208*a1157835SDaniel Fojt 	secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
209*a1157835SDaniel Fojt }
210*a1157835SDaniel Fojt 
211*a1157835SDaniel Fojt 
SM_STATE(CP,RECEIVE)212*a1157835SDaniel Fojt SM_STATE(CP, RECEIVE)
213*a1157835SDaniel Fojt {
214*a1157835SDaniel Fojt 	SM_ENTRY(CP, RECEIVE);
215*a1157835SDaniel Fojt 	/* RECEIVE state machine not keep with Figure 12-2 in
216*a1157835SDaniel Fojt 	 * IEEE Std 802.1X-2010 */
217*a1157835SDaniel Fojt 	if (sm->oki) {
218*a1157835SDaniel Fojt 		ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
219*a1157835SDaniel Fojt 		os_free(sm->oki);
220*a1157835SDaniel Fojt 	}
221*a1157835SDaniel Fojt 	sm->oki = sm->lki;
222*a1157835SDaniel Fojt 	sm->oan = sm->lan;
223*a1157835SDaniel Fojt 	sm->otx = sm->ltx;
224*a1157835SDaniel Fojt 	sm->orx = sm->lrx;
225*a1157835SDaniel Fojt 	ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
226*a1157835SDaniel Fojt 				       sm->otx, sm->orx);
227*a1157835SDaniel Fojt 
228*a1157835SDaniel Fojt 	sm->lki = os_malloc(sizeof(*sm->lki));
229*a1157835SDaniel Fojt 	if (!sm->lki) {
230*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "CP-%s: Out of memory", __func__);
231*a1157835SDaniel Fojt 		return;
232*a1157835SDaniel Fojt 	}
233*a1157835SDaniel Fojt 	os_memcpy(sm->lki, &sm->distributed_ki, sizeof(*sm->lki));
234*a1157835SDaniel Fojt 	sm->lan = sm->distributed_an;
235*a1157835SDaniel Fojt 	sm->ltx = FALSE;
236*a1157835SDaniel Fojt 	sm->lrx = FALSE;
237*a1157835SDaniel Fojt 	ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
238*a1157835SDaniel Fojt 					  sm->ltx, sm->lrx);
239*a1157835SDaniel Fojt 	ieee802_1x_kay_create_sas(sm->kay, sm->lki);
240*a1157835SDaniel Fojt 	ieee802_1x_kay_enable_rx_sas(sm->kay, sm->lki);
241*a1157835SDaniel Fojt 	sm->new_sak = FALSE;
242*a1157835SDaniel Fojt 	sm->all_receiving = FALSE;
243*a1157835SDaniel Fojt }
244*a1157835SDaniel Fojt 
245*a1157835SDaniel Fojt 
SM_STATE(CP,RECEIVING)246*a1157835SDaniel Fojt SM_STATE(CP, RECEIVING)
247*a1157835SDaniel Fojt {
248*a1157835SDaniel Fojt 	SM_ENTRY(CP, RECEIVING);
249*a1157835SDaniel Fojt 
250*a1157835SDaniel Fojt 	sm->lrx = TRUE;
251*a1157835SDaniel Fojt 	ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
252*a1157835SDaniel Fojt 					  sm->ltx, sm->lrx);
253*a1157835SDaniel Fojt 	sm->transmit_when = sm->transmit_delay;
254*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
255*a1157835SDaniel Fojt 	eloop_register_timeout(sm->transmit_when / 1000, 0,
256*a1157835SDaniel Fojt 			       ieee802_1x_cp_transmit_when_timeout, sm, NULL);
257*a1157835SDaniel Fojt 	/* the electedSelf have been set before CP entering to RECEIVING
258*a1157835SDaniel Fojt 	 * but the CP will transmit from RECEIVING to READY under
259*a1157835SDaniel Fojt 	 * the !electedSelf when KaY is not key server */
260*a1157835SDaniel Fojt 	ieee802_1x_cp_sm_step(sm);
261*a1157835SDaniel Fojt 	sm->using_receive_sas = FALSE;
262*a1157835SDaniel Fojt 	sm->server_transmitting = FALSE;
263*a1157835SDaniel Fojt }
264*a1157835SDaniel Fojt 
265*a1157835SDaniel Fojt 
SM_STATE(CP,READY)266*a1157835SDaniel Fojt SM_STATE(CP, READY)
267*a1157835SDaniel Fojt {
268*a1157835SDaniel Fojt 	SM_ENTRY(CP, READY);
269*a1157835SDaniel Fojt 
270*a1157835SDaniel Fojt 	ieee802_1x_kay_enable_new_info(sm->kay);
271*a1157835SDaniel Fojt }
272*a1157835SDaniel Fojt 
273*a1157835SDaniel Fojt 
SM_STATE(CP,TRANSMIT)274*a1157835SDaniel Fojt SM_STATE(CP, TRANSMIT)
275*a1157835SDaniel Fojt {
276*a1157835SDaniel Fojt 	SM_ENTRY(CP, TRANSMIT);
277*a1157835SDaniel Fojt 
278*a1157835SDaniel Fojt 	sm->controlled_port_enabled = TRUE;
279*a1157835SDaniel Fojt 	secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
280*a1157835SDaniel Fojt 	sm->ltx = TRUE;
281*a1157835SDaniel Fojt 	ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
282*a1157835SDaniel Fojt 					  sm->ltx, sm->lrx);
283*a1157835SDaniel Fojt 	ieee802_1x_kay_enable_tx_sas(sm->kay,  sm->lki);
284*a1157835SDaniel Fojt 	sm->all_receiving = FALSE;
285*a1157835SDaniel Fojt 	sm->server_transmitting = FALSE;
286*a1157835SDaniel Fojt }
287*a1157835SDaniel Fojt 
288*a1157835SDaniel Fojt 
SM_STATE(CP,TRANSMITTING)289*a1157835SDaniel Fojt SM_STATE(CP, TRANSMITTING)
290*a1157835SDaniel Fojt {
291*a1157835SDaniel Fojt 	SM_ENTRY(CP, TRANSMITTING);
292*a1157835SDaniel Fojt 	sm->retire_when = sm->orx ? sm->retire_delay : 0;
293*a1157835SDaniel Fojt 	sm->otx = FALSE;
294*a1157835SDaniel Fojt 	ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
295*a1157835SDaniel Fojt 				       sm->otx, sm->orx);
296*a1157835SDaniel Fojt 	ieee802_1x_kay_enable_new_info(sm->kay);
297*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
298*a1157835SDaniel Fojt 	eloop_register_timeout(sm->retire_when / 1000, 0,
299*a1157835SDaniel Fojt 			       ieee802_1x_cp_retire_when_timeout, sm, NULL);
300*a1157835SDaniel Fojt 	sm->using_transmit_sa = FALSE;
301*a1157835SDaniel Fojt }
302*a1157835SDaniel Fojt 
303*a1157835SDaniel Fojt 
SM_STATE(CP,ABANDON)304*a1157835SDaniel Fojt SM_STATE(CP, ABANDON)
305*a1157835SDaniel Fojt {
306*a1157835SDaniel Fojt 	SM_ENTRY(CP, ABANDON);
307*a1157835SDaniel Fojt 	sm->lrx = FALSE;
308*a1157835SDaniel Fojt 	ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
309*a1157835SDaniel Fojt 					  sm->ltx, sm->lrx);
310*a1157835SDaniel Fojt 	ieee802_1x_kay_delete_sas(sm->kay, sm->lki);
311*a1157835SDaniel Fojt 
312*a1157835SDaniel Fojt 	os_free(sm->lki);
313*a1157835SDaniel Fojt 	sm->lki = NULL;
314*a1157835SDaniel Fojt 	ieee802_1x_kay_set_latest_sa_attr(sm->kay, sm->lki, sm->lan,
315*a1157835SDaniel Fojt 					  sm->ltx, sm->lrx);
316*a1157835SDaniel Fojt 	sm->new_sak = FALSE;
317*a1157835SDaniel Fojt }
318*a1157835SDaniel Fojt 
319*a1157835SDaniel Fojt 
SM_STATE(CP,RETIRE)320*a1157835SDaniel Fojt SM_STATE(CP, RETIRE)
321*a1157835SDaniel Fojt {
322*a1157835SDaniel Fojt 	SM_ENTRY(CP, RETIRE);
323*a1157835SDaniel Fojt 	/* RETIRE state machine not keep with Figure 12-2 in
324*a1157835SDaniel Fojt 	 * IEEE Std 802.1X-2010 */
325*a1157835SDaniel Fojt 	if (sm->oki) {
326*a1157835SDaniel Fojt 		ieee802_1x_kay_delete_sas(sm->kay, sm->oki);
327*a1157835SDaniel Fojt 		os_free(sm->oki);
328*a1157835SDaniel Fojt 		sm->oki = NULL;
329*a1157835SDaniel Fojt 	}
330*a1157835SDaniel Fojt 	sm->orx = FALSE;
331*a1157835SDaniel Fojt 	sm->otx = FALSE;
332*a1157835SDaniel Fojt 	ieee802_1x_kay_set_old_sa_attr(sm->kay, sm->oki, sm->oan,
333*a1157835SDaniel Fojt 				       sm->otx, sm->orx);
334*a1157835SDaniel Fojt }
335*a1157835SDaniel Fojt 
336*a1157835SDaniel Fojt 
337*a1157835SDaniel Fojt /**
338*a1157835SDaniel Fojt  * CP state machine handler entry
339*a1157835SDaniel Fojt  */
SM_STEP(CP)340*a1157835SDaniel Fojt SM_STEP(CP)
341*a1157835SDaniel Fojt {
342*a1157835SDaniel Fojt 	if (!sm->port_enabled)
343*a1157835SDaniel Fojt 		SM_ENTER(CP, INIT);
344*a1157835SDaniel Fojt 
345*a1157835SDaniel Fojt 	switch (sm->CP_state) {
346*a1157835SDaniel Fojt 	case CP_BEGIN:
347*a1157835SDaniel Fojt 		SM_ENTER(CP, INIT);
348*a1157835SDaniel Fojt 		break;
349*a1157835SDaniel Fojt 
350*a1157835SDaniel Fojt 	case CP_INIT:
351*a1157835SDaniel Fojt 		SM_ENTER(CP, CHANGE);
352*a1157835SDaniel Fojt 		break;
353*a1157835SDaniel Fojt 
354*a1157835SDaniel Fojt 	case CP_CHANGE:
355*a1157835SDaniel Fojt 		if (sm->connect == UNAUTHENTICATED)
356*a1157835SDaniel Fojt 			SM_ENTER(CP, ALLOWED);
357*a1157835SDaniel Fojt 		else if (sm->connect == AUTHENTICATED)
358*a1157835SDaniel Fojt 			SM_ENTER(CP, AUTHENTICATED);
359*a1157835SDaniel Fojt 		else if (sm->connect == SECURE)
360*a1157835SDaniel Fojt 			SM_ENTER(CP, SECURED);
361*a1157835SDaniel Fojt 		break;
362*a1157835SDaniel Fojt 
363*a1157835SDaniel Fojt 	case CP_ALLOWED:
364*a1157835SDaniel Fojt 		if (sm->connect != UNAUTHENTICATED)
365*a1157835SDaniel Fojt 			SM_ENTER(CP, CHANGE);
366*a1157835SDaniel Fojt 		break;
367*a1157835SDaniel Fojt 
368*a1157835SDaniel Fojt 	case CP_AUTHENTICATED:
369*a1157835SDaniel Fojt 		if (sm->connect != AUTHENTICATED)
370*a1157835SDaniel Fojt 			SM_ENTER(CP, CHANGE);
371*a1157835SDaniel Fojt 		break;
372*a1157835SDaniel Fojt 
373*a1157835SDaniel Fojt 	case CP_SECURED:
374*a1157835SDaniel Fojt 		if (changed_connect(sm))
375*a1157835SDaniel Fojt 			SM_ENTER(CP, CHANGE);
376*a1157835SDaniel Fojt 		else if (sm->new_sak)
377*a1157835SDaniel Fojt 			SM_ENTER(CP, RECEIVE);
378*a1157835SDaniel Fojt 		break;
379*a1157835SDaniel Fojt 
380*a1157835SDaniel Fojt 	case CP_RECEIVE:
381*a1157835SDaniel Fojt 		if (sm->using_receive_sas)
382*a1157835SDaniel Fojt 			SM_ENTER(CP, RECEIVING);
383*a1157835SDaniel Fojt 		break;
384*a1157835SDaniel Fojt 
385*a1157835SDaniel Fojt 	case CP_RECEIVING:
386*a1157835SDaniel Fojt 		if (sm->new_sak || changed_connect(sm))
387*a1157835SDaniel Fojt 			SM_ENTER(CP, ABANDON);
388*a1157835SDaniel Fojt 		if (!sm->elected_self)
389*a1157835SDaniel Fojt 			SM_ENTER(CP, READY);
390*a1157835SDaniel Fojt 		if (sm->elected_self &&
391*a1157835SDaniel Fojt 		    (sm->all_receiving || !sm->controlled_port_enabled ||
392*a1157835SDaniel Fojt 		     !sm->transmit_when))
393*a1157835SDaniel Fojt 			SM_ENTER(CP, TRANSMIT);
394*a1157835SDaniel Fojt 		break;
395*a1157835SDaniel Fojt 
396*a1157835SDaniel Fojt 	case CP_TRANSMIT:
397*a1157835SDaniel Fojt 		if (sm->using_transmit_sa)
398*a1157835SDaniel Fojt 			SM_ENTER(CP, TRANSMITTING);
399*a1157835SDaniel Fojt 		break;
400*a1157835SDaniel Fojt 
401*a1157835SDaniel Fojt 	case CP_TRANSMITTING:
402*a1157835SDaniel Fojt 		if (!sm->retire_when || changed_connect(sm))
403*a1157835SDaniel Fojt 			SM_ENTER(CP, RETIRE);
404*a1157835SDaniel Fojt 		break;
405*a1157835SDaniel Fojt 
406*a1157835SDaniel Fojt 	case CP_RETIRE:
407*a1157835SDaniel Fojt 		if (changed_connect(sm))
408*a1157835SDaniel Fojt 			SM_ENTER(CP, CHANGE);
409*a1157835SDaniel Fojt 		else if (sm->new_sak)
410*a1157835SDaniel Fojt 			SM_ENTER(CP, RECEIVE);
411*a1157835SDaniel Fojt 		break;
412*a1157835SDaniel Fojt 
413*a1157835SDaniel Fojt 	case CP_READY:
414*a1157835SDaniel Fojt 		if (sm->new_sak || changed_connect(sm))
415*a1157835SDaniel Fojt 			SM_ENTER(CP, ABANDON);
416*a1157835SDaniel Fojt 		if (sm->server_transmitting || !sm->controlled_port_enabled)
417*a1157835SDaniel Fojt 			SM_ENTER(CP, TRANSMIT);
418*a1157835SDaniel Fojt 		break;
419*a1157835SDaniel Fojt 	case CP_ABANDON:
420*a1157835SDaniel Fojt 		if (changed_connect(sm))
421*a1157835SDaniel Fojt 			SM_ENTER(CP, RETIRE);
422*a1157835SDaniel Fojt 		else if (sm->new_sak)
423*a1157835SDaniel Fojt 			SM_ENTER(CP, RECEIVE);
424*a1157835SDaniel Fojt 		break;
425*a1157835SDaniel Fojt 	default:
426*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "CP: the state machine is not defined");
427*a1157835SDaniel Fojt 		break;
428*a1157835SDaniel Fojt 	}
429*a1157835SDaniel Fojt }
430*a1157835SDaniel Fojt 
431*a1157835SDaniel Fojt 
432*a1157835SDaniel Fojt /**
433*a1157835SDaniel Fojt  * ieee802_1x_cp_sm_init -
434*a1157835SDaniel Fojt  */
ieee802_1x_cp_sm_init(struct ieee802_1x_kay * kay)435*a1157835SDaniel Fojt struct ieee802_1x_cp_sm * ieee802_1x_cp_sm_init(struct ieee802_1x_kay *kay)
436*a1157835SDaniel Fojt {
437*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm;
438*a1157835SDaniel Fojt 
439*a1157835SDaniel Fojt 	sm = os_zalloc(sizeof(*sm));
440*a1157835SDaniel Fojt 	if (sm == NULL) {
441*a1157835SDaniel Fojt 		wpa_printf(MSG_ERROR, "CP-%s: out of memory", __func__);
442*a1157835SDaniel Fojt 		return NULL;
443*a1157835SDaniel Fojt 	}
444*a1157835SDaniel Fojt 
445*a1157835SDaniel Fojt 	sm->kay = kay;
446*a1157835SDaniel Fojt 
447*a1157835SDaniel Fojt 	sm->port_valid = FALSE;
448*a1157835SDaniel Fojt 
449*a1157835SDaniel Fojt 	sm->chgd_server = FALSE;
450*a1157835SDaniel Fojt 
451*a1157835SDaniel Fojt 	sm->protect_frames = kay->macsec_protect;
452*a1157835SDaniel Fojt 	sm->validate_frames = kay->macsec_validate;
453*a1157835SDaniel Fojt 	sm->replay_protect = kay->macsec_replay_protect;
454*a1157835SDaniel Fojt 	sm->replay_window = kay->macsec_replay_window;
455*a1157835SDaniel Fojt 
456*a1157835SDaniel Fojt 	sm->controlled_port_enabled = FALSE;
457*a1157835SDaniel Fojt 
458*a1157835SDaniel Fojt 	sm->lki = NULL;
459*a1157835SDaniel Fojt 	sm->lrx = FALSE;
460*a1157835SDaniel Fojt 	sm->ltx = FALSE;
461*a1157835SDaniel Fojt 	sm->oki = NULL;
462*a1157835SDaniel Fojt 	sm->orx = FALSE;
463*a1157835SDaniel Fojt 	sm->otx = FALSE;
464*a1157835SDaniel Fojt 
465*a1157835SDaniel Fojt 	sm->current_cipher_suite = default_cs_id;
466*a1157835SDaniel Fojt 	sm->cipher_suite = default_cs_id;
467*a1157835SDaniel Fojt 	sm->cipher_offset = CONFIDENTIALITY_OFFSET_0;
468*a1157835SDaniel Fojt 	sm->confidentiality_offset = sm->cipher_offset;
469*a1157835SDaniel Fojt 	sm->transmit_delay = MKA_LIFE_TIME;
470*a1157835SDaniel Fojt 	sm->retire_delay = MKA_SAK_RETIRE_TIME;
471*a1157835SDaniel Fojt 	sm->CP_state = CP_BEGIN;
472*a1157835SDaniel Fojt 	sm->changed = FALSE;
473*a1157835SDaniel Fojt 
474*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "CP: state machine created");
475*a1157835SDaniel Fojt 
476*a1157835SDaniel Fojt 	secy_cp_control_protect_frames(sm->kay, sm->protect_frames);
477*a1157835SDaniel Fojt 	secy_cp_control_encrypt(sm->kay, sm->kay->macsec_encrypt);
478*a1157835SDaniel Fojt 	secy_cp_control_validate_frames(sm->kay, sm->validate_frames);
479*a1157835SDaniel Fojt 	secy_cp_control_replay(sm->kay, sm->replay_protect, sm->replay_window);
480*a1157835SDaniel Fojt 	secy_cp_control_enable_port(sm->kay, sm->controlled_port_enabled);
481*a1157835SDaniel Fojt 	secy_cp_control_confidentiality_offset(sm->kay,
482*a1157835SDaniel Fojt 					       sm->confidentiality_offset);
483*a1157835SDaniel Fojt 
484*a1157835SDaniel Fojt 	SM_STEP_RUN(CP);
485*a1157835SDaniel Fojt 
486*a1157835SDaniel Fojt 	return sm;
487*a1157835SDaniel Fojt }
488*a1157835SDaniel Fojt 
489*a1157835SDaniel Fojt 
ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm * sm)490*a1157835SDaniel Fojt static void ieee802_1x_cp_step_run(struct ieee802_1x_cp_sm *sm)
491*a1157835SDaniel Fojt {
492*a1157835SDaniel Fojt 	enum cp_states prev_state;
493*a1157835SDaniel Fojt 	int i;
494*a1157835SDaniel Fojt 
495*a1157835SDaniel Fojt 	for (i = 0; i < 100; i++) {
496*a1157835SDaniel Fojt 		prev_state = sm->CP_state;
497*a1157835SDaniel Fojt 		SM_STEP_RUN(CP);
498*a1157835SDaniel Fojt 		if (prev_state == sm->CP_state)
499*a1157835SDaniel Fojt 			break;
500*a1157835SDaniel Fojt 	}
501*a1157835SDaniel Fojt }
502*a1157835SDaniel Fojt 
503*a1157835SDaniel Fojt 
ieee802_1x_cp_step_cb(void * eloop_ctx,void * timeout_ctx)504*a1157835SDaniel Fojt static void ieee802_1x_cp_step_cb(void *eloop_ctx, void *timeout_ctx)
505*a1157835SDaniel Fojt {
506*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = eloop_ctx;
507*a1157835SDaniel Fojt 	ieee802_1x_cp_step_run(sm);
508*a1157835SDaniel Fojt }
509*a1157835SDaniel Fojt 
510*a1157835SDaniel Fojt 
511*a1157835SDaniel Fojt /**
512*a1157835SDaniel Fojt  * ieee802_1x_cp_sm_deinit -
513*a1157835SDaniel Fojt  */
ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm * sm)514*a1157835SDaniel Fojt void ieee802_1x_cp_sm_deinit(struct ieee802_1x_cp_sm *sm)
515*a1157835SDaniel Fojt {
516*a1157835SDaniel Fojt 	wpa_printf(MSG_DEBUG, "CP: state machine removed");
517*a1157835SDaniel Fojt 	if (!sm)
518*a1157835SDaniel Fojt 		return;
519*a1157835SDaniel Fojt 
520*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_cp_retire_when_timeout, sm, NULL);
521*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_cp_transmit_when_timeout, sm, NULL);
522*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
523*a1157835SDaniel Fojt 	os_free(sm->lki);
524*a1157835SDaniel Fojt 	os_free(sm->oki);
525*a1157835SDaniel Fojt 	os_free(sm);
526*a1157835SDaniel Fojt }
527*a1157835SDaniel Fojt 
528*a1157835SDaniel Fojt 
529*a1157835SDaniel Fojt /**
530*a1157835SDaniel Fojt  * ieee802_1x_cp_connect_pending
531*a1157835SDaniel Fojt  */
ieee802_1x_cp_connect_pending(void * cp_ctx)532*a1157835SDaniel Fojt void ieee802_1x_cp_connect_pending(void *cp_ctx)
533*a1157835SDaniel Fojt {
534*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
535*a1157835SDaniel Fojt 
536*a1157835SDaniel Fojt 	sm->connect = PENDING;
537*a1157835SDaniel Fojt }
538*a1157835SDaniel Fojt 
539*a1157835SDaniel Fojt 
540*a1157835SDaniel Fojt /**
541*a1157835SDaniel Fojt  * ieee802_1x_cp_connect_unauthenticated
542*a1157835SDaniel Fojt  */
ieee802_1x_cp_connect_unauthenticated(void * cp_ctx)543*a1157835SDaniel Fojt void ieee802_1x_cp_connect_unauthenticated(void *cp_ctx)
544*a1157835SDaniel Fojt {
545*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = (struct ieee802_1x_cp_sm *)cp_ctx;
546*a1157835SDaniel Fojt 
547*a1157835SDaniel Fojt 	sm->connect = UNAUTHENTICATED;
548*a1157835SDaniel Fojt }
549*a1157835SDaniel Fojt 
550*a1157835SDaniel Fojt 
551*a1157835SDaniel Fojt /**
552*a1157835SDaniel Fojt  * ieee802_1x_cp_connect_authenticated
553*a1157835SDaniel Fojt  */
ieee802_1x_cp_connect_authenticated(void * cp_ctx)554*a1157835SDaniel Fojt void ieee802_1x_cp_connect_authenticated(void *cp_ctx)
555*a1157835SDaniel Fojt {
556*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
557*a1157835SDaniel Fojt 
558*a1157835SDaniel Fojt 	sm->connect = AUTHENTICATED;
559*a1157835SDaniel Fojt }
560*a1157835SDaniel Fojt 
561*a1157835SDaniel Fojt 
562*a1157835SDaniel Fojt /**
563*a1157835SDaniel Fojt  * ieee802_1x_cp_connect_secure
564*a1157835SDaniel Fojt  */
ieee802_1x_cp_connect_secure(void * cp_ctx)565*a1157835SDaniel Fojt void ieee802_1x_cp_connect_secure(void *cp_ctx)
566*a1157835SDaniel Fojt {
567*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
568*a1157835SDaniel Fojt 
569*a1157835SDaniel Fojt 	sm->connect = SECURE;
570*a1157835SDaniel Fojt }
571*a1157835SDaniel Fojt 
572*a1157835SDaniel Fojt 
573*a1157835SDaniel Fojt /**
574*a1157835SDaniel Fojt  * ieee802_1x_cp_set_chgdserver -
575*a1157835SDaniel Fojt  */
ieee802_1x_cp_signal_chgdserver(void * cp_ctx)576*a1157835SDaniel Fojt void ieee802_1x_cp_signal_chgdserver(void *cp_ctx)
577*a1157835SDaniel Fojt {
578*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
579*a1157835SDaniel Fojt 
580*a1157835SDaniel Fojt 	sm->chgd_server = TRUE;
581*a1157835SDaniel Fojt }
582*a1157835SDaniel Fojt 
583*a1157835SDaniel Fojt 
584*a1157835SDaniel Fojt /**
585*a1157835SDaniel Fojt  * ieee802_1x_cp_set_electedself -
586*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_electedself(void * cp_ctx,Boolean status)587*a1157835SDaniel Fojt void ieee802_1x_cp_set_electedself(void *cp_ctx, Boolean status)
588*a1157835SDaniel Fojt {
589*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
590*a1157835SDaniel Fojt 	sm->elected_self = status;
591*a1157835SDaniel Fojt }
592*a1157835SDaniel Fojt 
593*a1157835SDaniel Fojt 
594*a1157835SDaniel Fojt /**
595*a1157835SDaniel Fojt  * ieee802_1x_cp_set_ciphersuite -
596*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_ciphersuite(void * cp_ctx,u64 cs)597*a1157835SDaniel Fojt void ieee802_1x_cp_set_ciphersuite(void *cp_ctx, u64 cs)
598*a1157835SDaniel Fojt {
599*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
600*a1157835SDaniel Fojt 	sm->cipher_suite = cs;
601*a1157835SDaniel Fojt }
602*a1157835SDaniel Fojt 
603*a1157835SDaniel Fojt 
604*a1157835SDaniel Fojt /**
605*a1157835SDaniel Fojt  * ieee802_1x_cp_set_offset -
606*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_offset(void * cp_ctx,enum confidentiality_offset offset)607*a1157835SDaniel Fojt void ieee802_1x_cp_set_offset(void *cp_ctx, enum confidentiality_offset offset)
608*a1157835SDaniel Fojt {
609*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
610*a1157835SDaniel Fojt 	sm->cipher_offset = offset;
611*a1157835SDaniel Fojt }
612*a1157835SDaniel Fojt 
613*a1157835SDaniel Fojt 
614*a1157835SDaniel Fojt /**
615*a1157835SDaniel Fojt  * ieee802_1x_cp_signal_newsak -
616*a1157835SDaniel Fojt  */
ieee802_1x_cp_signal_newsak(void * cp_ctx)617*a1157835SDaniel Fojt void ieee802_1x_cp_signal_newsak(void *cp_ctx)
618*a1157835SDaniel Fojt {
619*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
620*a1157835SDaniel Fojt 	sm->new_sak = TRUE;
621*a1157835SDaniel Fojt }
622*a1157835SDaniel Fojt 
623*a1157835SDaniel Fojt 
624*a1157835SDaniel Fojt /**
625*a1157835SDaniel Fojt  * ieee802_1x_cp_set_distributedki -
626*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_distributedki(void * cp_ctx,const struct ieee802_1x_mka_ki * dki)627*a1157835SDaniel Fojt void ieee802_1x_cp_set_distributedki(void *cp_ctx,
628*a1157835SDaniel Fojt 				     const struct ieee802_1x_mka_ki *dki)
629*a1157835SDaniel Fojt {
630*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
631*a1157835SDaniel Fojt 	os_memcpy(&sm->distributed_ki, dki, sizeof(struct ieee802_1x_mka_ki));
632*a1157835SDaniel Fojt }
633*a1157835SDaniel Fojt 
634*a1157835SDaniel Fojt 
635*a1157835SDaniel Fojt /**
636*a1157835SDaniel Fojt  * ieee802_1x_cp_set_distributedan -
637*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_distributedan(void * cp_ctx,u8 an)638*a1157835SDaniel Fojt void ieee802_1x_cp_set_distributedan(void *cp_ctx, u8 an)
639*a1157835SDaniel Fojt {
640*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
641*a1157835SDaniel Fojt 	sm->distributed_an = an;
642*a1157835SDaniel Fojt }
643*a1157835SDaniel Fojt 
644*a1157835SDaniel Fojt 
645*a1157835SDaniel Fojt /**
646*a1157835SDaniel Fojt  * ieee802_1x_cp_set_usingreceivesas -
647*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_usingreceivesas(void * cp_ctx,Boolean status)648*a1157835SDaniel Fojt void ieee802_1x_cp_set_usingreceivesas(void *cp_ctx, Boolean status)
649*a1157835SDaniel Fojt {
650*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
651*a1157835SDaniel Fojt 	sm->using_receive_sas = status;
652*a1157835SDaniel Fojt }
653*a1157835SDaniel Fojt 
654*a1157835SDaniel Fojt 
655*a1157835SDaniel Fojt /**
656*a1157835SDaniel Fojt  * ieee802_1x_cp_set_allreceiving -
657*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_allreceiving(void * cp_ctx,Boolean status)658*a1157835SDaniel Fojt void ieee802_1x_cp_set_allreceiving(void *cp_ctx, Boolean status)
659*a1157835SDaniel Fojt {
660*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
661*a1157835SDaniel Fojt 	sm->all_receiving = status;
662*a1157835SDaniel Fojt }
663*a1157835SDaniel Fojt 
664*a1157835SDaniel Fojt 
665*a1157835SDaniel Fojt /**
666*a1157835SDaniel Fojt  * ieee802_1x_cp_set_servertransmitting -
667*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_servertransmitting(void * cp_ctx,Boolean status)668*a1157835SDaniel Fojt void ieee802_1x_cp_set_servertransmitting(void *cp_ctx, Boolean status)
669*a1157835SDaniel Fojt {
670*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
671*a1157835SDaniel Fojt 	sm->server_transmitting = status;
672*a1157835SDaniel Fojt }
673*a1157835SDaniel Fojt 
674*a1157835SDaniel Fojt 
675*a1157835SDaniel Fojt /**
676*a1157835SDaniel Fojt  * ieee802_1x_cp_set_usingtransmitsas -
677*a1157835SDaniel Fojt  */
ieee802_1x_cp_set_usingtransmitas(void * cp_ctx,Boolean status)678*a1157835SDaniel Fojt void ieee802_1x_cp_set_usingtransmitas(void *cp_ctx, Boolean status)
679*a1157835SDaniel Fojt {
680*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
681*a1157835SDaniel Fojt 	sm->using_transmit_sa = status;
682*a1157835SDaniel Fojt }
683*a1157835SDaniel Fojt 
684*a1157835SDaniel Fojt 
685*a1157835SDaniel Fojt /**
686*a1157835SDaniel Fojt  * ieee802_1x_cp_sm_step - Advance EAPOL state machines
687*a1157835SDaniel Fojt  * @sm: EAPOL state machine
688*a1157835SDaniel Fojt  *
689*a1157835SDaniel Fojt  * This function is called to advance CP state machines after any change
690*a1157835SDaniel Fojt  * that could affect their state.
691*a1157835SDaniel Fojt  */
ieee802_1x_cp_sm_step(void * cp_ctx)692*a1157835SDaniel Fojt void ieee802_1x_cp_sm_step(void *cp_ctx)
693*a1157835SDaniel Fojt {
694*a1157835SDaniel Fojt 	/*
695*a1157835SDaniel Fojt 	 * Run ieee802_1x_cp_step_run from a registered timeout
696*a1157835SDaniel Fojt 	 * to make sure that other possible timeouts/events are processed
697*a1157835SDaniel Fojt 	 * and to avoid long function call chains.
698*a1157835SDaniel Fojt 	 */
699*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = cp_ctx;
700*a1157835SDaniel Fojt 	eloop_cancel_timeout(ieee802_1x_cp_step_cb, sm, NULL);
701*a1157835SDaniel Fojt 	eloop_register_timeout(0, 0, ieee802_1x_cp_step_cb, sm, NULL);
702*a1157835SDaniel Fojt }
703*a1157835SDaniel Fojt 
704*a1157835SDaniel Fojt 
ieee802_1x_cp_retire_when_timeout(void * eloop_ctx,void * timeout_ctx)705*a1157835SDaniel Fojt static void ieee802_1x_cp_retire_when_timeout(void *eloop_ctx,
706*a1157835SDaniel Fojt 					      void *timeout_ctx)
707*a1157835SDaniel Fojt {
708*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = eloop_ctx;
709*a1157835SDaniel Fojt 	sm->retire_when = 0;
710*a1157835SDaniel Fojt 	ieee802_1x_cp_step_run(sm);
711*a1157835SDaniel Fojt }
712*a1157835SDaniel Fojt 
713*a1157835SDaniel Fojt 
714*a1157835SDaniel Fojt static void
ieee802_1x_cp_transmit_when_timeout(void * eloop_ctx,void * timeout_ctx)715*a1157835SDaniel Fojt ieee802_1x_cp_transmit_when_timeout(void *eloop_ctx, void *timeout_ctx)
716*a1157835SDaniel Fojt {
717*a1157835SDaniel Fojt 	struct ieee802_1x_cp_sm *sm = eloop_ctx;
718*a1157835SDaniel Fojt 	sm->transmit_when = 0;
719*a1157835SDaniel Fojt 	ieee802_1x_cp_step_run(sm);
720*a1157835SDaniel Fojt }
721