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