LCOV - code coverage report
Current view: top level - src/eap_server - eap_server.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1422976643 Lines: 888 1041 85.3 %
Date: 2015-02-03 Functions: 62 64 96.9 %

          Line data    Source code
       1             : /*
       2             :  * hostapd / EAP Full Authenticator state machine (RFC 4137)
       3             :  * Copyright (c) 2004-2014, 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             :  * This state machine is based on the full authenticator state machine defined
       9             :  * in RFC 4137. However, to support backend authentication in RADIUS
      10             :  * authentication server functionality, parts of backend authenticator (also
      11             :  * from RFC 4137) are mixed in. This functionality is enabled by setting
      12             :  * backend_auth configuration variable to TRUE.
      13             :  */
      14             : 
      15             : #include "includes.h"
      16             : 
      17             : #include "common.h"
      18             : #include "crypto/sha256.h"
      19             : #include "eap_i.h"
      20             : #include "state_machine.h"
      21             : #include "common/wpa_ctrl.h"
      22             : 
      23             : #define STATE_MACHINE_DATA struct eap_sm
      24             : #define STATE_MACHINE_DEBUG_PREFIX "EAP"
      25             : 
      26             : #define EAP_MAX_AUTH_ROUNDS 50
      27             : 
      28             : static void eap_user_free(struct eap_user *user);
      29             : 
      30             : 
      31             : /* EAP state machines are described in RFC 4137 */
      32             : 
      33             : static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
      34             :                                    int eapSRTT, int eapRTTVAR,
      35             :                                    int methodTimeout);
      36             : static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp);
      37             : static int eap_sm_getId(const struct wpabuf *data);
      38             : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id);
      39             : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id);
      40             : static int eap_sm_nextId(struct eap_sm *sm, int id);
      41             : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
      42             :                                  size_t len);
      43             : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
      44             : static int eap_sm_Policy_getDecision(struct eap_sm *sm);
      45             : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
      46             : 
      47             : 
      48        1329 : static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
      49             : {
      50        1329 :         if (sm->eapol_cb->get_erp_send_reauth_start)
      51        1314 :                 return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
      52          15 :         return 0;
      53             : }
      54             : 
      55             : 
      56          57 : static const char * eap_get_erp_domain(struct eap_sm *sm)
      57             : {
      58          57 :         if (sm->eapol_cb->get_erp_domain)
      59          57 :                 return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
      60           0 :         return NULL;
      61             : }
      62             : 
      63             : 
      64             : #ifdef CONFIG_ERP
      65             : 
      66          20 : static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
      67             :                                                    const char *keyname)
      68             : {
      69          20 :         if (sm->eapol_cb->erp_get_key)
      70          20 :                 return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
      71           0 :         return NULL;
      72             : }
      73             : 
      74             : 
      75          18 : static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
      76             : {
      77          18 :         if (sm->eapol_cb->erp_add_key)
      78          18 :                 return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
      79           0 :         return -1;
      80             : }
      81             : 
      82             : #endif /* CONFIG_ERP */
      83             : 
      84             : 
      85          39 : static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
      86             :                                                        u8 id)
      87             : {
      88             :         const char *domain;
      89          39 :         size_t plen = 1;
      90             :         struct wpabuf *msg;
      91          39 :         size_t domain_len = 0;
      92             : 
      93          39 :         domain = eap_get_erp_domain(sm);
      94          39 :         if (domain) {
      95          39 :                 domain_len = os_strlen(domain);
      96          39 :                 plen += 2 + domain_len;
      97             :         }
      98             : 
      99          39 :         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
     100             :                             EAP_CODE_INITIATE, id);
     101          39 :         if (msg == NULL)
     102           0 :                 return NULL;
     103          39 :         wpabuf_put_u8(msg, 0); /* Reserved */
     104          39 :         if (domain) {
     105             :                 /* Domain name TLV */
     106          39 :                 wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
     107          39 :                 wpabuf_put_u8(msg, domain_len);
     108          39 :                 wpabuf_put_data(msg, domain, domain_len);
     109             :         }
     110             : 
     111          39 :         return msg;
     112             : }
     113             : 
     114             : 
     115       14283 : static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
     116             : {
     117       14283 :         if (src == NULL)
     118           2 :                 return -1;
     119             : 
     120       14281 :         wpabuf_free(*dst);
     121       14281 :         *dst = wpabuf_dup(src);
     122       14281 :         return *dst ? 0 : -1;
     123             : }
     124             : 
     125             : 
     126         564 : static int eap_copy_data(u8 **dst, size_t *dst_len,
     127             :                          const u8 *src, size_t src_len)
     128             : {
     129         564 :         if (src == NULL)
     130           0 :                 return -1;
     131             : 
     132         564 :         os_free(*dst);
     133         564 :         *dst = os_malloc(src_len);
     134         564 :         if (*dst) {
     135         563 :                 os_memcpy(*dst, src, src_len);
     136         563 :                 *dst_len = src_len;
     137         563 :                 return 0;
     138             :         } else {
     139           1 :                 *dst_len = 0;
     140           1 :                 return -1;
     141             :         }
     142             : }
     143             : 
     144             : #define EAP_COPY(dst, src) \
     145             :         eap_copy_data((dst), (dst ## Len), (src), (src ## Len))
     146             : 
     147             : 
     148             : /**
     149             :  * eap_user_get - Fetch user information from the database
     150             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
     151             :  * @identity: Identity (User-Name) of the user
     152             :  * @identity_len: Length of identity in bytes
     153             :  * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
     154             :  * Returns: 0 on success, or -1 on failure
     155             :  *
     156             :  * This function is used to fetch user information for EAP. The user will be
     157             :  * selected based on the specified identity. sm->user and
     158             :  * sm->user_eap_method_index are updated for the new user when a matching user
     159             :  * is found. sm->user can be used to get user information (e.g., password).
     160             :  */
     161        1308 : int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
     162             :                  int phase2)
     163             : {
     164             :         struct eap_user *user;
     165             : 
     166        2616 :         if (sm == NULL || sm->eapol_cb == NULL ||
     167        1308 :             sm->eapol_cb->get_eap_user == NULL)
     168           0 :                 return -1;
     169             : 
     170        1308 :         eap_user_free(sm->user);
     171        1308 :         sm->user = NULL;
     172             : 
     173        1308 :         user = os_zalloc(sizeof(*user));
     174        1308 :         if (user == NULL)
     175           0 :             return -1;
     176             : 
     177        1308 :         if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
     178             :                                        identity_len, phase2, user) != 0) {
     179           5 :                 eap_user_free(user);
     180           5 :                 return -1;
     181             :         }
     182             : 
     183        1303 :         sm->user = user;
     184        1303 :         sm->user_eap_method_index = 0;
     185             : 
     186        1303 :         return 0;
     187             : }
     188             : 
     189             : 
     190        4560 : void eap_log_msg(struct eap_sm *sm, const char *fmt, ...)
     191             : {
     192             :         va_list ap;
     193             :         char *buf;
     194             :         int buflen;
     195             : 
     196        4560 :         if (sm == NULL || sm->eapol_cb == NULL || sm->eapol_cb->log_msg == NULL)
     197        5894 :                 return;
     198             : 
     199        1613 :         va_start(ap, fmt);
     200        1613 :         buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
     201        1613 :         va_end(ap);
     202             : 
     203        1613 :         buf = os_malloc(buflen);
     204        1613 :         if (buf == NULL)
     205           0 :                 return;
     206        1613 :         va_start(ap, fmt);
     207        1613 :         vsnprintf(buf, buflen, fmt, ap);
     208        1613 :         va_end(ap);
     209             : 
     210        1613 :         sm->eapol_cb->log_msg(sm->eapol_ctx, buf);
     211             : 
     212        1613 :         os_free(buf);
     213             : }
     214             : 
     215             : 
     216        1911 : SM_STATE(EAP, DISABLED)
     217             : {
     218        1911 :         SM_ENTRY(EAP, DISABLED);
     219        1911 :         sm->num_rounds = 0;
     220        1911 : }
     221             : 
     222             : 
     223        2001 : SM_STATE(EAP, INITIALIZE)
     224             : {
     225        2001 :         SM_ENTRY(EAP, INITIALIZE);
     226             : 
     227        2001 :         if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
     228             :                 /*
     229             :                  * Need to allow internal Identity method to be used instead
     230             :                  * of passthrough at the beginning of reauthentication.
     231             :                  */
     232          37 :                 eap_server_clear_identity(sm);
     233             :         }
     234             : 
     235        2001 :         sm->try_initiate_reauth = FALSE;
     236        2001 :         sm->currentId = -1;
     237        2001 :         sm->eap_if.eapSuccess = FALSE;
     238        2001 :         sm->eap_if.eapFail = FALSE;
     239        2001 :         sm->eap_if.eapTimeout = FALSE;
     240        2001 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     241        2001 :         sm->eap_if.eapKeyData = NULL;
     242        2001 :         sm->eap_if.eapKeyDataLen = 0;
     243        2001 :         os_free(sm->eap_if.eapSessionId);
     244        2001 :         sm->eap_if.eapSessionId = NULL;
     245        2001 :         sm->eap_if.eapSessionIdLen = 0;
     246        2001 :         sm->eap_if.eapKeyAvailable = FALSE;
     247        2001 :         sm->eap_if.eapRestart = FALSE;
     248             : 
     249             :         /*
     250             :          * This is not defined in RFC 4137, but method state needs to be
     251             :          * reseted here so that it does not remain in success state when
     252             :          * re-authentication starts.
     253             :          */
     254        2001 :         if (sm->m && sm->eap_method_priv) {
     255         112 :                 sm->m->reset(sm, sm->eap_method_priv);
     256         112 :                 sm->eap_method_priv = NULL;
     257             :         }
     258        2001 :         sm->m = NULL;
     259        2001 :         sm->user_eap_method_index = 0;
     260             : 
     261        2001 :         if (sm->backend_auth) {
     262         680 :                 sm->currentMethod = EAP_TYPE_NONE;
     263             :                 /* parse rxResp, respId, respMethod */
     264         680 :                 eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
     265         680 :                 if (sm->rxResp) {
     266         665 :                         sm->currentId = sm->respId;
     267             :                 }
     268             :         }
     269        2001 :         sm->num_rounds = 0;
     270        2001 :         sm->method_pending = METHOD_PENDING_NONE;
     271             : 
     272       12006 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
     273       12006 :                 MACSTR, MAC2STR(sm->peer_addr));
     274        2001 : }
     275             : 
     276             : 
     277         665 : SM_STATE(EAP, PICK_UP_METHOD)
     278             : {
     279         665 :         SM_ENTRY(EAP, PICK_UP_METHOD);
     280             : 
     281         665 :         if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
     282         665 :                 sm->currentMethod = sm->respMethod;
     283         665 :                 if (sm->m && sm->eap_method_priv) {
     284           0 :                         sm->m->reset(sm, sm->eap_method_priv);
     285           0 :                         sm->eap_method_priv = NULL;
     286             :                 }
     287         665 :                 sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF,
     288             :                                                   sm->currentMethod);
     289         665 :                 if (sm->m && sm->m->initPickUp) {
     290         665 :                         sm->eap_method_priv = sm->m->initPickUp(sm);
     291        1330 :                         if (sm->eap_method_priv == NULL) {
     292           0 :                                 wpa_printf(MSG_DEBUG, "EAP: Failed to "
     293             :                                            "initialize EAP method %d",
     294           0 :                                            sm->currentMethod);
     295           0 :                                 sm->m = NULL;
     296           0 :                                 sm->currentMethod = EAP_TYPE_NONE;
     297             :                         }
     298             :                 } else {
     299           0 :                         sm->m = NULL;
     300           0 :                         sm->currentMethod = EAP_TYPE_NONE;
     301             :                 }
     302             :         }
     303             : 
     304         665 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
     305         665 :                 "method=%u", sm->currentMethod);
     306         665 : }
     307             : 
     308             : 
     309        5129 : SM_STATE(EAP, IDLE)
     310             : {
     311        5129 :         SM_ENTRY(EAP, IDLE);
     312             : 
     313        5129 :         sm->eap_if.retransWhile = eap_sm_calculateTimeout(
     314             :                 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
     315             :                 sm->methodTimeout);
     316        5129 : }
     317             : 
     318             : 
     319           1 : SM_STATE(EAP, RETRANSMIT)
     320             : {
     321           1 :         SM_ENTRY(EAP, RETRANSMIT);
     322             : 
     323           1 :         sm->retransCount++;
     324           1 :         if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
     325           0 :                 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
     326           0 :                         sm->eap_if.eapReq = TRUE;
     327             :         }
     328           1 : }
     329             : 
     330             : 
     331        5067 : SM_STATE(EAP, RECEIVED)
     332             : {
     333        5067 :         SM_ENTRY(EAP, RECEIVED);
     334             : 
     335             :         /* parse rxResp, respId, respMethod */
     336        5067 :         eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
     337        5067 :         sm->num_rounds++;
     338        5067 : }
     339             : 
     340             : 
     341           6 : SM_STATE(EAP, DISCARD)
     342             : {
     343           6 :         SM_ENTRY(EAP, DISCARD);
     344           6 :         sm->eap_if.eapResp = FALSE;
     345           6 :         sm->eap_if.eapNoReq = TRUE;
     346           6 : }
     347             : 
     348             : 
     349        5122 : SM_STATE(EAP, SEND_REQUEST)
     350             : {
     351        5122 :         SM_ENTRY(EAP, SEND_REQUEST);
     352             : 
     353        5122 :         sm->retransCount = 0;
     354        5122 :         if (sm->eap_if.eapReqData) {
     355        5116 :                 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
     356             :                 {
     357        5116 :                         sm->eap_if.eapResp = FALSE;
     358        5116 :                         sm->eap_if.eapReq = TRUE;
     359             :                 } else {
     360           0 :                         sm->eap_if.eapResp = FALSE;
     361           0 :                         sm->eap_if.eapReq = FALSE;
     362             :                 }
     363             :         } else {
     364           6 :                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
     365           6 :                 sm->eap_if.eapResp = FALSE;
     366           6 :                 sm->eap_if.eapReq = FALSE;
     367           6 :                 sm->eap_if.eapNoReq = TRUE;
     368             :         }
     369        5122 : }
     370             : 
     371             : 
     372        4960 : SM_STATE(EAP, INTEGRITY_CHECK)
     373             : {
     374        4960 :         SM_ENTRY(EAP, INTEGRITY_CHECK);
     375             : 
     376        4960 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1)) {
     377           0 :                 sm->ignore = TRUE;
     378        4960 :                 return;
     379             :         }
     380             : 
     381        4960 :         if (sm->m->check) {
     382        4960 :                 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
     383             :                                           sm->eap_if.eapRespData);
     384             :         }
     385             : }
     386             : 
     387             : 
     388        5083 : SM_STATE(EAP, METHOD_REQUEST)
     389             : {
     390        5083 :         SM_ENTRY(EAP, METHOD_REQUEST);
     391             : 
     392        5083 :         if (sm->m == NULL) {
     393           0 :                 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
     394        5083 :                 return;
     395             :         }
     396             : 
     397        5083 :         sm->currentId = eap_sm_nextId(sm, sm->currentId);
     398        5083 :         wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
     399             :                    sm->currentId);
     400        5083 :         sm->lastId = sm->currentId;
     401        5083 :         wpabuf_free(sm->eap_if.eapReqData);
     402       10166 :         sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
     403        5083 :                                                 sm->currentId);
     404        5083 :         if (sm->m->getTimeout)
     405        1335 :                 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
     406             :         else
     407        3748 :                 sm->methodTimeout = 0;
     408             : }
     409             : 
     410             : 
     411          18 : static void eap_server_erp_init(struct eap_sm *sm)
     412             : {
     413             : #ifdef CONFIG_ERP
     414          18 :         u8 *emsk = NULL;
     415          18 :         size_t emsk_len = 0;
     416             :         u8 EMSKname[EAP_EMSK_NAME_LEN];
     417             :         u8 len[2];
     418             :         const char *domain;
     419             :         size_t domain_len, nai_buf_len;
     420          18 :         struct eap_server_erp_key *erp = NULL;
     421             :         int pos;
     422             : 
     423          18 :         domain = eap_get_erp_domain(sm);
     424          18 :         if (!domain)
     425           0 :                 return;
     426             : 
     427          18 :         domain_len = os_strlen(domain);
     428             : 
     429          18 :         nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
     430          18 :         if (nai_buf_len > 253) {
     431             :                 /*
     432             :                  * keyName-NAI has a maximum length of 253 octet to fit in
     433             :                  * RADIUS attributes.
     434             :                  */
     435           0 :                 wpa_printf(MSG_DEBUG,
     436             :                            "EAP: Too long realm for ERP keyName-NAI maximum length");
     437           0 :                 return;
     438             :         }
     439          18 :         nai_buf_len++; /* null termination */
     440          18 :         erp = os_zalloc(sizeof(*erp) + nai_buf_len);
     441          18 :         if (erp == NULL)
     442           0 :                 goto fail;
     443          18 :         erp->recv_seq = (u32) -1;
     444             : 
     445          18 :         emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
     446          18 :         if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
     447           0 :                 wpa_printf(MSG_DEBUG,
     448             :                            "EAP: No suitable EMSK available for ERP");
     449           0 :                 goto fail;
     450             :         }
     451             : 
     452          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
     453             : 
     454          18 :         WPA_PUT_BE16(len, 8);
     455          18 :         if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
     456             :                             "EMSK", len, sizeof(len),
     457             :                             EMSKname, EAP_EMSK_NAME_LEN) < 0) {
     458           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
     459           0 :                 goto fail;
     460             :         }
     461          18 :         wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
     462             : 
     463          18 :         pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
     464             :                                EMSKname, EAP_EMSK_NAME_LEN);
     465          18 :         erp->keyname_nai[pos] = '@';
     466          18 :         os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
     467             : 
     468          18 :         WPA_PUT_BE16(len, emsk_len);
     469          36 :         if (hmac_sha256_kdf(emsk, emsk_len,
     470             :                             "EAP Re-authentication Root Key@ietf.org",
     471          18 :                             len, sizeof(len), erp->rRK, emsk_len) < 0) {
     472           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
     473           0 :                 goto fail;
     474             :         }
     475          18 :         erp->rRK_len = emsk_len;
     476          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
     477             : 
     478          36 :         if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
     479             :                             "EAP Re-authentication Integrity Key@ietf.org",
     480          18 :                             len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
     481           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
     482           0 :                 goto fail;
     483             :         }
     484          18 :         erp->rIK_len = erp->rRK_len;
     485          18 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
     486             : 
     487          18 :         if (eap_erp_add_key(sm, erp) == 0) {
     488          18 :                 wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
     489          18 :                            erp->keyname_nai);
     490          18 :                 erp = NULL;
     491             :         }
     492             : 
     493             : fail:
     494          18 :         bin_clear_free(emsk, emsk_len);
     495          18 :         bin_clear_free(erp, sizeof(*erp));
     496             : #endif /* CONFIG_ERP */
     497             : }
     498             : 
     499             : 
     500        5733 : SM_STATE(EAP, METHOD_RESPONSE)
     501             : {
     502        5733 :         SM_ENTRY(EAP, METHOD_RESPONSE);
     503             : 
     504        5733 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
     505        5733 :                 return;
     506             : 
     507        5733 :         sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData);
     508        5733 :         if (sm->m->isDone(sm, sm->eap_method_priv)) {
     509        2909 :                 eap_sm_Policy_update(sm, NULL, 0);
     510        2909 :                 bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     511        2909 :                 if (sm->m->getKey) {
     512         700 :                         sm->eap_if.eapKeyData = sm->m->getKey(
     513             :                                 sm, sm->eap_method_priv,
     514             :                                 &sm->eap_if.eapKeyDataLen);
     515             :                 } else {
     516        2209 :                         sm->eap_if.eapKeyData = NULL;
     517        2209 :                         sm->eap_if.eapKeyDataLen = 0;
     518             :                 }
     519        2909 :                 os_free(sm->eap_if.eapSessionId);
     520        2909 :                 sm->eap_if.eapSessionId = NULL;
     521        2909 :                 if (sm->m->getSessionId) {
     522         685 :                         sm->eap_if.eapSessionId = sm->m->getSessionId(
     523             :                                 sm, sm->eap_method_priv,
     524             :                                 &sm->eap_if.eapSessionIdLen);
     525        1370 :                         wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
     526         685 :                                     sm->eap_if.eapSessionId,
     527             :                                     sm->eap_if.eapSessionIdLen);
     528             :                 }
     529        2909 :                 if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
     530          18 :                         eap_server_erp_init(sm);
     531        2909 :                 sm->methodState = METHOD_END;
     532             :         } else {
     533        2824 :                 sm->methodState = METHOD_CONTINUE;
     534             :         }
     535             : }
     536             : 
     537             : 
     538        2367 : SM_STATE(EAP, PROPOSE_METHOD)
     539             : {
     540             :         int vendor;
     541             :         EapType type;
     542             : 
     543        2367 :         SM_ENTRY(EAP, PROPOSE_METHOD);
     544             : 
     545        2367 :         sm->try_initiate_reauth = FALSE;
     546             : try_another_method:
     547        2368 :         type = eap_sm_Policy_getNextMethod(sm, &vendor);
     548        2368 :         if (vendor == EAP_VENDOR_IETF)
     549        2081 :                 sm->currentMethod = type;
     550             :         else
     551         287 :                 sm->currentMethod = EAP_TYPE_EXPANDED;
     552        2368 :         if (sm->m && sm->eap_method_priv) {
     553        1012 :                 sm->m->reset(sm, sm->eap_method_priv);
     554        1012 :                 sm->eap_method_priv = NULL;
     555             :         }
     556        2368 :         sm->m = eap_server_get_eap_method(vendor, type);
     557        2368 :         if (sm->m) {
     558        2368 :                 sm->eap_method_priv = sm->m->init(sm);
     559        2368 :                 if (sm->eap_method_priv == NULL) {
     560           1 :                         wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
     561           1 :                                    "method %d", sm->currentMethod);
     562           1 :                         sm->m = NULL;
     563           1 :                         sm->currentMethod = EAP_TYPE_NONE;
     564           1 :                         goto try_another_method;
     565             :                 }
     566             :         }
     567        2367 :         if (sm->m == NULL) {
     568           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not find suitable EAP method");
     569           0 :                 eap_log_msg(sm, "Could not find suitable EAP method");
     570           0 :                 sm->decision = DECISION_FAILURE;
     571        2367 :                 return;
     572             :         }
     573        3452 :         if (sm->currentMethod == EAP_TYPE_IDENTITY ||
     574        1085 :             sm->currentMethod == EAP_TYPE_NOTIFICATION)
     575        1282 :                 sm->methodState = METHOD_CONTINUE;
     576             :         else
     577        1085 :                 sm->methodState = METHOD_PROPOSED;
     578             : 
     579        2367 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
     580        2367 :                 "vendor=%u method=%u", vendor, sm->currentMethod);
     581        2367 :         eap_log_msg(sm, "Propose EAP method vendor=%u method=%u",
     582        2367 :                     vendor, sm->currentMethod);
     583             : }
     584             : 
     585             : 
     586          81 : SM_STATE(EAP, NAK)
     587             : {
     588             :         const struct eap_hdr *nak;
     589          81 :         size_t len = 0;
     590             :         const u8 *pos;
     591          81 :         const u8 *nak_list = NULL;
     592             : 
     593          81 :         SM_ENTRY(EAP, NAK);
     594             : 
     595          81 :         if (sm->eap_method_priv) {
     596          81 :                 sm->m->reset(sm, sm->eap_method_priv);
     597          81 :                 sm->eap_method_priv = NULL;
     598             :         }
     599          81 :         sm->m = NULL;
     600             : 
     601          81 :         if (!eap_hdr_len_valid(sm->eap_if.eapRespData, 1))
     602          81 :                 return;
     603             : 
     604          81 :         nak = wpabuf_head(sm->eap_if.eapRespData);
     605          81 :         if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) {
     606          81 :                 len = be_to_host16(nak->length);
     607          81 :                 if (len > wpabuf_len(sm->eap_if.eapRespData))
     608           0 :                         len = wpabuf_len(sm->eap_if.eapRespData);
     609          81 :                 pos = (const u8 *) (nak + 1);
     610          81 :                 len -= sizeof(*nak);
     611          81 :                 if (*pos == EAP_TYPE_NAK) {
     612          80 :                         pos++;
     613          80 :                         len--;
     614          80 :                         nak_list = pos;
     615             :                 }
     616             :         }
     617          81 :         eap_sm_Policy_update(sm, nak_list, len);
     618             : }
     619             : 
     620             : 
     621        4341 : SM_STATE(EAP, SELECT_ACTION)
     622             : {
     623        4341 :         SM_ENTRY(EAP, SELECT_ACTION);
     624             : 
     625        4341 :         sm->decision = eap_sm_Policy_getDecision(sm);
     626        4341 : }
     627             : 
     628             : 
     629           0 : SM_STATE(EAP, TIMEOUT_FAILURE)
     630             : {
     631           0 :         SM_ENTRY(EAP, TIMEOUT_FAILURE);
     632             : 
     633           0 :         sm->eap_if.eapTimeout = TRUE;
     634           0 : }
     635             : 
     636             : 
     637         384 : SM_STATE(EAP, FAILURE)
     638             : {
     639         384 :         SM_ENTRY(EAP, FAILURE);
     640             : 
     641         384 :         wpabuf_free(sm->eap_if.eapReqData);
     642         384 :         sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId);
     643         384 :         wpabuf_free(sm->lastReqData);
     644         384 :         sm->lastReqData = NULL;
     645         384 :         sm->eap_if.eapFail = TRUE;
     646             : 
     647        2304 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
     648        2304 :                 MACSTR, MAC2STR(sm->peer_addr));
     649         384 : }
     650             : 
     651             : 
     652         601 : SM_STATE(EAP, SUCCESS)
     653             : {
     654         601 :         SM_ENTRY(EAP, SUCCESS);
     655             : 
     656         601 :         wpabuf_free(sm->eap_if.eapReqData);
     657         601 :         sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId);
     658         601 :         wpabuf_free(sm->lastReqData);
     659         601 :         sm->lastReqData = NULL;
     660         601 :         if (sm->eap_if.eapKeyData)
     661         601 :                 sm->eap_if.eapKeyAvailable = TRUE;
     662         601 :         sm->eap_if.eapSuccess = TRUE;
     663             : 
     664        3606 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
     665        3606 :                 MACSTR, MAC2STR(sm->peer_addr));
     666         601 : }
     667             : 
     668             : 
     669          39 : SM_STATE(EAP, INITIATE_REAUTH_START)
     670             : {
     671          39 :         SM_ENTRY(EAP, INITIATE_REAUTH_START);
     672             : 
     673          39 :         sm->initiate_reauth_start_sent = TRUE;
     674          39 :         sm->try_initiate_reauth = TRUE;
     675          39 :         sm->currentId = eap_sm_nextId(sm, sm->currentId);
     676          39 :         wpa_printf(MSG_DEBUG,
     677             :                    "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
     678             :                    sm->currentId);
     679          39 :         sm->lastId = sm->currentId;
     680          39 :         wpabuf_free(sm->eap_if.eapReqData);
     681          39 :         sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
     682          39 :                                                                 sm->currentId);
     683          39 :         wpabuf_free(sm->lastReqData);
     684          39 :         sm->lastReqData = NULL;
     685          39 : }
     686             : 
     687             : 
     688             : #ifdef CONFIG_ERP
     689             : 
     690          20 : static void erp_send_finish_reauth(struct eap_sm *sm,
     691             :                                    struct eap_server_erp_key *erp, u8 id,
     692             :                                    u8 flags, u16 seq, const char *nai)
     693             : {
     694             :         size_t plen;
     695             :         struct wpabuf *msg;
     696             :         u8 hash[SHA256_MAC_LEN];
     697             :         size_t hash_len;
     698             :         u8 seed[4];
     699             : 
     700          20 :         if (erp) {
     701          19 :                 switch (erp->cryptosuite) {
     702             :                 case EAP_ERP_CS_HMAC_SHA256_256:
     703           0 :                         hash_len = 32;
     704           0 :                         break;
     705             :                 case EAP_ERP_CS_HMAC_SHA256_128:
     706          19 :                         hash_len = 16;
     707          19 :                         break;
     708             :                 default:
     709           1 :                         return;
     710             :                 }
     711             :         } else
     712           1 :                 hash_len = 0;
     713             : 
     714          20 :         plen = 1 + 2 + 2 + os_strlen(nai);
     715          20 :         if (hash_len)
     716          19 :                 plen += 1 + hash_len;
     717          20 :         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH, plen,
     718             :                             EAP_CODE_FINISH, id);
     719          20 :         if (msg == NULL)
     720           0 :                 return;
     721          20 :         wpabuf_put_u8(msg, flags);
     722          20 :         wpabuf_put_be16(msg, seq);
     723             : 
     724          20 :         wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
     725          20 :         wpabuf_put_u8(msg, os_strlen(nai));
     726          20 :         wpabuf_put_str(msg, nai);
     727             : 
     728          20 :         if (erp) {
     729          19 :                 wpabuf_put_u8(msg, erp->cryptosuite);
     730          38 :                 if (hmac_sha256(erp->rIK, erp->rIK_len,
     731          19 :                                 wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
     732           0 :                         wpabuf_free(msg);
     733           0 :                         return;
     734             :                 }
     735          19 :                 wpabuf_put_data(msg, hash, hash_len);
     736             :         }
     737             : 
     738          20 :         wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
     739          20 :                    flags & 0x80 ? "failure" : "success");
     740             : 
     741          20 :         sm->lastId = sm->currentId;
     742          20 :         sm->currentId = id;
     743          20 :         wpabuf_free(sm->eap_if.eapReqData);
     744          20 :         sm->eap_if.eapReqData = msg;
     745          20 :         wpabuf_free(sm->lastReqData);
     746          20 :         sm->lastReqData = NULL;
     747             : 
     748          20 :         if (flags & 0x80) {
     749           1 :                 sm->eap_if.eapFail = TRUE;
     750           6 :                 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
     751           6 :                         MACSTR, MAC2STR(sm->peer_addr));
     752           1 :                 return;
     753             :         }
     754             : 
     755          19 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     756          19 :         sm->eap_if.eapKeyDataLen = 0;
     757          19 :         sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
     758          19 :         if (!sm->eap_if.eapKeyData)
     759           0 :                 return;
     760             : 
     761          19 :         WPA_PUT_BE16(seed, seq);
     762          19 :         WPA_PUT_BE16(&seed[2], erp->rRK_len);
     763          19 :         if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
     764             :                             "Re-authentication Master Session Key@ietf.org",
     765             :                             seed, sizeof(seed),
     766             :                             sm->eap_if.eapKeyData, erp->rRK_len) < 0) {
     767           0 :                 wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
     768           0 :                 bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len);
     769           0 :                 sm->eap_if.eapKeyData = NULL;
     770           0 :                 return;
     771             :         }
     772          19 :         sm->eap_if.eapKeyDataLen = erp->rRK_len;
     773          19 :         sm->eap_if.eapKeyAvailable = TRUE;
     774          38 :         wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
     775          19 :                         sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
     776          19 :         sm->eap_if.eapSuccess = TRUE;
     777             : 
     778         114 :         wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
     779         114 :                 MACSTR, MAC2STR(sm->peer_addr));
     780             : }
     781             : 
     782             : 
     783          35 : SM_STATE(EAP, INITIATE_RECEIVED)
     784             : {
     785             :         const u8 *pos, *end, *start, *tlvs, *hdr;
     786             :         const struct eap_hdr *ehdr;
     787             :         size_t len;
     788             :         u8 flags;
     789             :         u16 seq;
     790             :         char nai[254];
     791             :         struct eap_server_erp_key *erp;
     792             :         int max_len;
     793             :         u8 hash[SHA256_MAC_LEN];
     794             :         size_t hash_len;
     795             :         struct erp_tlvs parse;
     796          35 :         u8 resp_flags = 0x80; /* default to failure; cleared on success */
     797             : 
     798          35 :         SM_ENTRY(EAP, INITIATE_RECEIVED);
     799             : 
     800          35 :         sm->rxInitiate = FALSE;
     801             : 
     802          35 :         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
     803          35 :                                sm->eap_if.eapRespData, &len);
     804          35 :         if (pos == NULL) {
     805           0 :                 wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
     806           0 :                 goto fail;
     807             :         }
     808          35 :         hdr = wpabuf_head(sm->eap_if.eapRespData);
     809          35 :         ehdr = wpabuf_head(sm->eap_if.eapRespData);
     810             : 
     811          35 :         wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
     812          35 :         if (len < 4) {
     813           0 :                 wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
     814           0 :                 goto fail;
     815             :         }
     816          35 :         end = pos + len;
     817             : 
     818          35 :         flags = *pos++;
     819          35 :         seq = WPA_GET_BE16(pos);
     820          35 :         pos += 2;
     821          35 :         wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
     822          35 :         tlvs = pos;
     823             : 
     824             :         /*
     825             :          * Parse TVs/TLVs. Since we do not yet know the length of the
     826             :          * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
     827             :          * just try to find the keyName-NAI first so that we can check the
     828             :          * Authentication Tag.
     829             :          */
     830          35 :         if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
     831           0 :                 goto fail;
     832             : 
     833          35 :         if (!parse.keyname) {
     834           0 :                 wpa_printf(MSG_DEBUG,
     835             :                            "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
     836           0 :                 goto fail;
     837             :         }
     838             : 
     839          70 :         wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
     840          70 :                           parse.keyname, parse.keyname_len);
     841          35 :         if (parse.keyname_len > 253) {
     842           0 :                 wpa_printf(MSG_DEBUG,
     843             :                            "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
     844           0 :                 goto fail;
     845             :         }
     846          35 :         os_memcpy(nai, parse.keyname, parse.keyname_len);
     847          35 :         nai[parse.keyname_len] = '\0';
     848             : 
     849          35 :         if (!sm->eap_server) {
     850             :                 /*
     851             :                  * In passthrough case, EAP-Initiate/Re-auth replaces
     852             :                  * EAP Identity exchange. Use keyName-NAI as the user identity
     853             :                  * and forward EAP-Initiate/Re-auth to the backend
     854             :                  * authentication server.
     855             :                  */
     856          15 :                 wpa_printf(MSG_DEBUG,
     857             :                            "EAP: Use keyName-NAI as user identity for backend authentication");
     858          15 :                 eap_server_clear_identity(sm);
     859          15 :                 sm->identity = (u8 *) dup_binstr(parse.keyname,
     860          15 :                                                  parse.keyname_len);
     861          15 :                 if (!sm->identity)
     862           0 :                         goto fail;
     863          15 :                 sm->identity_len = parse.keyname_len;
     864          50 :                 return;
     865             :         }
     866             : 
     867          20 :         erp = eap_erp_get_key(sm, nai);
     868          20 :         if (!erp) {
     869           1 :                 wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
     870             :                            nai);
     871           1 :                 goto report_error;
     872             :         }
     873             : 
     874          19 :         if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) {
     875           0 :                 wpa_printf(MSG_DEBUG,
     876             :                            "EAP: SEQ=%u replayed (already received SEQ=%u)",
     877             :                            seq, erp->recv_seq);
     878           0 :                 goto fail;
     879             :         }
     880             : 
     881             :         /* Is there enough room for Cryptosuite and Authentication Tag? */
     882          19 :         start = parse.keyname + parse.keyname_len;
     883          19 :         max_len = end - start;
     884          19 :         if (max_len <
     885          19 :             1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) {
     886           0 :                 wpa_printf(MSG_DEBUG,
     887             :                            "EAP: Not enough room for Authentication Tag");
     888           0 :                 goto fail;
     889             :         }
     890             : 
     891          19 :         switch (erp->cryptosuite) {
     892             :         case EAP_ERP_CS_HMAC_SHA256_256:
     893           0 :                 if (end[-33] != erp->cryptosuite) {
     894           0 :                         wpa_printf(MSG_DEBUG,
     895             :                                    "EAP: Different Cryptosuite used");
     896           0 :                         goto fail;
     897             :                 }
     898           0 :                 hash_len = 32;
     899           0 :                 break;
     900             :         case EAP_ERP_CS_HMAC_SHA256_128:
     901           4 :                 if (end[-17] != erp->cryptosuite) {
     902           0 :                         wpa_printf(MSG_DEBUG,
     903             :                                    "EAP: Different Cryptosuite used");
     904           0 :                         goto fail;
     905             :                 }
     906           4 :                 hash_len = 16;
     907           4 :                 break;
     908             :         default:
     909          15 :                 hash_len = 0;
     910          15 :                 break;
     911             :         }
     912             : 
     913          19 :         if (hash_len) {
     914           4 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     915           4 :                                 end - hdr - hash_len, hash) < 0)
     916           0 :                         goto fail;
     917           4 :                 if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
     918           0 :                         wpa_printf(MSG_DEBUG,
     919             :                                    "EAP: Authentication Tag mismatch");
     920           0 :                         goto fail;
     921             :                 }
     922             :         }
     923             : 
     924             :         /* Check if any supported CS results in matching tag */
     925          19 :         if (!hash_len && max_len >= 1 + 32 &&
     926           0 :             end[-33] == EAP_ERP_CS_HMAC_SHA256_256) {
     927           0 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     928           0 :                                 end - hdr - 32, hash) < 0)
     929           0 :                         goto fail;
     930           0 :                 if (os_memcmp(end - 32, hash, 32) == 0) {
     931           0 :                         wpa_printf(MSG_DEBUG,
     932             :                                    "EAP: Authentication Tag match using HMAC-SHA256-256");
     933           0 :                         hash_len = 32;
     934           0 :                         erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256;
     935             :                 }
     936             :         }
     937             : 
     938          19 :         if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
     939          15 :                 if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
     940          15 :                                 end - hdr - 16, hash) < 0)
     941           0 :                         goto fail;
     942          15 :                 if (os_memcmp(end - 16, hash, 16) == 0) {
     943          15 :                         wpa_printf(MSG_DEBUG,
     944             :                                    "EAP: Authentication Tag match using HMAC-SHA256-128");
     945          15 :                         hash_len = 16;
     946          15 :                         erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
     947             :                 }
     948             :         }
     949             : 
     950          19 :         if (!hash_len) {
     951           0 :                 wpa_printf(MSG_DEBUG,
     952             :                            "EAP: No supported cryptosuite matched Authentication Tag");
     953           0 :                 goto fail;
     954             :         }
     955          19 :         end -= 1 + hash_len;
     956             : 
     957             :         /*
     958             :          * Parse TVs/TLVs again now that we know the exact part of the buffer
     959             :          * that contains them.
     960             :          */
     961          19 :         wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
     962          19 :                     tlvs, end - tlvs);
     963          19 :         if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
     964           0 :                 goto fail;
     965             : 
     966          38 :         wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
     967          19 :                    erp->keyname_nai, seq);
     968          19 :         erp->recv_seq = seq;
     969          19 :         resp_flags &= ~0x80; /* R=0 - success */
     970             : 
     971             : report_error:
     972          20 :         erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
     973          20 :         return;
     974             : 
     975             : fail:
     976           0 :         sm->ignore = TRUE;
     977             : }
     978             : 
     979             : #endif /* CONFIG_ERP */
     980             : 
     981             : 
     982         935 : SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
     983             : {
     984         935 :         SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
     985             : 
     986         935 :         wpabuf_free(sm->eap_if.aaaEapRespData);
     987         935 :         sm->eap_if.aaaEapRespData = NULL;
     988         935 :         sm->try_initiate_reauth = FALSE;
     989         935 : }
     990             : 
     991             : 
     992        2613 : SM_STATE(EAP, IDLE2)
     993             : {
     994        2613 :         SM_ENTRY(EAP, IDLE2);
     995             : 
     996        2613 :         sm->eap_if.retransWhile = eap_sm_calculateTimeout(
     997             :                 sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR,
     998             :                 sm->methodTimeout);
     999        2613 : }
    1000             : 
    1001             : 
    1002           4 : SM_STATE(EAP, RETRANSMIT2)
    1003             : {
    1004           4 :         SM_ENTRY(EAP, RETRANSMIT2);
    1005             : 
    1006           4 :         sm->retransCount++;
    1007           4 :         if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) {
    1008           4 :                 if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0)
    1009           4 :                         sm->eap_if.eapReq = TRUE;
    1010             :         }
    1011           4 : }
    1012             : 
    1013             : 
    1014        2360 : SM_STATE(EAP, RECEIVED2)
    1015             : {
    1016        2360 :         SM_ENTRY(EAP, RECEIVED2);
    1017             : 
    1018             :         /* parse rxResp, respId, respMethod */
    1019        2360 :         eap_sm_parseEapResp(sm, sm->eap_if.eapRespData);
    1020        2360 : }
    1021             : 
    1022             : 
    1023           2 : SM_STATE(EAP, DISCARD2)
    1024             : {
    1025           2 :         SM_ENTRY(EAP, DISCARD2);
    1026           2 :         sm->eap_if.eapResp = FALSE;
    1027           2 :         sm->eap_if.eapNoReq = TRUE;
    1028           2 : }
    1029             : 
    1030             : 
    1031        2607 : SM_STATE(EAP, SEND_REQUEST2)
    1032             : {
    1033        2607 :         SM_ENTRY(EAP, SEND_REQUEST2);
    1034             : 
    1035        2607 :         sm->retransCount = 0;
    1036        2607 :         if (sm->eap_if.eapReqData) {
    1037        2605 :                 if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0)
    1038             :                 {
    1039        2605 :                         sm->eap_if.eapResp = FALSE;
    1040        2605 :                         sm->eap_if.eapReq = TRUE;
    1041             :                 } else {
    1042           0 :                         sm->eap_if.eapResp = FALSE;
    1043           0 :                         sm->eap_if.eapReq = FALSE;
    1044             :                 }
    1045             :         } else {
    1046           2 :                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData");
    1047           2 :                 sm->eap_if.eapResp = FALSE;
    1048           2 :                 sm->eap_if.eapReq = FALSE;
    1049           2 :                 sm->eap_if.eapNoReq = TRUE;
    1050             :         }
    1051        2607 : }
    1052             : 
    1053             : 
    1054        3293 : SM_STATE(EAP, AAA_REQUEST)
    1055             : {
    1056        3293 :         SM_ENTRY(EAP, AAA_REQUEST);
    1057             : 
    1058        3293 :         if (sm->eap_if.eapRespData == NULL) {
    1059           0 :                 wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData");
    1060        3293 :                 return;
    1061             :         }
    1062             : 
    1063             :         /*
    1064             :          * if (respMethod == IDENTITY)
    1065             :          *      aaaIdentity = eapRespData
    1066             :          * This is already taken care of by the EAP-Identity method which
    1067             :          * stores the identity into sm->identity.
    1068             :          */
    1069             : 
    1070        3293 :         eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData);
    1071             : }
    1072             : 
    1073             : 
    1074        2607 : SM_STATE(EAP, AAA_RESPONSE)
    1075             : {
    1076        2607 :         SM_ENTRY(EAP, AAA_RESPONSE);
    1077             : 
    1078        2607 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1079        2607 :         sm->currentId = eap_sm_getId(sm->eap_if.eapReqData);
    1080        2607 :         sm->methodTimeout = sm->eap_if.aaaMethodTimeout;
    1081        2607 : }
    1082             : 
    1083             : 
    1084        3293 : SM_STATE(EAP, AAA_IDLE)
    1085             : {
    1086        3293 :         SM_ENTRY(EAP, AAA_IDLE);
    1087             : 
    1088        3293 :         sm->eap_if.aaaFail = FALSE;
    1089        3293 :         sm->eap_if.aaaSuccess = FALSE;
    1090        3293 :         sm->eap_if.aaaEapReq = FALSE;
    1091        3293 :         sm->eap_if.aaaEapNoReq = FALSE;
    1092        3293 :         sm->eap_if.aaaEapResp = TRUE;
    1093        3293 : }
    1094             : 
    1095             : 
    1096           0 : SM_STATE(EAP, TIMEOUT_FAILURE2)
    1097             : {
    1098           0 :         SM_ENTRY(EAP, TIMEOUT_FAILURE2);
    1099             : 
    1100           0 :         sm->eap_if.eapTimeout = TRUE;
    1101           0 : }
    1102             : 
    1103             : 
    1104          89 : SM_STATE(EAP, FAILURE2)
    1105             : {
    1106          89 :         SM_ENTRY(EAP, FAILURE2);
    1107             : 
    1108          89 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1109          89 :         sm->eap_if.eapFail = TRUE;
    1110          89 : }
    1111             : 
    1112             : 
    1113         569 : SM_STATE(EAP, SUCCESS2)
    1114             : {
    1115         569 :         SM_ENTRY(EAP, SUCCESS2);
    1116             : 
    1117         569 :         eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData);
    1118             : 
    1119         569 :         sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable;
    1120         569 :         if (sm->eap_if.aaaEapKeyAvailable) {
    1121         564 :                 EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData);
    1122             :         } else {
    1123           5 :                 bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
    1124           5 :                 sm->eap_if.eapKeyData = NULL;
    1125           5 :                 sm->eap_if.eapKeyDataLen = 0;
    1126             :         }
    1127             : 
    1128         569 :         sm->eap_if.eapSuccess = TRUE;
    1129             : 
    1130             :         /*
    1131             :          * Start reauthentication with identity request even though we know the
    1132             :          * previously used identity. This is needed to get reauthentication
    1133             :          * started properly.
    1134             :          */
    1135         569 :         sm->start_reauth = TRUE;
    1136         569 : }
    1137             : 
    1138             : 
    1139       89115 : SM_STEP(EAP)
    1140             : {
    1141       89115 :         if (sm->eap_if.eapRestart && sm->eap_if.portEnabled)
    1142        2001 :                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
    1143       87114 :         else if (!sm->eap_if.portEnabled)
    1144        1911 :                 SM_ENTER_GLOBAL(EAP, DISABLED);
    1145       85203 :         else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
    1146           0 :                 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
    1147           0 :                         wpa_printf(MSG_DEBUG, "EAP: more than %d "
    1148             :                                    "authentication rounds - abort",
    1149             :                                    EAP_MAX_AUTH_ROUNDS);
    1150           0 :                         sm->num_rounds++;
    1151           0 :                         SM_ENTER_GLOBAL(EAP, FAILURE);
    1152             :                 }
    1153       85203 :         } else switch (sm->EAP_state) {
    1154             :         case EAP_INITIALIZE:
    1155        2001 :                 if (sm->backend_auth) {
    1156         680 :                         if (!sm->rxResp)
    1157          15 :                                 SM_ENTER(EAP, SELECT_ACTION);
    1158        1330 :                         else if (sm->rxResp &&
    1159        1330 :                                  (sm->respMethod == EAP_TYPE_NAK ||
    1160         665 :                                   (sm->respMethod == EAP_TYPE_EXPANDED &&
    1161           0 :                                    sm->respVendor == EAP_VENDOR_IETF &&
    1162           0 :                                    sm->respVendorMethod == EAP_TYPE_NAK)))
    1163           0 :                                 SM_ENTER(EAP, NAK);
    1164             :                         else
    1165         665 :                                 SM_ENTER(EAP, PICK_UP_METHOD);
    1166             :                 } else {
    1167        1321 :                         SM_ENTER(EAP, SELECT_ACTION);
    1168             :                 }
    1169        2001 :                 break;
    1170             :         case EAP_PICK_UP_METHOD:
    1171         665 :                 if (sm->currentMethod == EAP_TYPE_NONE) {
    1172           0 :                         SM_ENTER(EAP, SELECT_ACTION);
    1173             :                 } else {
    1174         665 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1175             :                 }
    1176         665 :                 break;
    1177             :         case EAP_DISABLED:
    1178           0 :                 if (sm->eap_if.portEnabled)
    1179           0 :                         SM_ENTER(EAP, INITIALIZE);
    1180           0 :                 break;
    1181             :         case EAP_IDLE:
    1182       17067 :                 if (sm->eap_if.retransWhile == 0) {
    1183           1 :                         if (sm->try_initiate_reauth) {
    1184           0 :                                 sm->try_initiate_reauth = FALSE;
    1185           0 :                                 SM_ENTER(EAP, SELECT_ACTION);
    1186             :                         } else {
    1187           1 :                                 SM_ENTER(EAP, RETRANSMIT);
    1188             :                         }
    1189       17066 :                 } else if (sm->eap_if.eapResp)
    1190        5067 :                         SM_ENTER(EAP, RECEIVED);
    1191       17067 :                 break;
    1192             :         case EAP_RETRANSMIT:
    1193           1 :                 if (sm->retransCount > sm->MaxRetrans)
    1194           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE);
    1195             :                 else
    1196           1 :                         SM_ENTER(EAP, IDLE);
    1197           1 :                 break;
    1198             :         case EAP_RECEIVED:
    1199       10108 :                 if (sm->rxResp && (sm->respId == sm->currentId) &&
    1200       10002 :                     (sm->respMethod == EAP_TYPE_NAK ||
    1201        6316 :                      (sm->respMethod == EAP_TYPE_EXPANDED &&
    1202        1356 :                       sm->respVendor == EAP_VENDOR_IETF &&
    1203           1 :                       sm->respVendorMethod == EAP_TYPE_NAK))
    1204          81 :                     && (sm->methodState == METHOD_PROPOSED))
    1205          81 :                         SM_ENTER(EAP, NAK);
    1206        9946 :                 else if (sm->rxResp && (sm->respId == sm->currentId) &&
    1207        4960 :                          ((sm->respMethod == sm->currentMethod) ||
    1208           0 :                           (sm->respMethod == EAP_TYPE_EXPANDED &&
    1209           0 :                            sm->respVendor == EAP_VENDOR_IETF &&
    1210           0 :                            sm->respVendorMethod == sm->currentMethod)))
    1211        4960 :                         SM_ENTER(EAP, INTEGRITY_CHECK);
    1212             : #ifdef CONFIG_ERP
    1213          26 :                 else if (sm->rxInitiate)
    1214          20 :                         SM_ENTER(EAP, INITIATE_RECEIVED);
    1215             : #endif /* CONFIG_ERP */
    1216             :                 else {
    1217          12 :                         wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
    1218             :                                    "rxResp=%d respId=%d currentId=%d "
    1219             :                                    "respMethod=%d currentMethod=%d",
    1220           6 :                                    sm->rxResp, sm->respId, sm->currentId,
    1221           6 :                                    sm->respMethod, sm->currentMethod);
    1222           6 :                         eap_log_msg(sm, "Discard received EAP message");
    1223           6 :                         SM_ENTER(EAP, DISCARD);
    1224             :                 }
    1225        5067 :                 break;
    1226             :         case EAP_DISCARD:
    1227           6 :                 SM_ENTER(EAP, IDLE);
    1228           6 :                 break;
    1229             :         case EAP_SEND_REQUEST:
    1230        5122 :                 SM_ENTER(EAP, IDLE);
    1231        5122 :                 break;
    1232             :         case EAP_INTEGRITY_CHECK:
    1233        4960 :                 if (sm->ignore)
    1234           0 :                         SM_ENTER(EAP, DISCARD);
    1235             :                 else
    1236        4960 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1237        4960 :                 break;
    1238             :         case EAP_METHOD_REQUEST:
    1239        5083 :                 if (sm->m == NULL) {
    1240             :                         /*
    1241             :                          * This transition is not mentioned in RFC 4137, but it
    1242             :                          * is needed to handle cleanly a case where EAP method
    1243             :                          * initialization fails.
    1244             :                          */
    1245           0 :                         SM_ENTER(EAP, FAILURE);
    1246           0 :                         break;
    1247             :                 }
    1248        5083 :                 SM_ENTER(EAP, SEND_REQUEST);
    1249        5083 :                 break;
    1250             :         case EAP_METHOD_RESPONSE:
    1251             :                 /*
    1252             :                  * Note: Mechanism to allow EAP methods to wait while going
    1253             :                  * through pending processing is an extension to RFC 4137
    1254             :                  * which only defines the transits to SELECT_ACTION and
    1255             :                  * METHOD_REQUEST from this METHOD_RESPONSE state.
    1256             :                  */
    1257        5876 :                 if (sm->methodState == METHOD_END)
    1258        2909 :                         SM_ENTER(EAP, SELECT_ACTION);
    1259        2967 :                 else if (sm->method_pending == METHOD_PENDING_WAIT) {
    1260         143 :                         wpa_printf(MSG_DEBUG, "EAP: Method has pending "
    1261             :                                    "processing - wait before proceeding to "
    1262             :                                    "METHOD_REQUEST state");
    1263        2824 :                 } else if (sm->method_pending == METHOD_PENDING_CONT) {
    1264         108 :                         wpa_printf(MSG_DEBUG, "EAP: Method has completed "
    1265             :                                    "pending processing - reprocess pending "
    1266             :                                    "EAP message");
    1267         108 :                         sm->method_pending = METHOD_PENDING_NONE;
    1268         108 :                         SM_ENTER(EAP, METHOD_RESPONSE);
    1269             :                 } else
    1270        2716 :                         SM_ENTER(EAP, METHOD_REQUEST);
    1271        5876 :                 break;
    1272             :         case EAP_PROPOSE_METHOD:
    1273             :                 /*
    1274             :                  * Note: Mechanism to allow EAP methods to wait while going
    1275             :                  * through pending processing is an extension to RFC 4137
    1276             :                  * which only defines the transit to METHOD_REQUEST from this
    1277             :                  * PROPOSE_METHOD state.
    1278             :                  */
    1279        2367 :                 if (sm->method_pending == METHOD_PENDING_WAIT) {
    1280           0 :                         wpa_printf(MSG_DEBUG, "EAP: Method has pending "
    1281             :                                    "processing - wait before proceeding to "
    1282             :                                    "METHOD_REQUEST state");
    1283           0 :                         if (sm->user_eap_method_index > 0)
    1284           0 :                                 sm->user_eap_method_index--;
    1285        2367 :                 } else if (sm->method_pending == METHOD_PENDING_CONT) {
    1286           0 :                         wpa_printf(MSG_DEBUG, "EAP: Method has completed "
    1287             :                                    "pending processing - reprocess pending "
    1288             :                                    "EAP message");
    1289           0 :                         sm->method_pending = METHOD_PENDING_NONE;
    1290           0 :                         SM_ENTER(EAP, PROPOSE_METHOD);
    1291             :                 } else
    1292        2367 :                         SM_ENTER(EAP, METHOD_REQUEST);
    1293        2367 :                 break;
    1294             :         case EAP_NAK:
    1295          81 :                 SM_ENTER(EAP, SELECT_ACTION);
    1296          81 :                 break;
    1297             :         case EAP_SELECT_ACTION:
    1298        4341 :                 if (sm->decision == DECISION_FAILURE)
    1299         384 :                         SM_ENTER(EAP, FAILURE);
    1300        3957 :                 else if (sm->decision == DECISION_SUCCESS)
    1301         601 :                         SM_ENTER(EAP, SUCCESS);
    1302        3356 :                 else if (sm->decision == DECISION_PASSTHROUGH)
    1303         935 :                         SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
    1304        2421 :                 else if (sm->decision == DECISION_INITIATE_REAUTH_START)
    1305          39 :                         SM_ENTER(EAP, INITIATE_REAUTH_START);
    1306             : #ifdef CONFIG_ERP
    1307        2382 :                 else if (sm->eap_server && sm->erp && sm->rxInitiate)
    1308          15 :                         SM_ENTER(EAP, INITIATE_RECEIVED);
    1309             : #endif /* CONFIG_ERP */
    1310             :                 else
    1311        2367 :                         SM_ENTER(EAP, PROPOSE_METHOD);
    1312        4341 :                 break;
    1313             :         case EAP_INITIATE_REAUTH_START:
    1314          39 :                 SM_ENTER(EAP, SEND_REQUEST);
    1315          39 :                 break;
    1316             :         case EAP_INITIATE_RECEIVED:
    1317          43 :                 if (!sm->eap_server)
    1318          15 :                         SM_ENTER(EAP, SELECT_ACTION);
    1319          43 :                 break;
    1320             :         case EAP_TIMEOUT_FAILURE:
    1321           0 :                 break;
    1322             :         case EAP_FAILURE:
    1323         384 :                 break;
    1324             :         case EAP_SUCCESS:
    1325         820 :                 break;
    1326             : 
    1327             :         case EAP_INITIALIZE_PASSTHROUGH:
    1328         935 :                 if (sm->currentId == -1)
    1329           0 :                         SM_ENTER(EAP, AAA_IDLE);
    1330             :                 else
    1331         935 :                         SM_ENTER(EAP, AAA_REQUEST);
    1332         935 :                 break;
    1333             :         case EAP_IDLE2:
    1334        7610 :                 if (sm->eap_if.eapResp)
    1335        2360 :                         SM_ENTER(EAP, RECEIVED2);
    1336        5250 :                 else if (sm->eap_if.retransWhile == 0)
    1337           4 :                         SM_ENTER(EAP, RETRANSMIT2);
    1338        7610 :                 break;
    1339             :         case EAP_RETRANSMIT2:
    1340           4 :                 if (sm->retransCount > sm->MaxRetrans)
    1341           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE2);
    1342             :                 else
    1343           4 :                         SM_ENTER(EAP, IDLE2);
    1344           4 :                 break;
    1345             :         case EAP_RECEIVED2:
    1346        2360 :                 if (sm->rxResp && (sm->respId == sm->currentId))
    1347        2358 :                         SM_ENTER(EAP, AAA_REQUEST);
    1348             :                 else
    1349           2 :                         SM_ENTER(EAP, DISCARD2);
    1350        2360 :                 break;
    1351             :         case EAP_DISCARD2:
    1352           2 :                 SM_ENTER(EAP, IDLE2);
    1353           2 :                 break;
    1354             :         case EAP_SEND_REQUEST2:
    1355        2607 :                 SM_ENTER(EAP, IDLE2);
    1356        2607 :                 break;
    1357             :         case EAP_AAA_REQUEST:
    1358        3293 :                 SM_ENTER(EAP, AAA_IDLE);
    1359        3293 :                 break;
    1360             :         case EAP_AAA_RESPONSE:
    1361        2607 :                 SM_ENTER(EAP, SEND_REQUEST2);
    1362        2607 :                 break;
    1363             :         case EAP_AAA_IDLE:
    1364        9982 :                 if (sm->eap_if.aaaFail)
    1365          89 :                         SM_ENTER(EAP, FAILURE2);
    1366        9893 :                 else if (sm->eap_if.aaaSuccess)
    1367         569 :                         SM_ENTER(EAP, SUCCESS2);
    1368        9324 :                 else if (sm->eap_if.aaaEapReq)
    1369        2607 :                         SM_ENTER(EAP, AAA_RESPONSE);
    1370        6717 :                 else if (sm->eap_if.aaaTimeout)
    1371           0 :                         SM_ENTER(EAP, TIMEOUT_FAILURE2);
    1372        9982 :                 break;
    1373             :         case EAP_TIMEOUT_FAILURE2:
    1374           0 :                 break;
    1375             :         case EAP_FAILURE2:
    1376          89 :                 break;
    1377             :         case EAP_SUCCESS2:
    1378        1791 :                 break;
    1379             :         }
    1380       89115 : }
    1381             : 
    1382             : 
    1383        7742 : static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
    1384             :                                    int eapSRTT, int eapRTTVAR,
    1385             :                                    int methodTimeout)
    1386             : {
    1387             :         int rto, i;
    1388             : 
    1389        7742 :         if (sm->try_initiate_reauth) {
    1390          39 :                 wpa_printf(MSG_DEBUG,
    1391             :                            "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
    1392          39 :                 return 1;
    1393             :         }
    1394             : 
    1395        7703 :         if (methodTimeout) {
    1396             :                 /*
    1397             :                  * EAP method (either internal or through AAA server, provided
    1398             :                  * timeout hint. Use that as-is as a timeout for retransmitting
    1399             :                  * the EAP request if no response is received.
    1400             :                  */
    1401        1335 :                 wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
    1402             :                            "(from EAP method hint)", methodTimeout);
    1403        1335 :                 return methodTimeout;
    1404             :         }
    1405             : 
    1406             :         /*
    1407             :          * RFC 3748 recommends algorithms described in RFC 2988 for estimation
    1408             :          * of the retransmission timeout. This should be implemented once
    1409             :          * round-trip time measurements are available. For nowm a simple
    1410             :          * backoff mechanism is used instead if there are no EAP method
    1411             :          * specific hints.
    1412             :          *
    1413             :          * SRTT = smoothed round-trip time
    1414             :          * RTTVAR = round-trip time variation
    1415             :          * RTO = retransmission timeout
    1416             :          */
    1417             : 
    1418             :         /*
    1419             :          * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for
    1420             :          * initial retransmission and then double the RTO to provide back off
    1421             :          * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3
    1422             :          * modified RTOmax.
    1423             :          */
    1424        6368 :         rto = 3;
    1425        6375 :         for (i = 0; i < retransCount; i++) {
    1426           7 :                 rto *= 2;
    1427           7 :                 if (rto >= 20) {
    1428           0 :                         rto = 20;
    1429           0 :                         break;
    1430             :                 }
    1431             :         }
    1432             : 
    1433        6368 :         wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds "
    1434             :                    "(from dynamic back off; retransCount=%d)",
    1435             :                    rto, retransCount);
    1436             : 
    1437        6368 :         return rto;
    1438             : }
    1439             : 
    1440             : 
    1441        8107 : static void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp)
    1442             : {
    1443             :         const struct eap_hdr *hdr;
    1444             :         size_t plen;
    1445             : 
    1446             :         /* parse rxResp, respId, respMethod */
    1447        8107 :         sm->rxResp = FALSE;
    1448        8107 :         sm->rxInitiate = FALSE;
    1449        8107 :         sm->respId = -1;
    1450        8107 :         sm->respMethod = EAP_TYPE_NONE;
    1451        8107 :         sm->respVendor = EAP_VENDOR_IETF;
    1452        8107 :         sm->respVendorMethod = EAP_TYPE_NONE;
    1453             : 
    1454        8107 :         if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) {
    1455           0 :                 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p "
    1456             :                            "len=%lu", resp,
    1457             :                            resp ? (unsigned long) wpabuf_len(resp) : 0);
    1458           0 :                 return;
    1459             :         }
    1460             : 
    1461        8107 :         hdr = wpabuf_head(resp);
    1462        8107 :         plen = be_to_host16(hdr->length);
    1463        8107 :         if (plen > wpabuf_len(resp)) {
    1464           0 :                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
    1465             :                            "(len=%lu plen=%lu)",
    1466             :                            (unsigned long) wpabuf_len(resp),
    1467             :                            (unsigned long) plen);
    1468           0 :                 return;
    1469             :         }
    1470             : 
    1471        8107 :         sm->respId = hdr->identifier;
    1472             : 
    1473        8107 :         if (hdr->code == EAP_CODE_RESPONSE)
    1474        8072 :                 sm->rxResp = TRUE;
    1475          35 :         else if (hdr->code == EAP_CODE_INITIATE)
    1476          35 :                 sm->rxInitiate = TRUE;
    1477             : 
    1478        8107 :         if (plen > sizeof(*hdr)) {
    1479        8107 :                 u8 *pos = (u8 *) (hdr + 1);
    1480        8107 :                 sm->respMethod = *pos++;
    1481        8107 :                 if (sm->respMethod == EAP_TYPE_EXPANDED) {
    1482        1378 :                         if (plen < sizeof(*hdr) + 8) {
    1483           0 :                                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
    1484             :                                            "expanded EAP-Packet (plen=%lu)",
    1485             :                                            (unsigned long) plen);
    1486           0 :                                 return;
    1487             :                         }
    1488        1378 :                         sm->respVendor = WPA_GET_BE24(pos);
    1489        1378 :                         pos += 3;
    1490        1378 :                         sm->respVendorMethod = WPA_GET_BE32(pos);
    1491             :                 }
    1492             :         }
    1493             : 
    1494       24321 :         wpa_printf(MSG_DEBUG,
    1495             :                    "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
    1496       16214 :                    sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
    1497             :                    sm->respVendor, sm->respVendorMethod);
    1498             : }
    1499             : 
    1500             : 
    1501        2607 : static int eap_sm_getId(const struct wpabuf *data)
    1502             : {
    1503             :         const struct eap_hdr *hdr;
    1504             : 
    1505        2607 :         if (data == NULL || wpabuf_len(data) < sizeof(*hdr))
    1506           2 :                 return -1;
    1507             : 
    1508        2605 :         hdr = wpabuf_head(data);
    1509        2605 :         wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier);
    1510        2605 :         return hdr->identifier;
    1511             : }
    1512             : 
    1513             : 
    1514         601 : static struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id)
    1515             : {
    1516             :         struct wpabuf *msg;
    1517             :         struct eap_hdr *resp;
    1518         601 :         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
    1519             : 
    1520         601 :         msg = wpabuf_alloc(sizeof(*resp));
    1521         601 :         if (msg == NULL)
    1522           0 :                 return NULL;
    1523         601 :         resp = wpabuf_put(msg, sizeof(*resp));
    1524         601 :         resp->code = EAP_CODE_SUCCESS;
    1525         601 :         resp->identifier = id;
    1526         601 :         resp->length = host_to_be16(sizeof(*resp));
    1527             : 
    1528         601 :         return msg;
    1529             : }
    1530             : 
    1531             : 
    1532         384 : static struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id)
    1533             : {
    1534             :         struct wpabuf *msg;
    1535             :         struct eap_hdr *resp;
    1536         384 :         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
    1537             : 
    1538         384 :         msg = wpabuf_alloc(sizeof(*resp));
    1539         384 :         if (msg == NULL)
    1540           0 :                 return NULL;
    1541         384 :         resp = wpabuf_put(msg, sizeof(*resp));
    1542         384 :         resp->code = EAP_CODE_FAILURE;
    1543         384 :         resp->identifier = id;
    1544         384 :         resp->length = host_to_be16(sizeof(*resp));
    1545             : 
    1546         384 :         return msg;
    1547             : }
    1548             : 
    1549             : 
    1550        5122 : static int eap_sm_nextId(struct eap_sm *sm, int id)
    1551             : {
    1552        5122 :         if (id < 0) {
    1553             :                 /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
    1554             :                  * random number */
    1555        1321 :                 id = rand() & 0xff;
    1556        1321 :                 if (id != sm->lastId)
    1557        1314 :                         return id;
    1558             :         }
    1559        3808 :         return (id + 1) & 0xff;
    1560             : }
    1561             : 
    1562             : 
    1563             : /**
    1564             :  * eap_sm_process_nak - Process EAP-Response/Nak
    1565             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1566             :  * @nak_list: Nak list (allowed methods) from the supplicant
    1567             :  * @len: Length of nak_list in bytes
    1568             :  *
    1569             :  * This function is called when EAP-Response/Nak is received from the
    1570             :  * supplicant. This can happen for both phase 1 and phase 2 authentications.
    1571             :  */
    1572         101 : void eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len)
    1573             : {
    1574             :         int i;
    1575             :         size_t j;
    1576             : 
    1577         101 :         if (sm->user == NULL)
    1578         101 :                 return;
    1579             : 
    1580         101 :         wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
    1581             :                    "index %d)", sm->user_eap_method_index);
    1582             : 
    1583         101 :         wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
    1584         101 :                     (u8 *) sm->user->methods,
    1585             :                     EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
    1586         101 :         wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
    1587             :                     nak_list, len);
    1588             : 
    1589         101 :         i = sm->user_eap_method_index;
    1590        1299 :         while (i < EAP_MAX_METHODS &&
    1591        1198 :                (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
    1592         599 :                 sm->user->methods[i].method != EAP_TYPE_NONE)) {
    1593         498 :                 if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
    1594           0 :                         goto not_found;
    1595         902 :                 for (j = 0; j < len; j++) {
    1596         498 :                         if (nak_list[j] == sm->user->methods[i].method) {
    1597          94 :                                 break;
    1598             :                         }
    1599             :                 }
    1600             : 
    1601         498 :                 if (j < len) {
    1602             :                         /* found */
    1603          94 :                         i++;
    1604          94 :                         continue;
    1605             :                 }
    1606             : 
    1607             :         not_found:
    1608             :                 /* not found - remove from the list */
    1609         404 :                 if (i + 1 < EAP_MAX_METHODS) {
    1610         404 :                         os_memmove(&sm->user->methods[i],
    1611             :                                    &sm->user->methods[i + 1],
    1612             :                                    (EAP_MAX_METHODS - i - 1) *
    1613             :                                    sizeof(sm->user->methods[0]));
    1614             :                 }
    1615         404 :                 sm->user->methods[EAP_MAX_METHODS - 1].vendor =
    1616             :                         EAP_VENDOR_IETF;
    1617         404 :                 sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
    1618             :         }
    1619             : 
    1620         101 :         wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
    1621         101 :                     (u8 *) sm->user->methods, EAP_MAX_METHODS *
    1622             :                     sizeof(sm->user->methods[0]));
    1623             : }
    1624             : 
    1625             : 
    1626        2990 : static void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list,
    1627             :                                  size_t len)
    1628             : {
    1629        2990 :         if (nak_list == NULL || sm == NULL || sm->user == NULL)
    1630        2910 :                 return;
    1631             : 
    1632          80 :         if (sm->user->phase2) {
    1633           0 :                 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
    1634             :                            " info was selected - reject");
    1635           0 :                 sm->decision = DECISION_FAILURE;
    1636           0 :                 return;
    1637             :         }
    1638             : 
    1639          80 :         eap_sm_process_nak(sm, nak_list, len);
    1640             : }
    1641             : 
    1642             : 
    1643        2368 : static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
    1644             : {
    1645             :         EapType next;
    1646        2368 :         int idx = sm->user_eap_method_index;
    1647             : 
    1648             :         /* In theory, there should be no problems with starting
    1649             :          * re-authentication with something else than EAP-Request/Identity and
    1650             :          * this does indeed work with wpa_supplicant. However, at least Funk
    1651             :          * Supplicant seemed to ignore re-auth if it skipped
    1652             :          * EAP-Request/Identity.
    1653             :          * Re-auth sets currentId == -1, so that can be used here to select
    1654             :          * whether Identity needs to be requested again. */
    1655        2368 :         if (sm->identity == NULL || sm->currentId == -1) {
    1656        1283 :                 *vendor = EAP_VENDOR_IETF;
    1657        1283 :                 next = EAP_TYPE_IDENTITY;
    1658        1283 :                 sm->update_user = TRUE;
    1659        2170 :         } else if (sm->user && idx < EAP_MAX_METHODS &&
    1660        1883 :                    (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
    1661         798 :                     sm->user->methods[idx].method != EAP_TYPE_NONE)) {
    1662        1085 :                 *vendor = sm->user->methods[idx].vendor;
    1663        1085 :                 next = sm->user->methods[idx].method;
    1664        1085 :                 sm->user_eap_method_index++;
    1665             :         } else {
    1666           0 :                 *vendor = EAP_VENDOR_IETF;
    1667           0 :                 next = EAP_TYPE_NONE;
    1668             :         }
    1669        2368 :         wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
    1670             :                    *vendor, next);
    1671        2368 :         return next;
    1672             : }
    1673             : 
    1674             : 
    1675        4341 : static int eap_sm_Policy_getDecision(struct eap_sm *sm)
    1676             : {
    1677        4341 :         if (!sm->eap_server && sm->identity && !sm->start_reauth) {
    1678         935 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
    1679         935 :                 return DECISION_PASSTHROUGH;
    1680             :         }
    1681             : 
    1682        4382 :         if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
    1683         976 :             sm->m->isSuccess(sm, sm->eap_method_priv)) {
    1684         601 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
    1685             :                            "SUCCESS");
    1686         601 :                 sm->update_user = TRUE;
    1687         601 :                 return DECISION_SUCCESS;
    1688             :         }
    1689             : 
    1690        4193 :         if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
    1691        1388 :             !sm->m->isSuccess(sm, sm->eap_method_priv)) {
    1692         376 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
    1693             :                            "FAILURE");
    1694         376 :                 sm->update_user = TRUE;
    1695         376 :                 return DECISION_FAILURE;
    1696             :         }
    1697             : 
    1698        3444 :         if ((sm->user == NULL || sm->update_user) && sm->identity &&
    1699        1015 :             !sm->start_reauth) {
    1700             :                 /*
    1701             :                  * Allow Identity method to be started once to allow identity
    1702             :                  * selection hint to be sent from the authentication server,
    1703             :                  * but prevent a loop of Identity requests by only allowing
    1704             :                  * this to happen once.
    1705             :                  */
    1706        1015 :                 int id_req = 0;
    1707        1022 :                 if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY &&
    1708          14 :                     sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
    1709           7 :                     sm->user->methods[0].method == EAP_TYPE_IDENTITY)
    1710           0 :                         id_req = 1;
    1711        1015 :                 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
    1712           0 :                         wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
    1713             :                                    "found from database -> FAILURE");
    1714           0 :                         return DECISION_FAILURE;
    1715             :                 }
    1716        1015 :                 if (id_req && sm->user &&
    1717           0 :                     sm->user->methods[0].vendor == EAP_VENDOR_IETF &&
    1718           0 :                     sm->user->methods[0].method == EAP_TYPE_IDENTITY) {
    1719           0 :                         wpa_printf(MSG_DEBUG, "EAP: getDecision: stop "
    1720             :                                    "identity request loop -> FAILURE");
    1721           0 :                         sm->update_user = TRUE;
    1722           0 :                         return DECISION_FAILURE;
    1723             :                 }
    1724        1015 :                 sm->update_user = FALSE;
    1725             :         }
    1726        2429 :         sm->start_reauth = FALSE;
    1727             : 
    1728        3529 :         if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
    1729        1100 :             (sm->user->methods[sm->user_eap_method_index].vendor !=
    1730         813 :              EAP_VENDOR_IETF ||
    1731         813 :              sm->user->methods[sm->user_eap_method_index].method !=
    1732             :              EAP_TYPE_NONE)) {
    1733        1092 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
    1734             :                            "available -> CONTINUE");
    1735        1092 :                 return DECISION_CONTINUE;
    1736             :         }
    1737             : 
    1738        1395 :         if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
    1739          58 :             !sm->initiate_reauth_start_sent) {
    1740          39 :                 wpa_printf(MSG_DEBUG,
    1741             :                            "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
    1742          39 :                 return DECISION_INITIATE_REAUTH_START;
    1743             :         }
    1744             : 
    1745        1298 :         if (sm->identity == NULL || sm->currentId == -1) {
    1746        1290 :                 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
    1747             :                            "yet -> CONTINUE");
    1748        1290 :                 return DECISION_CONTINUE;
    1749             :         }
    1750             : 
    1751           8 :         wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
    1752             :                    "FAILURE");
    1753           8 :         return DECISION_FAILURE;
    1754             : }
    1755             : 
    1756             : 
    1757         665 : static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
    1758             : {
    1759         665 :         return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
    1760             : }
    1761             : 
    1762             : 
    1763             : /**
    1764             :  * eap_server_sm_step - Step EAP server state machine
    1765             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1766             :  * Returns: 1 if EAP state was changed or 0 if not
    1767             :  *
    1768             :  * This function advances EAP state machine to a new state to match with the
    1769             :  * current variables. This should be called whenever variables used by the EAP
    1770             :  * state machine have changed.
    1771             :  */
    1772       28727 : int eap_server_sm_step(struct eap_sm *sm)
    1773             : {
    1774       28727 :         int res = 0;
    1775             :         do {
    1776       89115 :                 sm->changed = FALSE;
    1777       89115 :                 SM_STEP_RUN(EAP);
    1778       89115 :                 if (sm->changed)
    1779       60388 :                         res = 1;
    1780       89115 :         } while (sm->changed);
    1781       28727 :         return res;
    1782             : }
    1783             : 
    1784             : 
    1785        3218 : static void eap_user_free(struct eap_user *user)
    1786             : {
    1787        3218 :         if (user == NULL)
    1788        5128 :                 return;
    1789        1308 :         bin_clear_free(user->password, user->password_len);
    1790        1308 :         user->password = NULL;
    1791        1308 :         os_free(user);
    1792             : }
    1793             : 
    1794             : 
    1795             : /**
    1796             :  * eap_server_sm_init - Allocate and initialize EAP server state machine
    1797             :  * @eapol_ctx: Context data to be used with eapol_cb calls
    1798             :  * @eapol_cb: Pointer to EAPOL callback functions
    1799             :  * @conf: EAP configuration
    1800             :  * Returns: Pointer to the allocated EAP state machine or %NULL on failure
    1801             :  *
    1802             :  * This function allocates and initializes an EAP state machine.
    1803             :  */
    1804        1905 : struct eap_sm * eap_server_sm_init(void *eapol_ctx,
    1805             :                                    struct eapol_callbacks *eapol_cb,
    1806             :                                    struct eap_config *conf)
    1807             : {
    1808             :         struct eap_sm *sm;
    1809             : 
    1810        1905 :         sm = os_zalloc(sizeof(*sm));
    1811        1905 :         if (sm == NULL)
    1812           0 :                 return NULL;
    1813        1905 :         sm->eapol_ctx = eapol_ctx;
    1814        1905 :         sm->eapol_cb = eapol_cb;
    1815        1905 :         sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */
    1816        1905 :         sm->ssl_ctx = conf->ssl_ctx;
    1817        1905 :         sm->msg_ctx = conf->msg_ctx;
    1818        1905 :         sm->eap_sim_db_priv = conf->eap_sim_db_priv;
    1819        1905 :         sm->backend_auth = conf->backend_auth;
    1820        1905 :         sm->eap_server = conf->eap_server;
    1821        1905 :         if (conf->pac_opaque_encr_key) {
    1822         680 :                 sm->pac_opaque_encr_key = os_malloc(16);
    1823         680 :                 if (sm->pac_opaque_encr_key) {
    1824         680 :                         os_memcpy(sm->pac_opaque_encr_key,
    1825             :                                   conf->pac_opaque_encr_key, 16);
    1826             :                 }
    1827             :         }
    1828        1905 :         if (conf->eap_fast_a_id) {
    1829         680 :                 sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
    1830         680 :                 if (sm->eap_fast_a_id) {
    1831         680 :                         os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id,
    1832             :                                   conf->eap_fast_a_id_len);
    1833         680 :                         sm->eap_fast_a_id_len = conf->eap_fast_a_id_len;
    1834             :                 }
    1835             :         }
    1836        1905 :         if (conf->eap_fast_a_id_info)
    1837         680 :                 sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
    1838        1905 :         sm->eap_fast_prov = conf->eap_fast_prov;
    1839        1905 :         sm->pac_key_lifetime = conf->pac_key_lifetime;
    1840        1905 :         sm->pac_key_refresh_time = conf->pac_key_refresh_time;
    1841        1905 :         sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
    1842        1905 :         sm->tnc = conf->tnc;
    1843        1905 :         sm->wps = conf->wps;
    1844        1905 :         if (conf->assoc_wps_ie)
    1845         280 :                 sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie);
    1846        1905 :         if (conf->assoc_p2p_ie)
    1847         166 :                 sm->assoc_p2p_ie = wpabuf_dup(conf->assoc_p2p_ie);
    1848        1905 :         if (conf->peer_addr)
    1849        1222 :                 os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN);
    1850        1905 :         sm->fragment_size = conf->fragment_size;
    1851        1905 :         sm->pwd_group = conf->pwd_group;
    1852        1905 :         sm->pbc_in_m1 = conf->pbc_in_m1;
    1853        1905 :         sm->server_id = conf->server_id;
    1854        1905 :         sm->server_id_len = conf->server_id_len;
    1855        1905 :         sm->erp = conf->erp;
    1856             : 
    1857             : #ifdef CONFIG_TESTING_OPTIONS
    1858        1905 :         sm->tls_test_flags = conf->tls_test_flags;
    1859             : #endif /* CONFIG_TESTING_OPTIONS */
    1860             : 
    1861        1905 :         wpa_printf(MSG_DEBUG, "EAP: Server state machine created");
    1862             : 
    1863        1905 :         return sm;
    1864             : }
    1865             : 
    1866             : 
    1867             : /**
    1868             :  * eap_server_sm_deinit - Deinitialize and free an EAP server state machine
    1869             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1870             :  *
    1871             :  * This function deinitializes EAP state machine and frees all allocated
    1872             :  * resources.
    1873             :  */
    1874        1905 : void eap_server_sm_deinit(struct eap_sm *sm)
    1875             : {
    1876        1905 :         if (sm == NULL)
    1877        1905 :                 return;
    1878        1905 :         wpa_printf(MSG_DEBUG, "EAP: Server state machine removed");
    1879        1905 :         if (sm->m && sm->eap_method_priv)
    1880        1827 :                 sm->m->reset(sm, sm->eap_method_priv);
    1881        1905 :         wpabuf_free(sm->eap_if.eapReqData);
    1882        1905 :         bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
    1883        1905 :         os_free(sm->eap_if.eapSessionId);
    1884        1905 :         wpabuf_free(sm->lastReqData);
    1885        1905 :         wpabuf_free(sm->eap_if.eapRespData);
    1886        1905 :         os_free(sm->identity);
    1887        1905 :         os_free(sm->pac_opaque_encr_key);
    1888        1905 :         os_free(sm->eap_fast_a_id);
    1889        1905 :         os_free(sm->eap_fast_a_id_info);
    1890        1905 :         wpabuf_free(sm->eap_if.aaaEapReqData);
    1891        1905 :         wpabuf_free(sm->eap_if.aaaEapRespData);
    1892        1905 :         bin_clear_free(sm->eap_if.aaaEapKeyData, sm->eap_if.aaaEapKeyDataLen);
    1893        1905 :         eap_user_free(sm->user);
    1894        1905 :         wpabuf_free(sm->assoc_wps_ie);
    1895        1905 :         wpabuf_free(sm->assoc_p2p_ie);
    1896        1905 :         os_free(sm);
    1897             : }
    1898             : 
    1899             : 
    1900             : /**
    1901             :  * eap_sm_notify_cached - Notify EAP state machine of cached PMK
    1902             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1903             :  *
    1904             :  * This function is called when PMKSA caching is used to skip EAP
    1905             :  * authentication.
    1906             :  */
    1907          33 : void eap_sm_notify_cached(struct eap_sm *sm)
    1908             : {
    1909          33 :         if (sm == NULL)
    1910          33 :                 return;
    1911             : 
    1912          33 :         sm->EAP_state = EAP_SUCCESS;
    1913             : }
    1914             : 
    1915             : 
    1916             : /**
    1917             :  * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
    1918             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1919             :  *
    1920             :  * This function is called when data for a pending EAP-Request is received.
    1921             :  */
    1922         108 : void eap_sm_pending_cb(struct eap_sm *sm)
    1923             : {
    1924         108 :         if (sm == NULL)
    1925         108 :                 return;
    1926         108 :         wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
    1927         108 :         if (sm->method_pending == METHOD_PENDING_WAIT)
    1928         108 :                 sm->method_pending = METHOD_PENDING_CONT;
    1929             : }
    1930             : 
    1931             : 
    1932             : /**
    1933             :  * eap_sm_method_pending - Query whether EAP method is waiting for pending data
    1934             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1935             :  * Returns: 1 if method is waiting for pending data or 0 if not
    1936             :  */
    1937          82 : int eap_sm_method_pending(struct eap_sm *sm)
    1938             : {
    1939          82 :         if (sm == NULL)
    1940           0 :                 return 0;
    1941          82 :         return sm->method_pending == METHOD_PENDING_WAIT;
    1942             : }
    1943             : 
    1944             : 
    1945             : /**
    1946             :  * eap_get_identity - Get the user identity (from EAP-Response/Identity)
    1947             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1948             :  * @len: Buffer for returning identity length
    1949             :  * Returns: Pointer to the user identity or %NULL if not available
    1950             :  */
    1951         934 : const u8 * eap_get_identity(struct eap_sm *sm, size_t *len)
    1952             : {
    1953         934 :         *len = sm->identity_len;
    1954         934 :         return sm->identity;
    1955             : }
    1956             : 
    1957             : 
    1958             : /**
    1959             :  * eap_get_interface - Get pointer to EAP-EAPOL interface data
    1960             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1961             :  * Returns: Pointer to the EAP-EAPOL interface data
    1962             :  */
    1963        1905 : struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm)
    1964             : {
    1965        1905 :         return &sm->eap_if;
    1966             : }
    1967             : 
    1968             : 
    1969             : /**
    1970             :  * eap_server_clear_identity - Clear EAP identity information
    1971             :  * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
    1972             :  *
    1973             :  * This function can be used to clear the EAP identity information in the EAP
    1974             :  * server context. This allows the EAP/Identity method to be used again after
    1975             :  * EAPOL-Start or EAPOL-Logoff.
    1976             :  */
    1977         141 : void eap_server_clear_identity(struct eap_sm *sm)
    1978             : {
    1979         141 :         os_free(sm->identity);
    1980         141 :         sm->identity = NULL;
    1981         141 : }

Generated by: LCOV version 1.10