2 * hostapd / EAP Standalone Authenticator state machine
3 * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
20 #include <netinet/in.h>
22 #include <sys/socket.h>
30 extern const struct eap_method eap_method_identity;
32 extern const struct eap_method eap_method_md5;
35 extern const struct eap_method eap_method_tls;
38 extern const struct eap_method eap_method_mschapv2;
39 #endif /* EAP_MSCHAPv2 */
41 extern const struct eap_method eap_method_peap;
44 extern const struct eap_method eap_method_tlv;
47 extern const struct eap_method eap_method_gtc;
50 extern const struct eap_method eap_method_ttls;
53 extern const struct eap_method eap_method_sim;
56 static const struct eap_method *eap_methods[] =
67 #endif /* EAP_MSCHAPv2 */
84 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
87 const struct eap_method * eap_sm_get_eap_methods(int method)
90 for (i = 0; i < NUM_EAP_METHODS; i++) {
91 if (eap_methods[i]->method == method)
92 return eap_methods[i];
97 static void eap_user_free(struct eap_user *user);
100 /* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
102 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
103 int eapSRTT, int eapRTTVAR,
105 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len);
106 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
107 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
108 static int eap_sm_nextId(struct eap_sm *sm, int id);
109 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
110 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);
111 static int eap_sm_Policy_getDecision(struct eap_sm *sm);
112 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
115 /* Definitions for clarifying state machine implementation */
116 #define SM_STATE(machine, state) \
117 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
120 #define SM_ENTRY(machine, state) \
121 if (!global || sm->machine ## _state != machine ## _ ## state) { \
122 sm->changed = TRUE; \
123 wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
125 sm->machine ## _state = machine ## _ ## state;
127 #define SM_ENTER(machine, state) \
128 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
129 #define SM_ENTER_GLOBAL(machine, state) \
130 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
132 #define SM_STEP(machine) \
133 static void sm_ ## machine ## _Step(struct eap_sm *sm)
135 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
138 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
140 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
144 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
147 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
151 static void eapol_set_eapReqData(struct eap_sm *sm,
152 const u8 *eapReqData, size_t eapReqDataLen)
154 wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL",
155 sm->eapReqData, sm->eapReqDataLen);
156 sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);
160 static void eapol_set_eapKeyData(struct eap_sm *sm,
161 const u8 *eapKeyData, size_t eapKeyDataLen)
163 wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL",
164 sm->eapKeyData, sm->eapKeyDataLen);
165 sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);
169 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
172 struct eap_user *user;
174 if (sm == NULL || sm->eapol_cb == NULL ||
175 sm->eapol_cb->get_eap_user == NULL)
178 eap_user_free(sm->user);
181 user = malloc(sizeof(*user));
184 memset(user, 0, sizeof(*user));
186 if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
187 identity_len, phase2, user) != 0) {
193 sm->user_eap_method_index = 0;
199 SM_STATE(EAP, DISABLED)
201 SM_ENTRY(EAP, DISABLED);
205 SM_STATE(EAP, INITIALIZE)
207 SM_ENTRY(EAP, INITIALIZE);
210 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
211 eapol_set_bool(sm, EAPOL_eapFail, FALSE);
212 eapol_set_bool(sm, EAPOL_eapTimeout, FALSE);
213 free(sm->eapKeyData);
214 sm->eapKeyData = NULL;
215 sm->eapKeyDataLen = 0;
216 /* eapKeyAvailable = FALSE */
217 eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
219 /* This is not defined in draft-ietf-eap-statemachine-05.txt, but
220 * method state needs to be reseted here so that it does not remain in
221 * success state when re-authentication starts. */
222 if (sm->m && sm->eap_method_priv) {
223 sm->m->reset(sm, sm->eap_method_priv);
224 sm->eap_method_priv = NULL;
227 sm->user_eap_method_index = 0;
229 if (sm->backend_auth) {
230 sm->currentMethod = EAP_TYPE_NONE;
231 /* parse rxResp, respId, respMethod */
232 eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
234 sm->currentId = sm->respId;
240 SM_STATE(EAP, PICK_UP_METHOD)
242 SM_ENTRY(EAP, PICK_UP_METHOD);
244 if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
245 sm->currentMethod = sm->respMethod;
246 if (sm->m && sm->eap_method_priv) {
247 sm->m->reset(sm, sm->eap_method_priv);
248 sm->eap_method_priv = NULL;
250 sm->m = eap_sm_get_eap_methods(sm->currentMethod);
251 if (sm->m && sm->m->initPickUp) {
252 sm->eap_method_priv = sm->m->initPickUp(sm);
253 if (sm->eap_method_priv == NULL) {
254 wpa_printf(MSG_DEBUG, "EAP: Failed to "
255 "initialize EAP method %d",
258 sm->currentMethod = EAP_TYPE_NONE;
262 sm->currentMethod = EAP_TYPE_NONE;
272 sm->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount,
273 sm->eapSRTT, sm->eapRTTVAR,
278 SM_STATE(EAP, RETRANSMIT)
280 SM_ENTRY(EAP, RETRANSMIT);
282 /* TODO: Is this needed since EAPOL state machines take care of
287 SM_STATE(EAP, RECEIVED)
289 SM_ENTRY(EAP, RECEIVED);
291 /* parse rxResp, respId, respMethod */
292 eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
296 SM_STATE(EAP, DISCARD)
298 SM_ENTRY(EAP, DISCARD);
299 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
300 eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
304 SM_STATE(EAP, SEND_REQUEST)
306 SM_ENTRY(EAP, SEND_REQUEST);
308 sm->retransCount = 0;
309 if (sm->eapReqData) {
310 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
311 free(sm->lastReqData);
312 sm->lastReqData = sm->eapReqData;
313 sm->lastReqDataLen = sm->eapReqDataLen;
314 sm->eapReqData = NULL;
315 sm->eapReqDataLen = 0;
316 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
317 eapol_set_bool(sm, EAPOL_eapReq, TRUE);
319 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
320 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
321 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
322 eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
327 SM_STATE(EAP, INTEGRITY_CHECK)
329 SM_ENTRY(EAP, INTEGRITY_CHECK);
332 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
333 sm->eapRespData, sm->eapRespDataLen);
338 SM_STATE(EAP, METHOD_REQUEST)
340 SM_ENTRY(EAP, METHOD_REQUEST);
343 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
347 sm->currentId = eap_sm_nextId(sm, sm->currentId);
348 wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
350 sm->lastId = sm->currentId;
351 free(sm->eapReqData);
352 sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
353 sm->currentId, &sm->eapReqDataLen);
354 if (sm->m->getTimeout)
355 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
357 sm->methodTimeout = 0;
361 SM_STATE(EAP, METHOD_RESPONSE)
363 SM_ENTRY(EAP, METHOD_RESPONSE);
365 sm->m->process(sm, sm->eap_method_priv, sm->eapRespData,
367 if (sm->m->isDone(sm, sm->eap_method_priv)) {
368 eap_sm_Policy_update(sm, NULL, 0);
369 free(sm->eapKeyData);
371 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
374 sm->eapKeyData = NULL;
375 sm->eapKeyDataLen = 0;
377 sm->methodState = METHOD_END;
379 sm->methodState = METHOD_CONTINUE;
384 SM_STATE(EAP, PROPOSE_METHOD)
386 SM_ENTRY(EAP, PROPOSE_METHOD);
388 sm->currentMethod = eap_sm_Policy_getNextMethod(sm);
389 if (sm->m && sm->eap_method_priv) {
390 sm->m->reset(sm, sm->eap_method_priv);
391 sm->eap_method_priv = NULL;
393 sm->m = eap_sm_get_eap_methods(sm->currentMethod);
395 sm->eap_method_priv = sm->m->init(sm);
396 if (sm->eap_method_priv == NULL) {
397 wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
398 "method %d", sm->currentMethod);
400 sm->currentMethod = EAP_TYPE_NONE;
403 if (sm->currentMethod == EAP_TYPE_IDENTITY ||
404 sm->currentMethod == EAP_TYPE_NOTIFICATION)
405 sm->methodState = METHOD_CONTINUE;
407 sm->methodState = METHOD_PROPOSED;
415 u8 *pos, *nak_list = NULL;
419 if (sm->eap_method_priv) {
420 sm->m->reset(sm, sm->eap_method_priv);
421 sm->eap_method_priv = NULL;
425 nak = (struct eap_hdr *) sm->eapRespData;
426 if (nak && sm->eapRespDataLen > sizeof(*nak)) {
427 len = ntohs(nak->length);
428 if (len > sm->eapRespDataLen)
429 len = sm->eapRespDataLen;
430 pos = (u8 *) (nak + 1);
432 if (*pos == EAP_TYPE_NAK) {
438 eap_sm_Policy_update(sm, nak_list, len);
442 SM_STATE(EAP, SELECT_ACTION)
444 SM_ENTRY(EAP, SELECT_ACTION);
446 sm->decision = eap_sm_Policy_getDecision(sm);
450 SM_STATE(EAP, TIMEOUT_FAILURE)
452 SM_ENTRY(EAP, TIMEOUT_FAILURE);
454 eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);
458 SM_STATE(EAP, FAILURE)
460 SM_ENTRY(EAP, FAILURE);
462 free(sm->eapReqData);
463 sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,
465 if (sm->eapReqData) {
466 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
467 free(sm->eapReqData);
468 sm->eapReqData = NULL;
469 sm->eapReqDataLen = 0;
471 free(sm->lastReqData);
472 sm->lastReqData = NULL;
473 sm->lastReqDataLen = 0;
474 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
478 SM_STATE(EAP, SUCCESS)
480 SM_ENTRY(EAP, SUCCESS);
482 free(sm->eapReqData);
483 sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,
485 if (sm->eapReqData) {
486 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
487 free(sm->eapReqData);
488 sm->eapReqData = NULL;
489 sm->eapReqDataLen = 0;
491 free(sm->lastReqData);
492 sm->lastReqData = NULL;
493 sm->lastReqDataLen = 0;
494 if (sm->eapKeyData) {
495 eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);
497 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
503 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
504 eapol_get_bool(sm, EAPOL_portEnabled))
505 SM_ENTER_GLOBAL(EAP, INITIALIZE);
506 else if (!eapol_get_bool(sm, EAPOL_portEnabled))
507 SM_ENTER_GLOBAL(EAP, DISABLED);
508 else switch (sm->EAP_state) {
510 if (sm->backend_auth) {
512 SM_ENTER(EAP, SELECT_ACTION);
513 else if (sm->rxResp &&
514 (sm->respMethod == EAP_TYPE_NAK ||
515 sm->respMethod == EAP_TYPE_EXPANDED_NAK))
518 SM_ENTER(EAP, PICK_UP_METHOD);
520 SM_ENTER(EAP, SELECT_ACTION);
523 case EAP_PICK_UP_METHOD:
524 if (sm->currentMethod == EAP_TYPE_NONE) {
525 SM_ENTER(EAP, SELECT_ACTION);
527 SM_ENTER(EAP, METHOD_RESPONSE);
531 if (eapol_get_bool(sm, EAPOL_portEnabled))
532 SM_ENTER(EAP, INITIALIZE);
535 if (sm->retransWhile == 0)
536 SM_ENTER(EAP, RETRANSMIT);
537 else if (eapol_get_bool(sm, EAPOL_eapResp))
538 SM_ENTER(EAP, RECEIVED);
541 if (sm->retransCount > sm->MaxRetrans)
542 SM_ENTER(EAP, TIMEOUT_FAILURE);
547 if (sm->rxResp && (sm->respId == sm->currentId) &&
548 (sm->respMethod == EAP_TYPE_NAK ||
549 sm->respMethod == EAP_TYPE_EXPANDED_NAK)
550 && (sm->methodState == METHOD_PROPOSED))
552 else if (sm->rxResp && (sm->respId == sm->currentId) &&
553 (sm->respMethod == sm->currentMethod))
554 SM_ENTER(EAP, INTEGRITY_CHECK);
556 SM_ENTER(EAP, DISCARD);
561 case EAP_SEND_REQUEST:
564 case EAP_INTEGRITY_CHECK:
566 SM_ENTER(EAP, DISCARD);
568 SM_ENTER(EAP, METHOD_RESPONSE);
570 case EAP_METHOD_REQUEST:
571 SM_ENTER(EAP, SEND_REQUEST);
573 case EAP_METHOD_RESPONSE:
574 if (sm->methodState == METHOD_END)
575 SM_ENTER(EAP, SELECT_ACTION);
577 SM_ENTER(EAP, METHOD_REQUEST);
579 case EAP_PROPOSE_METHOD:
580 SM_ENTER(EAP, METHOD_REQUEST);
583 SM_ENTER(EAP, SELECT_ACTION);
585 case EAP_SELECT_ACTION:
586 if (sm->decision == DECISION_FAILURE)
587 SM_ENTER(EAP, FAILURE);
588 else if (sm->decision == DECISION_SUCCESS)
589 SM_ENTER(EAP, SUCCESS);
591 SM_ENTER(EAP, PROPOSE_METHOD);
593 case EAP_TIMEOUT_FAILURE:
603 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
604 int eapSRTT, int eapRTTVAR,
607 /* For now, retransmission is done in EAPOL state machines, so make
608 * sure EAP state machine does not end up trying to retransmit packets.
614 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
619 /* parse rxResp, respId, respMethod */
622 sm->respMethod = EAP_TYPE_NONE;
624 if (resp == NULL || len < sizeof(*hdr))
627 hdr = (struct eap_hdr *) resp;
628 plen = ntohs(hdr->length);
630 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
631 "(len=%lu plen=%lu)", (unsigned long) len,
632 (unsigned long) plen);
636 sm->respId = hdr->identifier;
638 if (hdr->code == EAP_CODE_RESPONSE)
641 if (len > sizeof(*hdr))
642 sm->respMethod = *((u8 *) (hdr + 1));
644 wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
645 "respMethod=%d", sm->rxResp, sm->respId, sm->respMethod);
649 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len)
651 struct eap_hdr *resp;
652 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
654 *len = sizeof(*resp);
658 resp->code = EAP_CODE_SUCCESS;
659 resp->identifier = id;
660 resp->length = htons(*len);
666 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
668 struct eap_hdr *resp;
669 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
671 *len = sizeof(*resp);
675 resp->code = EAP_CODE_FAILURE;
676 resp->identifier = id;
677 resp->length = htons(*len);
683 static int eap_sm_nextId(struct eap_sm *sm, int id)
686 /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
689 if (id != sm->lastId)
692 return (id + 1) & 0xff;
696 void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
700 wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
701 "index %d)", sm->user_eap_method_index);
703 wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
704 sm->user->methods, EAP_MAX_METHODS);
705 wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
708 i = sm->user_eap_method_index;
709 while (i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE) {
710 for (j = 0; j < len; j++) {
711 if (nak_list[j] == sm->user->methods[i]) {
722 /* not found - remove from the list */
723 memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
724 EAP_MAX_METHODS - i - 1);
725 sm->user->methods[EAP_MAX_METHODS - 1] = EAP_TYPE_NONE;
728 wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
729 sm->user->methods, EAP_MAX_METHODS);
733 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
735 if (nak_list == NULL || sm == NULL || sm->user == NULL)
738 if (sm->user->phase2) {
739 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
740 " info was selected - reject");
741 sm->decision = DECISION_FAILURE;
745 eap_sm_process_nak(sm, nak_list, len);
749 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
753 /* In theory, there should be no problems with starting
754 * re-authentication with something else than EAP-Request/Identity and
755 * this does indeed work with wpa_supplicant. However, at least Funk
756 * Supplicant seemed to ignore re-auth if it skipped
757 * EAP-Request/Identity.
758 * Re-auth sets currentId == -1, so that can be used here to select
759 * whether Identity needs to be requested again. */
760 if (sm->identity == NULL || sm->currentId == -1) {
761 next = EAP_TYPE_IDENTITY;
762 sm->update_user = TRUE;
763 } else if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
764 sm->user->methods[sm->user_eap_method_index] !=
766 next = sm->user->methods[sm->user_eap_method_index++];
768 next = EAP_TYPE_NONE;
770 wpa_printf(MSG_DEBUG, "EAP: getNextMethod: type %d", next);
775 static int eap_sm_Policy_getDecision(struct eap_sm *sm)
777 if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
778 sm->m->isSuccess(sm, sm->eap_method_priv)) {
779 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
781 sm->update_user = TRUE;
782 return DECISION_SUCCESS;
785 if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
786 !sm->m->isSuccess(sm, sm->eap_method_priv)) {
787 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
789 sm->update_user = TRUE;
790 return DECISION_FAILURE;
793 if ((sm->user == NULL || sm->update_user) && sm->identity) {
794 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
795 wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
796 "found from database -> FAILURE");
797 return DECISION_FAILURE;
799 sm->update_user = FALSE;
802 if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
803 sm->user->methods[sm->user_eap_method_index] != EAP_TYPE_NONE) {
804 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
805 "available -> CONTINUE");
806 return DECISION_CONTINUE;
809 if (sm->identity == NULL || sm->currentId == -1) {
810 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
812 return DECISION_CONTINUE;
815 wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
817 return DECISION_FAILURE;
821 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
823 return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
827 int eap_sm_step(struct eap_sm *sm)
835 } while (sm->changed);
840 u8 eap_get_type(const char *name)
843 for (i = 0; i < NUM_EAP_METHODS; i++) {
844 if (strcmp(eap_methods[i]->name, name) == 0)
845 return eap_methods[i]->method;
847 return EAP_TYPE_NONE;
851 void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
852 size_t eapRespDataLen)
856 free(sm->eapRespData);
857 sm->eapRespData = malloc(eapRespDataLen);
858 if (sm->eapRespData == NULL)
860 memcpy(sm->eapRespData, eapRespData, eapRespDataLen);
861 sm->eapRespDataLen = eapRespDataLen;
862 wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received",
863 eapRespData, eapRespDataLen);
867 static void eap_user_free(struct eap_user *user)
871 free(user->password);
872 user->password = NULL;
877 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
878 struct eap_config *eap_conf)
882 sm = malloc(sizeof(*sm));
885 memset(sm, 0, sizeof(*sm));
886 sm->eapol_ctx = eapol_ctx;
887 sm->eapol_cb = eapol_cb;
889 sm->ssl_ctx = eap_conf->ssl_ctx;
890 sm->eap_sim_db_priv = eap_conf->eap_sim_db_priv;
891 sm->backend_auth = eap_conf->backend_auth;
893 wpa_printf(MSG_DEBUG, "EAP: State machine created");
899 void eap_sm_deinit(struct eap_sm *sm)
903 wpa_printf(MSG_DEBUG, "EAP: State machine removed");
904 if (sm->m && sm->eap_method_priv)
905 sm->m->reset(sm, sm->eap_method_priv);
906 free(sm->eapReqData);
907 free(sm->eapKeyData);
908 free(sm->lastReqData);
909 free(sm->eapRespData);
911 eap_user_free(sm->user);
915 void eap_sm_notify_cached(struct eap_sm *sm)
920 sm->EAP_state = EAP_SUCCESS;