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