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 1475438200 Lines: 817 894 91.4 %
Date: 2016-10-02 Functions: 78 81 96.3 %

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

Generated by: LCOV version 1.10