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

Generated by: LCOV version 1.10