LCOV - code coverage report
Current view: top level - src/eapol_auth - eapol_auth_sm.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1426431149 Lines: 590 690 85.5 %
Date: 2015-03-15 Functions: 50 55 90.9 %

          Line data    Source code
       1             : /*
       2             :  * IEEE 802.1X-2004 Authenticator - EAPOL state machine
       3             :  * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : 
      11             : #include "common.h"
      12             : #include "eloop.h"
      13             : #include "state_machine.h"
      14             : #include "common/eapol_common.h"
      15             : #include "eap_common/eap_defs.h"
      16             : #include "eap_common/eap_common.h"
      17             : #include "eap_server/eap.h"
      18             : #include "eapol_auth_sm.h"
      19             : #include "eapol_auth_sm_i.h"
      20             : 
      21             : #define STATE_MACHINE_DATA struct eapol_state_machine
      22             : #define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
      23             : #define STATE_MACHINE_ADDR sm->addr
      24             : 
      25             : static struct eapol_callbacks eapol_cb;
      26             : 
      27             : /* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
      28             : 
      29             : #define setPortAuthorized() \
      30             : sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
      31             : #define setPortUnauthorized() \
      32             : sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
      33             : 
      34             : /* procedures */
      35             : #define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
      36             : #define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
      37             : #define txReq() eapol_auth_tx_req(sm)
      38             : #define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
      39             : #define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
      40             : #define processKey() do { } while (0)
      41             : 
      42             : 
      43             : static void eapol_sm_step_run(struct eapol_state_machine *sm);
      44             : static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
      45             : static void eapol_auth_initialize(struct eapol_state_machine *sm);
      46             : static void eapol_auth_conf_free(struct eapol_auth_config *conf);
      47             : 
      48             : 
      49        8119 : static void eapol_auth_logger(struct eapol_authenticator *eapol,
      50             :                               const u8 *addr, eapol_logger_level level,
      51             :                               const char *txt)
      52             : {
      53        8119 :         if (eapol->cb.logger == NULL)
      54        8119 :                 return;
      55        8119 :         eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
      56             : }
      57             : 
      58             : 
      59        8122 : static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
      60             :                                const u8 *addr, eapol_logger_level level,
      61             :                                const char *fmt, ...)
      62             : {
      63             :         char *format;
      64             :         int maxlen;
      65             :         va_list ap;
      66             : 
      67        8122 :         if (eapol->cb.logger == NULL)
      68           4 :                 return;
      69             : 
      70        8122 :         maxlen = os_strlen(fmt) + 100;
      71        8122 :         format = os_malloc(maxlen);
      72        8122 :         if (!format)
      73           4 :                 return;
      74             : 
      75        8118 :         va_start(ap, fmt);
      76        8118 :         vsnprintf(format, maxlen, fmt, ap);
      77        8118 :         va_end(ap);
      78             : 
      79        8118 :         eapol_auth_logger(eapol, addr, level, format);
      80             : 
      81        8118 :         os_free(format);
      82             : }
      83             : 
      84             : 
      85           0 : static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
      86             :                                      int success)
      87             : {
      88             :         struct eap_hdr eap;
      89             : 
      90           0 :         os_memset(&eap, 0, sizeof(eap));
      91             : 
      92           0 :         eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
      93           0 :         eap.identifier = ++sm->last_eap_id;
      94           0 :         eap.length = host_to_be16(sizeof(eap));
      95             : 
      96           0 :         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
      97             :                            "Sending canned EAP packet %s (identifier %d)",
      98           0 :                            success ? "SUCCESS" : "FAILURE", eap.identifier);
      99           0 :         sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
     100             :                                  IEEE802_1X_TYPE_EAP_PACKET,
     101             :                                  (u8 *) &eap, sizeof(eap));
     102           0 :         sm->dot1xAuthEapolFramesTx++;
     103           0 : }
     104             : 
     105             : 
     106        6762 : static void eapol_auth_tx_req(struct eapol_state_machine *sm)
     107             : {
     108       13523 :         if (sm->eap_if->eapReqData == NULL ||
     109        6761 :             wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
     110           1 :                 eapol_auth_logger(sm->eapol, sm->addr,
     111             :                                   EAPOL_LOGGER_DEBUG,
     112             :                                   "TxReq called, but there is no EAP request "
     113             :                                   "from authentication server");
     114           1 :                 return;
     115             :         }
     116             : 
     117        6761 :         if (sm->flags & EAPOL_SM_WAIT_START) {
     118          12 :                 wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
     119             :                            " while waiting for EAPOL-Start",
     120          12 :                            MAC2STR(sm->addr));
     121           2 :                 return;
     122             :         }
     123             : 
     124        6759 :         sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
     125        6759 :         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
     126             :                            "Sending EAP Packet (identifier %d)",
     127        6759 :                            sm->last_eap_id);
     128       20277 :         sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
     129             :                                  IEEE802_1X_TYPE_EAP_PACKET,
     130        6759 :                                  wpabuf_head(sm->eap_if->eapReqData),
     131        6759 :                                  wpabuf_len(sm->eap_if->eapReqData));
     132        6759 :         sm->dot1xAuthEapolFramesTx++;
     133        6759 :         if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
     134        1367 :                 sm->dot1xAuthEapolReqIdFramesTx++;
     135             :         else
     136        5392 :                 sm->dot1xAuthEapolReqFramesTx++;
     137             : }
     138             : 
     139             : 
     140             : /**
     141             :  * eapol_port_timers_tick - Port Timers state machine
     142             :  * @eloop_ctx: struct eapol_state_machine *
     143             :  * @timeout_ctx: Not used
     144             :  *
     145             :  * This statemachine is implemented as a function that will be called
     146             :  * once a second as a registered event loop timeout.
     147             :  */
     148         316 : static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
     149             : {
     150         316 :         struct eapol_state_machine *state = timeout_ctx;
     151             : 
     152         316 :         if (state->aWhile > 0) {
     153         289 :                 state->aWhile--;
     154         289 :                 if (state->aWhile == 0) {
     155           0 :                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
     156             :                                    " - aWhile --> 0",
     157           0 :                                    MAC2STR(state->addr));
     158             :                 }
     159             :         }
     160             : 
     161         316 :         if (state->quietWhile > 0) {
     162          11 :                 state->quietWhile--;
     163          11 :                 if (state->quietWhile == 0) {
     164           0 :                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
     165             :                                    " - quietWhile --> 0",
     166           0 :                                    MAC2STR(state->addr));
     167             :                 }
     168             :         }
     169             : 
     170         316 :         if (state->reAuthWhen > 0) {
     171         316 :                 state->reAuthWhen--;
     172         316 :                 if (state->reAuthWhen == 0) {
     173           6 :                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
     174             :                                    " - reAuthWhen --> 0",
     175           6 :                                    MAC2STR(state->addr));
     176             :                 }
     177             :         }
     178             : 
     179         316 :         if (state->eap_if->retransWhile > 0) {
     180         228 :                 state->eap_if->retransWhile--;
     181         228 :                 if (state->eap_if->retransWhile == 0) {
     182         300 :                         wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
     183             :                                    " - (EAP) retransWhile --> 0",
     184         300 :                                    MAC2STR(state->addr));
     185             :                 }
     186             :         }
     187             : 
     188         316 :         eapol_sm_step_run(state);
     189             : 
     190         316 :         eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
     191         316 : }
     192             : 
     193             : 
     194             : 
     195             : /* Authenticator PAE state machine */
     196             : 
     197        5736 : SM_STATE(AUTH_PAE, INITIALIZE)
     198             : {
     199        5736 :         SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
     200        5736 :         sm->portMode = Auto;
     201        5736 : }
     202             : 
     203             : 
     204        1281 : SM_STATE(AUTH_PAE, DISCONNECTED)
     205             : {
     206        1281 :         int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
     207             : 
     208        1281 :         if (sm->eapolLogoff) {
     209           2 :                 if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
     210           0 :                         sm->authEapLogoffsWhileConnecting++;
     211           2 :                 else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
     212           2 :                         sm->authAuthEapLogoffWhileAuthenticated++;
     213             :         }
     214             : 
     215        1281 :         SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
     216             : 
     217        1281 :         sm->authPortStatus = Unauthorized;
     218        1281 :         setPortUnauthorized();
     219        1281 :         sm->reAuthCount = 0;
     220        1281 :         sm->eapolLogoff = FALSE;
     221        1281 :         if (!from_initialize) {
     222           4 :                 sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
     223           2 :                                        sm->flags & EAPOL_SM_PREAUTH,
     224             :                                        sm->remediation);
     225             :         }
     226        1281 : }
     227             : 
     228             : 
     229        1366 : SM_STATE(AUTH_PAE, RESTART)
     230             : {
     231        1366 :         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
     232          63 :                 if (sm->reAuthenticate)
     233           1 :                         sm->authAuthReauthsWhileAuthenticated++;
     234          63 :                 if (sm->eapolStart)
     235          62 :                         sm->authAuthEapStartsWhileAuthenticated++;
     236          63 :                 if (sm->eapolLogoff)
     237           0 :                         sm->authAuthEapLogoffWhileAuthenticated++;
     238             :         }
     239             : 
     240        1366 :         SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
     241             : 
     242        1366 :         sm->eap_if->eapRestart = TRUE;
     243        1366 : }
     244             : 
     245             : 
     246        1366 : SM_STATE(AUTH_PAE, CONNECTING)
     247             : {
     248        1366 :         if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
     249        1366 :                 sm->authEntersConnecting++;
     250             : 
     251        1366 :         SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
     252             : 
     253        1366 :         sm->reAuthenticate = FALSE;
     254        1366 :         sm->reAuthCount++;
     255        1366 : }
     256             : 
     257             : 
     258         391 : SM_STATE(AUTH_PAE, HELD)
     259             : {
     260         391 :         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
     261         391 :                 sm->authAuthFailWhileAuthenticating++;
     262             : 
     263         391 :         SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
     264             : 
     265         391 :         sm->authPortStatus = Unauthorized;
     266         391 :         setPortUnauthorized();
     267         391 :         sm->quietWhile = sm->quietPeriod;
     268         391 :         sm->eapolLogoff = FALSE;
     269             : 
     270         782 :         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
     271             :                            "authentication failed - EAP type: %d (%s)",
     272         391 :                            sm->eap_type_authsrv,
     273         391 :                            eap_server_get_name(0, sm->eap_type_authsrv));
     274         391 :         if (sm->eap_type_authsrv != sm->eap_type_supp) {
     275         612 :                 eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
     276             :                                    "Supplicant used different EAP type: "
     277         306 :                                    "%d (%s)", sm->eap_type_supp,
     278         306 :                                    eap_server_get_name(0, sm->eap_type_supp));
     279             :         }
     280         782 :         sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
     281         391 :                                sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
     282         391 : }
     283             : 
     284             : 
     285         666 : SM_STATE(AUTH_PAE, AUTHENTICATED)
     286             : {
     287         666 :         char *extra = "";
     288             : 
     289         666 :         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
     290         666 :                 sm->authAuthSuccessesWhileAuthenticating++;
     291             :                                                         
     292         666 :         SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
     293             : 
     294         666 :         sm->authPortStatus = Authorized;
     295         666 :         setPortAuthorized();
     296         666 :         sm->reAuthCount = 0;
     297         666 :         if (sm->flags & EAPOL_SM_PREAUTH)
     298           2 :                 extra = " (pre-authentication)";
     299         664 :         else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
     300          32 :                 extra = " (PMKSA cache)";
     301        1332 :         eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
     302             :                            "authenticated - EAP type: %d (%s)%s",
     303         666 :                            sm->eap_type_authsrv,
     304         666 :                            eap_server_get_name(0, sm->eap_type_authsrv),
     305             :                            extra);
     306        1332 :         sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
     307         666 :                                sm->flags & EAPOL_SM_PREAUTH, sm->remediation);
     308         666 : }
     309             : 
     310             : 
     311        1364 : SM_STATE(AUTH_PAE, AUTHENTICATING)
     312             : {
     313        1364 :         SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
     314             : 
     315        1364 :         sm->eapolStart = FALSE;
     316        1364 :         sm->authSuccess = FALSE;
     317        1364 :         sm->authFail = FALSE;
     318        1364 :         sm->authTimeout = FALSE;
     319        1364 :         sm->authStart = TRUE;
     320        1364 :         sm->keyRun = FALSE;
     321        1364 :         sm->keyDone = FALSE;
     322        1364 : }
     323             : 
     324             : 
     325          24 : SM_STATE(AUTH_PAE, ABORTING)
     326             : {
     327          24 :         if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
     328          24 :                 if (sm->authTimeout)
     329           0 :                         sm->authAuthTimeoutsWhileAuthenticating++;
     330          24 :                 if (sm->eapolStart)
     331          24 :                         sm->authAuthEapStartsWhileAuthenticating++;
     332          24 :                 if (sm->eapolLogoff)
     333           0 :                         sm->authAuthEapLogoffWhileAuthenticating++;
     334             :         }
     335             : 
     336          24 :         SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
     337             : 
     338          24 :         sm->authAbort = TRUE;
     339          24 :         sm->keyRun = FALSE;
     340          24 :         sm->keyDone = FALSE;
     341          24 : }
     342             : 
     343             : 
     344           0 : SM_STATE(AUTH_PAE, FORCE_AUTH)
     345             : {
     346           0 :         SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
     347             : 
     348           0 :         sm->authPortStatus = Authorized;
     349           0 :         setPortAuthorized();
     350           0 :         sm->portMode = ForceAuthorized;
     351           0 :         sm->eapolStart = FALSE;
     352           0 :         txCannedSuccess();
     353           0 : }
     354             : 
     355             : 
     356           0 : SM_STATE(AUTH_PAE, FORCE_UNAUTH)
     357             : {
     358           0 :         SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
     359             : 
     360           0 :         sm->authPortStatus = Unauthorized;
     361           0 :         setPortUnauthorized();
     362           0 :         sm->portMode = ForceUnauthorized;
     363           0 :         sm->eapolStart = FALSE;
     364           0 :         txCannedFail();
     365           0 : }
     366             : 
     367             : 
     368       48737 : SM_STEP(AUTH_PAE)
     369             : {
     370       96207 :         if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
     371       94940 :             sm->initialize || !sm->eap_if->portEnabled)
     372        5736 :                 SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
     373       43001 :         else if (sm->portControl == ForceAuthorized &&
     374           0 :                  sm->portMode != sm->portControl &&
     375           0 :                  !(sm->initialize || !sm->eap_if->portEnabled))
     376           0 :                 SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
     377       43001 :         else if (sm->portControl == ForceUnauthorized &&
     378           0 :                  sm->portMode != sm->portControl &&
     379           0 :                  !(sm->initialize || !sm->eap_if->portEnabled))
     380           0 :                 SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
     381             :         else {
     382       43001 :                 switch (sm->auth_pae_state) {
     383             :                 case AUTH_PAE_INITIALIZE:
     384        1279 :                         SM_ENTER(AUTH_PAE, DISCONNECTED);
     385        1279 :                         break;
     386             :                 case AUTH_PAE_DISCONNECTED:
     387        1279 :                         SM_ENTER(AUTH_PAE, RESTART);
     388        1279 :                         break;
     389             :                 case AUTH_PAE_RESTART:
     390        2732 :                         if (!sm->eap_if->eapRestart)
     391        1366 :                                 SM_ENTER(AUTH_PAE, CONNECTING);
     392        2732 :                         break;
     393             :                 case AUTH_PAE_HELD:
     394           0 :                         if (sm->quietWhile == 0)
     395           0 :                                 SM_ENTER(AUTH_PAE, RESTART);
     396           0 :                         break;
     397             :                 case AUTH_PAE_CONNECTING:
     398        1423 :                         if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
     399           0 :                                 SM_ENTER(AUTH_PAE, DISCONNECTED);
     400        2786 :                         else if ((sm->eap_if->eapReq &&
     401        1423 :                                   sm->reAuthCount <= sm->reAuthMax) ||
     402         119 :                                  sm->eap_if->eapSuccess || sm->eap_if->eapFail)
     403        1364 :                                 SM_ENTER(AUTH_PAE, AUTHENTICATING);
     404        1423 :                         break;
     405             :                 case AUTH_PAE_AUTHENTICATED:
     406         913 :                         if (sm->eapolStart || sm->reAuthenticate)
     407          63 :                                 SM_ENTER(AUTH_PAE, RESTART);
     408         850 :                         else if (sm->eapolLogoff || !sm->portValid)
     409           2 :                                 SM_ENTER(AUTH_PAE, DISCONNECTED);
     410         913 :                         break;
     411             :                 case AUTH_PAE_AUTHENTICATING:
     412       35351 :                         if (sm->authSuccess && sm->portValid)
     413         666 :                                 SM_ENTER(AUTH_PAE, AUTHENTICATED);
     414       68979 :                         else if (sm->authFail ||
     415       34294 :                                  (sm->keyDone && !sm->portValid))
     416         391 :                                 SM_ENTER(AUTH_PAE, HELD);
     417       68564 :                         else if (sm->eapolStart || sm->eapolLogoff ||
     418       34270 :                                  sm->authTimeout)
     419          24 :                                 SM_ENTER(AUTH_PAE, ABORTING);
     420       35351 :                         break;
     421             :                 case AUTH_PAE_ABORTING:
     422          24 :                         if (sm->eapolLogoff && !sm->authAbort)
     423           0 :                                 SM_ENTER(AUTH_PAE, DISCONNECTED);
     424          24 :                         else if (!sm->eapolLogoff && !sm->authAbort)
     425          24 :                                 SM_ENTER(AUTH_PAE, RESTART);
     426          24 :                         break;
     427             :                 case AUTH_PAE_FORCE_AUTH:
     428           0 :                         if (sm->eapolStart)
     429           0 :                                 SM_ENTER(AUTH_PAE, FORCE_AUTH);
     430           0 :                         break;
     431             :                 case AUTH_PAE_FORCE_UNAUTH:
     432           0 :                         if (sm->eapolStart)
     433           0 :                                 SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
     434           0 :                         break;
     435             :                 }
     436             :         }
     437       48737 : }
     438             : 
     439             : 
     440             : 
     441             : /* Backend Authentication state machine */
     442             : 
     443        1291 : SM_STATE(BE_AUTH, INITIALIZE)
     444             : {
     445        1291 :         SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
     446             : 
     447        1291 :         abortAuth();
     448        1291 :         sm->eap_if->eapNoReq = FALSE;
     449        1291 :         sm->authAbort = FALSE;
     450        1291 : }
     451             : 
     452             : 
     453        5726 : SM_STATE(BE_AUTH, REQUEST)
     454             : {
     455        5726 :         SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
     456             : 
     457        5726 :         txReq();
     458        5726 :         sm->eap_if->eapReq = FALSE;
     459        5726 :         sm->backendOtherRequestsToSupplicant++;
     460             : 
     461             :         /*
     462             :          * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
     463             :          * it looks like this would be logical thing to do there since the old
     464             :          * EAP response would not be valid anymore after the new EAP request
     465             :          * was sent out.
     466             :          *
     467             :          * A race condition has been reported, in which hostapd ended up
     468             :          * sending out EAP-Response/Identity as a response to the first
     469             :          * EAP-Request from the main EAP method. This can be avoided by
     470             :          * clearing eapolEap here.
     471             :          */
     472        5726 :         sm->eapolEap = FALSE;
     473        5726 : }
     474             : 
     475             : 
     476        5436 : SM_STATE(BE_AUTH, RESPONSE)
     477             : {
     478        5436 :         SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
     479             : 
     480        5436 :         sm->authTimeout = FALSE;
     481        5436 :         sm->eapolEap = FALSE;
     482        5436 :         sm->eap_if->eapNoReq = FALSE;
     483        5436 :         sm->aWhile = sm->serverTimeout;
     484        5436 :         sm->eap_if->eapResp = TRUE;
     485             :         /* sendRespToServer(); */
     486        5436 :         sm->backendResponses++;
     487        5436 : }
     488             : 
     489             : 
     490         646 : SM_STATE(BE_AUTH, SUCCESS)
     491             : {
     492         646 :         SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
     493             : 
     494         646 :         txReq();
     495         646 :         sm->authSuccess = TRUE;
     496         646 :         sm->keyRun = TRUE;
     497         646 : }
     498             : 
     499             : 
     500         390 : SM_STATE(BE_AUTH, FAIL)
     501             : {
     502         390 :         SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
     503             : 
     504         390 :         txReq();
     505         390 :         sm->authFail = TRUE;
     506         390 : }
     507             : 
     508             : 
     509           0 : SM_STATE(BE_AUTH, TIMEOUT)
     510             : {
     511           0 :         SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
     512             : 
     513           0 :         sm->authTimeout = TRUE;
     514           0 : }
     515             : 
     516             : 
     517        2362 : SM_STATE(BE_AUTH, IDLE)
     518             : {
     519        2362 :         SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
     520             : 
     521        2362 :         sm->authStart = FALSE;
     522        2362 : }
     523             : 
     524             : 
     525          11 : SM_STATE(BE_AUTH, IGNORE)
     526             : {
     527          11 :         SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
     528             : 
     529          11 :         sm->eap_if->eapNoReq = FALSE;
     530          11 : }
     531             : 
     532             : 
     533       48737 : SM_STEP(BE_AUTH)
     534             : {
     535       48737 :         if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
     536        1291 :                 SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
     537       50028 :                 return;
     538             :         }
     539             : 
     540       47446 :         switch (sm->be_auth_state) {
     541             :         case BE_AUTH_INITIALIZE:
     542        1291 :                 SM_ENTER(BE_AUTH, IDLE);
     543        1291 :                 break;
     544             :         case BE_AUTH_REQUEST:
     545       15279 :                 if (sm->eapolEap)
     546        5435 :                         SM_ENTER(BE_AUTH, RESPONSE);
     547        9844 :                 else if (sm->eap_if->eapReq)
     548           9 :                         SM_ENTER(BE_AUTH, REQUEST);
     549        9835 :                 else if (sm->eap_if->eapTimeout)
     550           0 :                         SM_ENTER(BE_AUTH, TIMEOUT);
     551       15279 :                 break;
     552             :         case BE_AUTH_RESPONSE:
     553       17812 :                 if (sm->eap_if->eapNoReq)
     554          11 :                         SM_ENTER(BE_AUTH, IGNORE);
     555       17812 :                 if (sm->eap_if->eapReq) {
     556        4358 :                         sm->backendAccessChallenges++;
     557        4358 :                         SM_ENTER(BE_AUTH, REQUEST);
     558       13454 :                 } else if (sm->aWhile == 0)
     559           0 :                         SM_ENTER(BE_AUTH, TIMEOUT);
     560       13454 :                 else if (sm->eap_if->eapFail) {
     561         390 :                         sm->backendAuthFails++;
     562         390 :                         SM_ENTER(BE_AUTH, FAIL);
     563       13064 :                 } else if (sm->eap_if->eapSuccess) {
     564         646 :                         sm->backendAuthSuccesses++;
     565         646 :                         SM_ENTER(BE_AUTH, SUCCESS);
     566             :                 }
     567       17812 :                 break;
     568             :         case BE_AUTH_SUCCESS:
     569         681 :                 SM_ENTER(BE_AUTH, IDLE);
     570         681 :                 break;
     571             :         case BE_AUTH_FAIL:
     572         390 :                 SM_ENTER(BE_AUTH, IDLE);
     573         390 :                 break;
     574             :         case BE_AUTH_TIMEOUT:
     575           0 :                 SM_ENTER(BE_AUTH, IDLE);
     576           0 :                 break;
     577             :         case BE_AUTH_IDLE:
     578       11971 :                 if (sm->eap_if->eapFail && sm->authStart)
     579           0 :                         SM_ENTER(BE_AUTH, FAIL);
     580       11971 :                 else if (sm->eap_if->eapReq && sm->authStart)
     581        1357 :                         SM_ENTER(BE_AUTH, REQUEST);
     582       10614 :                 else if (sm->eap_if->eapSuccess && sm->authStart)
     583           0 :                         SM_ENTER(BE_AUTH, SUCCESS);
     584       11971 :                 break;
     585             :         case BE_AUTH_IGNORE:
     586          22 :                 if (sm->eapolEap)
     587           1 :                         SM_ENTER(BE_AUTH, RESPONSE);
     588          21 :                 else if (sm->eap_if->eapReq)
     589           2 :                         SM_ENTER(BE_AUTH, REQUEST);
     590          19 :                 else if (sm->eap_if->eapTimeout)
     591           0 :                         SM_ENTER(BE_AUTH, TIMEOUT);
     592          22 :                 break;
     593             :         }
     594             : }
     595             : 
     596             : 
     597             : 
     598             : /* Reauthentication Timer state machine */
     599             : 
     600       42666 : SM_STATE(REAUTH_TIMER, INITIALIZE)
     601             : {
     602       42666 :         SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
     603             : 
     604       42666 :         sm->reAuthWhen = sm->reAuthPeriod;
     605       42666 : }
     606             : 
     607             : 
     608           1 : SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
     609             : {
     610           1 :         SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
     611             : 
     612           1 :         sm->reAuthenticate = TRUE;
     613           1 :         sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
     614             :                                   EAPOL_AUTH_REAUTHENTICATE);
     615           1 : }
     616             : 
     617             : 
     618       48737 : SM_STEP(REAUTH_TIMER)
     619             : {
     620       96207 :         if (sm->portControl != Auto || sm->initialize ||
     621       53542 :             sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
     622       42665 :                 SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
     623       91402 :                 return;
     624             :         }
     625             : 
     626        6072 :         switch (sm->reauth_timer_state) {
     627             :         case REAUTH_TIMER_INITIALIZE:
     628        6071 :                 if (sm->reAuthWhen == 0)
     629           1 :                         SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
     630        6071 :                 break;
     631             :         case REAUTH_TIMER_REAUTHENTICATE:
     632           1 :                 SM_ENTER(REAUTH_TIMER, INITIALIZE);
     633           1 :                 break;
     634             :         }
     635             : }
     636             : 
     637             : 
     638             : 
     639             : /* Authenticator Key Transmit state machine */
     640             : 
     641        1267 : SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
     642             : {
     643        1267 :         SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
     644        1267 : }
     645             : 
     646             : 
     647           2 : SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
     648             : {
     649           2 :         SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
     650             : 
     651           2 :         txKey();
     652           2 :         sm->eap_if->eapKeyAvailable = FALSE;
     653           2 :         sm->keyDone = TRUE;
     654           2 : }
     655             : 
     656             : 
     657       48737 : SM_STEP(AUTH_KEY_TX)
     658             : {
     659       48737 :         if (sm->initialize || sm->portControl != Auto) {
     660        1267 :                 SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
     661       50004 :                 return;
     662             :         }
     663             : 
     664       47470 :         switch (sm->auth_key_tx_state) {
     665             :         case AUTH_KEY_TX_NO_KEY_TRANSMIT:
     666       47468 :                 if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
     667           4 :                     sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
     668           2 :                         SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
     669       47466 :                 break;
     670             :         case AUTH_KEY_TX_KEY_TRANSMIT:
     671           4 :                 if (!sm->keyTxEnabled || !sm->keyRun)
     672           0 :                         SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
     673           4 :                 else if (sm->eap_if->eapKeyAvailable)
     674           0 :                         SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
     675           4 :                 break;
     676             :         }
     677             : }
     678             : 
     679             : 
     680             : 
     681             : /* Key Receive state machine */
     682             : 
     683        6129 : SM_STATE(KEY_RX, NO_KEY_RECEIVE)
     684             : {
     685        6129 :         SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
     686        6129 : }
     687             : 
     688             : 
     689           0 : SM_STATE(KEY_RX, KEY_RECEIVE)
     690             : {
     691           0 :         SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
     692             : 
     693             :         processKey();
     694           0 :         sm->rxKey = FALSE;
     695           0 : }
     696             : 
     697             : 
     698       48737 : SM_STEP(KEY_RX)
     699             : {
     700       48737 :         if (sm->initialize || !sm->eap_if->portEnabled) {
     701        6129 :                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
     702       54866 :                 return;
     703             :         }
     704             : 
     705       42608 :         switch (sm->key_rx_state) {
     706             :         case KEY_RX_NO_KEY_RECEIVE:
     707       42608 :                 if (sm->rxKey)
     708           0 :                         SM_ENTER(KEY_RX, KEY_RECEIVE);
     709       42608 :                 break;
     710             :         case KEY_RX_KEY_RECEIVE:
     711           0 :                 if (sm->rxKey)
     712           0 :                         SM_ENTER(KEY_RX, KEY_RECEIVE);
     713           0 :                 break;
     714             :         }
     715             : }
     716             : 
     717             : 
     718             : 
     719             : /* Controlled Directions state machine */
     720             : 
     721        1267 : SM_STATE(CTRL_DIR, FORCE_BOTH)
     722             : {
     723        1267 :         SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
     724        1267 :         sm->operControlledDirections = Both;
     725        1267 : }
     726             : 
     727             : 
     728        1267 : SM_STATE(CTRL_DIR, IN_OR_BOTH)
     729             : {
     730        1267 :         SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
     731        1267 :         sm->operControlledDirections = sm->adminControlledDirections;
     732        1267 : }
     733             : 
     734             : 
     735       48737 : SM_STEP(CTRL_DIR)
     736             : {
     737       48737 :         if (sm->initialize) {
     738        1267 :                 SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
     739       50004 :                 return;
     740             :         }
     741             : 
     742       47470 :         switch (sm->ctrl_dir_state) {
     743             :         case CTRL_DIR_FORCE_BOTH:
     744       46203 :                 if (sm->eap_if->portEnabled && sm->operEdge)
     745           0 :                         SM_ENTER(CTRL_DIR, IN_OR_BOTH);
     746       46203 :                 break;
     747             :         case CTRL_DIR_IN_OR_BOTH:
     748        2534 :                 if (sm->operControlledDirections !=
     749        1267 :                     sm->adminControlledDirections)
     750           0 :                         SM_ENTER(CTRL_DIR, IN_OR_BOTH);
     751        1267 :                 if (!sm->eap_if->portEnabled || !sm->operEdge)
     752        1267 :                         SM_ENTER(CTRL_DIR, FORCE_BOTH);
     753        1267 :                 break;
     754             :         }
     755             : }
     756             : 
     757             : 
     758             : 
     759             : struct eapol_state_machine *
     760        1267 : eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
     761             :                  int flags, const struct wpabuf *assoc_wps_ie,
     762             :                  const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
     763             :                  const char *identity, const char *radius_cui)
     764             : {
     765             :         struct eapol_state_machine *sm;
     766             :         struct eap_config eap_conf;
     767             : 
     768        1267 :         if (eapol == NULL)
     769           0 :                 return NULL;
     770             : 
     771        1267 :         sm = os_zalloc(sizeof(*sm));
     772        1267 :         if (sm == NULL) {
     773           0 :                 wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
     774             :                            "failed");
     775           0 :                 return NULL;
     776             :         }
     777        1267 :         sm->radius_identifier = -1;
     778        1267 :         os_memcpy(sm->addr, addr, ETH_ALEN);
     779        1267 :         sm->flags = flags;
     780             : 
     781        1267 :         sm->eapol = eapol;
     782        1267 :         sm->sta = sta_ctx;
     783             : 
     784             :         /* Set default values for state machine constants */
     785        1267 :         sm->auth_pae_state = AUTH_PAE_INITIALIZE;
     786        1267 :         sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
     787        1267 :         sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
     788             : 
     789        1267 :         sm->be_auth_state = BE_AUTH_INITIALIZE;
     790        1267 :         sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
     791             : 
     792        1267 :         sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
     793        1267 :         sm->reAuthPeriod = eapol->conf.eap_reauth_period;
     794        1267 :         sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0 ? TRUE : FALSE;
     795             : 
     796        1267 :         sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
     797             : 
     798        1267 :         sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
     799             : 
     800        1267 :         sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
     801             : 
     802        1267 :         sm->portControl = Auto;
     803             : 
     804        1295 :         if (!eapol->conf.wpa &&
     805          54 :             (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
     806           2 :                 sm->keyTxEnabled = TRUE;
     807             :         else
     808        1265 :                 sm->keyTxEnabled = FALSE;
     809        1267 :         if (eapol->conf.wpa)
     810        1239 :                 sm->portValid = FALSE;
     811             :         else
     812          28 :                 sm->portValid = TRUE;
     813             : 
     814        1267 :         os_memset(&eap_conf, 0, sizeof(eap_conf));
     815        1267 :         eap_conf.eap_server = eapol->conf.eap_server;
     816        1267 :         eap_conf.ssl_ctx = eapol->conf.ssl_ctx;
     817        1267 :         eap_conf.msg_ctx = eapol->conf.msg_ctx;
     818        1267 :         eap_conf.eap_sim_db_priv = eapol->conf.eap_sim_db_priv;
     819        1267 :         eap_conf.pac_opaque_encr_key = eapol->conf.pac_opaque_encr_key;
     820        1267 :         eap_conf.eap_fast_a_id = eapol->conf.eap_fast_a_id;
     821        1267 :         eap_conf.eap_fast_a_id_len = eapol->conf.eap_fast_a_id_len;
     822        1267 :         eap_conf.eap_fast_a_id_info = eapol->conf.eap_fast_a_id_info;
     823        1267 :         eap_conf.eap_fast_prov = eapol->conf.eap_fast_prov;
     824        1267 :         eap_conf.pac_key_lifetime = eapol->conf.pac_key_lifetime;
     825        1267 :         eap_conf.pac_key_refresh_time = eapol->conf.pac_key_refresh_time;
     826        1267 :         eap_conf.eap_sim_aka_result_ind = eapol->conf.eap_sim_aka_result_ind;
     827        1267 :         eap_conf.tnc = eapol->conf.tnc;
     828        1267 :         eap_conf.wps = eapol->conf.wps;
     829        1267 :         eap_conf.assoc_wps_ie = assoc_wps_ie;
     830        1267 :         eap_conf.assoc_p2p_ie = assoc_p2p_ie;
     831        1267 :         eap_conf.peer_addr = addr;
     832        1267 :         eap_conf.fragment_size = eapol->conf.fragment_size;
     833        1267 :         eap_conf.pwd_group = eapol->conf.pwd_group;
     834        1267 :         eap_conf.pbc_in_m1 = eapol->conf.pbc_in_m1;
     835        1267 :         eap_conf.server_id = eapol->conf.server_id;
     836        1267 :         eap_conf.server_id_len = eapol->conf.server_id_len;
     837        1267 :         eap_conf.erp = eapol->conf.erp;
     838        1267 :         sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
     839        1267 :         if (sm->eap == NULL) {
     840           0 :                 eapol_auth_free(sm);
     841           0 :                 return NULL;
     842             :         }
     843        1267 :         sm->eap_if = eap_get_interface(sm->eap);
     844             : 
     845        1267 :         eapol_auth_initialize(sm);
     846             : 
     847        1267 :         if (identity) {
     848           0 :                 sm->identity = (u8 *) os_strdup(identity);
     849           0 :                 if (sm->identity)
     850           0 :                         sm->identity_len = os_strlen(identity);
     851             :         }
     852        1267 :         if (radius_cui)
     853           0 :                 sm->radius_cui = wpabuf_alloc_copy(radius_cui,
     854             :                                                    os_strlen(radius_cui));
     855             : 
     856        1267 :         sm->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo++;
     857        1267 :         if (eapol->acct_multi_session_id_lo == 0)
     858           0 :                 eapol->acct_multi_session_id_hi++;
     859        1267 :         sm->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
     860             : 
     861        1267 :         return sm;
     862             : }
     863             : 
     864             : 
     865        1267 : void eapol_auth_free(struct eapol_state_machine *sm)
     866             : {
     867        1267 :         if (sm == NULL)
     868        1267 :                 return;
     869             : 
     870        1267 :         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
     871        1267 :         eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
     872        1267 :         if (sm->eap)
     873        1267 :                 eap_server_sm_deinit(sm->eap);
     874        1267 :         os_free(sm);
     875             : }
     876             : 
     877             : 
     878      272366 : static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
     879             :                                     const u8 *addr)
     880             : {
     881      272366 :         return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
     882             : }
     883             : 
     884             : 
     885       18538 : static void eapol_sm_step_run(struct eapol_state_machine *sm)
     886             : {
     887       18538 :         struct eapol_authenticator *eapol = sm->eapol;
     888             :         u8 addr[ETH_ALEN];
     889             :         unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
     890             :                 prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
     891       18538 :         int max_steps = 100;
     892             : 
     893       18538 :         os_memcpy(addr, sm->addr, ETH_ALEN);
     894             : 
     895             :         /*
     896             :          * Allow EAPOL state machines to run as long as there are state
     897             :          * changes, but exit and return here through event loop if more than
     898             :          * 100 steps is needed as a precaution against infinite loops inside
     899             :          * eloop callback.
     900             :          */
     901             : restart:
     902       48737 :         prev_auth_pae = sm->auth_pae_state;
     903       48737 :         prev_be_auth = sm->be_auth_state;
     904       48737 :         prev_reauth_timer = sm->reauth_timer_state;
     905       48737 :         prev_auth_key_tx = sm->auth_key_tx_state;
     906       48737 :         prev_key_rx = sm->key_rx_state;
     907       48737 :         prev_ctrl_dir = sm->ctrl_dir_state;
     908             : 
     909       48737 :         SM_STEP_RUN(AUTH_PAE);
     910       48737 :         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
     911       48737 :                 SM_STEP_RUN(BE_AUTH);
     912       48737 :         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
     913       48737 :                 SM_STEP_RUN(REAUTH_TIMER);
     914       48737 :         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
     915       48737 :                 SM_STEP_RUN(AUTH_KEY_TX);
     916       48737 :         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
     917       48737 :                 SM_STEP_RUN(KEY_RX);
     918       48737 :         if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
     919       48737 :                 SM_STEP_RUN(CTRL_DIR);
     920             : 
     921       90603 :         if (prev_auth_pae != sm->auth_pae_state ||
     922       71017 :             prev_be_auth != sm->be_auth_state ||
     923       58301 :             prev_reauth_timer != sm->reauth_timer_state ||
     924       58300 :             prev_auth_key_tx != sm->auth_key_tx_state ||
     925       58300 :             prev_key_rx != sm->key_rx_state ||
     926       29150 :             prev_ctrl_dir != sm->ctrl_dir_state) {
     927       19587 :                 if (--max_steps > 0)
     928       19587 :                         goto restart;
     929             :                 /* Re-run from eloop timeout */
     930           0 :                 eapol_auth_step(sm);
     931           0 :                 return;
     932             :         }
     933             : 
     934       29150 :         if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
     935       26616 :                 if (eap_server_sm_step(sm->eap)) {
     936       10612 :                         if (--max_steps > 0)
     937       10612 :                                 goto restart;
     938             :                         /* Re-run from eloop timeout */
     939           0 :                         eapol_auth_step(sm);
     940           0 :                         return;
     941             :                 }
     942             : 
     943             :                 /* TODO: find a better location for this */
     944       16004 :                 if (sm->eap_if->aaaEapResp) {
     945        3391 :                         sm->eap_if->aaaEapResp = FALSE;
     946        3391 :                         if (sm->eap_if->aaaEapRespData == NULL) {
     947           2 :                                 wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
     948             :                                            "but no aaaEapRespData available");
     949           2 :                                 return;
     950             :                         }
     951       13556 :                         sm->eapol->cb.aaa_send(
     952        3389 :                                 sm->eapol->conf.ctx, sm->sta,
     953        3389 :                                 wpabuf_head(sm->eap_if->aaaEapRespData),
     954        3389 :                                 wpabuf_len(sm->eap_if->aaaEapRespData));
     955             :                 }
     956             :         }
     957             : 
     958       18536 :         if (eapol_sm_sta_entry_alive(eapol, addr))
     959       16002 :                 sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
     960             :                                           EAPOL_AUTH_SM_CHANGE);
     961             : }
     962             : 
     963             : 
     964       15688 : static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
     965             : {
     966       15688 :         struct eapol_state_machine *sm = eloop_ctx;
     967       15688 :         eapol_sm_step_run(sm);
     968       15688 : }
     969             : 
     970             : 
     971             : /**
     972             :  * eapol_auth_step - Advance EAPOL state machines
     973             :  * @sm: EAPOL state machine
     974             :  *
     975             :  * This function is called to advance EAPOL state machines after any change
     976             :  * that could affect their state.
     977             :  */
     978       18620 : void eapol_auth_step(struct eapol_state_machine *sm)
     979             : {
     980             :         /*
     981             :          * Run eapol_sm_step_run from a registered timeout to make sure that
     982             :          * other possible timeouts/events are processed and to avoid long
     983             :          * function call chains.
     984             :          */
     985             : 
     986       18620 :         eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
     987       18620 : }
     988             : 
     989             : 
     990        1267 : static void eapol_auth_initialize(struct eapol_state_machine *sm)
     991             : {
     992        1267 :         sm->initializing = TRUE;
     993             :         /* Initialize the state machines by asserting initialize and then
     994             :          * deasserting it after one step */
     995        1267 :         sm->initialize = TRUE;
     996        1267 :         eapol_sm_step_run(sm);
     997        1267 :         sm->initialize = FALSE;
     998        1267 :         eapol_sm_step_run(sm);
     999        1267 :         sm->initializing = FALSE;
    1000             : 
    1001             :         /* Start one second tick for port timers state machine */
    1002        1267 :         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
    1003        1267 :         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
    1004        1267 : }
    1005             : 
    1006             : 
    1007         395 : static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
    1008             :                                  size_t identity_len, int phase2,
    1009             :                                  struct eap_user *user)
    1010             : {
    1011         395 :         struct eapol_state_machine *sm = ctx;
    1012             :         int ret;
    1013             : 
    1014         395 :         ret = sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
    1015             :                                          identity_len, phase2, user);
    1016         395 :         if (user->remediation)
    1017           0 :                 sm->remediation = 1;
    1018         395 :         return ret;
    1019             : }
    1020             : 
    1021             : 
    1022        1332 : static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
    1023             : {
    1024        1332 :         struct eapol_state_machine *sm = ctx;
    1025        1332 :         *len = sm->eapol->conf.eap_req_id_text_len;
    1026        1332 :         return sm->eapol->conf.eap_req_id_text;
    1027             : }
    1028             : 
    1029             : 
    1030        1359 : static int eapol_sm_get_erp_send_reauth_start(void *ctx)
    1031             : {
    1032        1359 :         struct eapol_state_machine *sm = ctx;
    1033        1359 :         return sm->eapol->conf.erp_send_reauth_start;
    1034             : }
    1035             : 
    1036             : 
    1037          44 : static const char * eapol_sm_get_erp_domain(void *ctx)
    1038             : {
    1039          44 :         struct eapol_state_machine *sm = ctx;
    1040          44 :         return sm->eapol->conf.erp_domain;
    1041             : }
    1042             : 
    1043             : 
    1044           5 : static struct eap_server_erp_key * eapol_sm_erp_get_key(void *ctx,
    1045             :                                                         const char *keyname)
    1046             : {
    1047           5 :         struct eapol_state_machine *sm = ctx;
    1048           5 :         return sm->eapol->cb.erp_get_key(sm->eapol->conf.ctx, keyname);
    1049             : }
    1050             : 
    1051             : 
    1052           5 : static int eapol_sm_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
    1053             : {
    1054           5 :         struct eapol_state_machine *sm = ctx;
    1055           5 :         return sm->eapol->cb.erp_add_key(sm->eapol->conf.ctx, erp);
    1056             : }
    1057             : 
    1058             : 
    1059             : static struct eapol_callbacks eapol_cb =
    1060             : {
    1061             :         eapol_sm_get_eap_user,
    1062             :         eapol_sm_get_eap_req_id_text,
    1063             :         NULL,
    1064             :         eapol_sm_get_erp_send_reauth_start,
    1065             :         eapol_sm_get_erp_domain,
    1066             :         eapol_sm_erp_get_key,
    1067             :         eapol_sm_erp_add_key,
    1068             : };
    1069             : 
    1070             : 
    1071          30 : int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
    1072             : {
    1073          30 :         if (sm == NULL || ctx == NULL || ctx != sm->eap)
    1074           0 :                 return -1;
    1075             : 
    1076          30 :         eap_sm_pending_cb(sm->eap);
    1077          30 :         eapol_auth_step(sm);
    1078             : 
    1079          30 :         return 0;
    1080             : }
    1081             : 
    1082             : 
    1083        1384 : static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
    1084             :                                  struct eapol_auth_config *src)
    1085             : {
    1086        1384 :         dst->ctx = src->ctx;
    1087        1384 :         dst->eap_reauth_period = src->eap_reauth_period;
    1088        1384 :         dst->wpa = src->wpa;
    1089        1384 :         dst->individual_wep_key_len = src->individual_wep_key_len;
    1090        1384 :         dst->eap_server = src->eap_server;
    1091        1384 :         dst->ssl_ctx = src->ssl_ctx;
    1092        1384 :         dst->msg_ctx = src->msg_ctx;
    1093        1384 :         dst->eap_sim_db_priv = src->eap_sim_db_priv;
    1094        1384 :         os_free(dst->eap_req_id_text);
    1095        1384 :         dst->pwd_group = src->pwd_group;
    1096        1384 :         dst->pbc_in_m1 = src->pbc_in_m1;
    1097        1384 :         dst->server_id = src->server_id;
    1098        1384 :         dst->server_id_len = src->server_id_len;
    1099        1384 :         if (src->eap_req_id_text) {
    1100           1 :                 dst->eap_req_id_text = os_malloc(src->eap_req_id_text_len);
    1101           1 :                 if (dst->eap_req_id_text == NULL)
    1102           0 :                         return -1;
    1103           1 :                 os_memcpy(dst->eap_req_id_text, src->eap_req_id_text,
    1104             :                           src->eap_req_id_text_len);
    1105           1 :                 dst->eap_req_id_text_len = src->eap_req_id_text_len;
    1106             :         } else {
    1107        1383 :                 dst->eap_req_id_text = NULL;
    1108        1383 :                 dst->eap_req_id_text_len = 0;
    1109             :         }
    1110        1384 :         if (src->pac_opaque_encr_key) {
    1111          13 :                 dst->pac_opaque_encr_key = os_malloc(16);
    1112          13 :                 if (dst->pac_opaque_encr_key == NULL)
    1113           0 :                         goto fail;
    1114          13 :                 os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
    1115             :                           16);
    1116             :         } else
    1117        1371 :                 dst->pac_opaque_encr_key = NULL;
    1118        1384 :         if (src->eap_fast_a_id) {
    1119          13 :                 dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
    1120          13 :                 if (dst->eap_fast_a_id == NULL)
    1121           0 :                         goto fail;
    1122          13 :                 os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
    1123             :                           src->eap_fast_a_id_len);
    1124          13 :                 dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
    1125             :         } else
    1126        1371 :                 dst->eap_fast_a_id = NULL;
    1127        1384 :         if (src->eap_fast_a_id_info) {
    1128          13 :                 dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
    1129          13 :                 if (dst->eap_fast_a_id_info == NULL)
    1130           0 :                         goto fail;
    1131             :         } else
    1132        1371 :                 dst->eap_fast_a_id_info = NULL;
    1133        1384 :         dst->eap_fast_prov = src->eap_fast_prov;
    1134        1384 :         dst->pac_key_lifetime = src->pac_key_lifetime;
    1135        1384 :         dst->pac_key_refresh_time = src->pac_key_refresh_time;
    1136        1384 :         dst->eap_sim_aka_result_ind = src->eap_sim_aka_result_ind;
    1137        1384 :         dst->tnc = src->tnc;
    1138        1384 :         dst->wps = src->wps;
    1139        1384 :         dst->fragment_size = src->fragment_size;
    1140             : 
    1141        1384 :         os_free(dst->erp_domain);
    1142        1384 :         if (src->erp_domain) {
    1143           9 :                 dst->erp_domain = os_strdup(src->erp_domain);
    1144           9 :                 if (dst->erp_domain == NULL)
    1145           0 :                         goto fail;
    1146             :         } else {
    1147        1375 :                 dst->erp_domain = NULL;
    1148             :         }
    1149        1384 :         dst->erp_send_reauth_start = src->erp_send_reauth_start;
    1150        1384 :         dst->erp = src->erp;
    1151             : 
    1152        1384 :         return 0;
    1153             : 
    1154             : fail:
    1155           0 :         eapol_auth_conf_free(dst);
    1156           0 :         return -1;
    1157             : }
    1158             : 
    1159             : 
    1160        1384 : static void eapol_auth_conf_free(struct eapol_auth_config *conf)
    1161             : {
    1162        1384 :         os_free(conf->eap_req_id_text);
    1163        1384 :         conf->eap_req_id_text = NULL;
    1164        1384 :         os_free(conf->pac_opaque_encr_key);
    1165        1384 :         conf->pac_opaque_encr_key = NULL;
    1166        1384 :         os_free(conf->eap_fast_a_id);
    1167        1384 :         conf->eap_fast_a_id = NULL;
    1168        1384 :         os_free(conf->eap_fast_a_id_info);
    1169        1384 :         conf->eap_fast_a_id_info = NULL;
    1170        1384 :         os_free(conf->erp_domain);
    1171        1384 :         conf->erp_domain = NULL;
    1172        1384 : }
    1173             : 
    1174             : 
    1175        1384 : struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
    1176             :                                              struct eapol_auth_cb *cb)
    1177             : {
    1178             :         struct eapol_authenticator *eapol;
    1179             :         struct os_time now;
    1180             : 
    1181        1384 :         eapol = os_zalloc(sizeof(*eapol));
    1182        1384 :         if (eapol == NULL)
    1183           0 :                 return NULL;
    1184             : 
    1185        1384 :         if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
    1186           0 :                 os_free(eapol);
    1187           0 :                 return NULL;
    1188             :         }
    1189             : 
    1190        1384 :         if (conf->individual_wep_key_len > 0) {
    1191             :                 /* use key0 in individual key and key1 in broadcast key */
    1192           2 :                 eapol->default_wep_key_idx = 1;
    1193             :         }
    1194             : 
    1195        1384 :         eapol->cb.eapol_send = cb->eapol_send;
    1196        1384 :         eapol->cb.aaa_send = cb->aaa_send;
    1197        1384 :         eapol->cb.finished = cb->finished;
    1198        1384 :         eapol->cb.get_eap_user = cb->get_eap_user;
    1199        1384 :         eapol->cb.sta_entry_alive = cb->sta_entry_alive;
    1200        1384 :         eapol->cb.logger = cb->logger;
    1201        1384 :         eapol->cb.set_port_authorized = cb->set_port_authorized;
    1202        1384 :         eapol->cb.abort_auth = cb->abort_auth;
    1203        1384 :         eapol->cb.tx_key = cb->tx_key;
    1204        1384 :         eapol->cb.eapol_event = cb->eapol_event;
    1205        1384 :         eapol->cb.erp_get_key = cb->erp_get_key;
    1206        1384 :         eapol->cb.erp_add_key = cb->erp_add_key;
    1207             : 
    1208             :         /* Acct-Multi-Session-Id should be unique over reboots. If reliable
    1209             :          * clock is not available, this could be replaced with reboot counter,
    1210             :          * etc. */
    1211        1384 :         os_get_time(&now);
    1212        1384 :         eapol->acct_multi_session_id_hi = now.sec;
    1213             : 
    1214        1384 :         return eapol;
    1215             : }
    1216             : 
    1217             : 
    1218        1388 : void eapol_auth_deinit(struct eapol_authenticator *eapol)
    1219             : {
    1220        1388 :         if (eapol == NULL)
    1221        1392 :                 return;
    1222             : 
    1223        1384 :         eapol_auth_conf_free(&eapol->conf);
    1224        1384 :         os_free(eapol->default_wep_key);
    1225        1384 :         os_free(eapol);
    1226             : }

Generated by: LCOV version 1.10