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