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 1388943092 Lines: 668 865 77.2 %
Date: 2014-01-05 Functions: 70 79 88.6 %
Branches: 326 593 55.0 %

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

Generated by: LCOV version 1.9