supplicant_pae_fsm.c
Go to the documentation of this file.
1 /**
2  * @file supplicant_pae_fsm.c
3  * @brief Supplicant 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.4
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SUPPLICANT_TRACE_LEVEL
33 
34 //Dependencies
35 #include "supplicant/supplicant.h"
40 #include "eap/eap_debug.h"
41 #include "debug.h"
42 
43 //Check TCP/IP stack configuration
44 #if (SUPPLICANT_SUPPORT == ENABLED)
45 
46 //Supplicant PAE states
48 {
49  {SUPPLICANT_PAE_STATE_LOGOFF, "LOGOFF"},
50  {SUPPLICANT_PAE_STATE_DISCONNECTED, "DISCONNECTED"},
51  {SUPPLICANT_PAE_STATE_CONNECTING, "CONNECTING"},
52  {SUPPLICANT_PAE_STATE_AUTHENTICATING, "AUTHENTICATING"},
53  {SUPPLICANT_PAE_STATE_AUTHENTICATED, "AUTHENTICATED"},
54  {SUPPLICANT_PAE_STATE_HELD, "HELD"},
55  {SUPPLICANT_PAE_STATE_RESTART, "RESTART"},
56  {SUPPLICANT_PAE_STATE_S_FORCE_AUTH, "S_FORCE_AUTH"},
57  {SUPPLICANT_PAE_STATE_S_FORCE_UNAUTH, "S_FORCE_UNAUTH"}
58 };
59 
60 
61 /**
62  * @brief Supplicant PAE state machine initialization
63  * @param[in] context Pointer to the 802.1X supplicant context
64  **/
65 
67 {
68  //Enter initial state
70 }
71 
72 
73 /**
74  * @brief Supplicant PAE state machine implementation
75  * @param[in] context Pointer to the 802.1X supplicant context
76  **/
77 
79 {
80  //A global transition can occur from any of the possible states. When the
81  //condition associated with a global transition is met, it supersedes all
82  //other exit conditions
83  if(context->userLogoff && !context->logoffSent &&
84  !(context->initialize || !context->portEnabled))
85  {
86  //Switch to the LOGOFF state
88  }
89  else if((context->portControl == SUPPLICANT_PORT_MODE_AUTO &&
90  context->sPortMode != context->portControl) ||
91  context->initialize || !context->portEnabled)
92  {
93  //Switch to the DISCONNECTED state
95  }
96  else if(context->portControl == SUPPLICANT_PORT_MODE_FORCE_AUTH &&
97  context->sPortMode != context->portControl &&
98  !(context->initialize || !context->portEnabled))
99  {
100  //Switch to the S_FORCE_AUTH state
102  }
103  else if(context->portControl == SUPPLICANT_PORT_MODE_FORCE_UNAUTH &&
104  context->sPortMode != context->portControl &&
105  !(context->initialize || !context->portEnabled))
106  {
107  //Switch to the S_FORCE_UNAUTH state
109  }
110  else
111  {
112  //All exit conditions for the state are evaluated continuously until one
113  //of the conditions is met (refer to IEEE Std 802.1X-2004, section 8.2.1)
114  switch(context->suppPaeState)
115  {
116  //LOGOFF state?
118  //Evaluate conditions for the current state
119  if(!context->userLogoff)
120  {
121  //Switch to the DISCONNECTED state
123  }
124 
125  break;
126 
127  //DISCONNECTED state?
129  //Unconditional transition (UCT) to CONNECTING state
131  break;
132 
133  //CONNECTING state?
135  //Evaluate conditions for the current state
136  if(context->startWhen == 0)
137  {
138  //If the startWhen timer expires, the transmission is repeated up
139  //to a maximum of maxStart transmissions
140  if(context->startCount < context->maxStart)
141  {
142  //An EAPOL-Start packet is transmitted by the supplicant, and
143  //the startWhen timer is started, to cause retransmission if no
144  //response is received from the authenticator
146  }
147  else
148  {
149  //If no response is received after maxStart transmissions, the state
150  //machine assumes that it is attached to a system that is not EAPOL
151  //aware, and transitions to AUTHENTICATED state if portValid is TRUE
152  if(context->portValid)
153  {
154  //Switch to the AUTHENTICATED state
156  }
157  else
158  {
159  //Switch to the HELD state
161  }
162  }
163  }
164  else if(context->eapolEap)
165  {
166  //If an EAP-Request frame is received, the supplicant transitions
167  //to the RESTART state
169  }
170  else if(context->eapSuccess || context->eapFail)
171  {
172 //Errata
173 #if 0
174  //If the higher layer has decided it is satisfied with an
175  //eapSuccess or eapFail, the supplicant transitions directly to
176  //the AUTHENTICATING state
178 #endif
179  }
180  else
181  {
182  //Just for sanity
183  }
184 
185  break;
186 
187  //AUTHENTICATING state?
189  //Evaluate conditions for the current state
190  if(context->suppSuccess && context->portValid)
191  {
192  //Switch to the AUTHENTICATED state
194  }
195  else if(context->suppFail || (context->keyDone && !context->portValid))
196  {
197  //Switch to the HELD state
199  }
200  else if(context->suppTimeout)
201  {
202  //Switch to the CONNECTING state
204  }
205  else
206  {
207  //Just for sanity
208  }
209 
210  break;
211 
212  //AUTHENTICATED state?
214  //Evaluate conditions for the current state
215  if(context->eapolEap && context->portValid)
216  {
217  //Switch to the RESTART state
219  }
220  else if(!context->portValid)
221  {
222  //Switch to the DISCONNECTED state
224  }
225  else
226  {
227  //Just for sanity
228  }
229 
230  break;
231 
232  //HELD state?
234  //Evaluate conditions for the current state
235  if(context->heldWhile == 0)
236  {
237  //Switch to the CONNECTING state
239  }
240  else if(context->eapolEap)
241  {
242  //Switch to the RESTART state
244  }
245  else
246  {
247  //Just for sanity
248  }
249 
250  break;
251 
252  //RESTART state?
254  //Evaluate conditions for the current state
255  if(!context->eapRestart)
256  {
257  //Switch to the AUTHENTICATING state
259  }
260 
261  break;
262 
263  //S_FORCE_AUTH state?
265  //Force the port state to Authorized
266  break;
267 
268  //S_FORCE_UNAUTH state?
270  //Force the port state to Unauthorized
271  break;
272 
273  //Invalid state?
274  default:
275  //Just for sanity
276  supplicantFsmError(context);
277  break;
278  }
279  }
280 }
281 
282 
283 /**
284  * @brief Update supplicant PAE state
285  * @param[in] context Pointer to the 802.1X supplicant context
286  * @param[in] newState New state to switch to
287  **/
288 
290  SupplicantPaeState newState)
291 {
292  SupplicantPaeState oldState;
293 
294  //Retrieve current state
295  oldState = context->suppPaeState;
296 
297  //Any state change?
298  if(newState != oldState)
299  {
300  //Dump the state transition
301  TRACE_DEBUG("Supplicant PAE state machine %s -> %s\r\n",
306  }
307 
308  //Switch to the new state
309  context->suppPaeState = newState;
310 
311  //On entry to a state, the procedures defined for the state are executed
312  //exactly once (refer to IEEE Std 802.1X-2004, section 8.2.1)
313  switch(newState)
314  {
315  //LOGOFF state?
317  //The user of the system requests an explicit logoff
318  supplicantTxLogoff(context);
319  context->logoffSent = TRUE;
320  context->suppPortStatus = SUPPLICANT_PORT_STATUS_UNAUTH;
321  break;
322 
323  //DISCONNECTED state?
325  //This state is entered from any other state when the MAC service
326  //associated with the port is inoperable, or when the system is
327  //initialized or reinitialized
328  context->sPortMode = SUPPLICANT_PORT_MODE_AUTO;
329  context->startCount = 0;
330  context->logoffSent = FALSE;
331  context->suppPortStatus = SUPPLICANT_PORT_STATUS_UNAUTH;
332  context->suppAbort = TRUE;
333  break;
334 
335  //CONNECTING state?
337  //In this state, the port has become operable and the supplicant is
338  //attempting to acquire an authenticator
339  context->startWhen = context->startPeriod;
340  context->startCount++;
341  context->eapolEap = FALSE;
342  supplicantTxStart(context);
343  break;
344 
345  //AUTHENTICATING state?
347  //An EAP Request packet has been received from the authenticator
348  context->startCount = 0;
349  context->suppSuccess = FALSE;
350  context->suppFail = FALSE;
351  context->suppTimeout = FALSE;
352  context->keyRun = FALSE;
353  context->keyDone = FALSE;
354  context->suppStart = TRUE;
355  break;
356 
357  //AUTHENTICATED state?
359  //The supplicant has been successfully authenticated by the authenticator,
360  //or it has assumed that the authenticator is not EAPOL aware
361  context->suppPortStatus = SUPPLICANT_PORT_STATUS_AUTH;
362  break;
363 
364  //HELD state?
366  //The state provides a delay period before the supplicant will attempt to
367  //acquire an authenticator
368  context->heldWhile = context->heldPeriod;
369  context->suppPortStatus = SUPPLICANT_PORT_STATUS_UNAUTH;
370  break;
371 
372  //RESTART state?
374  //The RESTART state is entered when the supplicant PAE needs to inform the
375  //higher layer that it has restarted
376  context->eapRestart = TRUE;
377  break;
378 
379  //S_FORCE_AUTH state?
381  //The effect of these actions is to force the port state to Authorized
382  context->suppPortStatus = SUPPLICANT_PORT_STATUS_AUTH;
383  context->sPortMode = SUPPLICANT_PORT_MODE_FORCE_AUTH;
384  break;
385 
386  //S_FORCE_UNAUTH state?
388  //The effect of this set of actions is to force the port state to
389  //Unauthorized, and to reflect this state back to the authenticator by
390  //issuing a logoff request
391  context->suppPortStatus = SUPPLICANT_PORT_STATUS_UNAUTH;
392  context->sPortMode = SUPPLICANT_PORT_MODE_FORCE_UNAUTH;
393  supplicantTxLogoff(context);
394  break;
395 
396  //Invalid state?
397  default:
398  //Just for sanity
399  break;
400  }
401 
402  //Any state change?
403  if(newState != oldState)
404  {
405  //Any registered callback?
406  if(context->paeStateChangeCallback != NULL)
407  {
408  //Invoke user callback function
409  context->paeStateChangeCallback(context, newState);
410  }
411  }
412 
413  //Check whether the port is enabled
414  if(!context->initialize && context->portEnabled)
415  {
416  //The supplicant PAE state machine is busy
417  context->busy = TRUE;
418  }
419 }
420 
421 #endif
@ SUPPLICANT_PORT_STATUS_UNAUTH
Supplicant state machine.
void supplicantFsmError(SupplicantContext *context)
Supplicant state machine error handler.
@ SUPPLICANT_PORT_MODE_FORCE_UNAUTH
Supplicant state machine procedures.
const char_t * eapGetParamName(uint_t value, const EapParamName *paramList, size_t paramListLen)
Convert a parameter to string representation.
Definition: eap_debug.c:219
802.1X supplicant
@ SUPPLICANT_PAE_STATE_HELD
@ SUPPLICANT_PAE_STATE_S_FORCE_AUTH
@ SUPPLICANT_PAE_STATE_CONNECTING
#define TRUE
Definition: os_port.h:50
#define SupplicantContext
Definition: supplicant.h:36
@ SUPPLICANT_PORT_MODE_FORCE_AUTH
@ SUPPLICANT_PAE_STATE_S_FORCE_UNAUTH
void supplicantTxStart(SupplicantContext *context)
Transmit an EAPOL-Start packet (8.2.11.1.3 a)
const EapParamName supplicantPaeStates[]
@ SUPPLICANT_PAE_STATE_AUTHENTICATED
SupplicantPaeState
Supplicant PAE states.
#define FALSE
Definition: os_port.h:46
void supplicantPaeInitFsm(SupplicantContext *context)
Supplicant PAE state machine initialization.
@ SUPPLICANT_PAE_STATE_LOGOFF
#define TRACE_DEBUG(...)
Definition: debug.h:107
Data logging functions for debugging purpose (EAP)
Supplicant PAE state machine.
@ SUPPLICANT_PAE_STATE_AUTHENTICATING
void supplicantPaeChangeState(SupplicantContext *context, SupplicantPaeState newState)
Update supplicant PAE state.
void supplicantPaeFsm(SupplicantContext *context)
Supplicant PAE state machine implementation.
@ SUPPLICANT_PORT_MODE_AUTO
@ SUPPLICANT_PAE_STATE_DISCONNECTED
@ SUPPLICANT_PORT_STATUS_AUTH
Parameter value/name binding.
Definition: eap_debug.h:50
Debugging facilities.
Helper functions for 802.1X supplicant.
#define arraysize(a)
Definition: os_port.h:71
void supplicantTxLogoff(SupplicantContext *context)
Transmit an EAPOL-Logoff packet (8.2.11.1.3 b)
@ SUPPLICANT_PAE_STATE_RESTART