LCOV - code coverage report
Current view: top level - src/eapol_supp - eapol_supp_sm.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1401264779 Lines: 695 874 79.5 %
Date: 2014-05-28 Functions: 72 80 90.0 %

          Line data    Source code
       1             : /*
       2             :  * EAPOL supplicant state machines
       3             :  * Copyright (c) 2004-2012, 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 "state_machine.h"
      13             : #include "wpabuf.h"
      14             : #include "eloop.h"
      15             : #include "crypto/crypto.h"
      16             : #include "crypto/md5.h"
      17             : #include "common/eapol_common.h"
      18             : #include "eap_peer/eap.h"
      19             : #include "eap_peer/eap_proxy.h"
      20             : #include "eapol_supp_sm.h"
      21             : 
      22             : #define STATE_MACHINE_DATA struct eapol_sm
      23             : #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
      24             : 
      25             : 
      26             : /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
      27             : 
      28             : /**
      29             :  * struct eapol_sm - Internal data for EAPOL state machines
      30             :  */
      31             : struct eapol_sm {
      32             :         /* Timers */
      33             :         unsigned int authWhile;
      34             :         unsigned int heldWhile;
      35             :         unsigned int startWhen;
      36             :         unsigned int idleWhile; /* for EAP state machine */
      37             :         int timer_tick_enabled;
      38             : 
      39             :         /* Global variables */
      40             :         Boolean eapFail;
      41             :         Boolean eapolEap;
      42             :         Boolean eapSuccess;
      43             :         Boolean initialize;
      44             :         Boolean keyDone;
      45             :         Boolean keyRun;
      46             :         PortControl portControl;
      47             :         Boolean portEnabled;
      48             :         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
      49             :         Boolean portValid;
      50             :         Boolean suppAbort;
      51             :         Boolean suppFail;
      52             :         Boolean suppStart;
      53             :         Boolean suppSuccess;
      54             :         Boolean suppTimeout;
      55             : 
      56             :         /* Supplicant PAE state machine */
      57             :         enum {
      58             :                 SUPP_PAE_UNKNOWN = 0,
      59             :                 SUPP_PAE_DISCONNECTED = 1,
      60             :                 SUPP_PAE_LOGOFF = 2,
      61             :                 SUPP_PAE_CONNECTING = 3,
      62             :                 SUPP_PAE_AUTHENTICATING = 4,
      63             :                 SUPP_PAE_AUTHENTICATED = 5,
      64             :                 /* unused(6) */
      65             :                 SUPP_PAE_HELD = 7,
      66             :                 SUPP_PAE_RESTART = 8,
      67             :                 SUPP_PAE_S_FORCE_AUTH = 9,
      68             :                 SUPP_PAE_S_FORCE_UNAUTH = 10
      69             :         } SUPP_PAE_state; /* dot1xSuppPaeState */
      70             :         /* Variables */
      71             :         Boolean userLogoff;
      72             :         Boolean logoffSent;
      73             :         unsigned int startCount;
      74             :         Boolean eapRestart;
      75             :         PortControl sPortMode;
      76             :         /* Constants */
      77             :         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
      78             :         unsigned int startPeriod; /* dot1xSuppStartPeriod */
      79             :         unsigned int maxStart; /* dot1xSuppMaxStart */
      80             : 
      81             :         /* Key Receive state machine */
      82             :         enum {
      83             :                 KEY_RX_UNKNOWN = 0,
      84             :                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
      85             :         } KEY_RX_state;
      86             :         /* Variables */
      87             :         Boolean rxKey;
      88             : 
      89             :         /* Supplicant Backend state machine */
      90             :         enum {
      91             :                 SUPP_BE_UNKNOWN = 0,
      92             :                 SUPP_BE_INITIALIZE = 1,
      93             :                 SUPP_BE_IDLE = 2,
      94             :                 SUPP_BE_REQUEST = 3,
      95             :                 SUPP_BE_RECEIVE = 4,
      96             :                 SUPP_BE_RESPONSE = 5,
      97             :                 SUPP_BE_FAIL = 6,
      98             :                 SUPP_BE_TIMEOUT = 7, 
      99             :                 SUPP_BE_SUCCESS = 8
     100             :         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
     101             :         /* Variables */
     102             :         Boolean eapNoResp;
     103             :         Boolean eapReq;
     104             :         Boolean eapResp;
     105             :         /* Constants */
     106             :         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
     107             : 
     108             :         /* Statistics */
     109             :         unsigned int dot1xSuppEapolFramesRx;
     110             :         unsigned int dot1xSuppEapolFramesTx;
     111             :         unsigned int dot1xSuppEapolStartFramesTx;
     112             :         unsigned int dot1xSuppEapolLogoffFramesTx;
     113             :         unsigned int dot1xSuppEapolRespFramesTx;
     114             :         unsigned int dot1xSuppEapolReqIdFramesRx;
     115             :         unsigned int dot1xSuppEapolReqFramesRx;
     116             :         unsigned int dot1xSuppInvalidEapolFramesRx;
     117             :         unsigned int dot1xSuppEapLengthErrorFramesRx;
     118             :         unsigned int dot1xSuppLastEapolFrameVersion;
     119             :         unsigned char dot1xSuppLastEapolFrameSource[6];
     120             : 
     121             :         /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
     122             :         Boolean changed;
     123             :         struct eap_sm *eap;
     124             :         struct eap_peer_config *config;
     125             :         Boolean initial_req;
     126             :         u8 *last_rx_key;
     127             :         size_t last_rx_key_len;
     128             :         struct wpabuf *eapReqData; /* for EAP */
     129             :         Boolean altAccept; /* for EAP */
     130             :         Boolean altReject; /* for EAP */
     131             :         Boolean replay_counter_valid;
     132             :         u8 last_replay_counter[16];
     133             :         struct eapol_config conf;
     134             :         struct eapol_ctx *ctx;
     135             :         enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
     136             :                 cb_status;
     137             :         Boolean cached_pmk;
     138             : 
     139             :         Boolean unicast_key_received, broadcast_key_received;
     140             : 
     141             :         Boolean force_authorized_update;
     142             : 
     143             : #ifdef CONFIG_EAP_PROXY
     144             :         Boolean use_eap_proxy;
     145             :         struct eap_proxy_sm *eap_proxy;
     146             : #endif /* CONFIG_EAP_PROXY */
     147             : };
     148             : 
     149             : 
     150             : static void eapol_sm_txLogoff(struct eapol_sm *sm);
     151             : static void eapol_sm_txStart(struct eapol_sm *sm);
     152             : static void eapol_sm_processKey(struct eapol_sm *sm);
     153             : static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
     154             : static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
     155             : static void eapol_sm_abortSupp(struct eapol_sm *sm);
     156             : static void eapol_sm_abort_cached(struct eapol_sm *sm);
     157             : static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
     158             : static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
     159             : static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
     160             : 
     161             : 
     162             : /* Port Timers state machine - implemented as a function that will be called
     163             :  * once a second as a registered event loop timeout */
     164         651 : static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
     165             : {
     166         651 :         struct eapol_sm *sm = timeout_ctx;
     167             : 
     168         651 :         if (sm->authWhile > 0) {
     169          82 :                 sm->authWhile--;
     170          82 :                 if (sm->authWhile == 0)
     171           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
     172             :         }
     173         651 :         if (sm->heldWhile > 0) {
     174           3 :                 sm->heldWhile--;
     175           3 :                 if (sm->heldWhile == 0)
     176           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
     177             :         }
     178         651 :         if (sm->startWhen > 0) {
     179         196 :                 sm->startWhen--;
     180         196 :                 if (sm->startWhen == 0)
     181         192 :                         wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
     182             :         }
     183         651 :         if (sm->idleWhile > 0) {
     184         126 :                 sm->idleWhile--;
     185         126 :                 if (sm->idleWhile == 0)
     186           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
     187             :         }
     188             : 
     189         651 :         if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
     190         127 :                 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
     191             :                                        sm);
     192             :         } else {
     193         524 :                 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
     194         524 :                 sm->timer_tick_enabled = 0;
     195             :         }
     196         651 :         eapol_sm_step(sm);
     197         651 : }
     198             : 
     199             : 
     200        8624 : static void eapol_enable_timer_tick(struct eapol_sm *sm)
     201             : {
     202        8624 :         if (sm->timer_tick_enabled)
     203       16754 :                 return;
     204         494 :         wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
     205         494 :         sm->timer_tick_enabled = 1;
     206         494 :         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
     207         494 :         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
     208             : }
     209             : 
     210             : 
     211           1 : SM_STATE(SUPP_PAE, LOGOFF)
     212             : {
     213           1 :         SM_ENTRY(SUPP_PAE, LOGOFF);
     214           1 :         eapol_sm_txLogoff(sm);
     215           1 :         sm->logoffSent = TRUE;
     216           1 :         eapol_sm_set_port_unauthorized(sm);
     217           1 : }
     218             : 
     219             : 
     220       13865 : SM_STATE(SUPP_PAE, DISCONNECTED)
     221             : {
     222       13865 :         SM_ENTRY(SUPP_PAE, DISCONNECTED);
     223       13865 :         sm->sPortMode = Auto;
     224       13865 :         sm->startCount = 0;
     225       13865 :         sm->logoffSent = FALSE;
     226       13865 :         eapol_sm_set_port_unauthorized(sm);
     227       13865 :         sm->suppAbort = TRUE;
     228             : 
     229       13865 :         sm->unicast_key_received = FALSE;
     230       13865 :         sm->broadcast_key_received = FALSE;
     231             : 
     232             :         /*
     233             :          * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
     234             :          * allows the timer tick to be stopped more quickly when the port is
     235             :          * not enabled. Since this variable is used only within HELD state,
     236             :          * clearing it on initialization does not change actual state machine
     237             :          * behavior.
     238             :          */
     239       13865 :         sm->heldWhile = 0;
     240       13865 : }
     241             : 
     242             : 
     243         876 : SM_STATE(SUPP_PAE, CONNECTING)
     244             : {
     245         876 :         int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
     246         876 :         SM_ENTRY(SUPP_PAE, CONNECTING);
     247         876 :         if (send_start) {
     248          18 :                 sm->startWhen = sm->startPeriod;
     249          18 :                 sm->startCount++;
     250             :         } else {
     251             :                 /*
     252             :                  * Do not send EAPOL-Start immediately since in most cases,
     253             :                  * Authenticator is going to start authentication immediately
     254             :                  * after association and an extra EAPOL-Start is just going to
     255             :                  * delay authentication. Use a short timeout to send the first
     256             :                  * EAPOL-Start if Authenticator does not start authentication.
     257             :                  */
     258             : #ifdef CONFIG_WPS
     259             :                 /* Reduce latency on starting WPS negotiation. */
     260         858 :                 sm->startWhen = 1;
     261             : #else /* CONFIG_WPS */
     262             :                 sm->startWhen = 3;
     263             : #endif /* CONFIG_WPS */
     264             :         }
     265         876 :         eapol_enable_timer_tick(sm);
     266         876 :         sm->eapolEap = FALSE;
     267         876 :         if (send_start)
     268          18 :                 eapol_sm_txStart(sm);
     269         876 : }
     270             : 
     271             : 
     272         906 : SM_STATE(SUPP_PAE, AUTHENTICATING)
     273             : {
     274         906 :         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
     275         906 :         sm->startCount = 0;
     276         906 :         sm->suppSuccess = FALSE;
     277         906 :         sm->suppFail = FALSE;
     278         906 :         sm->suppTimeout = FALSE;
     279         906 :         sm->keyRun = FALSE;
     280         906 :         sm->keyDone = FALSE;
     281         906 :         sm->suppStart = TRUE;
     282         906 : }
     283             : 
     284             : 
     285         248 : SM_STATE(SUPP_PAE, HELD)
     286             : {
     287         248 :         SM_ENTRY(SUPP_PAE, HELD);
     288         248 :         sm->heldWhile = sm->heldPeriod;
     289         248 :         eapol_enable_timer_tick(sm);
     290         248 :         eapol_sm_set_port_unauthorized(sm);
     291         248 :         sm->cb_status = EAPOL_CB_FAILURE;
     292         248 : }
     293             : 
     294             : 
     295         639 : SM_STATE(SUPP_PAE, AUTHENTICATED)
     296             : {
     297         639 :         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
     298         639 :         eapol_sm_set_port_authorized(sm);
     299         639 :         sm->cb_status = EAPOL_CB_SUCCESS;
     300         639 : }
     301             : 
     302             : 
     303         543 : SM_STATE(SUPP_PAE, RESTART)
     304             : {
     305         543 :         SM_ENTRY(SUPP_PAE, RESTART);
     306         543 :         sm->eapRestart = TRUE;
     307         543 : }
     308             : 
     309             : 
     310         190 : SM_STATE(SUPP_PAE, S_FORCE_AUTH)
     311             : {
     312         190 :         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
     313         190 :         eapol_sm_set_port_authorized(sm);
     314         190 :         sm->sPortMode = ForceAuthorized;
     315         190 : }
     316             : 
     317             : 
     318           0 : SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
     319             : {
     320           0 :         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
     321           0 :         eapol_sm_set_port_unauthorized(sm);
     322           0 :         sm->sPortMode = ForceUnauthorized;
     323           0 :         eapol_sm_txLogoff(sm);
     324           0 : }
     325             : 
     326             : 
     327       35550 : SM_STEP(SUPP_PAE)
     328             : {
     329       35553 :         if ((sm->userLogoff && !sm->logoffSent) &&
     330           6 :             !(sm->initialize || !sm->portEnabled))
     331           1 :                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
     332       68266 :         else if (((sm->portControl == Auto) &&
     333       68266 :                   (sm->sPortMode != sm->portControl)) ||
     334       70956 :                  sm->initialize || !sm->portEnabled)
     335       13845 :                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
     336       22134 :         else if ((sm->portControl == ForceAuthorized) &&
     337         620 :                  (sm->sPortMode != sm->portControl) &&
     338         380 :                  !(sm->initialize || !sm->portEnabled))
     339         190 :                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
     340       21514 :         else if ((sm->portControl == ForceUnauthorized) &&
     341           0 :                  (sm->sPortMode != sm->portControl) &&
     342           0 :                  !(sm->initialize || !sm->portEnabled))
     343           0 :                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
     344       21514 :         else switch (sm->SUPP_PAE_state) {
     345             :         case SUPP_PAE_UNKNOWN:
     346           0 :                 break;
     347             :         case SUPP_PAE_LOGOFF:
     348           1 :                 if (!sm->userLogoff)
     349           0 :                         SM_ENTER(SUPP_PAE, DISCONNECTED);
     350           1 :                 break;
     351             :         case SUPP_PAE_DISCONNECTED:
     352         858 :                 SM_ENTER(SUPP_PAE, CONNECTING);
     353         858 :                 break;
     354             :         case SUPP_PAE_CONNECTING:
     355        2533 :                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
     356          18 :                         SM_ENTER(SUPP_PAE, CONNECTING);
     357        2515 :                 else if (sm->startWhen == 0 &&
     358           0 :                          sm->startCount >= sm->maxStart &&
     359           0 :                          sm->portValid)
     360           0 :                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
     361        2515 :                 else if (sm->eapSuccess || sm->eapFail)
     362         363 :                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
     363        2152 :                 else if (sm->eapolEap)
     364         487 :                         SM_ENTER(SUPP_PAE, RESTART);
     365        1665 :                 else if (sm->startWhen == 0 &&
     366           0 :                          sm->startCount >= sm->maxStart &&
     367           0 :                          !sm->portValid)
     368           0 :                         SM_ENTER(SUPP_PAE, HELD);
     369        2533 :                 break;
     370             :         case SUPP_PAE_AUTHENTICATING:
     371       16434 :                 if (sm->eapSuccess && !sm->portValid &&
     372        1877 :                     sm->conf.accept_802_1x_keys &&
     373          16 :                     sm->conf.required_keys == 0) {
     374           2 :                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
     375             :                                    "plaintext connection; no EAPOL-Key frames "
     376             :                                    "required");
     377           2 :                         sm->portValid = TRUE;
     378           2 :                         if (sm->ctx->eapol_done_cb)
     379           2 :                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
     380             :                 }
     381       14573 :                 if (sm->eapSuccess && sm->portValid)
     382         639 :                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
     383       13934 :                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
     384         248 :                         SM_ENTER(SUPP_PAE, HELD);
     385       13686 :                 else if (sm->suppTimeout)
     386           0 :                         SM_ENTER(SUPP_PAE, CONNECTING);
     387       14573 :                 break;
     388             :         case SUPP_PAE_HELD:
     389         747 :                 if (sm->heldWhile == 0)
     390           0 :                         SM_ENTER(SUPP_PAE, CONNECTING);
     391         747 :                 else if (sm->eapolEap)
     392           0 :                         SM_ENTER(SUPP_PAE, RESTART);
     393         747 :                 break;
     394             :         case SUPP_PAE_AUTHENTICATED:
     395        2019 :                 if (sm->eapolEap && sm->portValid)
     396          56 :                         SM_ENTER(SUPP_PAE, RESTART);
     397        1963 :                 else if (!sm->portValid)
     398          20 :                         SM_ENTER(SUPP_PAE, DISCONNECTED);
     399        2019 :                 break;
     400             :         case SUPP_PAE_RESTART:
     401         543 :                 if (!sm->eapRestart)
     402         543 :                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
     403         543 :                 break;
     404             :         case SUPP_PAE_S_FORCE_AUTH:
     405         240 :                 break;
     406             :         case SUPP_PAE_S_FORCE_UNAUTH:
     407           0 :                 break;
     408             :         }
     409       35550 : }
     410             : 
     411             : 
     412       13845 : SM_STATE(KEY_RX, NO_KEY_RECEIVE)
     413             : {
     414       13845 :         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
     415       13845 : }
     416             : 
     417             : 
     418           4 : SM_STATE(KEY_RX, KEY_RECEIVE)
     419             : {
     420           4 :         SM_ENTRY(KEY_RX, KEY_RECEIVE);
     421           4 :         eapol_sm_processKey(sm);
     422           4 :         sm->rxKey = FALSE;
     423           4 : }
     424             : 
     425             : 
     426       35550 : SM_STEP(KEY_RX)
     427             : {
     428       35550 :         if (sm->initialize || !sm->portEnabled)
     429       13845 :                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
     430       35550 :         switch (sm->KEY_RX_state) {
     431             :         case KEY_RX_UNKNOWN:
     432           0 :                 break;
     433             :         case KEY_RX_NO_KEY_RECEIVE:
     434       35542 :                 if (sm->rxKey)
     435           2 :                         SM_ENTER(KEY_RX, KEY_RECEIVE);
     436       35542 :                 break;
     437             :         case KEY_RX_KEY_RECEIVE:
     438           8 :                 if (sm->rxKey)
     439           2 :                         SM_ENTER(KEY_RX, KEY_RECEIVE);
     440           8 :                 break;
     441             :         }
     442       35550 : }
     443             : 
     444             : 
     445        3479 : SM_STATE(SUPP_BE, REQUEST)
     446             : {
     447        3479 :         SM_ENTRY(SUPP_BE, REQUEST);
     448        3479 :         sm->authWhile = 0;
     449        3479 :         sm->eapReq = TRUE;
     450        3479 :         eapol_sm_getSuppRsp(sm);
     451        3479 : }
     452             : 
     453             : 
     454        2947 : SM_STATE(SUPP_BE, RESPONSE)
     455             : {
     456        2947 :         SM_ENTRY(SUPP_BE, RESPONSE);
     457        2947 :         eapol_sm_txSuppRsp(sm);
     458        2947 :         sm->eapResp = FALSE;
     459        2947 : }
     460             : 
     461             : 
     462         646 : SM_STATE(SUPP_BE, SUCCESS)
     463             : {
     464         646 :         SM_ENTRY(SUPP_BE, SUCCESS);
     465         646 :         sm->keyRun = TRUE;
     466         646 :         sm->suppSuccess = TRUE;
     467             : 
     468             : #ifdef CONFIG_EAP_PROXY
     469             :         if (sm->use_eap_proxy) {
     470             :                 if (eap_proxy_key_available(sm->eap_proxy)) {
     471             :                         /* New key received - clear IEEE 802.1X EAPOL-Key replay
     472             :                          * counter */
     473             :                         sm->replay_counter_valid = FALSE;
     474             :                 }
     475             :                 return;
     476             :         }
     477             : #endif /* CONFIG_EAP_PROXY */
     478             : 
     479         646 :         if (eap_key_available(sm->eap)) {
     480             :                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
     481             :                  * counter */
     482         381 :                 sm->replay_counter_valid = FALSE;
     483             :         }
     484         646 : }
     485             : 
     486             : 
     487         248 : SM_STATE(SUPP_BE, FAIL)
     488             : {
     489         248 :         SM_ENTRY(SUPP_BE, FAIL);
     490         248 :         sm->suppFail = TRUE;
     491         248 : }
     492             : 
     493             : 
     494           0 : SM_STATE(SUPP_BE, TIMEOUT)
     495             : {
     496           0 :         SM_ENTRY(SUPP_BE, TIMEOUT);
     497           0 :         sm->suppTimeout = TRUE;
     498           0 : }
     499             : 
     500             : 
     501        1942 : SM_STATE(SUPP_BE, IDLE)
     502             : {
     503        1942 :         SM_ENTRY(SUPP_BE, IDLE);
     504        1942 :         sm->suppStart = FALSE;
     505        1942 :         sm->initial_req = TRUE;
     506        1942 : }
     507             : 
     508             : 
     509       13865 : SM_STATE(SUPP_BE, INITIALIZE)
     510             : {
     511       13865 :         SM_ENTRY(SUPP_BE, INITIALIZE);
     512       13865 :         eapol_sm_abortSupp(sm);
     513       13865 :         sm->suppAbort = FALSE;
     514             : 
     515             :         /*
     516             :          * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
     517             :          * allows the timer tick to be stopped more quickly when the port is
     518             :          * not enabled. Since this variable is used only within RECEIVE state,
     519             :          * clearing it on initialization does not change actual state machine
     520             :          * behavior.
     521             :          */
     522       13865 :         sm->authWhile = 0;
     523       13865 : }
     524             : 
     525             : 
     526        3478 : SM_STATE(SUPP_BE, RECEIVE)
     527             : {
     528        3478 :         SM_ENTRY(SUPP_BE, RECEIVE);
     529        3478 :         sm->authWhile = sm->authPeriod;
     530        3478 :         eapol_enable_timer_tick(sm);
     531        3478 :         sm->eapolEap = FALSE;
     532        3478 :         sm->eapNoResp = FALSE;
     533        3478 :         sm->initial_req = FALSE;
     534        3478 : }
     535             : 
     536             : 
     537       35550 : SM_STEP(SUPP_BE)
     538             : {
     539       35550 :         if (sm->initialize || sm->suppAbort)
     540       13865 :                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
     541       21685 :         else switch (sm->SUPP_BE_state) {
     542             :         case SUPP_BE_UNKNOWN:
     543           0 :                 break;
     544             :         case SUPP_BE_REQUEST:
     545             :                 /*
     546             :                  * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
     547             :                  * and SUCCESS based on eapFail and eapSuccess, respectively.
     548             :                  * However, IEEE Std 802.1X-2004 is also specifying that
     549             :                  * eapNoResp should be set in conjunction with eapSuccess and
     550             :                  * eapFail which would mean that more than one of the
     551             :                  * transitions here would be activated at the same time.
     552             :                  * Skipping RESPONSE and/or RECEIVE states in these cases can
     553             :                  * cause problems and the direct transitions to do not seem
     554             :                  * correct. Because of this, the conditions for these
     555             :                  * transitions are verified only after eapNoResp. They are
     556             :                  * unlikely to be used since eapNoResp should always be set if
     557             :                  * either of eapSuccess or eapFail is set.
     558             :                  */
     559        3507 :                 if (sm->eapResp && sm->eapNoResp) {
     560           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
     561             :                                    "eapResp and eapNoResp set?!");
     562             :                 }
     563        3507 :                 if (sm->eapResp)
     564        2947 :                         SM_ENTER(SUPP_BE, RESPONSE);
     565         560 :                 else if (sm->eapNoResp)
     566         531 :                         SM_ENTER(SUPP_BE, RECEIVE);
     567          29 :                 else if (sm->eapFail)
     568           0 :                         SM_ENTER(SUPP_BE, FAIL);
     569          29 :                 else if (sm->eapSuccess)
     570           1 :                         SM_ENTER(SUPP_BE, SUCCESS);
     571        3507 :                 break;
     572             :         case SUPP_BE_RESPONSE:
     573        2947 :                 SM_ENTER(SUPP_BE, RECEIVE);
     574        2947 :                 break;
     575             :         case SUPP_BE_SUCCESS:
     576         646 :                 SM_ENTER(SUPP_BE, IDLE);
     577         646 :                 break;
     578             :         case SUPP_BE_FAIL:
     579         248 :                 SM_ENTER(SUPP_BE, IDLE);
     580         248 :                 break;
     581             :         case SUPP_BE_TIMEOUT:
     582           0 :                 SM_ENTER(SUPP_BE, IDLE);
     583           0 :                 break;
     584             :         case SUPP_BE_IDLE:
     585        6853 :                 if (sm->eapFail && sm->suppStart)
     586           0 :                         SM_ENTER(SUPP_BE, FAIL);
     587        6853 :                 else if (sm->eapolEap && sm->suppStart)
     588         544 :                         SM_ENTER(SUPP_BE, REQUEST);
     589        6309 :                 else if (sm->eapSuccess && sm->suppStart)
     590         362 :                         SM_ENTER(SUPP_BE, SUCCESS);
     591        6853 :                 break;
     592             :         case SUPP_BE_INITIALIZE:
     593        1048 :                 SM_ENTER(SUPP_BE, IDLE);
     594        1048 :                 break;
     595             :         case SUPP_BE_RECEIVE:
     596        6436 :                 if (sm->eapolEap)
     597        2935 :                         SM_ENTER(SUPP_BE, REQUEST);
     598        3501 :                 else if (sm->eapFail)
     599         248 :                         SM_ENTER(SUPP_BE, FAIL);
     600        3253 :                 else if (sm->authWhile == 0)
     601           0 :                         SM_ENTER(SUPP_BE, TIMEOUT);
     602        3253 :                 else if (sm->eapSuccess)
     603         283 :                         SM_ENTER(SUPP_BE, SUCCESS);
     604        6436 :                 break;
     605             :         }
     606       35550 : }
     607             : 
     608             : 
     609           1 : static void eapol_sm_txLogoff(struct eapol_sm *sm)
     610             : {
     611           1 :         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
     612           1 :         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
     613             :                             IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
     614           1 :         sm->dot1xSuppEapolLogoffFramesTx++;
     615           1 :         sm->dot1xSuppEapolFramesTx++;
     616           1 : }
     617             : 
     618             : 
     619          73 : static void eapol_sm_txStart(struct eapol_sm *sm)
     620             : {
     621          73 :         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
     622          73 :         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
     623             :                             IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
     624          73 :         sm->dot1xSuppEapolStartFramesTx++;
     625          73 :         sm->dot1xSuppEapolFramesTx++;
     626          73 : }
     627             : 
     628             : 
     629             : #define IEEE8021X_ENCR_KEY_LEN 32
     630             : #define IEEE8021X_SIGN_KEY_LEN 32
     631             : 
     632             : struct eap_key_data {
     633             :         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
     634             :         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
     635             : };
     636             : 
     637             : 
     638           4 : static void eapol_sm_processKey(struct eapol_sm *sm)
     639             : {
     640             : #ifndef CONFIG_FIPS
     641             :         struct ieee802_1x_hdr *hdr;
     642             :         struct ieee802_1x_eapol_key *key;
     643             :         struct eap_key_data keydata;
     644             :         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
     645             :         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
     646             :         int key_len, res, sign_key_len, encr_key_len;
     647             :         u16 rx_key_length;
     648             :         size_t plen;
     649             : 
     650           4 :         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
     651           4 :         if (sm->last_rx_key == NULL)
     652           0 :                 return;
     653             : 
     654           4 :         if (!sm->conf.accept_802_1x_keys) {
     655           0 :                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
     656             :                            " even though this was not accepted - "
     657             :                            "ignoring this packet");
     658           0 :                 return;
     659             :         }
     660             : 
     661           4 :         if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
     662           0 :                 return;
     663           4 :         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
     664           4 :         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
     665           4 :         plen = be_to_host16(hdr->length);
     666           4 :         if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
     667           0 :                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
     668           0 :                 return;
     669             :         }
     670           4 :         rx_key_length = WPA_GET_BE16(key->key_length);
     671          20 :         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
     672             :                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
     673          12 :                    hdr->version, hdr->type, be_to_host16(hdr->length),
     674           8 :                    key->type, rx_key_length, key->key_index);
     675             : 
     676           4 :         eapol_sm_notify_lower_layer_success(sm, 1);
     677           4 :         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
     678           4 :         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
     679           4 :         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
     680           4 :         if (res < 0) {
     681           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
     682             :                            "decrypting EAPOL-Key keys");
     683           0 :                 return;
     684             :         }
     685           4 :         if (res == 16) {
     686             :                 /* LEAP derives only 16 bytes of keying material. */
     687           0 :                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
     688           0 :                 if (res) {
     689           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
     690             :                                    "master key for decrypting EAPOL-Key keys");
     691           0 :                         return;
     692             :                 }
     693           0 :                 sign_key_len = 16;
     694           0 :                 encr_key_len = 16;
     695           0 :                 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
     696           4 :         } else if (res) {
     697           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
     698             :                            "data for decrypting EAPOL-Key keys (res=%d)", res);
     699           0 :                 return;
     700             :         }
     701             : 
     702             :         /* The key replay_counter must increase when same master key */
     703           6 :         if (sm->replay_counter_valid &&
     704           2 :             os_memcmp(sm->last_replay_counter, key->replay_counter,
     705             :                       IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
     706           0 :                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
     707             :                            "not increase - ignoring key");
     708           0 :                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
     709           0 :                             sm->last_replay_counter,
     710             :                             IEEE8021X_REPLAY_COUNTER_LEN);
     711           0 :                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
     712           0 :                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
     713           0 :                 return;
     714             :         }
     715             : 
     716             :         /* Verify key signature (HMAC-MD5) */
     717           4 :         os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
     718           4 :         os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
     719           8 :         hmac_md5(keydata.sign_key, sign_key_len,
     720           8 :                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
     721           4 :                  key->key_signature);
     722           4 :         if (os_memcmp(orig_key_sign, key->key_signature,
     723             :                       IEEE8021X_KEY_SIGN_LEN) != 0) {
     724           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
     725             :                            "EAPOL-Key packet");
     726           0 :                 os_memcpy(key->key_signature, orig_key_sign,
     727             :                           IEEE8021X_KEY_SIGN_LEN);
     728           0 :                 return;
     729             :         }
     730           4 :         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
     731             : 
     732           4 :         key_len = plen - sizeof(*key);
     733           4 :         if (key_len > 32 || rx_key_length > 32) {
     734           0 :                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
     735             :                            key_len ? key_len : rx_key_length);
     736           0 :                 return;
     737             :         }
     738           4 :         if (key_len == rx_key_length) {
     739           4 :                 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
     740           4 :                 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
     741             :                           encr_key_len);
     742           4 :                 os_memcpy(datakey, key + 1, key_len);
     743           4 :                 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
     744             :                          datakey, key_len);
     745           4 :                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
     746             :                                 datakey, key_len);
     747           0 :         } else if (key_len == 0) {
     748             :                 /*
     749             :                  * IEEE 802.1X-2004 specifies that least significant Key Length
     750             :                  * octets from MS-MPPE-Send-Key are used as the key if the key
     751             :                  * data is not present. This seems to be meaning the beginning
     752             :                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
     753             :                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
     754             :                  * Anyway, taking the beginning of the keying material from EAP
     755             :                  * seems to interoperate with Authenticators.
     756             :                  */
     757           0 :                 key_len = rx_key_length;
     758           0 :                 os_memcpy(datakey, keydata.encr_key, key_len);
     759           0 :                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
     760             :                                 "material data encryption key",
     761             :                                 datakey, key_len);
     762             :         } else {
     763           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
     764             :                            "(key_length=%d)", key_len, rx_key_length);
     765           0 :                 return;
     766             :         }
     767             : 
     768           4 :         sm->replay_counter_valid = TRUE;
     769           4 :         os_memcpy(sm->last_replay_counter, key->replay_counter,
     770             :                   IEEE8021X_REPLAY_COUNTER_LEN);
     771             : 
     772           8 :         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
     773             :                    "len %d",
     774           4 :                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
     775             :                    "unicast" : "broadcast",
     776           4 :                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
     777             : 
     778           8 :         if (sm->ctx->set_wep_key &&
     779          12 :             sm->ctx->set_wep_key(sm->ctx->ctx,
     780           4 :                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
     781           4 :                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
     782             :                                  datakey, key_len) < 0) {
     783           0 :                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
     784             :                            " driver.");
     785             :         } else {
     786           4 :                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
     787           2 :                         sm->unicast_key_received = TRUE;
     788             :                 else
     789           2 :                         sm->broadcast_key_received = TRUE;
     790             : 
     791           6 :                 if ((sm->unicast_key_received ||
     792           4 :                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
     793           2 :                     (sm->broadcast_key_received ||
     794           0 :                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
     795             :                 {
     796           2 :                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
     797             :                                    "frames received");
     798           2 :                         sm->portValid = TRUE;
     799           2 :                         if (sm->ctx->eapol_done_cb)
     800           2 :                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
     801             :                 }
     802             :         }
     803             : #endif /* CONFIG_FIPS */
     804             : }
     805             : 
     806             : 
     807        3479 : static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
     808             : {
     809        3479 :         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
     810             :         /* EAP layer processing; no special code is needed, since Supplicant
     811             :          * Backend state machine is waiting for eapNoResp or eapResp to be set
     812             :          * and these are only set in the EAP state machine when the processing
     813             :          * has finished. */
     814        3479 : }
     815             : 
     816             : 
     817        2947 : static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
     818             : {
     819             :         struct wpabuf *resp;
     820             : 
     821        2947 :         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
     822             : 
     823             : #ifdef CONFIG_EAP_PROXY
     824             :         if (sm->use_eap_proxy) {
     825             :                 /* Get EAP Response from EAP Proxy */
     826             :                 resp = eap_proxy_get_eapRespData(sm->eap_proxy);
     827             :                 if (resp == NULL) {
     828             :                         wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
     829             :                                    "response data not available");
     830             :                         return;
     831             :                 }
     832             :         } else
     833             : #endif /* CONFIG_EAP_PROXY */
     834             : 
     835        2947 :         resp = eap_get_eapRespData(sm->eap);
     836        2947 :         if (resp == NULL) {
     837           0 :                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
     838             :                            "not available");
     839        2947 :                 return;
     840             :         }
     841             : 
     842             :         /* Send EAP-Packet from the EAP layer to the Authenticator */
     843        5894 :         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
     844        2947 :                             IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
     845             :                             wpabuf_len(resp));
     846             : 
     847             :         /* eapRespData is not used anymore, so free it here */
     848        2947 :         wpabuf_free(resp);
     849             : 
     850        2947 :         if (sm->initial_req)
     851         543 :                 sm->dot1xSuppEapolReqIdFramesRx++;
     852             :         else
     853        2404 :                 sm->dot1xSuppEapolReqFramesRx++;
     854        2947 :         sm->dot1xSuppEapolRespFramesTx++;
     855        2947 :         sm->dot1xSuppEapolFramesTx++;
     856             : }
     857             : 
     858             : 
     859       13865 : static void eapol_sm_abortSupp(struct eapol_sm *sm)
     860             : {
     861             :         /* release system resources that may have been allocated for the
     862             :          * authentication session */
     863       13865 :         os_free(sm->last_rx_key);
     864       13865 :         sm->last_rx_key = NULL;
     865       13865 :         wpabuf_free(sm->eapReqData);
     866       13865 :         sm->eapReqData = NULL;
     867       13865 :         eap_sm_abort(sm->eap);
     868       13865 : }
     869             : 
     870             : 
     871           0 : static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
     872             : {
     873           0 :         eapol_sm_step(timeout_ctx);
     874           0 : }
     875             : 
     876             : 
     877         829 : static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
     878             : {
     879             :         int cb;
     880             : 
     881         829 :         cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
     882         829 :         sm->force_authorized_update = FALSE;
     883         829 :         sm->suppPortStatus = Authorized;
     884         829 :         if (cb && sm->ctx->port_cb)
     885         776 :                 sm->ctx->port_cb(sm->ctx->ctx, 1);
     886         829 : }
     887             : 
     888             : 
     889       14126 : static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
     890             : {
     891             :         int cb;
     892             : 
     893       14126 :         cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
     894       14126 :         sm->force_authorized_update = FALSE;
     895       14126 :         sm->suppPortStatus = Unauthorized;
     896       14126 :         if (cb && sm->ctx->port_cb)
     897        1375 :                 sm->ctx->port_cb(sm->ctx->ctx, 0);
     898       14126 : }
     899             : 
     900             : 
     901             : /**
     902             :  * eapol_sm_step - EAPOL state machine step function
     903             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
     904             :  *
     905             :  * This function is called to notify the state machine about changed external
     906             :  * variables. It will step through the EAPOL state machines in loop to process
     907             :  * all triggered state changes.
     908             :  */
     909       20573 : void eapol_sm_step(struct eapol_sm *sm)
     910             : {
     911             :         int i;
     912             : 
     913             :         /* In theory, it should be ok to run this in loop until !changed.
     914             :          * However, it is better to use a limit on number of iterations to
     915             :          * allow events (e.g., SIGTERM) to stop the program cleanly if the
     916             :          * state machine were to generate a busy loop. */
     917       35550 :         for (i = 0; i < 100; i++) {
     918       35550 :                 sm->changed = FALSE;
     919       35550 :                 SM_STEP_RUN(SUPP_PAE);
     920       35550 :                 SM_STEP_RUN(KEY_RX);
     921       35550 :                 SM_STEP_RUN(SUPP_BE);
     922             : #ifdef CONFIG_EAP_PROXY
     923             :                 if (sm->use_eap_proxy) {
     924             :                         /* Drive the EAP proxy state machine */
     925             :                         if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
     926             :                                 sm->changed = TRUE;
     927             :                 } else
     928             : #endif /* CONFIG_EAP_PROXY */
     929       35550 :                 if (eap_peer_sm_step(sm->eap))
     930        5482 :                         sm->changed = TRUE;
     931       35550 :                 if (!sm->changed)
     932       20573 :                         break;
     933             :         }
     934             : 
     935       20573 :         if (sm->changed) {
     936             :                 /* restart EAPOL state machine step from timeout call in order
     937             :                  * to allow other events to be processed. */
     938           0 :                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
     939           0 :                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
     940             :         }
     941             : 
     942       20573 :         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
     943             :                 enum eapol_supp_result result;
     944         887 :                 if (sm->cb_status == EAPOL_CB_SUCCESS)
     945         639 :                         result = EAPOL_SUPP_RESULT_SUCCESS;
     946         248 :                 else if (eap_peer_was_failure_expected(sm->eap))
     947           4 :                         result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
     948             :                 else
     949         244 :                         result = EAPOL_SUPP_RESULT_FAILURE;
     950         887 :                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
     951         887 :                 sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
     952             :         }
     953       20573 : }
     954             : 
     955             : 
     956             : #ifdef CONFIG_CTRL_IFACE
     957         194 : static const char *eapol_supp_pae_state(int state)
     958             : {
     959         194 :         switch (state) {
     960             :         case SUPP_PAE_LOGOFF:
     961           0 :                 return "LOGOFF";
     962             :         case SUPP_PAE_DISCONNECTED:
     963           0 :                 return "DISCONNECTED";
     964             :         case SUPP_PAE_CONNECTING:
     965           1 :                 return "CONNECTING";
     966             :         case SUPP_PAE_AUTHENTICATING:
     967           0 :                 return "AUTHENTICATING";
     968             :         case SUPP_PAE_HELD:
     969           0 :                 return "HELD";
     970             :         case SUPP_PAE_AUTHENTICATED:
     971         193 :                 return "AUTHENTICATED";
     972             :         case SUPP_PAE_RESTART:
     973           0 :                 return "RESTART";
     974             :         default:
     975           0 :                 return "UNKNOWN";
     976             :         }
     977             : }
     978             : 
     979             : 
     980           0 : static const char *eapol_supp_be_state(int state)
     981             : {
     982           0 :         switch (state) {
     983             :         case SUPP_BE_REQUEST:
     984           0 :                 return "REQUEST";
     985             :         case SUPP_BE_RESPONSE:
     986           0 :                 return "RESPONSE";
     987             :         case SUPP_BE_SUCCESS:
     988           0 :                 return "SUCCESS";
     989             :         case SUPP_BE_FAIL:
     990           0 :                 return "FAIL";
     991             :         case SUPP_BE_TIMEOUT:
     992           0 :                 return "TIMEOUT";
     993             :         case SUPP_BE_IDLE:
     994           0 :                 return "IDLE";
     995             :         case SUPP_BE_INITIALIZE:
     996           0 :                 return "INITIALIZE";
     997             :         case SUPP_BE_RECEIVE:
     998           0 :                 return "RECEIVE";
     999             :         default:
    1000           0 :                 return "UNKNOWN";
    1001             :         }
    1002             : }
    1003             : 
    1004             : 
    1005         194 : static const char * eapol_port_status(PortStatus status)
    1006             : {
    1007         194 :         if (status == Authorized)
    1008         193 :                 return "Authorized";
    1009             :         else
    1010           1 :                 return "Unauthorized";
    1011             : }
    1012             : #endif /* CONFIG_CTRL_IFACE */
    1013             : 
    1014             : 
    1015             : #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
    1016        1092 : static const char * eapol_port_control(PortControl ctrl)
    1017             : {
    1018        1092 :         switch (ctrl) {
    1019             :         case Auto:
    1020         875 :                 return "Auto";
    1021             :         case ForceUnauthorized:
    1022           0 :                 return "ForceUnauthorized";
    1023             :         case ForceAuthorized:
    1024         217 :                 return "ForceAuthorized";
    1025             :         default:
    1026           0 :                 return "Unknown";
    1027             :         }
    1028             : }
    1029             : #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
    1030             : 
    1031             : 
    1032             : /**
    1033             :  * eapol_sm_configure - Set EAPOL variables
    1034             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1035             :  * @heldPeriod: dot1xSuppHeldPeriod
    1036             :  * @authPeriod: dot1xSuppAuthPeriod
    1037             :  * @startPeriod: dot1xSuppStartPeriod
    1038             :  * @maxStart: dot1xSuppMaxStart
    1039             :  *
    1040             :  * Set configurable EAPOL state machine variables. Each variable can be set to
    1041             :  * the given value or ignored if set to -1 (to set only some of the variables).
    1042             :  */
    1043           6 : void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
    1044             :                         int startPeriod, int maxStart)
    1045             : {
    1046           6 :         if (sm == NULL)
    1047           6 :                 return;
    1048           6 :         if (heldPeriod >= 0)
    1049           1 :                 sm->heldPeriod = heldPeriod;
    1050           6 :         if (authPeriod >= 0)
    1051           1 :                 sm->authPeriod = authPeriod;
    1052           6 :         if (startPeriod >= 0)
    1053           3 :                 sm->startPeriod = startPeriod;
    1054           6 :         if (maxStart >= 0)
    1055           3 :                 sm->maxStart = maxStart;
    1056             : }
    1057             : 
    1058             : 
    1059             : /**
    1060             :  * eapol_sm_get_method_name - Get EAPOL method name
    1061             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1062             :  * Returns: Static string containing name of current eap method or NULL
    1063             :  */
    1064           0 : const char * eapol_sm_get_method_name(struct eapol_sm *sm)
    1065             : {
    1066           0 :         if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
    1067           0 :             sm->suppPortStatus != Authorized)
    1068           0 :                 return NULL;
    1069             : 
    1070           0 :         return eap_sm_get_method_name(sm->eap);
    1071             : }
    1072             : 
    1073             : 
    1074             : #ifdef CONFIG_CTRL_IFACE
    1075             : /**
    1076             :  * eapol_sm_get_status - Get EAPOL state machine status
    1077             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1078             :  * @buf: Buffer for status information
    1079             :  * @buflen: Maximum buffer length
    1080             :  * @verbose: Whether to include verbose status information
    1081             :  * Returns: Number of bytes written to buf.
    1082             :  *
    1083             :  * Query EAPOL state machine for status information. This function fills in a
    1084             :  * text area with current status information from the EAPOL state machine. If
    1085             :  * the buffer (buf) is not large enough, status information will be truncated
    1086             :  * to fit the buffer.
    1087             :  */
    1088         194 : int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
    1089             :                         int verbose)
    1090             : {
    1091             :         int len, ret;
    1092         194 :         if (sm == NULL)
    1093           0 :                 return 0;
    1094             : 
    1095         388 :         len = os_snprintf(buf, buflen,
    1096             :                           "Supplicant PAE state=%s\n"
    1097             :                           "suppPortStatus=%s\n",
    1098         194 :                           eapol_supp_pae_state(sm->SUPP_PAE_state),
    1099             :                           eapol_port_status(sm->suppPortStatus));
    1100         194 :         if (len < 0 || (size_t) len >= buflen)
    1101           0 :                 return 0;
    1102             : 
    1103         194 :         if (verbose) {
    1104           0 :                 ret = os_snprintf(buf + len, buflen - len,
    1105             :                                   "heldPeriod=%u\n"
    1106             :                                   "authPeriod=%u\n"
    1107             :                                   "startPeriod=%u\n"
    1108             :                                   "maxStart=%u\n"
    1109             :                                   "portControl=%s\n"
    1110             :                                   "Supplicant Backend state=%s\n",
    1111             :                                   sm->heldPeriod,
    1112             :                                   sm->authPeriod,
    1113             :                                   sm->startPeriod,
    1114             :                                   sm->maxStart,
    1115             :                                   eapol_port_control(sm->portControl),
    1116           0 :                                   eapol_supp_be_state(sm->SUPP_BE_state));
    1117           0 :                 if (ret < 0 || (size_t) ret >= buflen - len)
    1118           0 :                         return len;
    1119           0 :                 len += ret;
    1120             :         }
    1121             : 
    1122             : #ifdef CONFIG_EAP_PROXY
    1123             :         if (sm->use_eap_proxy)
    1124             :                 len += eap_proxy_sm_get_status(sm->eap_proxy,
    1125             :                                                buf + len, buflen - len,
    1126             :                                                verbose);
    1127             :         else
    1128             : #endif /* CONFIG_EAP_PROXY */
    1129         194 :         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
    1130             : 
    1131         194 :         return len;
    1132             : }
    1133             : 
    1134             : 
    1135             : /**
    1136             :  * eapol_sm_get_mib - Get EAPOL state machine MIBs
    1137             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1138             :  * @buf: Buffer for MIB information
    1139             :  * @buflen: Maximum buffer length
    1140             :  * Returns: Number of bytes written to buf.
    1141             :  *
    1142             :  * Query EAPOL state machine for MIB information. This function fills in a
    1143             :  * text area with current MIB information from the EAPOL state machine. If
    1144             :  * the buffer (buf) is not large enough, MIB information will be truncated to
    1145             :  * fit the buffer.
    1146             :  */
    1147           8 : int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
    1148             : {
    1149             :         size_t len;
    1150             :         int ret;
    1151             : 
    1152           8 :         if (sm == NULL)
    1153           0 :                 return 0;
    1154          16 :         ret = os_snprintf(buf, buflen,
    1155             :                           "dot1xSuppPaeState=%d\n"
    1156             :                           "dot1xSuppHeldPeriod=%u\n"
    1157             :                           "dot1xSuppAuthPeriod=%u\n"
    1158             :                           "dot1xSuppStartPeriod=%u\n"
    1159             :                           "dot1xSuppMaxStart=%u\n"
    1160             :                           "dot1xSuppSuppControlledPortStatus=%s\n"
    1161             :                           "dot1xSuppBackendPaeState=%d\n",
    1162           8 :                           sm->SUPP_PAE_state,
    1163             :                           sm->heldPeriod,
    1164             :                           sm->authPeriod,
    1165             :                           sm->startPeriod,
    1166             :                           sm->maxStart,
    1167           8 :                           sm->suppPortStatus == Authorized ?
    1168             :                           "Authorized" : "Unauthorized",
    1169           8 :                           sm->SUPP_BE_state);
    1170             : 
    1171           8 :         if (ret < 0 || (size_t) ret >= buflen)
    1172           0 :                 return 0;
    1173           8 :         len = ret;
    1174             : 
    1175          48 :         ret = os_snprintf(buf + len, buflen - len,
    1176             :                           "dot1xSuppEapolFramesRx=%u\n"
    1177             :                           "dot1xSuppEapolFramesTx=%u\n"
    1178             :                           "dot1xSuppEapolStartFramesTx=%u\n"
    1179             :                           "dot1xSuppEapolLogoffFramesTx=%u\n"
    1180             :                           "dot1xSuppEapolRespFramesTx=%u\n"
    1181             :                           "dot1xSuppEapolReqIdFramesRx=%u\n"
    1182             :                           "dot1xSuppEapolReqFramesRx=%u\n"
    1183             :                           "dot1xSuppInvalidEapolFramesRx=%u\n"
    1184             :                           "dot1xSuppEapLengthErrorFramesRx=%u\n"
    1185             :                           "dot1xSuppLastEapolFrameVersion=%u\n"
    1186             :                           "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
    1187             :                           sm->dot1xSuppEapolFramesRx,
    1188             :                           sm->dot1xSuppEapolFramesTx,
    1189             :                           sm->dot1xSuppEapolStartFramesTx,
    1190             :                           sm->dot1xSuppEapolLogoffFramesTx,
    1191             :                           sm->dot1xSuppEapolRespFramesTx,
    1192             :                           sm->dot1xSuppEapolReqIdFramesRx,
    1193             :                           sm->dot1xSuppEapolReqFramesRx,
    1194             :                           sm->dot1xSuppInvalidEapolFramesRx,
    1195             :                           sm->dot1xSuppEapLengthErrorFramesRx,
    1196             :                           sm->dot1xSuppLastEapolFrameVersion,
    1197          48 :                           MAC2STR(sm->dot1xSuppLastEapolFrameSource));
    1198             : 
    1199           8 :         if (ret < 0 || (size_t) ret >= buflen - len)
    1200           0 :                 return len;
    1201           8 :         len += ret;
    1202             : 
    1203           8 :         return len;
    1204             : }
    1205             : #endif /* CONFIG_CTRL_IFACE */
    1206             : 
    1207             : 
    1208             : /**
    1209             :  * eapol_sm_rx_eapol - Process received EAPOL frames
    1210             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1211             :  * @src: Source MAC address of the EAPOL packet
    1212             :  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
    1213             :  * @len: Length of the EAPOL frame
    1214             :  * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
    1215             :  * -1 failure
    1216             :  */
    1217        4058 : int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
    1218             :                       size_t len)
    1219             : {
    1220             :         const struct ieee802_1x_hdr *hdr;
    1221             :         const struct ieee802_1x_eapol_key *key;
    1222             :         int data_len;
    1223        4058 :         int res = 1;
    1224             :         size_t plen;
    1225             : 
    1226        4058 :         if (sm == NULL)
    1227           0 :                 return 0;
    1228        4058 :         sm->dot1xSuppEapolFramesRx++;
    1229        4058 :         if (len < sizeof(*hdr)) {
    1230           0 :                 sm->dot1xSuppInvalidEapolFramesRx++;
    1231           0 :                 return 0;
    1232             :         }
    1233        4058 :         hdr = (const struct ieee802_1x_hdr *) buf;
    1234        4058 :         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
    1235        4058 :         os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
    1236        4058 :         if (hdr->version < EAPOL_VERSION) {
    1237             :                 /* TODO: backwards compatibility */
    1238             :         }
    1239        4058 :         plen = be_to_host16(hdr->length);
    1240        4058 :         if (plen > len - sizeof(*hdr)) {
    1241           0 :                 sm->dot1xSuppEapLengthErrorFramesRx++;
    1242           0 :                 return 0;
    1243             :         }
    1244             : #ifdef CONFIG_WPS
    1245        8116 :         if (sm->conf.workaround &&
    1246        4058 :             plen < len - sizeof(*hdr) &&
    1247           0 :             hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
    1248           0 :             len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
    1249           0 :                 const struct eap_hdr *ehdr =
    1250             :                         (const struct eap_hdr *) (hdr + 1);
    1251             :                 u16 elen;
    1252             : 
    1253           0 :                 elen = be_to_host16(ehdr->length);
    1254           0 :                 if (elen > plen && elen <= len - sizeof(*hdr)) {
    1255             :                         /*
    1256             :                          * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
    1257             :                          * packets with too short EAPOL header length field
    1258             :                          * (14 octets). This is fixed in firmware Ver.1.49.
    1259             :                          * As a workaround, fix the EAPOL header based on the
    1260             :                          * correct length in the EAP packet.
    1261             :                          */
    1262           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
    1263             :                                    "payload length based on EAP header: "
    1264             :                                    "%d -> %d", (int) plen, elen);
    1265           0 :                         plen = elen;
    1266             :                 }
    1267             :         }
    1268             : #endif /* CONFIG_WPS */
    1269        4058 :         data_len = plen + sizeof(*hdr);
    1270             : 
    1271        4058 :         switch (hdr->type) {
    1272             :         case IEEE802_1X_TYPE_EAP_PACKET:
    1273        3479 :                 if (sm->conf.workaround) {
    1274             :                         /*
    1275             :                          * An AP has been reported to send out EAP message with
    1276             :                          * undocumented code 10 at some point near the
    1277             :                          * completion of EAP authentication. This can result in
    1278             :                          * issues with the unexpected EAP message triggering
    1279             :                          * restart of EAPOL authentication. Avoid this by
    1280             :                          * skipping the message without advancing the state
    1281             :                          * machine.
    1282             :                          */
    1283        3479 :                         const struct eap_hdr *ehdr =
    1284             :                                 (const struct eap_hdr *) (hdr + 1);
    1285        3479 :                         if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
    1286           0 :                                 wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
    1287           0 :                                 break;
    1288             :                         }
    1289             :                 }
    1290             : 
    1291        3479 :                 if (sm->cached_pmk) {
    1292             :                         /* Trying to use PMKSA caching, but Authenticator did
    1293             :                          * not seem to have a matching entry. Need to restart
    1294             :                          * EAPOL state machines.
    1295             :                          */
    1296          12 :                         eapol_sm_abort_cached(sm);
    1297             :                 }
    1298        3479 :                 wpabuf_free(sm->eapReqData);
    1299        3479 :                 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
    1300        3479 :                 if (sm->eapReqData) {
    1301        3479 :                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
    1302             :                                    "frame");
    1303        3479 :                         sm->eapolEap = TRUE;
    1304             : #ifdef CONFIG_EAP_PROXY
    1305             :                         if (sm->use_eap_proxy) {
    1306             :                                 eap_proxy_packet_update(
    1307             :                                         sm->eap_proxy,
    1308             :                                         wpabuf_mhead_u8(sm->eapReqData),
    1309             :                                         wpabuf_len(sm->eapReqData));
    1310             :                                 wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
    1311             :                                            "EAP Req updated");
    1312             :                         }
    1313             : #endif /* CONFIG_EAP_PROXY */
    1314        3479 :                         eapol_sm_step(sm);
    1315             :                 }
    1316        3479 :                 break;
    1317             :         case IEEE802_1X_TYPE_EAPOL_KEY:
    1318         579 :                 if (plen < sizeof(*key)) {
    1319           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
    1320             :                                    "frame received");
    1321           0 :                         break;
    1322             :                 }
    1323         579 :                 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
    1324        1152 :                 if (key->type == EAPOL_KEY_TYPE_WPA ||
    1325         573 :                     key->type == EAPOL_KEY_TYPE_RSN) {
    1326             :                         /* WPA Supplicant takes care of this frame. */
    1327         575 :                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
    1328             :                                    "frame in EAPOL state machines");
    1329         575 :                         res = 0;
    1330         575 :                         break;
    1331             :                 }
    1332           4 :                 if (key->type != EAPOL_KEY_TYPE_RC4) {
    1333           0 :                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
    1334           0 :                                    "EAPOL-Key type %d", key->type);
    1335           0 :                         break;
    1336             :                 }
    1337           4 :                 os_free(sm->last_rx_key);
    1338           4 :                 sm->last_rx_key = os_malloc(data_len);
    1339           4 :                 if (sm->last_rx_key) {
    1340           4 :                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
    1341             :                                    "frame");
    1342           4 :                         os_memcpy(sm->last_rx_key, buf, data_len);
    1343           4 :                         sm->last_rx_key_len = data_len;
    1344           4 :                         sm->rxKey = TRUE;
    1345           4 :                         eapol_sm_step(sm);
    1346             :                 }
    1347           4 :                 break;
    1348             : #ifdef CONFIG_MACSEC
    1349             :         case IEEE802_1X_TYPE_EAPOL_MKA:
    1350             :                 wpa_printf(MSG_EXCESSIVE,
    1351             :                            "EAPOL type %d will be handled by MKA",
    1352             :                            hdr->type);
    1353             :                 break;
    1354             : #endif /* CONFIG_MACSEC */
    1355             :         default:
    1356           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
    1357           0 :                            hdr->type);
    1358           0 :                 sm->dot1xSuppInvalidEapolFramesRx++;
    1359           0 :                 break;
    1360             :         }
    1361             : 
    1362        4058 :         return res;
    1363             : }
    1364             : 
    1365             : 
    1366             : /**
    1367             :  * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
    1368             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1369             :  *
    1370             :  * Notify EAPOL state machine about transmitted EAPOL packet from an external
    1371             :  * component, e.g., WPA. This will update the statistics.
    1372             :  */
    1373        1311 : void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
    1374             : {
    1375        1311 :         if (sm)
    1376        1287 :                 sm->dot1xSuppEapolFramesTx++;
    1377        1311 : }
    1378             : 
    1379             : 
    1380             : /**
    1381             :  * eapol_sm_notify_portEnabled - Notification about portEnabled change
    1382             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1383             :  * @enabled: New portEnabled value
    1384             :  *
    1385             :  * Notify EAPOL state machine about new portEnabled value.
    1386             :  */
    1387        4314 : void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
    1388             : {
    1389        4314 :         if (sm == NULL)
    1390        4385 :                 return;
    1391        4243 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1392             :                    "portEnabled=%d", enabled);
    1393        4243 :         if (sm->portEnabled != enabled)
    1394        2054 :                 sm->force_authorized_update = TRUE;
    1395        4243 :         sm->portEnabled = enabled;
    1396        4243 :         eapol_sm_step(sm);
    1397             : }
    1398             : 
    1399             : 
    1400             : /**
    1401             :  * eapol_sm_notify_portValid - Notification about portValid change
    1402             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1403             :  * @valid: New portValid value
    1404             :  *
    1405             :  * Notify EAPOL state machine about new portValid value.
    1406             :  */
    1407        4568 : void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
    1408             : {
    1409        4568 :         if (sm == NULL)
    1410        4659 :                 return;
    1411        4477 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1412             :                    "portValid=%d", valid);
    1413        4477 :         sm->portValid = valid;
    1414        4477 :         eapol_sm_step(sm);
    1415             : }
    1416             : 
    1417             : 
    1418             : /**
    1419             :  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
    1420             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1421             :  * @success: %TRUE = set success, %FALSE = clear success
    1422             :  *
    1423             :  * Notify the EAPOL state machine that external event has forced EAP state to
    1424             :  * success (success = %TRUE). This can be cleared by setting success = %FALSE.
    1425             :  *
    1426             :  * This function is called to update EAP state when WPA-PSK key handshake has
    1427             :  * been completed successfully since WPA-PSK does not use EAP state machine.
    1428             :  */
    1429        2190 : void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
    1430             : {
    1431        2190 :         if (sm == NULL)
    1432        2200 :                 return;
    1433        2180 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1434             :                    "EAP success=%d", success);
    1435        2180 :         sm->eapSuccess = success;
    1436        2180 :         sm->altAccept = success;
    1437        2180 :         if (success)
    1438         373 :                 eap_notify_success(sm->eap);
    1439        2180 :         eapol_sm_step(sm);
    1440             : }
    1441             : 
    1442             : 
    1443             : /**
    1444             :  * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
    1445             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1446             :  * @fail: %TRUE = set failure, %FALSE = clear failure
    1447             :  *
    1448             :  * Notify EAPOL state machine that external event has forced EAP state to
    1449             :  * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
    1450             :  */
    1451        1092 : void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
    1452             : {
    1453        1092 :         if (sm == NULL)
    1454        1092 :                 return;
    1455        1092 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1456             :                    "EAP fail=%d", fail);
    1457        1092 :         sm->eapFail = fail;
    1458        1092 :         sm->altReject = fail;
    1459        1092 :         eapol_sm_step(sm);
    1460             : }
    1461             : 
    1462             : 
    1463             : /**
    1464             :  * eapol_sm_notify_config - Notification of EAPOL configuration change
    1465             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1466             :  * @config: Pointer to current network EAP configuration
    1467             :  * @conf: Pointer to EAPOL configuration data
    1468             :  *
    1469             :  * Notify EAPOL state machine that configuration has changed. config will be
    1470             :  * stored as a backpointer to network configuration. This can be %NULL to clear
    1471             :  * the stored pointed. conf will be copied to local EAPOL/EAP configuration
    1472             :  * data. If conf is %NULL, this part of the configuration change will be
    1473             :  * skipped.
    1474             :  */
    1475        5464 : void eapol_sm_notify_config(struct eapol_sm *sm,
    1476             :                             struct eap_peer_config *config,
    1477             :                             const struct eapol_config *conf)
    1478             : {
    1479        5464 :         if (sm == NULL)
    1480           0 :                 return;
    1481             : 
    1482        5464 :         sm->config = config;
    1483             : #ifdef CONFIG_EAP_PROXY
    1484             :         sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
    1485             : #endif /* CONFIG_EAP_PROXY */
    1486             : 
    1487        5464 :         if (conf == NULL)
    1488        4376 :                 return;
    1489             : 
    1490        1088 :         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
    1491        1088 :         sm->conf.required_keys = conf->required_keys;
    1492        1088 :         sm->conf.fast_reauth = conf->fast_reauth;
    1493        1088 :         sm->conf.workaround = conf->workaround;
    1494             : #ifdef CONFIG_EAP_PROXY
    1495             :         if (sm->use_eap_proxy) {
    1496             :                 /* Using EAP Proxy, so skip EAP state machine update */
    1497             :                 return;
    1498             :         }
    1499             : #endif /* CONFIG_EAP_PROXY */
    1500        1088 :         if (sm->eap) {
    1501        1088 :                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
    1502        1088 :                 eap_set_workaround(sm->eap, conf->workaround);
    1503        1088 :                 eap_set_force_disabled(sm->eap, conf->eap_disabled);
    1504        1088 :                 eap_set_external_sim(sm->eap, conf->external_sim);
    1505             :         }
    1506             : }
    1507             : 
    1508             : 
    1509             : /**
    1510             :  * eapol_sm_get_key - Get master session key (MSK) from EAP
    1511             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1512             :  * @key: Pointer for key buffer
    1513             :  * @len: Number of bytes to copy to key
    1514             :  * Returns: 0 on success (len of key available), maximum available key len
    1515             :  * (>0) if key is available but it is shorter than len, or -1 on failure.
    1516             :  *
    1517             :  * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
    1518             :  * is available only after a successful authentication.
    1519             :  */
    1520         559 : int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
    1521             : {
    1522             :         const u8 *eap_key;
    1523             :         size_t eap_len;
    1524             : 
    1525             : #ifdef CONFIG_EAP_PROXY
    1526             :         if (sm->use_eap_proxy) {
    1527             :                 /* Get key from EAP proxy */
    1528             :                 if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
    1529             :                         wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
    1530             :                         return -1;
    1531             :                 }
    1532             :                 eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
    1533             :                 if (eap_key == NULL) {
    1534             :                         wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
    1535             :                                    "eapKeyData");
    1536             :                         return -1;
    1537             :                 }
    1538             :                 goto key_fetched;
    1539             :         }
    1540             : #endif /* CONFIG_EAP_PROXY */
    1541         559 :         if (sm == NULL || !eap_key_available(sm->eap)) {
    1542           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
    1543           0 :                 return -1;
    1544             :         }
    1545         559 :         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
    1546         559 :         if (eap_key == NULL) {
    1547           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
    1548           0 :                 return -1;
    1549             :         }
    1550             : #ifdef CONFIG_EAP_PROXY
    1551             : key_fetched:
    1552             : #endif /* CONFIG_EAP_PROXY */
    1553         559 :         if (len > eap_len) {
    1554           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
    1555             :                            "available (len=%lu)",
    1556             :                            (unsigned long) len, (unsigned long) eap_len);
    1557           0 :                 return eap_len;
    1558             :         }
    1559         559 :         os_memcpy(key, eap_key, len);
    1560         559 :         wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
    1561             :                    (unsigned long) len);
    1562         559 :         return 0;
    1563             : }
    1564             : 
    1565             : 
    1566             : /**
    1567             :  * eapol_sm_get_session_id - Get EAP Session-Id
    1568             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1569             :  * @len: Pointer to variable that will be set to number of bytes in the session
    1570             :  * Returns: Pointer to the EAP Session-Id or %NULL on failure
    1571             :  *
    1572             :  * The Session-Id is available only after a successful authentication.
    1573             :  */
    1574           0 : const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
    1575             : {
    1576           0 :         if (sm == NULL || !eap_key_available(sm->eap)) {
    1577           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
    1578           0 :                 return NULL;
    1579             :         }
    1580           0 :         return eap_get_eapSessionId(sm->eap, len);
    1581             : }
    1582             : 
    1583             : 
    1584             : /**
    1585             :  * eapol_sm_notify_logoff - Notification of logon/logoff commands
    1586             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1587             :  * @logoff: Whether command was logoff
    1588             :  *
    1589             :  * Notify EAPOL state machines that user requested logon/logoff.
    1590             :  */
    1591        1905 : void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
    1592             : {
    1593        1905 :         if (sm) {
    1594        1905 :                 sm->userLogoff = logoff;
    1595        1905 :                 if (!logoff) {
    1596             :                         /* If there is a delayed txStart queued, start now. */
    1597        1904 :                         sm->startWhen = 0;
    1598             :                 }
    1599        1905 :                 eapol_sm_step(sm);
    1600             :         }
    1601        1905 : }
    1602             : 
    1603             : 
    1604             : /**
    1605             :  * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
    1606             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1607             :  *
    1608             :  * Notify EAPOL state machines that PMKSA caching was successful. This is used
    1609             :  * to move EAPOL and EAP state machines into authenticated/successful state.
    1610             :  */
    1611          10 : void eapol_sm_notify_cached(struct eapol_sm *sm)
    1612             : {
    1613          10 :         if (sm == NULL)
    1614          10 :                 return;
    1615          10 :         wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
    1616          10 :         sm->eapSuccess = TRUE;
    1617          10 :         eap_notify_success(sm->eap);
    1618          10 :         eapol_sm_step(sm);
    1619             : }
    1620             : 
    1621             : 
    1622             : /**
    1623             :  * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
    1624             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1625             :  * @attempt: Whether PMKSA caching is tried
    1626             :  *
    1627             :  * Notify EAPOL state machines whether PMKSA caching is used.
    1628             :  */
    1629          15 : void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
    1630             : {
    1631          15 :         if (sm == NULL)
    1632          15 :                 return;
    1633          15 :         if (attempt) {
    1634          15 :                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
    1635          15 :                 sm->cached_pmk = TRUE;
    1636             :         } else {
    1637           0 :                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
    1638           0 :                 sm->cached_pmk = FALSE;
    1639             :         }
    1640             : }
    1641             : 
    1642             : 
    1643          12 : static void eapol_sm_abort_cached(struct eapol_sm *sm)
    1644             : {
    1645          12 :         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
    1646             :                    "doing full EAP authentication");
    1647          12 :         if (sm == NULL)
    1648          12 :                 return;
    1649          12 :         sm->cached_pmk = FALSE;
    1650          12 :         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
    1651          12 :         eapol_sm_set_port_unauthorized(sm);
    1652             : 
    1653             :         /* Make sure we do not start sending EAPOL-Start frames first, but
    1654             :          * instead move to RESTART state to start EAPOL authentication. */
    1655          12 :         sm->startWhen = 3;
    1656          12 :         eapol_enable_timer_tick(sm);
    1657             : 
    1658          12 :         if (sm->ctx->aborted_cached)
    1659          12 :                 sm->ctx->aborted_cached(sm->ctx->ctx);
    1660             : }
    1661             : 
    1662             : 
    1663             : /**
    1664             :  * eapol_sm_register_scard_ctx - Notification of smart card context
    1665             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1666             :  * @ctx: Context data for smart card operations
    1667             :  *
    1668             :  * Notify EAPOL state machines of context data for smart card operations. This
    1669             :  * context data will be used as a parameter for scard_*() functions.
    1670             :  */
    1671          78 : void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
    1672             : {
    1673          78 :         if (sm) {
    1674          69 :                 sm->ctx->scard_ctx = ctx;
    1675          69 :                 eap_register_scard_ctx(sm->eap, ctx);
    1676             :         }
    1677          78 : }
    1678             : 
    1679             : 
    1680             : /**
    1681             :  * eapol_sm_notify_portControl - Notification of portControl changes
    1682             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1683             :  * @portControl: New value for portControl variable
    1684             :  *
    1685             :  * Notify EAPOL state machines that portControl variable has changed.
    1686             :  */
    1687        1092 : void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
    1688             : {
    1689        1092 :         if (sm == NULL)
    1690        1092 :                 return;
    1691        1092 :         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
    1692             :                    "portControl=%s", eapol_port_control(portControl));
    1693        1092 :         sm->portControl = portControl;
    1694        1092 :         eapol_sm_step(sm);
    1695             : }
    1696             : 
    1697             : 
    1698             : /**
    1699             :  * eapol_sm_notify_ctrl_attached - Notification of attached monitor
    1700             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1701             :  *
    1702             :  * Notify EAPOL state machines that a monitor was attached to the control
    1703             :  * interface to trigger re-sending of pending requests for user input.
    1704             :  */
    1705          63 : void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
    1706             : {
    1707          63 :         if (sm == NULL)
    1708          63 :                 return;
    1709          63 :         eap_sm_notify_ctrl_attached(sm->eap);
    1710             : }
    1711             : 
    1712             : 
    1713             : /**
    1714             :  * eapol_sm_notify_ctrl_response - Notification of received user input
    1715             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1716             :  *
    1717             :  * Notify EAPOL state machines that a control response, i.e., user
    1718             :  * input, was received in order to trigger retrying of a pending EAP request.
    1719             :  */
    1720          14 : void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
    1721             : {
    1722          14 :         if (sm == NULL)
    1723          14 :                 return;
    1724          14 :         if (sm->eapReqData && !sm->eapReq) {
    1725          14 :                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
    1726             :                            "input) notification - retrying pending EAP "
    1727             :                            "Request");
    1728          14 :                 sm->eapolEap = TRUE;
    1729          14 :                 sm->eapReq = TRUE;
    1730          14 :                 eapol_sm_step(sm);
    1731             :         }
    1732             : }
    1733             : 
    1734             : 
    1735             : /**
    1736             :  * eapol_sm_request_reauth - Request reauthentication
    1737             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1738             :  *
    1739             :  * This function can be used to request EAPOL reauthentication, e.g., when the
    1740             :  * current PMKSA entry is nearing expiration.
    1741             :  */
    1742          55 : void eapol_sm_request_reauth(struct eapol_sm *sm)
    1743             : {
    1744          55 :         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
    1745          55 :                 return;
    1746          55 :         eapol_sm_txStart(sm);
    1747             : }
    1748             : 
    1749             : 
    1750             : /**
    1751             :  * eapol_sm_notify_lower_layer_success - Notification of lower layer success
    1752             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1753             :  * @in_eapol_sm: Whether the caller is already running inside EAPOL state
    1754             :  * machine loop (eapol_sm_step())
    1755             :  *
    1756             :  * Notify EAPOL (and EAP) state machines that a lower layer has detected a
    1757             :  * successful authentication. This is used to recover from dropped EAP-Success
    1758             :  * messages.
    1759             :  */
    1760        1312 : void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
    1761             : {
    1762        1312 :         if (sm == NULL)
    1763        1336 :                 return;
    1764        1288 :         eap_notify_lower_layer_success(sm->eap);
    1765        1288 :         if (!in_eapol_sm)
    1766        1284 :                 eapol_sm_step(sm);
    1767             : }
    1768             : 
    1769             : 
    1770             : /**
    1771             :  * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
    1772             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    1773             :  */
    1774        5019 : void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
    1775             : {
    1776        5019 :         if (sm)
    1777        5019 :                 eap_invalidate_cached_session(sm->eap);
    1778        5019 : }
    1779             : 
    1780             : 
    1781        5589 : static struct eap_peer_config * eapol_sm_get_config(void *ctx)
    1782             : {
    1783        5589 :         struct eapol_sm *sm = ctx;
    1784        5589 :         return sm ? sm->config : NULL;
    1785             : }
    1786             : 
    1787             : 
    1788        6386 : static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
    1789             : {
    1790        6386 :         struct eapol_sm *sm = ctx;
    1791        6386 :         if (sm == NULL || sm->eapReqData == NULL)
    1792           0 :                 return NULL;
    1793             : 
    1794        6386 :         return sm->eapReqData;
    1795             : }
    1796             : 
    1797             : 
    1798      163202 : static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
    1799             : {
    1800      163202 :         struct eapol_sm *sm = ctx;
    1801      163202 :         if (sm == NULL)
    1802           0 :                 return FALSE;
    1803      163202 :         switch (variable) {
    1804             :         case EAPOL_eapSuccess:
    1805        1288 :                 return sm->eapSuccess;
    1806             :         case EAPOL_eapRestart:
    1807       52034 :                 return sm->eapRestart;
    1808             :         case EAPOL_eapFail:
    1809           0 :                 return sm->eapFail;
    1810             :         case EAPOL_eapResp:
    1811           0 :                 return sm->eapResp;
    1812             :         case EAPOL_eapNoResp:
    1813           0 :                 return sm->eapNoResp;
    1814             :         case EAPOL_eapReq:
    1815       16955 :                 return sm->eapReq;
    1816             :         case EAPOL_portEnabled:
    1817       52539 :                 return sm->portEnabled;
    1818             :         case EAPOL_altAccept:
    1819       26924 :                 return sm->altAccept;
    1820             :         case EAPOL_altReject:
    1821       13462 :                 return sm->altReject;
    1822             :         }
    1823           0 :         return FALSE;
    1824             : }
    1825             : 
    1826             : 
    1827       26825 : static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
    1828             :                               Boolean value)
    1829             : {
    1830       26825 :         struct eapol_sm *sm = ctx;
    1831       26825 :         if (sm == NULL)
    1832       26825 :                 return;
    1833       26825 :         switch (variable) {
    1834             :         case EAPOL_eapSuccess:
    1835       15413 :                 sm->eapSuccess = value;
    1836       15413 :                 break;
    1837             :         case EAPOL_eapRestart:
    1838        1048 :                 sm->eapRestart = value;
    1839        1048 :                 break;
    1840             :         case EAPOL_eapFail:
    1841        1296 :                 sm->eapFail = value;
    1842        1296 :                 break;
    1843             :         case EAPOL_eapResp:
    1844        3996 :                 sm->eapResp = value;
    1845        3996 :                 break;
    1846             :         case EAPOL_eapNoResp:
    1847        1579 :                 sm->eapNoResp = value;
    1848        1579 :                 break;
    1849             :         case EAPOL_eapReq:
    1850        3493 :                 sm->eapReq = value;
    1851        3493 :                 break;
    1852             :         case EAPOL_portEnabled:
    1853           0 :                 sm->portEnabled = value;
    1854           0 :                 break;
    1855             :         case EAPOL_altAccept:
    1856           0 :                 sm->altAccept = value;
    1857           0 :                 break;
    1858             :         case EAPOL_altReject:
    1859           0 :                 sm->altReject = value;
    1860           0 :                 break;
    1861             :         }
    1862             : }
    1863             : 
    1864             : 
    1865       26924 : static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
    1866             : {
    1867       26924 :         struct eapol_sm *sm = ctx;
    1868       26924 :         if (sm == NULL)
    1869           0 :                 return 0;
    1870       26924 :         switch (variable) {
    1871             :         case EAPOL_idleWhile:
    1872       26924 :                 return sm->idleWhile;
    1873             :         }
    1874           0 :         return 0;
    1875             : }
    1876             : 
    1877             : 
    1878       22831 : static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
    1879             :                              unsigned int value)
    1880             : {
    1881       22831 :         struct eapol_sm *sm = ctx;
    1882       22831 :         if (sm == NULL)
    1883       22831 :                 return;
    1884       22831 :         switch (variable) {
    1885             :         case EAPOL_idleWhile:
    1886       22831 :                 sm->idleWhile = value;
    1887       22831 :                 if (sm->idleWhile > 0)
    1888        4010 :                         eapol_enable_timer_tick(sm);
    1889       22831 :                 break;
    1890             :         }
    1891             : }
    1892             : 
    1893             : 
    1894           7 : static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
    1895             : {
    1896             : #ifndef CONFIG_NO_CONFIG_BLOBS
    1897           7 :         struct eapol_sm *sm = ctx;
    1898           7 :         if (sm && sm->ctx && sm->ctx->set_config_blob)
    1899           7 :                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
    1900             : #endif /* CONFIG_NO_CONFIG_BLOBS */
    1901           7 : }
    1902             : 
    1903             : 
    1904             : static const struct wpa_config_blob *
    1905          20 : eapol_sm_get_config_blob(void *ctx, const char *name)
    1906             : {
    1907             : #ifndef CONFIG_NO_CONFIG_BLOBS
    1908          20 :         struct eapol_sm *sm = ctx;
    1909          20 :         if (sm && sm->ctx && sm->ctx->get_config_blob)
    1910          20 :                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
    1911             :         else
    1912           0 :                 return NULL;
    1913             : #else /* CONFIG_NO_CONFIG_BLOBS */
    1914             :         return NULL;
    1915             : #endif /* CONFIG_NO_CONFIG_BLOBS */
    1916             : }
    1917             : 
    1918             : 
    1919           0 : static void eapol_sm_notify_pending(void *ctx)
    1920             : {
    1921           0 :         struct eapol_sm *sm = ctx;
    1922           0 :         if (sm == NULL)
    1923           0 :                 return;
    1924           0 :         if (sm->eapReqData && !sm->eapReq) {
    1925           0 :                 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
    1926             :                            "state machine - retrying pending EAP Request");
    1927           0 :                 sm->eapolEap = TRUE;
    1928           0 :                 sm->eapReq = TRUE;
    1929           0 :                 eapol_sm_step(sm);
    1930             :         }
    1931             : }
    1932             : 
    1933             : 
    1934             : #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
    1935          15 : static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
    1936             :                                       const char *txt)
    1937             : {
    1938          15 :         struct eapol_sm *sm = ctx;
    1939          15 :         wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
    1940          15 :         if (sm->ctx->eap_param_needed)
    1941          15 :                 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
    1942          15 : }
    1943             : #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
    1944             : #define eapol_sm_eap_param_needed NULL
    1945             : #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
    1946             : 
    1947         396 : static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
    1948             :                                  const char *cert_hash,
    1949             :                                  const struct wpabuf *cert)
    1950             : {
    1951         396 :         struct eapol_sm *sm = ctx;
    1952         396 :         if (sm->ctx->cert_cb)
    1953         396 :                 sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
    1954             :                                  cert_hash, cert);
    1955         396 : }
    1956             : 
    1957             : 
    1958        2096 : static void eapol_sm_notify_status(void *ctx, const char *status,
    1959             :                                    const char *parameter)
    1960             : {
    1961        2096 :         struct eapol_sm *sm = ctx;
    1962             : 
    1963        2096 :         if (sm->ctx->status_cb)
    1964        2093 :                 sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
    1965        2096 : }
    1966             : 
    1967             : 
    1968          49 : static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
    1969             : {
    1970          49 :         struct eapol_sm *sm = ctx;
    1971             : 
    1972          49 :         if (sm->ctx->set_anon_id)
    1973          49 :                 sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
    1974          49 : }
    1975             : 
    1976             : 
    1977             : static struct eapol_callbacks eapol_cb =
    1978             : {
    1979             :         eapol_sm_get_config,
    1980             :         eapol_sm_get_bool,
    1981             :         eapol_sm_set_bool,
    1982             :         eapol_sm_get_int,
    1983             :         eapol_sm_set_int,
    1984             :         eapol_sm_get_eapReqData,
    1985             :         eapol_sm_set_config_blob,
    1986             :         eapol_sm_get_config_blob,
    1987             :         eapol_sm_notify_pending,
    1988             :         eapol_sm_eap_param_needed,
    1989             :         eapol_sm_notify_cert,
    1990             :         eapol_sm_notify_status,
    1991             :         eapol_sm_set_anon_id
    1992             : };
    1993             : 
    1994             : 
    1995             : /**
    1996             :  * eapol_sm_init - Initialize EAPOL state machine
    1997             :  * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
    1998             :  * and EAPOL state machine will free it in eapol_sm_deinit()
    1999             :  * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
    2000             :  *
    2001             :  * Allocate and initialize an EAPOL state machine.
    2002             :  */
    2003          71 : struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
    2004             : {
    2005             :         struct eapol_sm *sm;
    2006             :         struct eap_config conf;
    2007          71 :         sm = os_zalloc(sizeof(*sm));
    2008          71 :         if (sm == NULL)
    2009           0 :                 return NULL;
    2010          71 :         sm->ctx = ctx;
    2011             : 
    2012          71 :         sm->portControl = Auto;
    2013             : 
    2014             :         /* Supplicant PAE state machine */
    2015          71 :         sm->heldPeriod = 60;
    2016          71 :         sm->startPeriod = 30;
    2017          71 :         sm->maxStart = 3;
    2018             : 
    2019             :         /* Supplicant Backend state machine */
    2020          71 :         sm->authPeriod = 30;
    2021             : 
    2022          71 :         os_memset(&conf, 0, sizeof(conf));
    2023          71 :         conf.opensc_engine_path = ctx->opensc_engine_path;
    2024          71 :         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
    2025          71 :         conf.pkcs11_module_path = ctx->pkcs11_module_path;
    2026          71 :         conf.wps = ctx->wps;
    2027          71 :         conf.cert_in_cb = ctx->cert_in_cb;
    2028             : 
    2029          71 :         sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
    2030          71 :         if (sm->eap == NULL) {
    2031           0 :                 os_free(sm);
    2032           0 :                 return NULL;
    2033             :         }
    2034             : 
    2035             : #ifdef CONFIG_EAP_PROXY
    2036             :         sm->use_eap_proxy = FALSE;
    2037             :         sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
    2038             :         if (sm->eap_proxy == NULL) {
    2039             :                 wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
    2040             :         }
    2041             : #endif /* CONFIG_EAP_PROXY */
    2042             : 
    2043             :         /* Initialize EAPOL state machines */
    2044          71 :         sm->force_authorized_update = TRUE;
    2045          71 :         sm->initialize = TRUE;
    2046          71 :         eapol_sm_step(sm);
    2047          71 :         sm->initialize = FALSE;
    2048          71 :         eapol_sm_step(sm);
    2049             : 
    2050          71 :         sm->timer_tick_enabled = 1;
    2051          71 :         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
    2052             : 
    2053          71 :         return sm;
    2054             : }
    2055             : 
    2056             : 
    2057             : /**
    2058             :  * eapol_sm_deinit - Deinitialize EAPOL state machine
    2059             :  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
    2060             :  *
    2061             :  * Deinitialize and free EAPOL state machine.
    2062             :  */
    2063          80 : void eapol_sm_deinit(struct eapol_sm *sm)
    2064             : {
    2065          80 :         if (sm == NULL)
    2066          89 :                 return;
    2067          71 :         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
    2068          71 :         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
    2069          71 :         eap_peer_sm_deinit(sm->eap);
    2070             : #ifdef CONFIG_EAP_PROXY
    2071             :         eap_proxy_deinit(sm->eap_proxy);
    2072             : #endif /* CONFIG_EAP_PROXY */
    2073          71 :         os_free(sm->last_rx_key);
    2074          71 :         wpabuf_free(sm->eapReqData);
    2075          71 :         os_free(sm->ctx);
    2076          71 :         os_free(sm);
    2077             : }
    2078             : 
    2079             : 
    2080          83 : void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
    2081             :                              struct ext_password_data *ext)
    2082             : {
    2083          83 :         if (sm && sm->eap)
    2084          83 :                 eap_sm_set_ext_pw_ctx(sm->eap, ext);
    2085          83 : }
    2086             : 
    2087             : 
    2088         247 : int eapol_sm_failed(struct eapol_sm *sm)
    2089             : {
    2090         247 :         if (sm == NULL)
    2091           0 :                 return 0;
    2092         247 :         return !sm->eapSuccess && sm->eapFail;
    2093             : }
    2094             : 
    2095             : 
    2096           0 : int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
    2097             : {
    2098             : #ifdef CONFIG_EAP_PROXY
    2099             :         if (sm->eap_proxy == NULL)
    2100             :                 return -1;
    2101             :         return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
    2102             : #else /* CONFIG_EAP_PROXY */
    2103           0 :         return -1;
    2104             : #endif /* CONFIG_EAP_PROXY */
    2105             : }

Generated by: LCOV version 1.10