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 1426431149 Lines: 781 889 87.9 %
Date: 2015-03-15 Functions: 78 81 96.3 %

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

Generated by: LCOV version 1.10