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