1214501Srpaulo/* 2214501Srpaulo * hostapd / EAP Full Authenticator state machine (RFC 4137) 3214501Srpaulo * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> 4214501Srpaulo * 5214501Srpaulo * This program is free software; you can redistribute it and/or modify 6214501Srpaulo * it under the terms of the GNU General Public License version 2 as 7214501Srpaulo * published by the Free Software Foundation. 8214501Srpaulo * 9214501Srpaulo * Alternatively, this software may be distributed under the terms of BSD 10214501Srpaulo * license. 11214501Srpaulo * 12214501Srpaulo * See README and COPYING for more details. 13214501Srpaulo * 14214501Srpaulo * This state machine is based on the full authenticator state machine defined 15214501Srpaulo * in RFC 4137. However, to support backend authentication in RADIUS 16214501Srpaulo * authentication server functionality, parts of backend authenticator (also 17214501Srpaulo * from RFC 4137) are mixed in. This functionality is enabled by setting 18214501Srpaulo * backend_auth configuration variable to TRUE. 19214501Srpaulo */ 20214501Srpaulo 21214501Srpaulo#include "includes.h" 22214501Srpaulo 23214501Srpaulo#include "common.h" 24214501Srpaulo#include "eap_i.h" 25214501Srpaulo#include "state_machine.h" 26214501Srpaulo#include "common/wpa_ctrl.h" 27214501Srpaulo 28214501Srpaulo#define STATE_MACHINE_DATA struct eap_sm 29214501Srpaulo#define STATE_MACHINE_DEBUG_PREFIX "EAP" 30214501Srpaulo 31214501Srpaulo#define EAP_MAX_AUTH_ROUNDS 50 32214501Srpaulo 33214501Srpaulostatic void eap_user_free(struct eap_user *user); 34214501Srpaulo 35214501Srpaulo 36214501Srpaulo/* EAP state machines are described in RFC 4137 */ 37214501Srpaulo 38214501Srpaulostatic int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 39214501Srpaulo int eapSRTT, int eapRTTVAR, 40214501Srpaulo int methodTimeout); 41214501Srpaulostatic void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp); 42214501Srpaulostatic int eap_sm_getId(const struct wpabuf *data); 43214501Srpaulostatic struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id); 44214501Srpaulostatic struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id); 45214501Srpaulostatic int eap_sm_nextId(struct eap_sm *sm, int id); 46214501Srpaulostatic void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 47214501Srpaulo size_t len); 48214501Srpaulostatic EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor); 49214501Srpaulostatic int eap_sm_Policy_getDecision(struct eap_sm *sm); 50214501Srpaulostatic Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method); 51214501Srpaulo 52214501Srpaulo 53214501Srpaulostatic int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src) 54214501Srpaulo{ 55214501Srpaulo if (src == NULL) 56214501Srpaulo return -1; 57214501Srpaulo 58214501Srpaulo wpabuf_free(*dst); 59214501Srpaulo *dst = wpabuf_dup(src); 60214501Srpaulo return *dst ? 0 : -1; 61214501Srpaulo} 62214501Srpaulo 63214501Srpaulo 64214501Srpaulostatic int eap_copy_data(u8 **dst, size_t *dst_len, 65214501Srpaulo const u8 *src, size_t src_len) 66214501Srpaulo{ 67214501Srpaulo if (src == NULL) 68214501Srpaulo return -1; 69214501Srpaulo 70214501Srpaulo os_free(*dst); 71214501Srpaulo *dst = os_malloc(src_len); 72214501Srpaulo if (*dst) { 73214501Srpaulo os_memcpy(*dst, src, src_len); 74214501Srpaulo *dst_len = src_len; 75214501Srpaulo return 0; 76214501Srpaulo } else { 77214501Srpaulo *dst_len = 0; 78214501Srpaulo return -1; 79214501Srpaulo } 80214501Srpaulo} 81214501Srpaulo 82214501Srpaulo#define EAP_COPY(dst, src) \ 83214501Srpaulo eap_copy_data((dst), (dst ## Len), (src), (src ## Len)) 84214501Srpaulo 85214501Srpaulo 86214501Srpaulo/** 87214501Srpaulo * eap_user_get - Fetch user information from the database 88214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 89214501Srpaulo * @identity: Identity (User-Name) of the user 90214501Srpaulo * @identity_len: Length of identity in bytes 91214501Srpaulo * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user 92214501Srpaulo * Returns: 0 on success, or -1 on failure 93214501Srpaulo * 94214501Srpaulo * This function is used to fetch user information for EAP. The user will be 95214501Srpaulo * selected based on the specified identity. sm->user and 96214501Srpaulo * sm->user_eap_method_index are updated for the new user when a matching user 97214501Srpaulo * is found. sm->user can be used to get user information (e.g., password). 98214501Srpaulo */ 99214501Srpauloint eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len, 100214501Srpaulo int phase2) 101214501Srpaulo{ 102214501Srpaulo struct eap_user *user; 103214501Srpaulo 104214501Srpaulo if (sm == NULL || sm->eapol_cb == NULL || 105214501Srpaulo sm->eapol_cb->get_eap_user == NULL) 106214501Srpaulo return -1; 107214501Srpaulo 108214501Srpaulo eap_user_free(sm->user); 109214501Srpaulo sm->user = NULL; 110214501Srpaulo 111214501Srpaulo user = os_zalloc(sizeof(*user)); 112214501Srpaulo if (user == NULL) 113214501Srpaulo return -1; 114214501Srpaulo 115214501Srpaulo if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity, 116214501Srpaulo identity_len, phase2, user) != 0) { 117214501Srpaulo eap_user_free(user); 118214501Srpaulo return -1; 119214501Srpaulo } 120214501Srpaulo 121214501Srpaulo sm->user = user; 122214501Srpaulo sm->user_eap_method_index = 0; 123214501Srpaulo 124214501Srpaulo return 0; 125214501Srpaulo} 126214501Srpaulo 127214501Srpaulo 128214501SrpauloSM_STATE(EAP, DISABLED) 129214501Srpaulo{ 130214501Srpaulo SM_ENTRY(EAP, DISABLED); 131214501Srpaulo sm->num_rounds = 0; 132214501Srpaulo} 133214501Srpaulo 134214501Srpaulo 135214501SrpauloSM_STATE(EAP, INITIALIZE) 136214501Srpaulo{ 137214501Srpaulo SM_ENTRY(EAP, INITIALIZE); 138214501Srpaulo 139214501Srpaulo sm->currentId = -1; 140214501Srpaulo sm->eap_if.eapSuccess = FALSE; 141214501Srpaulo sm->eap_if.eapFail = FALSE; 142214501Srpaulo sm->eap_if.eapTimeout = FALSE; 143214501Srpaulo os_free(sm->eap_if.eapKeyData); 144214501Srpaulo sm->eap_if.eapKeyData = NULL; 145214501Srpaulo sm->eap_if.eapKeyDataLen = 0; 146214501Srpaulo sm->eap_if.eapKeyAvailable = FALSE; 147214501Srpaulo sm->eap_if.eapRestart = FALSE; 148214501Srpaulo 149214501Srpaulo /* 150214501Srpaulo * This is not defined in RFC 4137, but method state needs to be 151214501Srpaulo * reseted here so that it does not remain in success state when 152214501Srpaulo * re-authentication starts. 153214501Srpaulo */ 154214501Srpaulo if (sm->m && sm->eap_method_priv) { 155214501Srpaulo sm->m->reset(sm, sm->eap_method_priv); 156214501Srpaulo sm->eap_method_priv = NULL; 157214501Srpaulo } 158214501Srpaulo sm->m = NULL; 159214501Srpaulo sm->user_eap_method_index = 0; 160214501Srpaulo 161214501Srpaulo if (sm->backend_auth) { 162214501Srpaulo sm->currentMethod = EAP_TYPE_NONE; 163214501Srpaulo /* parse rxResp, respId, respMethod */ 164214501Srpaulo eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 165214501Srpaulo if (sm->rxResp) { 166214501Srpaulo sm->currentId = sm->respId; 167214501Srpaulo } 168214501Srpaulo } 169214501Srpaulo sm->num_rounds = 0; 170214501Srpaulo sm->method_pending = METHOD_PENDING_NONE; 171214501Srpaulo 172214501Srpaulo wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED 173214501Srpaulo MACSTR, MAC2STR(sm->peer_addr)); 174214501Srpaulo} 175214501Srpaulo 176214501Srpaulo 177214501SrpauloSM_STATE(EAP, PICK_UP_METHOD) 178214501Srpaulo{ 179214501Srpaulo SM_ENTRY(EAP, PICK_UP_METHOD); 180214501Srpaulo 181214501Srpaulo if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) { 182214501Srpaulo sm->currentMethod = sm->respMethod; 183214501Srpaulo if (sm->m && sm->eap_method_priv) { 184214501Srpaulo sm->m->reset(sm, sm->eap_method_priv); 185214501Srpaulo sm->eap_method_priv = NULL; 186214501Srpaulo } 187214501Srpaulo sm->m = eap_server_get_eap_method(EAP_VENDOR_IETF, 188214501Srpaulo sm->currentMethod); 189214501Srpaulo if (sm->m && sm->m->initPickUp) { 190214501Srpaulo sm->eap_method_priv = sm->m->initPickUp(sm); 191214501Srpaulo if (sm->eap_method_priv == NULL) { 192214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Failed to " 193214501Srpaulo "initialize EAP method %d", 194214501Srpaulo sm->currentMethod); 195214501Srpaulo sm->m = NULL; 196214501Srpaulo sm->currentMethod = EAP_TYPE_NONE; 197214501Srpaulo } 198214501Srpaulo } else { 199214501Srpaulo sm->m = NULL; 200214501Srpaulo sm->currentMethod = EAP_TYPE_NONE; 201214501Srpaulo } 202214501Srpaulo } 203214501Srpaulo 204214501Srpaulo wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 205214501Srpaulo "method=%u", sm->currentMethod); 206214501Srpaulo} 207214501Srpaulo 208214501Srpaulo 209214501SrpauloSM_STATE(EAP, IDLE) 210214501Srpaulo{ 211214501Srpaulo SM_ENTRY(EAP, IDLE); 212214501Srpaulo 213214501Srpaulo sm->eap_if.retransWhile = eap_sm_calculateTimeout( 214214501Srpaulo sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 215214501Srpaulo sm->methodTimeout); 216214501Srpaulo} 217214501Srpaulo 218214501Srpaulo 219214501SrpauloSM_STATE(EAP, RETRANSMIT) 220214501Srpaulo{ 221214501Srpaulo SM_ENTRY(EAP, RETRANSMIT); 222214501Srpaulo 223214501Srpaulo sm->retransCount++; 224214501Srpaulo if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 225214501Srpaulo if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 226214501Srpaulo sm->eap_if.eapReq = TRUE; 227214501Srpaulo } 228214501Srpaulo} 229214501Srpaulo 230214501Srpaulo 231214501SrpauloSM_STATE(EAP, RECEIVED) 232214501Srpaulo{ 233214501Srpaulo SM_ENTRY(EAP, RECEIVED); 234214501Srpaulo 235214501Srpaulo /* parse rxResp, respId, respMethod */ 236214501Srpaulo eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 237214501Srpaulo sm->num_rounds++; 238214501Srpaulo} 239214501Srpaulo 240214501Srpaulo 241214501SrpauloSM_STATE(EAP, DISCARD) 242214501Srpaulo{ 243214501Srpaulo SM_ENTRY(EAP, DISCARD); 244214501Srpaulo sm->eap_if.eapResp = FALSE; 245214501Srpaulo sm->eap_if.eapNoReq = TRUE; 246214501Srpaulo} 247214501Srpaulo 248214501Srpaulo 249214501SrpauloSM_STATE(EAP, SEND_REQUEST) 250214501Srpaulo{ 251214501Srpaulo SM_ENTRY(EAP, SEND_REQUEST); 252214501Srpaulo 253214501Srpaulo sm->retransCount = 0; 254214501Srpaulo if (sm->eap_if.eapReqData) { 255214501Srpaulo if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 256214501Srpaulo { 257214501Srpaulo sm->eap_if.eapResp = FALSE; 258214501Srpaulo sm->eap_if.eapReq = TRUE; 259214501Srpaulo } else { 260214501Srpaulo sm->eap_if.eapResp = FALSE; 261214501Srpaulo sm->eap_if.eapReq = FALSE; 262214501Srpaulo } 263214501Srpaulo } else { 264214501Srpaulo wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData"); 265214501Srpaulo sm->eap_if.eapResp = FALSE; 266214501Srpaulo sm->eap_if.eapReq = FALSE; 267214501Srpaulo sm->eap_if.eapNoReq = TRUE; 268214501Srpaulo } 269214501Srpaulo} 270214501Srpaulo 271214501Srpaulo 272214501SrpauloSM_STATE(EAP, INTEGRITY_CHECK) 273214501Srpaulo{ 274214501Srpaulo SM_ENTRY(EAP, INTEGRITY_CHECK); 275214501Srpaulo 276214501Srpaulo if (sm->m->check) { 277214501Srpaulo sm->ignore = sm->m->check(sm, sm->eap_method_priv, 278214501Srpaulo sm->eap_if.eapRespData); 279214501Srpaulo } 280214501Srpaulo} 281214501Srpaulo 282214501Srpaulo 283214501SrpauloSM_STATE(EAP, METHOD_REQUEST) 284214501Srpaulo{ 285214501Srpaulo SM_ENTRY(EAP, METHOD_REQUEST); 286214501Srpaulo 287214501Srpaulo if (sm->m == NULL) { 288214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: method not initialized"); 289214501Srpaulo return; 290214501Srpaulo } 291214501Srpaulo 292214501Srpaulo sm->currentId = eap_sm_nextId(sm, sm->currentId); 293214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d", 294214501Srpaulo sm->currentId); 295214501Srpaulo sm->lastId = sm->currentId; 296214501Srpaulo wpabuf_free(sm->eap_if.eapReqData); 297214501Srpaulo sm->eap_if.eapReqData = sm->m->buildReq(sm, sm->eap_method_priv, 298214501Srpaulo sm->currentId); 299214501Srpaulo if (sm->m->getTimeout) 300214501Srpaulo sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv); 301214501Srpaulo else 302214501Srpaulo sm->methodTimeout = 0; 303214501Srpaulo} 304214501Srpaulo 305214501Srpaulo 306214501SrpauloSM_STATE(EAP, METHOD_RESPONSE) 307214501Srpaulo{ 308214501Srpaulo SM_ENTRY(EAP, METHOD_RESPONSE); 309214501Srpaulo 310214501Srpaulo sm->m->process(sm, sm->eap_method_priv, sm->eap_if.eapRespData); 311214501Srpaulo if (sm->m->isDone(sm, sm->eap_method_priv)) { 312214501Srpaulo eap_sm_Policy_update(sm, NULL, 0); 313214501Srpaulo os_free(sm->eap_if.eapKeyData); 314214501Srpaulo if (sm->m->getKey) { 315214501Srpaulo sm->eap_if.eapKeyData = sm->m->getKey( 316214501Srpaulo sm, sm->eap_method_priv, 317214501Srpaulo &sm->eap_if.eapKeyDataLen); 318214501Srpaulo } else { 319214501Srpaulo sm->eap_if.eapKeyData = NULL; 320214501Srpaulo sm->eap_if.eapKeyDataLen = 0; 321214501Srpaulo } 322214501Srpaulo sm->methodState = METHOD_END; 323214501Srpaulo } else { 324214501Srpaulo sm->methodState = METHOD_CONTINUE; 325214501Srpaulo } 326214501Srpaulo} 327214501Srpaulo 328214501Srpaulo 329214501SrpauloSM_STATE(EAP, PROPOSE_METHOD) 330214501Srpaulo{ 331214501Srpaulo int vendor; 332214501Srpaulo EapType type; 333214501Srpaulo 334214501Srpaulo SM_ENTRY(EAP, PROPOSE_METHOD); 335214501Srpaulo 336214501Srpaulo type = eap_sm_Policy_getNextMethod(sm, &vendor); 337214501Srpaulo if (vendor == EAP_VENDOR_IETF) 338214501Srpaulo sm->currentMethod = type; 339214501Srpaulo else 340214501Srpaulo sm->currentMethod = EAP_TYPE_EXPANDED; 341214501Srpaulo if (sm->m && sm->eap_method_priv) { 342214501Srpaulo sm->m->reset(sm, sm->eap_method_priv); 343214501Srpaulo sm->eap_method_priv = NULL; 344214501Srpaulo } 345214501Srpaulo sm->m = eap_server_get_eap_method(vendor, type); 346214501Srpaulo if (sm->m) { 347214501Srpaulo sm->eap_method_priv = sm->m->init(sm); 348214501Srpaulo if (sm->eap_method_priv == NULL) { 349214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP " 350214501Srpaulo "method %d", sm->currentMethod); 351214501Srpaulo sm->m = NULL; 352214501Srpaulo sm->currentMethod = EAP_TYPE_NONE; 353214501Srpaulo } 354214501Srpaulo } 355214501Srpaulo if (sm->currentMethod == EAP_TYPE_IDENTITY || 356214501Srpaulo sm->currentMethod == EAP_TYPE_NOTIFICATION) 357214501Srpaulo sm->methodState = METHOD_CONTINUE; 358214501Srpaulo else 359214501Srpaulo sm->methodState = METHOD_PROPOSED; 360214501Srpaulo 361214501Srpaulo wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD 362214501Srpaulo "vendor=%u method=%u", vendor, sm->currentMethod); 363214501Srpaulo} 364214501Srpaulo 365214501Srpaulo 366214501SrpauloSM_STATE(EAP, NAK) 367214501Srpaulo{ 368214501Srpaulo const struct eap_hdr *nak; 369214501Srpaulo size_t len = 0; 370214501Srpaulo const u8 *pos; 371214501Srpaulo const u8 *nak_list = NULL; 372214501Srpaulo 373214501Srpaulo SM_ENTRY(EAP, NAK); 374214501Srpaulo 375214501Srpaulo if (sm->eap_method_priv) { 376214501Srpaulo sm->m->reset(sm, sm->eap_method_priv); 377214501Srpaulo sm->eap_method_priv = NULL; 378214501Srpaulo } 379214501Srpaulo sm->m = NULL; 380214501Srpaulo 381214501Srpaulo nak = wpabuf_head(sm->eap_if.eapRespData); 382214501Srpaulo if (nak && wpabuf_len(sm->eap_if.eapRespData) > sizeof(*nak)) { 383214501Srpaulo len = be_to_host16(nak->length); 384214501Srpaulo if (len > wpabuf_len(sm->eap_if.eapRespData)) 385214501Srpaulo len = wpabuf_len(sm->eap_if.eapRespData); 386214501Srpaulo pos = (const u8 *) (nak + 1); 387214501Srpaulo len -= sizeof(*nak); 388214501Srpaulo if (*pos == EAP_TYPE_NAK) { 389214501Srpaulo pos++; 390214501Srpaulo len--; 391214501Srpaulo nak_list = pos; 392214501Srpaulo } 393214501Srpaulo } 394214501Srpaulo eap_sm_Policy_update(sm, nak_list, len); 395214501Srpaulo} 396214501Srpaulo 397214501Srpaulo 398214501SrpauloSM_STATE(EAP, SELECT_ACTION) 399214501Srpaulo{ 400214501Srpaulo SM_ENTRY(EAP, SELECT_ACTION); 401214501Srpaulo 402214501Srpaulo sm->decision = eap_sm_Policy_getDecision(sm); 403214501Srpaulo} 404214501Srpaulo 405214501Srpaulo 406214501SrpauloSM_STATE(EAP, TIMEOUT_FAILURE) 407214501Srpaulo{ 408214501Srpaulo SM_ENTRY(EAP, TIMEOUT_FAILURE); 409214501Srpaulo 410214501Srpaulo sm->eap_if.eapTimeout = TRUE; 411214501Srpaulo} 412214501Srpaulo 413214501Srpaulo 414214501SrpauloSM_STATE(EAP, FAILURE) 415214501Srpaulo{ 416214501Srpaulo SM_ENTRY(EAP, FAILURE); 417214501Srpaulo 418214501Srpaulo wpabuf_free(sm->eap_if.eapReqData); 419214501Srpaulo sm->eap_if.eapReqData = eap_sm_buildFailure(sm, sm->currentId); 420214501Srpaulo wpabuf_free(sm->lastReqData); 421214501Srpaulo sm->lastReqData = NULL; 422214501Srpaulo sm->eap_if.eapFail = TRUE; 423214501Srpaulo 424214501Srpaulo wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE 425214501Srpaulo MACSTR, MAC2STR(sm->peer_addr)); 426214501Srpaulo} 427214501Srpaulo 428214501Srpaulo 429214501SrpauloSM_STATE(EAP, SUCCESS) 430214501Srpaulo{ 431214501Srpaulo SM_ENTRY(EAP, SUCCESS); 432214501Srpaulo 433214501Srpaulo wpabuf_free(sm->eap_if.eapReqData); 434214501Srpaulo sm->eap_if.eapReqData = eap_sm_buildSuccess(sm, sm->currentId); 435214501Srpaulo wpabuf_free(sm->lastReqData); 436214501Srpaulo sm->lastReqData = NULL; 437214501Srpaulo if (sm->eap_if.eapKeyData) 438214501Srpaulo sm->eap_if.eapKeyAvailable = TRUE; 439214501Srpaulo sm->eap_if.eapSuccess = TRUE; 440214501Srpaulo 441214501Srpaulo wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS 442214501Srpaulo MACSTR, MAC2STR(sm->peer_addr)); 443214501Srpaulo} 444214501Srpaulo 445214501Srpaulo 446214501SrpauloSM_STATE(EAP, INITIALIZE_PASSTHROUGH) 447214501Srpaulo{ 448214501Srpaulo SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH); 449214501Srpaulo 450214501Srpaulo wpabuf_free(sm->eap_if.aaaEapRespData); 451214501Srpaulo sm->eap_if.aaaEapRespData = NULL; 452214501Srpaulo} 453214501Srpaulo 454214501Srpaulo 455214501SrpauloSM_STATE(EAP, IDLE2) 456214501Srpaulo{ 457214501Srpaulo SM_ENTRY(EAP, IDLE2); 458214501Srpaulo 459214501Srpaulo sm->eap_if.retransWhile = eap_sm_calculateTimeout( 460214501Srpaulo sm, sm->retransCount, sm->eap_if.eapSRTT, sm->eap_if.eapRTTVAR, 461214501Srpaulo sm->methodTimeout); 462214501Srpaulo} 463214501Srpaulo 464214501Srpaulo 465214501SrpauloSM_STATE(EAP, RETRANSMIT2) 466214501Srpaulo{ 467214501Srpaulo SM_ENTRY(EAP, RETRANSMIT2); 468214501Srpaulo 469214501Srpaulo sm->retransCount++; 470214501Srpaulo if (sm->retransCount <= sm->MaxRetrans && sm->lastReqData) { 471214501Srpaulo if (eap_copy_buf(&sm->eap_if.eapReqData, sm->lastReqData) == 0) 472214501Srpaulo sm->eap_if.eapReq = TRUE; 473214501Srpaulo } 474214501Srpaulo} 475214501Srpaulo 476214501Srpaulo 477214501SrpauloSM_STATE(EAP, RECEIVED2) 478214501Srpaulo{ 479214501Srpaulo SM_ENTRY(EAP, RECEIVED2); 480214501Srpaulo 481214501Srpaulo /* parse rxResp, respId, respMethod */ 482214501Srpaulo eap_sm_parseEapResp(sm, sm->eap_if.eapRespData); 483214501Srpaulo} 484214501Srpaulo 485214501Srpaulo 486214501SrpauloSM_STATE(EAP, DISCARD2) 487214501Srpaulo{ 488214501Srpaulo SM_ENTRY(EAP, DISCARD2); 489214501Srpaulo sm->eap_if.eapResp = FALSE; 490214501Srpaulo sm->eap_if.eapNoReq = TRUE; 491214501Srpaulo} 492214501Srpaulo 493214501Srpaulo 494214501SrpauloSM_STATE(EAP, SEND_REQUEST2) 495214501Srpaulo{ 496214501Srpaulo SM_ENTRY(EAP, SEND_REQUEST2); 497214501Srpaulo 498214501Srpaulo sm->retransCount = 0; 499214501Srpaulo if (sm->eap_if.eapReqData) { 500214501Srpaulo if (eap_copy_buf(&sm->lastReqData, sm->eap_if.eapReqData) == 0) 501214501Srpaulo { 502214501Srpaulo sm->eap_if.eapResp = FALSE; 503214501Srpaulo sm->eap_if.eapReq = TRUE; 504214501Srpaulo } else { 505214501Srpaulo sm->eap_if.eapResp = FALSE; 506214501Srpaulo sm->eap_if.eapReq = FALSE; 507214501Srpaulo } 508214501Srpaulo } else { 509214501Srpaulo wpa_printf(MSG_INFO, "EAP: SEND_REQUEST2 - no eapReqData"); 510214501Srpaulo sm->eap_if.eapResp = FALSE; 511214501Srpaulo sm->eap_if.eapReq = FALSE; 512214501Srpaulo sm->eap_if.eapNoReq = TRUE; 513214501Srpaulo } 514214501Srpaulo} 515214501Srpaulo 516214501Srpaulo 517214501SrpauloSM_STATE(EAP, AAA_REQUEST) 518214501Srpaulo{ 519214501Srpaulo SM_ENTRY(EAP, AAA_REQUEST); 520214501Srpaulo 521214501Srpaulo if (sm->eap_if.eapRespData == NULL) { 522214501Srpaulo wpa_printf(MSG_INFO, "EAP: AAA_REQUEST - no eapRespData"); 523214501Srpaulo return; 524214501Srpaulo } 525214501Srpaulo 526214501Srpaulo /* 527214501Srpaulo * if (respMethod == IDENTITY) 528214501Srpaulo * aaaIdentity = eapRespData 529214501Srpaulo * This is already taken care of by the EAP-Identity method which 530214501Srpaulo * stores the identity into sm->identity. 531214501Srpaulo */ 532214501Srpaulo 533214501Srpaulo eap_copy_buf(&sm->eap_if.aaaEapRespData, sm->eap_if.eapRespData); 534214501Srpaulo} 535214501Srpaulo 536214501Srpaulo 537214501SrpauloSM_STATE(EAP, AAA_RESPONSE) 538214501Srpaulo{ 539214501Srpaulo SM_ENTRY(EAP, AAA_RESPONSE); 540214501Srpaulo 541214501Srpaulo eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 542214501Srpaulo sm->currentId = eap_sm_getId(sm->eap_if.eapReqData); 543214501Srpaulo sm->methodTimeout = sm->eap_if.aaaMethodTimeout; 544214501Srpaulo} 545214501Srpaulo 546214501Srpaulo 547214501SrpauloSM_STATE(EAP, AAA_IDLE) 548214501Srpaulo{ 549214501Srpaulo SM_ENTRY(EAP, AAA_IDLE); 550214501Srpaulo 551214501Srpaulo sm->eap_if.aaaFail = FALSE; 552214501Srpaulo sm->eap_if.aaaSuccess = FALSE; 553214501Srpaulo sm->eap_if.aaaEapReq = FALSE; 554214501Srpaulo sm->eap_if.aaaEapNoReq = FALSE; 555214501Srpaulo sm->eap_if.aaaEapResp = TRUE; 556214501Srpaulo} 557214501Srpaulo 558214501Srpaulo 559214501SrpauloSM_STATE(EAP, TIMEOUT_FAILURE2) 560214501Srpaulo{ 561214501Srpaulo SM_ENTRY(EAP, TIMEOUT_FAILURE2); 562214501Srpaulo 563214501Srpaulo sm->eap_if.eapTimeout = TRUE; 564214501Srpaulo} 565214501Srpaulo 566214501Srpaulo 567214501SrpauloSM_STATE(EAP, FAILURE2) 568214501Srpaulo{ 569214501Srpaulo SM_ENTRY(EAP, FAILURE2); 570214501Srpaulo 571214501Srpaulo eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 572214501Srpaulo sm->eap_if.eapFail = TRUE; 573214501Srpaulo} 574214501Srpaulo 575214501Srpaulo 576214501SrpauloSM_STATE(EAP, SUCCESS2) 577214501Srpaulo{ 578214501Srpaulo SM_ENTRY(EAP, SUCCESS2); 579214501Srpaulo 580214501Srpaulo eap_copy_buf(&sm->eap_if.eapReqData, sm->eap_if.aaaEapReqData); 581214501Srpaulo 582214501Srpaulo sm->eap_if.eapKeyAvailable = sm->eap_if.aaaEapKeyAvailable; 583214501Srpaulo if (sm->eap_if.aaaEapKeyAvailable) { 584214501Srpaulo EAP_COPY(&sm->eap_if.eapKeyData, sm->eap_if.aaaEapKeyData); 585214501Srpaulo } else { 586214501Srpaulo os_free(sm->eap_if.eapKeyData); 587214501Srpaulo sm->eap_if.eapKeyData = NULL; 588214501Srpaulo sm->eap_if.eapKeyDataLen = 0; 589214501Srpaulo } 590214501Srpaulo 591214501Srpaulo sm->eap_if.eapSuccess = TRUE; 592214501Srpaulo 593214501Srpaulo /* 594214501Srpaulo * Start reauthentication with identity request even though we know the 595214501Srpaulo * previously used identity. This is needed to get reauthentication 596214501Srpaulo * started properly. 597214501Srpaulo */ 598214501Srpaulo sm->start_reauth = TRUE; 599214501Srpaulo} 600214501Srpaulo 601214501Srpaulo 602214501SrpauloSM_STEP(EAP) 603214501Srpaulo{ 604214501Srpaulo if (sm->eap_if.eapRestart && sm->eap_if.portEnabled) 605214501Srpaulo SM_ENTER_GLOBAL(EAP, INITIALIZE); 606214501Srpaulo else if (!sm->eap_if.portEnabled) 607214501Srpaulo SM_ENTER_GLOBAL(EAP, DISABLED); 608214501Srpaulo else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) { 609214501Srpaulo if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) { 610214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: more than %d " 611214501Srpaulo "authentication rounds - abort", 612214501Srpaulo EAP_MAX_AUTH_ROUNDS); 613214501Srpaulo sm->num_rounds++; 614214501Srpaulo SM_ENTER_GLOBAL(EAP, FAILURE); 615214501Srpaulo } 616214501Srpaulo } else switch (sm->EAP_state) { 617214501Srpaulo case EAP_INITIALIZE: 618214501Srpaulo if (sm->backend_auth) { 619214501Srpaulo if (!sm->rxResp) 620214501Srpaulo SM_ENTER(EAP, SELECT_ACTION); 621214501Srpaulo else if (sm->rxResp && 622214501Srpaulo (sm->respMethod == EAP_TYPE_NAK || 623214501Srpaulo (sm->respMethod == EAP_TYPE_EXPANDED && 624214501Srpaulo sm->respVendor == EAP_VENDOR_IETF && 625214501Srpaulo sm->respVendorMethod == EAP_TYPE_NAK))) 626214501Srpaulo SM_ENTER(EAP, NAK); 627214501Srpaulo else 628214501Srpaulo SM_ENTER(EAP, PICK_UP_METHOD); 629214501Srpaulo } else { 630214501Srpaulo SM_ENTER(EAP, SELECT_ACTION); 631214501Srpaulo } 632214501Srpaulo break; 633214501Srpaulo case EAP_PICK_UP_METHOD: 634214501Srpaulo if (sm->currentMethod == EAP_TYPE_NONE) { 635214501Srpaulo SM_ENTER(EAP, SELECT_ACTION); 636214501Srpaulo } else { 637214501Srpaulo SM_ENTER(EAP, METHOD_RESPONSE); 638214501Srpaulo } 639214501Srpaulo break; 640214501Srpaulo case EAP_DISABLED: 641214501Srpaulo if (sm->eap_if.portEnabled) 642214501Srpaulo SM_ENTER(EAP, INITIALIZE); 643214501Srpaulo break; 644214501Srpaulo case EAP_IDLE: 645214501Srpaulo if (sm->eap_if.retransWhile == 0) 646214501Srpaulo SM_ENTER(EAP, RETRANSMIT); 647214501Srpaulo else if (sm->eap_if.eapResp) 648214501Srpaulo SM_ENTER(EAP, RECEIVED); 649214501Srpaulo break; 650214501Srpaulo case EAP_RETRANSMIT: 651214501Srpaulo if (sm->retransCount > sm->MaxRetrans) 652214501Srpaulo SM_ENTER(EAP, TIMEOUT_FAILURE); 653214501Srpaulo else 654214501Srpaulo SM_ENTER(EAP, IDLE); 655214501Srpaulo break; 656214501Srpaulo case EAP_RECEIVED: 657214501Srpaulo if (sm->rxResp && (sm->respId == sm->currentId) && 658214501Srpaulo (sm->respMethod == EAP_TYPE_NAK || 659214501Srpaulo (sm->respMethod == EAP_TYPE_EXPANDED && 660214501Srpaulo sm->respVendor == EAP_VENDOR_IETF && 661214501Srpaulo sm->respVendorMethod == EAP_TYPE_NAK)) 662214501Srpaulo && (sm->methodState == METHOD_PROPOSED)) 663214501Srpaulo SM_ENTER(EAP, NAK); 664214501Srpaulo else if (sm->rxResp && (sm->respId == sm->currentId) && 665214501Srpaulo ((sm->respMethod == sm->currentMethod) || 666214501Srpaulo (sm->respMethod == EAP_TYPE_EXPANDED && 667214501Srpaulo sm->respVendor == EAP_VENDOR_IETF && 668214501Srpaulo sm->respVendorMethod == sm->currentMethod))) 669214501Srpaulo SM_ENTER(EAP, INTEGRITY_CHECK); 670214501Srpaulo else { 671214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: " 672214501Srpaulo "rxResp=%d respId=%d currentId=%d " 673214501Srpaulo "respMethod=%d currentMethod=%d", 674214501Srpaulo sm->rxResp, sm->respId, sm->currentId, 675214501Srpaulo sm->respMethod, sm->currentMethod); 676214501Srpaulo SM_ENTER(EAP, DISCARD); 677214501Srpaulo } 678214501Srpaulo break; 679214501Srpaulo case EAP_DISCARD: 680214501Srpaulo SM_ENTER(EAP, IDLE); 681214501Srpaulo break; 682214501Srpaulo case EAP_SEND_REQUEST: 683214501Srpaulo SM_ENTER(EAP, IDLE); 684214501Srpaulo break; 685214501Srpaulo case EAP_INTEGRITY_CHECK: 686214501Srpaulo if (sm->ignore) 687214501Srpaulo SM_ENTER(EAP, DISCARD); 688214501Srpaulo else 689214501Srpaulo SM_ENTER(EAP, METHOD_RESPONSE); 690214501Srpaulo break; 691214501Srpaulo case EAP_METHOD_REQUEST: 692214501Srpaulo SM_ENTER(EAP, SEND_REQUEST); 693214501Srpaulo break; 694214501Srpaulo case EAP_METHOD_RESPONSE: 695214501Srpaulo /* 696214501Srpaulo * Note: Mechanism to allow EAP methods to wait while going 697214501Srpaulo * through pending processing is an extension to RFC 4137 698214501Srpaulo * which only defines the transits to SELECT_ACTION and 699214501Srpaulo * METHOD_REQUEST from this METHOD_RESPONSE state. 700214501Srpaulo */ 701214501Srpaulo if (sm->methodState == METHOD_END) 702214501Srpaulo SM_ENTER(EAP, SELECT_ACTION); 703214501Srpaulo else if (sm->method_pending == METHOD_PENDING_WAIT) { 704214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Method has pending " 705214501Srpaulo "processing - wait before proceeding to " 706214501Srpaulo "METHOD_REQUEST state"); 707214501Srpaulo } else if (sm->method_pending == METHOD_PENDING_CONT) { 708214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Method has completed " 709214501Srpaulo "pending processing - reprocess pending " 710214501Srpaulo "EAP message"); 711214501Srpaulo sm->method_pending = METHOD_PENDING_NONE; 712214501Srpaulo SM_ENTER(EAP, METHOD_RESPONSE); 713214501Srpaulo } else 714214501Srpaulo SM_ENTER(EAP, METHOD_REQUEST); 715214501Srpaulo break; 716214501Srpaulo case EAP_PROPOSE_METHOD: 717214501Srpaulo /* 718214501Srpaulo * Note: Mechanism to allow EAP methods to wait while going 719214501Srpaulo * through pending processing is an extension to RFC 4137 720214501Srpaulo * which only defines the transit to METHOD_REQUEST from this 721214501Srpaulo * PROPOSE_METHOD state. 722214501Srpaulo */ 723214501Srpaulo if (sm->method_pending == METHOD_PENDING_WAIT) { 724214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Method has pending " 725214501Srpaulo "processing - wait before proceeding to " 726214501Srpaulo "METHOD_REQUEST state"); 727214501Srpaulo if (sm->user_eap_method_index > 0) 728214501Srpaulo sm->user_eap_method_index--; 729214501Srpaulo } else if (sm->method_pending == METHOD_PENDING_CONT) { 730214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Method has completed " 731214501Srpaulo "pending processing - reprocess pending " 732214501Srpaulo "EAP message"); 733214501Srpaulo sm->method_pending = METHOD_PENDING_NONE; 734214501Srpaulo SM_ENTER(EAP, PROPOSE_METHOD); 735214501Srpaulo } else 736214501Srpaulo SM_ENTER(EAP, METHOD_REQUEST); 737214501Srpaulo break; 738214501Srpaulo case EAP_NAK: 739214501Srpaulo SM_ENTER(EAP, SELECT_ACTION); 740214501Srpaulo break; 741214501Srpaulo case EAP_SELECT_ACTION: 742214501Srpaulo if (sm->decision == DECISION_FAILURE) 743214501Srpaulo SM_ENTER(EAP, FAILURE); 744214501Srpaulo else if (sm->decision == DECISION_SUCCESS) 745214501Srpaulo SM_ENTER(EAP, SUCCESS); 746214501Srpaulo else if (sm->decision == DECISION_PASSTHROUGH) 747214501Srpaulo SM_ENTER(EAP, INITIALIZE_PASSTHROUGH); 748214501Srpaulo else 749214501Srpaulo SM_ENTER(EAP, PROPOSE_METHOD); 750214501Srpaulo break; 751214501Srpaulo case EAP_TIMEOUT_FAILURE: 752214501Srpaulo break; 753214501Srpaulo case EAP_FAILURE: 754214501Srpaulo break; 755214501Srpaulo case EAP_SUCCESS: 756214501Srpaulo break; 757214501Srpaulo 758214501Srpaulo case EAP_INITIALIZE_PASSTHROUGH: 759214501Srpaulo if (sm->currentId == -1) 760214501Srpaulo SM_ENTER(EAP, AAA_IDLE); 761214501Srpaulo else 762214501Srpaulo SM_ENTER(EAP, AAA_REQUEST); 763214501Srpaulo break; 764214501Srpaulo case EAP_IDLE2: 765214501Srpaulo if (sm->eap_if.eapResp) 766214501Srpaulo SM_ENTER(EAP, RECEIVED2); 767214501Srpaulo else if (sm->eap_if.retransWhile == 0) 768214501Srpaulo SM_ENTER(EAP, RETRANSMIT2); 769214501Srpaulo break; 770214501Srpaulo case EAP_RETRANSMIT2: 771214501Srpaulo if (sm->retransCount > sm->MaxRetrans) 772214501Srpaulo SM_ENTER(EAP, TIMEOUT_FAILURE2); 773214501Srpaulo else 774214501Srpaulo SM_ENTER(EAP, IDLE2); 775214501Srpaulo break; 776214501Srpaulo case EAP_RECEIVED2: 777214501Srpaulo if (sm->rxResp && (sm->respId == sm->currentId)) 778214501Srpaulo SM_ENTER(EAP, AAA_REQUEST); 779214501Srpaulo else 780214501Srpaulo SM_ENTER(EAP, DISCARD2); 781214501Srpaulo break; 782214501Srpaulo case EAP_DISCARD2: 783214501Srpaulo SM_ENTER(EAP, IDLE2); 784214501Srpaulo break; 785214501Srpaulo case EAP_SEND_REQUEST2: 786214501Srpaulo SM_ENTER(EAP, IDLE2); 787214501Srpaulo break; 788214501Srpaulo case EAP_AAA_REQUEST: 789214501Srpaulo SM_ENTER(EAP, AAA_IDLE); 790214501Srpaulo break; 791214501Srpaulo case EAP_AAA_RESPONSE: 792214501Srpaulo SM_ENTER(EAP, SEND_REQUEST2); 793214501Srpaulo break; 794214501Srpaulo case EAP_AAA_IDLE: 795214501Srpaulo if (sm->eap_if.aaaFail) 796214501Srpaulo SM_ENTER(EAP, FAILURE2); 797214501Srpaulo else if (sm->eap_if.aaaSuccess) 798214501Srpaulo SM_ENTER(EAP, SUCCESS2); 799214501Srpaulo else if (sm->eap_if.aaaEapReq) 800214501Srpaulo SM_ENTER(EAP, AAA_RESPONSE); 801214501Srpaulo else if (sm->eap_if.aaaTimeout) 802214501Srpaulo SM_ENTER(EAP, TIMEOUT_FAILURE2); 803214501Srpaulo break; 804214501Srpaulo case EAP_TIMEOUT_FAILURE2: 805214501Srpaulo break; 806214501Srpaulo case EAP_FAILURE2: 807214501Srpaulo break; 808214501Srpaulo case EAP_SUCCESS2: 809214501Srpaulo break; 810214501Srpaulo } 811214501Srpaulo} 812214501Srpaulo 813214501Srpaulo 814214501Srpaulostatic int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount, 815214501Srpaulo int eapSRTT, int eapRTTVAR, 816214501Srpaulo int methodTimeout) 817214501Srpaulo{ 818214501Srpaulo int rto, i; 819214501Srpaulo 820214501Srpaulo if (methodTimeout) { 821214501Srpaulo /* 822214501Srpaulo * EAP method (either internal or through AAA server, provided 823214501Srpaulo * timeout hint. Use that as-is as a timeout for retransmitting 824214501Srpaulo * the EAP request if no response is received. 825214501Srpaulo */ 826214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 827214501Srpaulo "(from EAP method hint)", methodTimeout); 828214501Srpaulo return methodTimeout; 829214501Srpaulo } 830214501Srpaulo 831214501Srpaulo /* 832214501Srpaulo * RFC 3748 recommends algorithms described in RFC 2988 for estimation 833214501Srpaulo * of the retransmission timeout. This should be implemented once 834214501Srpaulo * round-trip time measurements are available. For nowm a simple 835214501Srpaulo * backoff mechanism is used instead if there are no EAP method 836214501Srpaulo * specific hints. 837214501Srpaulo * 838214501Srpaulo * SRTT = smoothed round-trip time 839214501Srpaulo * RTTVAR = round-trip time variation 840214501Srpaulo * RTO = retransmission timeout 841214501Srpaulo */ 842214501Srpaulo 843214501Srpaulo /* 844214501Srpaulo * RFC 2988, 2.1: before RTT measurement, set RTO to 3 seconds for 845214501Srpaulo * initial retransmission and then double the RTO to provide back off 846214501Srpaulo * per 5.5. Limit the maximum RTO to 20 seconds per RFC 3748, 4.3 847214501Srpaulo * modified RTOmax. 848214501Srpaulo */ 849214501Srpaulo rto = 3; 850214501Srpaulo for (i = 0; i < retransCount; i++) { 851214501Srpaulo rto *= 2; 852214501Srpaulo if (rto >= 20) { 853214501Srpaulo rto = 20; 854214501Srpaulo break; 855214501Srpaulo } 856214501Srpaulo } 857214501Srpaulo 858214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: retransmit timeout %d seconds " 859214501Srpaulo "(from dynamic back off; retransCount=%d)", 860214501Srpaulo rto, retransCount); 861214501Srpaulo 862214501Srpaulo return rto; 863214501Srpaulo} 864214501Srpaulo 865214501Srpaulo 866214501Srpaulostatic void eap_sm_parseEapResp(struct eap_sm *sm, const struct wpabuf *resp) 867214501Srpaulo{ 868214501Srpaulo const struct eap_hdr *hdr; 869214501Srpaulo size_t plen; 870214501Srpaulo 871214501Srpaulo /* parse rxResp, respId, respMethod */ 872214501Srpaulo sm->rxResp = FALSE; 873214501Srpaulo sm->respId = -1; 874214501Srpaulo sm->respMethod = EAP_TYPE_NONE; 875214501Srpaulo sm->respVendor = EAP_VENDOR_IETF; 876214501Srpaulo sm->respVendorMethod = EAP_TYPE_NONE; 877214501Srpaulo 878214501Srpaulo if (resp == NULL || wpabuf_len(resp) < sizeof(*hdr)) { 879214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: parseEapResp: invalid resp=%p " 880214501Srpaulo "len=%lu", resp, 881214501Srpaulo resp ? (unsigned long) wpabuf_len(resp) : 0); 882214501Srpaulo return; 883214501Srpaulo } 884214501Srpaulo 885214501Srpaulo hdr = wpabuf_head(resp); 886214501Srpaulo plen = be_to_host16(hdr->length); 887214501Srpaulo if (plen > wpabuf_len(resp)) { 888214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet " 889214501Srpaulo "(len=%lu plen=%lu)", 890214501Srpaulo (unsigned long) wpabuf_len(resp), 891214501Srpaulo (unsigned long) plen); 892214501Srpaulo return; 893214501Srpaulo } 894214501Srpaulo 895214501Srpaulo sm->respId = hdr->identifier; 896214501Srpaulo 897214501Srpaulo if (hdr->code == EAP_CODE_RESPONSE) 898214501Srpaulo sm->rxResp = TRUE; 899214501Srpaulo 900214501Srpaulo if (plen > sizeof(*hdr)) { 901214501Srpaulo u8 *pos = (u8 *) (hdr + 1); 902214501Srpaulo sm->respMethod = *pos++; 903214501Srpaulo if (sm->respMethod == EAP_TYPE_EXPANDED) { 904214501Srpaulo if (plen < sizeof(*hdr) + 8) { 905214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Ignored truncated " 906214501Srpaulo "expanded EAP-Packet (plen=%lu)", 907214501Srpaulo (unsigned long) plen); 908214501Srpaulo return; 909214501Srpaulo } 910214501Srpaulo sm->respVendor = WPA_GET_BE24(pos); 911214501Srpaulo pos += 3; 912214501Srpaulo sm->respVendorMethod = WPA_GET_BE32(pos); 913214501Srpaulo } 914214501Srpaulo } 915214501Srpaulo 916214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d " 917214501Srpaulo "respMethod=%u respVendor=%u respVendorMethod=%u", 918214501Srpaulo sm->rxResp, sm->respId, sm->respMethod, sm->respVendor, 919214501Srpaulo sm->respVendorMethod); 920214501Srpaulo} 921214501Srpaulo 922214501Srpaulo 923214501Srpaulostatic int eap_sm_getId(const struct wpabuf *data) 924214501Srpaulo{ 925214501Srpaulo const struct eap_hdr *hdr; 926214501Srpaulo 927214501Srpaulo if (data == NULL || wpabuf_len(data) < sizeof(*hdr)) 928214501Srpaulo return -1; 929214501Srpaulo 930214501Srpaulo hdr = wpabuf_head(data); 931214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getId: id=%d", hdr->identifier); 932214501Srpaulo return hdr->identifier; 933214501Srpaulo} 934214501Srpaulo 935214501Srpaulo 936214501Srpaulostatic struct wpabuf * eap_sm_buildSuccess(struct eap_sm *sm, u8 id) 937214501Srpaulo{ 938214501Srpaulo struct wpabuf *msg; 939214501Srpaulo struct eap_hdr *resp; 940214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id); 941214501Srpaulo 942214501Srpaulo msg = wpabuf_alloc(sizeof(*resp)); 943214501Srpaulo if (msg == NULL) 944214501Srpaulo return NULL; 945214501Srpaulo resp = wpabuf_put(msg, sizeof(*resp)); 946214501Srpaulo resp->code = EAP_CODE_SUCCESS; 947214501Srpaulo resp->identifier = id; 948214501Srpaulo resp->length = host_to_be16(sizeof(*resp)); 949214501Srpaulo 950214501Srpaulo return msg; 951214501Srpaulo} 952214501Srpaulo 953214501Srpaulo 954214501Srpaulostatic struct wpabuf * eap_sm_buildFailure(struct eap_sm *sm, u8 id) 955214501Srpaulo{ 956214501Srpaulo struct wpabuf *msg; 957214501Srpaulo struct eap_hdr *resp; 958214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id); 959214501Srpaulo 960214501Srpaulo msg = wpabuf_alloc(sizeof(*resp)); 961214501Srpaulo if (msg == NULL) 962214501Srpaulo return NULL; 963214501Srpaulo resp = wpabuf_put(msg, sizeof(*resp)); 964214501Srpaulo resp->code = EAP_CODE_FAILURE; 965214501Srpaulo resp->identifier = id; 966214501Srpaulo resp->length = host_to_be16(sizeof(*resp)); 967214501Srpaulo 968214501Srpaulo return msg; 969214501Srpaulo} 970214501Srpaulo 971214501Srpaulo 972214501Srpaulostatic int eap_sm_nextId(struct eap_sm *sm, int id) 973214501Srpaulo{ 974214501Srpaulo if (id < 0) { 975214501Srpaulo /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a 976214501Srpaulo * random number */ 977214501Srpaulo id = rand() & 0xff; 978214501Srpaulo if (id != sm->lastId) 979214501Srpaulo return id; 980214501Srpaulo } 981214501Srpaulo return (id + 1) & 0xff; 982214501Srpaulo} 983214501Srpaulo 984214501Srpaulo 985214501Srpaulo/** 986214501Srpaulo * eap_sm_process_nak - Process EAP-Response/Nak 987214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 988214501Srpaulo * @nak_list: Nak list (allowed methods) from the supplicant 989214501Srpaulo * @len: Length of nak_list in bytes 990214501Srpaulo * 991214501Srpaulo * This function is called when EAP-Response/Nak is received from the 992214501Srpaulo * supplicant. This can happen for both phase 1 and phase 2 authentications. 993214501Srpaulo */ 994214501Srpaulovoid eap_sm_process_nak(struct eap_sm *sm, const u8 *nak_list, size_t len) 995214501Srpaulo{ 996214501Srpaulo int i; 997214501Srpaulo size_t j; 998214501Srpaulo 999214501Srpaulo if (sm->user == NULL) 1000214501Srpaulo return; 1001214501Srpaulo 1002214501Srpaulo wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method " 1003214501Srpaulo "index %d)", sm->user_eap_method_index); 1004214501Srpaulo 1005214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods", 1006214501Srpaulo (u8 *) sm->user->methods, 1007214501Srpaulo EAP_MAX_METHODS * sizeof(sm->user->methods[0])); 1008214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer", 1009214501Srpaulo nak_list, len); 1010214501Srpaulo 1011214501Srpaulo i = sm->user_eap_method_index; 1012214501Srpaulo while (i < EAP_MAX_METHODS && 1013214501Srpaulo (sm->user->methods[i].vendor != EAP_VENDOR_IETF || 1014214501Srpaulo sm->user->methods[i].method != EAP_TYPE_NONE)) { 1015214501Srpaulo if (sm->user->methods[i].vendor != EAP_VENDOR_IETF) 1016214501Srpaulo goto not_found; 1017214501Srpaulo for (j = 0; j < len; j++) { 1018214501Srpaulo if (nak_list[j] == sm->user->methods[i].method) { 1019214501Srpaulo break; 1020214501Srpaulo } 1021214501Srpaulo } 1022214501Srpaulo 1023214501Srpaulo if (j < len) { 1024214501Srpaulo /* found */ 1025214501Srpaulo i++; 1026214501Srpaulo continue; 1027214501Srpaulo } 1028214501Srpaulo 1029214501Srpaulo not_found: 1030214501Srpaulo /* not found - remove from the list */ 1031214501Srpaulo os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1], 1032214501Srpaulo (EAP_MAX_METHODS - i - 1) * 1033214501Srpaulo sizeof(sm->user->methods[0])); 1034214501Srpaulo sm->user->methods[EAP_MAX_METHODS - 1].vendor = 1035214501Srpaulo EAP_VENDOR_IETF; 1036214501Srpaulo sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE; 1037214501Srpaulo } 1038214501Srpaulo 1039214501Srpaulo wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods", 1040214501Srpaulo (u8 *) sm->user->methods, EAP_MAX_METHODS * 1041214501Srpaulo sizeof(sm->user->methods[0])); 1042214501Srpaulo} 1043214501Srpaulo 1044214501Srpaulo 1045214501Srpaulostatic void eap_sm_Policy_update(struct eap_sm *sm, const u8 *nak_list, 1046214501Srpaulo size_t len) 1047214501Srpaulo{ 1048214501Srpaulo if (nak_list == NULL || sm == NULL || sm->user == NULL) 1049214501Srpaulo return; 1050214501Srpaulo 1051214501Srpaulo if (sm->user->phase2) { 1052214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user" 1053214501Srpaulo " info was selected - reject"); 1054214501Srpaulo sm->decision = DECISION_FAILURE; 1055214501Srpaulo return; 1056214501Srpaulo } 1057214501Srpaulo 1058214501Srpaulo eap_sm_process_nak(sm, nak_list, len); 1059214501Srpaulo} 1060214501Srpaulo 1061214501Srpaulo 1062214501Srpaulostatic EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor) 1063214501Srpaulo{ 1064214501Srpaulo EapType next; 1065214501Srpaulo int idx = sm->user_eap_method_index; 1066214501Srpaulo 1067214501Srpaulo /* In theory, there should be no problems with starting 1068214501Srpaulo * re-authentication with something else than EAP-Request/Identity and 1069214501Srpaulo * this does indeed work with wpa_supplicant. However, at least Funk 1070214501Srpaulo * Supplicant seemed to ignore re-auth if it skipped 1071214501Srpaulo * EAP-Request/Identity. 1072214501Srpaulo * Re-auth sets currentId == -1, so that can be used here to select 1073214501Srpaulo * whether Identity needs to be requested again. */ 1074214501Srpaulo if (sm->identity == NULL || sm->currentId == -1) { 1075214501Srpaulo *vendor = EAP_VENDOR_IETF; 1076214501Srpaulo next = EAP_TYPE_IDENTITY; 1077214501Srpaulo sm->update_user = TRUE; 1078214501Srpaulo } else if (sm->user && idx < EAP_MAX_METHODS && 1079214501Srpaulo (sm->user->methods[idx].vendor != EAP_VENDOR_IETF || 1080214501Srpaulo sm->user->methods[idx].method != EAP_TYPE_NONE)) { 1081214501Srpaulo *vendor = sm->user->methods[idx].vendor; 1082214501Srpaulo next = sm->user->methods[idx].method; 1083214501Srpaulo sm->user_eap_method_index++; 1084214501Srpaulo } else { 1085214501Srpaulo *vendor = EAP_VENDOR_IETF; 1086214501Srpaulo next = EAP_TYPE_NONE; 1087214501Srpaulo } 1088214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d", 1089214501Srpaulo *vendor, next); 1090214501Srpaulo return next; 1091214501Srpaulo} 1092214501Srpaulo 1093214501Srpaulo 1094214501Srpaulostatic int eap_sm_Policy_getDecision(struct eap_sm *sm) 1095214501Srpaulo{ 1096214501Srpaulo if (!sm->eap_server && sm->identity && !sm->start_reauth) { 1097214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH"); 1098214501Srpaulo return DECISION_PASSTHROUGH; 1099214501Srpaulo } 1100214501Srpaulo 1101214501Srpaulo if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY && 1102214501Srpaulo sm->m->isSuccess(sm, sm->eap_method_priv)) { 1103214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> " 1104214501Srpaulo "SUCCESS"); 1105214501Srpaulo sm->update_user = TRUE; 1106214501Srpaulo return DECISION_SUCCESS; 1107214501Srpaulo } 1108214501Srpaulo 1109214501Srpaulo if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) && 1110214501Srpaulo !sm->m->isSuccess(sm, sm->eap_method_priv)) { 1111214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> " 1112214501Srpaulo "FAILURE"); 1113214501Srpaulo sm->update_user = TRUE; 1114214501Srpaulo return DECISION_FAILURE; 1115214501Srpaulo } 1116214501Srpaulo 1117214501Srpaulo if ((sm->user == NULL || sm->update_user) && sm->identity && 1118214501Srpaulo !sm->start_reauth) { 1119214501Srpaulo /* 1120214501Srpaulo * Allow Identity method to be started once to allow identity 1121214501Srpaulo * selection hint to be sent from the authentication server, 1122214501Srpaulo * but prevent a loop of Identity requests by only allowing 1123214501Srpaulo * this to happen once. 1124214501Srpaulo */ 1125214501Srpaulo int id_req = 0; 1126214501Srpaulo if (sm->user && sm->currentMethod == EAP_TYPE_IDENTITY && 1127214501Srpaulo sm->user->methods[0].vendor == EAP_VENDOR_IETF && 1128214501Srpaulo sm->user->methods[0].method == EAP_TYPE_IDENTITY) 1129214501Srpaulo id_req = 1; 1130214501Srpaulo if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) { 1131214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: user not " 1132214501Srpaulo "found from database -> FAILURE"); 1133214501Srpaulo return DECISION_FAILURE; 1134214501Srpaulo } 1135214501Srpaulo if (id_req && sm->user && 1136214501Srpaulo sm->user->methods[0].vendor == EAP_VENDOR_IETF && 1137214501Srpaulo sm->user->methods[0].method == EAP_TYPE_IDENTITY) { 1138214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: stop " 1139214501Srpaulo "identity request loop -> FAILURE"); 1140214501Srpaulo sm->update_user = TRUE; 1141214501Srpaulo return DECISION_FAILURE; 1142214501Srpaulo } 1143214501Srpaulo sm->update_user = FALSE; 1144214501Srpaulo } 1145214501Srpaulo sm->start_reauth = FALSE; 1146214501Srpaulo 1147214501Srpaulo if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS && 1148214501Srpaulo (sm->user->methods[sm->user_eap_method_index].vendor != 1149214501Srpaulo EAP_VENDOR_IETF || 1150214501Srpaulo sm->user->methods[sm->user_eap_method_index].method != 1151214501Srpaulo EAP_TYPE_NONE)) { 1152214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: another method " 1153214501Srpaulo "available -> CONTINUE"); 1154214501Srpaulo return DECISION_CONTINUE; 1155214501Srpaulo } 1156214501Srpaulo 1157214501Srpaulo if (sm->identity == NULL || sm->currentId == -1) { 1158214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known " 1159214501Srpaulo "yet -> CONTINUE"); 1160214501Srpaulo return DECISION_CONTINUE; 1161214501Srpaulo } 1162214501Srpaulo 1163214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> " 1164214501Srpaulo "FAILURE"); 1165214501Srpaulo return DECISION_FAILURE; 1166214501Srpaulo} 1167214501Srpaulo 1168214501Srpaulo 1169214501Srpaulostatic Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method) 1170214501Srpaulo{ 1171214501Srpaulo return method == EAP_TYPE_IDENTITY ? TRUE : FALSE; 1172214501Srpaulo} 1173214501Srpaulo 1174214501Srpaulo 1175214501Srpaulo/** 1176214501Srpaulo * eap_server_sm_step - Step EAP server state machine 1177214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1178214501Srpaulo * Returns: 1 if EAP state was changed or 0 if not 1179214501Srpaulo * 1180214501Srpaulo * This function advances EAP state machine to a new state to match with the 1181214501Srpaulo * current variables. This should be called whenever variables used by the EAP 1182214501Srpaulo * state machine have changed. 1183214501Srpaulo */ 1184214501Srpauloint eap_server_sm_step(struct eap_sm *sm) 1185214501Srpaulo{ 1186214501Srpaulo int res = 0; 1187214501Srpaulo do { 1188214501Srpaulo sm->changed = FALSE; 1189214501Srpaulo SM_STEP_RUN(EAP); 1190214501Srpaulo if (sm->changed) 1191214501Srpaulo res = 1; 1192214501Srpaulo } while (sm->changed); 1193214501Srpaulo return res; 1194214501Srpaulo} 1195214501Srpaulo 1196214501Srpaulo 1197214501Srpaulostatic void eap_user_free(struct eap_user *user) 1198214501Srpaulo{ 1199214501Srpaulo if (user == NULL) 1200214501Srpaulo return; 1201214501Srpaulo os_free(user->password); 1202214501Srpaulo user->password = NULL; 1203214501Srpaulo os_free(user); 1204214501Srpaulo} 1205214501Srpaulo 1206214501Srpaulo 1207214501Srpaulo/** 1208214501Srpaulo * eap_server_sm_init - Allocate and initialize EAP server state machine 1209214501Srpaulo * @eapol_ctx: Context data to be used with eapol_cb calls 1210214501Srpaulo * @eapol_cb: Pointer to EAPOL callback functions 1211214501Srpaulo * @conf: EAP configuration 1212214501Srpaulo * Returns: Pointer to the allocated EAP state machine or %NULL on failure 1213214501Srpaulo * 1214214501Srpaulo * This function allocates and initializes an EAP state machine. 1215214501Srpaulo */ 1216214501Srpaulostruct eap_sm * eap_server_sm_init(void *eapol_ctx, 1217214501Srpaulo struct eapol_callbacks *eapol_cb, 1218214501Srpaulo struct eap_config *conf) 1219214501Srpaulo{ 1220214501Srpaulo struct eap_sm *sm; 1221214501Srpaulo 1222214501Srpaulo sm = os_zalloc(sizeof(*sm)); 1223214501Srpaulo if (sm == NULL) 1224214501Srpaulo return NULL; 1225214501Srpaulo sm->eapol_ctx = eapol_ctx; 1226214501Srpaulo sm->eapol_cb = eapol_cb; 1227214501Srpaulo sm->MaxRetrans = 5; /* RFC 3748: max 3-5 retransmissions suggested */ 1228214501Srpaulo sm->ssl_ctx = conf->ssl_ctx; 1229214501Srpaulo sm->msg_ctx = conf->msg_ctx; 1230214501Srpaulo sm->eap_sim_db_priv = conf->eap_sim_db_priv; 1231214501Srpaulo sm->backend_auth = conf->backend_auth; 1232214501Srpaulo sm->eap_server = conf->eap_server; 1233214501Srpaulo if (conf->pac_opaque_encr_key) { 1234214501Srpaulo sm->pac_opaque_encr_key = os_malloc(16); 1235214501Srpaulo if (sm->pac_opaque_encr_key) { 1236214501Srpaulo os_memcpy(sm->pac_opaque_encr_key, 1237214501Srpaulo conf->pac_opaque_encr_key, 16); 1238214501Srpaulo } 1239214501Srpaulo } 1240214501Srpaulo if (conf->eap_fast_a_id) { 1241214501Srpaulo sm->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len); 1242214501Srpaulo if (sm->eap_fast_a_id) { 1243214501Srpaulo os_memcpy(sm->eap_fast_a_id, conf->eap_fast_a_id, 1244214501Srpaulo conf->eap_fast_a_id_len); 1245214501Srpaulo sm->eap_fast_a_id_len = conf->eap_fast_a_id_len; 1246214501Srpaulo } 1247214501Srpaulo } 1248214501Srpaulo if (conf->eap_fast_a_id_info) 1249214501Srpaulo sm->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info); 1250214501Srpaulo sm->eap_fast_prov = conf->eap_fast_prov; 1251214501Srpaulo sm->pac_key_lifetime = conf->pac_key_lifetime; 1252214501Srpaulo sm->pac_key_refresh_time = conf->pac_key_refresh_time; 1253214501Srpaulo sm->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind; 1254214501Srpaulo sm->tnc = conf->tnc; 1255214501Srpaulo sm->wps = conf->wps; 1256214501Srpaulo if (conf->assoc_wps_ie) 1257214501Srpaulo sm->assoc_wps_ie = wpabuf_dup(conf->assoc_wps_ie); 1258214501Srpaulo if (conf->peer_addr) 1259214501Srpaulo os_memcpy(sm->peer_addr, conf->peer_addr, ETH_ALEN); 1260214501Srpaulo 1261214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Server state machine created"); 1262214501Srpaulo 1263214501Srpaulo return sm; 1264214501Srpaulo} 1265214501Srpaulo 1266214501Srpaulo 1267214501Srpaulo/** 1268214501Srpaulo * eap_server_sm_deinit - Deinitialize and free an EAP server state machine 1269214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1270214501Srpaulo * 1271214501Srpaulo * This function deinitializes EAP state machine and frees all allocated 1272214501Srpaulo * resources. 1273214501Srpaulo */ 1274214501Srpaulovoid eap_server_sm_deinit(struct eap_sm *sm) 1275214501Srpaulo{ 1276214501Srpaulo if (sm == NULL) 1277214501Srpaulo return; 1278214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Server state machine removed"); 1279214501Srpaulo if (sm->m && sm->eap_method_priv) 1280214501Srpaulo sm->m->reset(sm, sm->eap_method_priv); 1281214501Srpaulo wpabuf_free(sm->eap_if.eapReqData); 1282214501Srpaulo os_free(sm->eap_if.eapKeyData); 1283214501Srpaulo wpabuf_free(sm->lastReqData); 1284214501Srpaulo wpabuf_free(sm->eap_if.eapRespData); 1285214501Srpaulo os_free(sm->identity); 1286214501Srpaulo os_free(sm->pac_opaque_encr_key); 1287214501Srpaulo os_free(sm->eap_fast_a_id); 1288214501Srpaulo os_free(sm->eap_fast_a_id_info); 1289214501Srpaulo wpabuf_free(sm->eap_if.aaaEapReqData); 1290214501Srpaulo wpabuf_free(sm->eap_if.aaaEapRespData); 1291214501Srpaulo os_free(sm->eap_if.aaaEapKeyData); 1292214501Srpaulo eap_user_free(sm->user); 1293214501Srpaulo wpabuf_free(sm->assoc_wps_ie); 1294214501Srpaulo os_free(sm); 1295214501Srpaulo} 1296214501Srpaulo 1297214501Srpaulo 1298214501Srpaulo/** 1299214501Srpaulo * eap_sm_notify_cached - Notify EAP state machine of cached PMK 1300214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1301214501Srpaulo * 1302214501Srpaulo * This function is called when PMKSA caching is used to skip EAP 1303214501Srpaulo * authentication. 1304214501Srpaulo */ 1305214501Srpaulovoid eap_sm_notify_cached(struct eap_sm *sm) 1306214501Srpaulo{ 1307214501Srpaulo if (sm == NULL) 1308214501Srpaulo return; 1309214501Srpaulo 1310214501Srpaulo sm->EAP_state = EAP_SUCCESS; 1311214501Srpaulo} 1312214501Srpaulo 1313214501Srpaulo 1314214501Srpaulo/** 1315214501Srpaulo * eap_sm_pending_cb - EAP state machine callback for a pending EAP request 1316214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1317214501Srpaulo * 1318214501Srpaulo * This function is called when data for a pending EAP-Request is received. 1319214501Srpaulo */ 1320214501Srpaulovoid eap_sm_pending_cb(struct eap_sm *sm) 1321214501Srpaulo{ 1322214501Srpaulo if (sm == NULL) 1323214501Srpaulo return; 1324214501Srpaulo wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received"); 1325214501Srpaulo if (sm->method_pending == METHOD_PENDING_WAIT) 1326214501Srpaulo sm->method_pending = METHOD_PENDING_CONT; 1327214501Srpaulo} 1328214501Srpaulo 1329214501Srpaulo 1330214501Srpaulo/** 1331214501Srpaulo * eap_sm_method_pending - Query whether EAP method is waiting for pending data 1332214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1333214501Srpaulo * Returns: 1 if method is waiting for pending data or 0 if not 1334214501Srpaulo */ 1335214501Srpauloint eap_sm_method_pending(struct eap_sm *sm) 1336214501Srpaulo{ 1337214501Srpaulo if (sm == NULL) 1338214501Srpaulo return 0; 1339214501Srpaulo return sm->method_pending == METHOD_PENDING_WAIT; 1340214501Srpaulo} 1341214501Srpaulo 1342214501Srpaulo 1343214501Srpaulo/** 1344214501Srpaulo * eap_get_identity - Get the user identity (from EAP-Response/Identity) 1345214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1346214501Srpaulo * @len: Buffer for returning identity length 1347214501Srpaulo * Returns: Pointer to the user identity or %NULL if not available 1348214501Srpaulo */ 1349214501Srpauloconst u8 * eap_get_identity(struct eap_sm *sm, size_t *len) 1350214501Srpaulo{ 1351214501Srpaulo *len = sm->identity_len; 1352214501Srpaulo return sm->identity; 1353214501Srpaulo} 1354214501Srpaulo 1355214501Srpaulo 1356214501Srpaulo/** 1357214501Srpaulo * eap_get_interface - Get pointer to EAP-EAPOL interface data 1358214501Srpaulo * @sm: Pointer to EAP state machine allocated with eap_server_sm_init() 1359214501Srpaulo * Returns: Pointer to the EAP-EAPOL interface data 1360214501Srpaulo */ 1361214501Srpaulostruct eap_eapol_interface * eap_get_interface(struct eap_sm *sm) 1362214501Srpaulo{ 1363214501Srpaulo return &sm->eap_if; 1364214501Srpaulo} 1365