authenticator_pae_fsm.c
Go to the documentation of this file.
1 /**
2  * @file authenticator_pae_fsm.c
3  * @brief Authenticator PAE state machine
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2022-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneEAP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL AUTHENTICATOR_TRACE_LEVEL
33 
34 //Dependencies
40 #include "eap/eap_debug.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (AUTHENTICATOR_SUPPORT == ENABLED)
45 
46 //Authenticator PAE states
48 {
49  {AUTHENTICATOR_PAE_STATE_INITIALIZE, "INITIALIZE"},
50  {AUTHENTICATOR_PAE_STATE_DISCONNECTED, "DISCONNECTED"},
52  {AUTHENTICATOR_PAE_STATE_CONNECTING, "CONNECTING"},
53  {AUTHENTICATOR_PAE_STATE_AUTHENTICATING, "AUTHENTICATING"},
54  {AUTHENTICATOR_PAE_STATE_AUTHENTICATED, "AUTHENTICATED"},
57  {AUTHENTICATOR_PAE_STATE_FORCE_AUTH, "FORCE_AUTH"},
58  {AUTHENTICATOR_PAE_STATE_FORCE_UNAUTH, "FORCE_UNAUTH"}
59 };
60 
61 
62 /**
63  * @brief Authenticator PAE state machine initialization
64  * @param[in] port Pointer to the port context
65  **/
66 
68 {
69  //Enter initial state
71 }
72 
73 
74 /**
75  * @brief Authenticator PAE state machine implementation
76  * @param[in] port Pointer to the port context
77  **/
78 
80 {
81  //A global transition can occur from any of the possible states. When the
82  //condition associated with a global transition is met, it supersedes all
83  //other exit conditions
84  if((port->portControl == AUTHENTICATOR_PORT_MODE_AUTO &&
85  port->portMode != port->portControl) ||
86  port->initialize || !port->portEnabled)
87  {
88  //Switch to the INITIALIZE state
90  }
91  else if(port->portControl == AUTHENTICATOR_PORT_MODE_FORCE_AUTH &&
92  port->portMode != port->portControl &&
93  !(port->initialize || !port->portEnabled))
94  {
95  //Switch to the FORCE_AUTH state
97  }
98  else if(port->portControl == AUTHENTICATOR_PORT_MODE_FORCE_UNAUTH &&
99  port->portMode != port->portControl &&
100  !(port->initialize || !port->portEnabled))
101  {
102  //Switch to the FORCE_UNAUTH state
104  }
105  else
106  {
107  //All exit conditions for the state are evaluated continuously until one
108  //of the conditions is met (refer to IEEE Std 802.1X-2004, section 8.2.1)
109  switch(port->authPaeState)
110  {
111  //INITIALIZE state?
113  //Unconditional transition (UCT) to DISCONNECTED state
115  break;
116 
117  //DISCONNECTED state?
119  //Unconditional transition (UCT) to RESTART state
121  break;
122 
123  //RESTART state?
125  //This state will exit to CONNECTING when EAP has acknowledged the
126  //restart by resetting eapRestart to FALSE
127  if(!port->eapRestart)
128  {
129  //Switch to the CONNECTING state
131  }
132 
133  break;
134 
135  //CONNECTING state?
137  //Evaluate conditions for the current state
138  if(port->eapolLogoff || port->reAuthCount > port->reAuthMax)
139  {
140  //Switch to the DISCONNECTED state
142  }
143  else if((port->eapReq && port->reAuthCount <= port->reAuthMax) ||
144  port->eapSuccess || port->eapFail)
145  {
146  //Switch to the AUTHENTICATING state
148  }
149  else
150  {
151  //Just for sanity
152  }
153 
154  break;
155 
156  //AUTHENTICATING state?
158  //Evaluate conditions for the current state
159  if(port->authSuccess && port->portValid)
160  {
161  //Switch to the AUTHENTICATED state
163  }
164  else if(port->eapolStart || port->eapolLogoff || port->authTimeout)
165  {
166  //Switch to the ABORTING state
168  }
169  else if(port->authFail || (port->keyDone && !port->portValid))
170  {
171  //Switch to the HELD state
173  }
174  else
175  {
176  //Just for sanity
177  }
178 
179  break;
180 
181  //AUTHENTICATED state?
183  //Evaluate conditions for the current state
184  if(port->eapolStart || port->reAuthenticate)
185  {
186  //Switch to the RESTART state
188  }
189  else if(port->eapolLogoff || !port->portValid)
190  {
191  //Switch to the DISCONNECTED state
193  }
194  else
195  {
196  //Just for sanity
197  }
198 
199  break;
200 
201  //ABORTING state?
203  //Evaluate conditions for the current state
204  if(port->eapolLogoff && !port->authAbort)
205  {
206  //Switch to the DISCONNECTED state
208  }
209  else if(!port->eapolLogoff && !port->authAbort)
210  {
211  //Switch to the RESTART state
213  }
214  else
215  {
216  //Just for sanity
217  }
218 
219  break;
220 
221  //HELD state?
223  //At the expiration of the quietWhile timer, the state machine
224  //transitions to the RESTART state
225  if(port->quietWhile == 0)
226  {
227  //Switch to the RESTART state
229  }
230 
231  break;
232 
233  //FORCE_AUTH state?
235  //If an EAPOL-Start message is received from the supplicant, the state
236  //is re-entered and a further EAP success message is sent
237  if(port->eapolStart)
238  {
239  //Switch to the FORCE_AUTH state
241  }
242 
243  break;
244 
245  //FORCE_UNAUTH state?
247  //If an EAPOL-Start message is received from the supplicant, the state
248  //is re-entered and a further EAP failure message is sent
249  if(port->eapolStart)
250  {
251  //Switch to the FORCE_UNAUTH state
253  }
254 
255  break;
256 
257  //Invalid state?
258  default:
259  //Just for sanity
260  authenticatorFsmError(port->context);
261  break;
262  }
263  }
264 }
265 
266 
267 /**
268  * @brief Update authenticator PAE state
269  * @param[in] port Pointer to the port context
270  * @param[in] newState New state to switch to
271  **/
272 
274  AuthenticatorPaeState newState)
275 {
276  AuthenticatorPaeState oldState;
277 
278  //Retrieve current state
279  oldState = port->authPaeState;
280 
281  //Any state change?
282  if(newState != oldState)
283  {
284  //Dump the state transition
285  TRACE_DEBUG("Port %" PRIu8 ": Authenticator PAE state machine %s -> %s\r\n",
286  port->portIndex,
291  }
292 
293  //Switch to the new state
294  port->authPaeState = newState;
295 
296  //On entry to a state, the procedures defined for the state are executed
297  //exactly once (refer to IEEE Std 802.1X-2004, section 8.2.1)
298  switch(newState)
299  {
300  //INITIALIZE state?
302  //The value of the portMode variable is set to Auto
304 
305  //Errata
306  if(port->authPortStatus != AUTHENTICATOR_PORT_STATUS_UNAUTH)
307  {
309  }
310 
311  break;
312 
313  //DISCONNECTED state?
315  //Errata
316  if(port->eapolStart)
317  {
318  port->sessionStats.sessionTerminateCause =
320  }
321  else if(port->eapolLogoff)
322  {
323  port->sessionStats.sessionTerminateCause =
325  }
326  else if(port->reAuthCount > port->reAuthMax)
327  {
328  port->sessionStats.sessionTerminateCause =
330  }
331  else
332  {
333  }
334 
335  //The authPortStatus variable is set to Unauthorized in this state,
336  //thereby setting the value of AuthControlledPortStatus to Unauthorized,
337  //the eapolLogoff variable is cleared and the reAuthCount is reset
339  port->reAuthCount = 0;
340  port->eapolLogoff = FALSE;
341  break;
342 
343  //RESTART state?
345  //The RESTART state is entered when the authenticator PAE needs to
346  //inform the higher layer that it has restarted
347  port->eapRestart = TRUE;
348  break;
349 
350  //CONNECTING state?
352  //In this state, the port is operable, the higher layer is in sync and
353  //ready to attempt to establish communication with a supplicant
354  port->reAuthenticate = FALSE;
355  port->reAuthCount++;
356  break;
357 
358  //AUTHENTICATING state?
360  //In this state, a supplicant is being authenticated
361  port->eapolStart = FALSE;
362  port->authSuccess = FALSE;
363  port->authFail = FALSE;
364  port->authTimeout = FALSE;
365  port->authStart = TRUE;
366  port->keyRun = FALSE;
367  port->keyDone = FALSE;
368  break;
369 
370  //AUTHENTICATED state?
372  //In this state, the Authenticator has successfully authenticated the
373  //supplicant and the portValid variable has become TRUE
375  port->reAuthCount = 0;
376 
377  //Errata
378  port->sessionStats.sessionTerminateCause =
380 
381  break;
382 
383  //ABORTING state?
385  //In this state, the authentication procedure is being prematurely
386  //aborted due to receipt of an EAPOL-Start frame, an EAPOL-Logoff
387  //frame, or an authTimeout
388  port->authAbort = TRUE;
389  port->keyRun = FALSE;
390  port->keyDone = FALSE;
391  break;
392 
393  //HELD state?
395  //In this state, the state machine ignores and discards all EAPOL
396  //packets, so as to discourage brute force attacks
398  port->quietWhile = port->quietPeriod;
399  port->eapolLogoff = FALSE;
400  break;
401 
402  //FORCE_AUTH state?
404  //The authPortStatus is set to Authorized, and a canned EAP success
405  //packet is sent to the supplicant
408  port->eapolStart = FALSE;
410 
411  //Errata
412  port->sessionStats.sessionTerminateCause =
414 
415  break;
416 
417  //FORCE_UNAUTH state?
419  //The authPortStatus is set to Unauthorized, and a canned EAP failure
420  //packet is sent to the supplicant
423  port->eapolStart = FALSE;
425 
426  //Errata
427  port->sessionStats.sessionTerminateCause =
429 
430  break;
431 
432  //Invalid state?
433  default:
434  //Just for sanity
435  break;
436  }
437 
438  //Any state change?
439  if(newState != oldState)
440  {
441  //Any registered callback?
442  if(port->context->paeStateChangeCallback != NULL)
443  {
444  //Invoke user callback function
445  port->context->paeStateChangeCallback(port, newState);
446  }
447  }
448 
449  //Check whether the port is enabled
450  if(!port->initialize && port->portEnabled)
451  {
452  //The authenticator PAE state machine is busy
453  port->context->busy = TRUE;
454  }
455 }
456 
457 #endif
802.1X authenticator
#define AuthenticatorPort
Definition: authenticator.h:40
@ AUTHENTICATOR_TERMINATE_CAUSE_SUPPLICANT_RESTART
@ AUTHENTICATOR_TERMINATE_CAUSE_SUPPLICANT_LOGOFF
@ AUTHENTICATOR_TERMINATE_CAUSE_NOT_TERMINATED_YET
@ AUTHENTICATOR_TERMINATE_CAUSE_AUTH_CONTROL_FORCE_UNAUTH
@ AUTHENTICATOR_TERMINATE_CAUSE_REAUTH_FAILED
void authenticatorFsmError(AuthenticatorContext *context)
Authenticator state machine error handler.
Authenticator state machine.
Helper functions for 802.1X authenticator.
void authenticatorPaeInitFsm(AuthenticatorPort *port)
Authenticator PAE state machine initialization.
void authenticatorPaeChangeState(AuthenticatorPort *port, AuthenticatorPaeState newState)
Update authenticator PAE state.
const EapParamName authenticatorPaeStates[]
void authenticatorPaeFsm(AuthenticatorPort *port)
Authenticator PAE state machine implementation.
Authenticator PAE state machine.
@ AUTHENTICATOR_PORT_STATUS_AUTH
@ AUTHENTICATOR_PORT_STATUS_UNAUTH
AuthenticatorPaeState
Authenticator PAE states.
@ AUTHENTICATOR_PAE_STATE_CONNECTING
@ AUTHENTICATOR_PAE_STATE_FORCE_AUTH
@ AUTHENTICATOR_PAE_STATE_AUTHENTICATING
@ AUTHENTICATOR_PAE_STATE_RESTART
@ AUTHENTICATOR_PAE_STATE_DISCONNECTED
@ AUTHENTICATOR_PAE_STATE_INITIALIZE
@ AUTHENTICATOR_PAE_STATE_ABORTING
@ AUTHENTICATOR_PAE_STATE_AUTHENTICATED
@ AUTHENTICATOR_PAE_STATE_FORCE_UNAUTH
@ AUTHENTICATOR_PAE_STATE_HELD
@ AUTHENTICATOR_PORT_MODE_FORCE_AUTH
@ AUTHENTICATOR_PORT_MODE_AUTO
@ AUTHENTICATOR_PORT_MODE_FORCE_UNAUTH
void authenticatorSetAuthPortStatus(AuthenticatorPort *port, AuthenticatorPortStatus status)
Set authorization state for a given port.
void authenticatorTxCannedSuccess(AuthenticatorPort *port)
Transmit an EAPOL frame containing an EAP success (8.2.4.1.3 b)
void authenticatorTxCannedFail(AuthenticatorPort *port)
Transmit an EAPOL frame containing an EAP failure (8.2.4.1.3 a)
Authenticator state machine procedures.
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint16_t port
Definition: dns_common.h:267
const char_t * eapGetParamName(uint_t value, const EapParamName *paramList, size_t paramListLen)
Convert a parameter to string representation.
Definition: eap_debug.c:219
Data logging functions for debugging purpose (EAP)
#define arraysize(a)
Definition: os_port.h:71
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
Parameter value/name binding.
Definition: eap_debug.h:50