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.
18 #include <netinet/in.h>
20 #include <sys/socket.h>
27 #define EAP_MAX_AUTH_ROUNDS 50
29 extern const struct eap_method eap_method_identity
;
31 extern const struct eap_method eap_method_md5
;
34 extern const struct eap_method eap_method_tls
;
37 extern const struct eap_method eap_method_mschapv2
;
38 #endif /* EAP_MSCHAPv2 */
40 extern const struct eap_method eap_method_peap
;
43 extern const struct eap_method eap_method_tlv
;
46 extern const struct eap_method eap_method_gtc
;
49 extern const struct eap_method eap_method_ttls
;
52 extern const struct eap_method eap_method_sim
;
55 extern const struct eap_method eap_method_pax
;
58 extern const struct eap_method eap_method_psk
;
61 static const struct eap_method
*eap_methods
[] =
72 #endif /* EAP_MSCHAPv2 */
95 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
98 const struct eap_method
* eap_sm_get_eap_methods(int method
)
101 for (i
= 0; i
< NUM_EAP_METHODS
; i
++) {
102 if (eap_methods
[i
]->method
== method
)
103 return eap_methods
[i
];
108 static void eap_user_free(struct eap_user
*user
);
111 /* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
113 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
114 int eapSRTT
, int eapRTTVAR
,
116 static void eap_sm_parseEapResp(struct eap_sm
*sm
, u8
*resp
, size_t len
);
117 static u8
* eap_sm_buildSuccess(struct eap_sm
*sm
, int id
, size_t *len
);
118 static u8
* eap_sm_buildFailure(struct eap_sm
*sm
, int id
, size_t *len
);
119 static int eap_sm_nextId(struct eap_sm
*sm
, int id
);
120 static void eap_sm_Policy_update(struct eap_sm
*sm
, u8
*nak_list
, size_t len
);
121 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
);
122 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
);
123 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
);
126 /* Definitions for clarifying state machine implementation */
127 #define SM_STATE(machine, state) \
128 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
131 #define SM_ENTRY(machine, state) \
132 if (!global || sm->machine ## _state != machine ## _ ## state) { \
133 sm->changed = TRUE; \
134 wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
136 sm->machine ## _state = machine ## _ ## state;
138 #define SM_ENTER(machine, state) \
139 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
140 #define SM_ENTER_GLOBAL(machine, state) \
141 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
143 #define SM_STEP(machine) \
144 static void sm_ ## machine ## _Step(struct eap_sm *sm)
146 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
149 static Boolean
eapol_get_bool(struct eap_sm
*sm
, enum eapol_bool_var var
)
151 return sm
->eapol_cb
->get_bool(sm
->eapol_ctx
, var
);
155 static void eapol_set_bool(struct eap_sm
*sm
, enum eapol_bool_var var
,
158 sm
->eapol_cb
->set_bool(sm
->eapol_ctx
, var
, value
);
162 static void eapol_set_eapReqData(struct eap_sm
*sm
,
163 const u8
*eapReqData
, size_t eapReqDataLen
)
165 wpa_hexdump(MSG_MSGDUMP
, "EAP: eapReqData -> EAPOL",
166 sm
->eapReqData
, sm
->eapReqDataLen
);
167 sm
->eapol_cb
->set_eapReqData(sm
->eapol_ctx
, eapReqData
, eapReqDataLen
);
171 static void eapol_set_eapKeyData(struct eap_sm
*sm
,
172 const u8
*eapKeyData
, size_t eapKeyDataLen
)
174 wpa_hexdump(MSG_MSGDUMP
, "EAP: eapKeyData -> EAPOL",
175 sm
->eapKeyData
, sm
->eapKeyDataLen
);
176 sm
->eapol_cb
->set_eapKeyData(sm
->eapol_ctx
, eapKeyData
, eapKeyDataLen
);
180 int eap_user_get(struct eap_sm
*sm
, const u8
*identity
, size_t identity_len
,
183 struct eap_user
*user
;
185 if (sm
== NULL
|| sm
->eapol_cb
== NULL
||
186 sm
->eapol_cb
->get_eap_user
== NULL
)
189 eap_user_free(sm
->user
);
192 user
= malloc(sizeof(*user
));
195 memset(user
, 0, sizeof(*user
));
197 if (sm
->eapol_cb
->get_eap_user(sm
->eapol_ctx
, identity
,
198 identity_len
, phase2
, user
) != 0) {
204 sm
->user_eap_method_index
= 0;
210 SM_STATE(EAP
, DISABLED
)
212 SM_ENTRY(EAP
, DISABLED
);
217 SM_STATE(EAP
, INITIALIZE
)
219 SM_ENTRY(EAP
, INITIALIZE
);
222 eapol_set_bool(sm
, EAPOL_eapSuccess
, FALSE
);
223 eapol_set_bool(sm
, EAPOL_eapFail
, FALSE
);
224 eapol_set_bool(sm
, EAPOL_eapTimeout
, FALSE
);
225 free(sm
->eapKeyData
);
226 sm
->eapKeyData
= NULL
;
227 sm
->eapKeyDataLen
= 0;
228 /* eapKeyAvailable = FALSE */
229 eapol_set_bool(sm
, EAPOL_eapRestart
, FALSE
);
231 /* This is not defined in draft-ietf-eap-statemachine-05.txt, but
232 * method state needs to be reseted here so that it does not remain in
233 * success state when re-authentication starts. */
234 if (sm
->m
&& sm
->eap_method_priv
) {
235 sm
->m
->reset(sm
, sm
->eap_method_priv
);
236 sm
->eap_method_priv
= NULL
;
239 sm
->user_eap_method_index
= 0;
241 if (sm
->backend_auth
) {
242 sm
->currentMethod
= EAP_TYPE_NONE
;
243 /* parse rxResp, respId, respMethod */
244 eap_sm_parseEapResp(sm
, sm
->eapRespData
, sm
->eapRespDataLen
);
246 sm
->currentId
= sm
->respId
;
253 SM_STATE(EAP
, PICK_UP_METHOD
)
255 SM_ENTRY(EAP
, PICK_UP_METHOD
);
257 if (eap_sm_Policy_doPickUp(sm
, sm
->respMethod
)) {
258 sm
->currentMethod
= sm
->respMethod
;
259 if (sm
->m
&& sm
->eap_method_priv
) {
260 sm
->m
->reset(sm
, sm
->eap_method_priv
);
261 sm
->eap_method_priv
= NULL
;
263 sm
->m
= eap_sm_get_eap_methods(sm
->currentMethod
);
264 if (sm
->m
&& sm
->m
->initPickUp
) {
265 sm
->eap_method_priv
= sm
->m
->initPickUp(sm
);
266 if (sm
->eap_method_priv
== NULL
) {
267 wpa_printf(MSG_DEBUG
, "EAP: Failed to "
268 "initialize EAP method %d",
271 sm
->currentMethod
= EAP_TYPE_NONE
;
275 sm
->currentMethod
= EAP_TYPE_NONE
;
285 sm
->retransWhile
= eap_sm_calculateTimeout(sm
, sm
->retransCount
,
286 sm
->eapSRTT
, sm
->eapRTTVAR
,
291 SM_STATE(EAP
, RETRANSMIT
)
293 SM_ENTRY(EAP
, RETRANSMIT
);
295 /* TODO: Is this needed since EAPOL state machines take care of
300 SM_STATE(EAP
, RECEIVED
)
302 SM_ENTRY(EAP
, RECEIVED
);
304 /* parse rxResp, respId, respMethod */
305 eap_sm_parseEapResp(sm
, sm
->eapRespData
, sm
->eapRespDataLen
);
310 SM_STATE(EAP
, DISCARD
)
312 SM_ENTRY(EAP
, DISCARD
);
313 eapol_set_bool(sm
, EAPOL_eapResp
, FALSE
);
314 eapol_set_bool(sm
, EAPOL_eapNoReq
, TRUE
);
318 SM_STATE(EAP
, SEND_REQUEST
)
320 SM_ENTRY(EAP
, SEND_REQUEST
);
322 sm
->retransCount
= 0;
323 if (sm
->eapReqData
) {
324 eapol_set_eapReqData(sm
, sm
->eapReqData
, sm
->eapReqDataLen
);
325 free(sm
->lastReqData
);
326 sm
->lastReqData
= sm
->eapReqData
;
327 sm
->lastReqDataLen
= sm
->eapReqDataLen
;
328 sm
->eapReqData
= NULL
;
329 sm
->eapReqDataLen
= 0;
330 eapol_set_bool(sm
, EAPOL_eapResp
, FALSE
);
331 eapol_set_bool(sm
, EAPOL_eapReq
, TRUE
);
333 wpa_printf(MSG_INFO
, "EAP: SEND_REQUEST - no eapReqData");
334 eapol_set_bool(sm
, EAPOL_eapResp
, FALSE
);
335 eapol_set_bool(sm
, EAPOL_eapReq
, FALSE
);
336 eapol_set_bool(sm
, EAPOL_eapNoReq
, TRUE
);
341 SM_STATE(EAP
, INTEGRITY_CHECK
)
343 SM_ENTRY(EAP
, INTEGRITY_CHECK
);
346 sm
->ignore
= sm
->m
->check(sm
, sm
->eap_method_priv
,
347 sm
->eapRespData
, sm
->eapRespDataLen
);
352 SM_STATE(EAP
, METHOD_REQUEST
)
354 SM_ENTRY(EAP
, METHOD_REQUEST
);
357 wpa_printf(MSG_DEBUG
, "EAP: method not initialized");
361 sm
->currentId
= eap_sm_nextId(sm
, sm
->currentId
);
362 wpa_printf(MSG_DEBUG
, "EAP: building EAP-Request: Identifier %d",
364 sm
->lastId
= sm
->currentId
;
365 free(sm
->eapReqData
);
366 sm
->eapReqData
= sm
->m
->buildReq(sm
, sm
->eap_method_priv
,
367 sm
->currentId
, &sm
->eapReqDataLen
);
368 if (sm
->m
->getTimeout
)
369 sm
->methodTimeout
= sm
->m
->getTimeout(sm
, sm
->eap_method_priv
);
371 sm
->methodTimeout
= 0;
375 SM_STATE(EAP
, METHOD_RESPONSE
)
377 SM_ENTRY(EAP
, METHOD_RESPONSE
);
379 sm
->m
->process(sm
, sm
->eap_method_priv
, sm
->eapRespData
,
381 if (sm
->m
->isDone(sm
, sm
->eap_method_priv
)) {
382 eap_sm_Policy_update(sm
, NULL
, 0);
383 free(sm
->eapKeyData
);
385 sm
->eapKeyData
= sm
->m
->getKey(sm
, sm
->eap_method_priv
,
388 sm
->eapKeyData
= NULL
;
389 sm
->eapKeyDataLen
= 0;
391 sm
->methodState
= METHOD_END
;
393 sm
->methodState
= METHOD_CONTINUE
;
398 SM_STATE(EAP
, PROPOSE_METHOD
)
400 SM_ENTRY(EAP
, PROPOSE_METHOD
);
402 sm
->currentMethod
= eap_sm_Policy_getNextMethod(sm
);
403 if (sm
->m
&& sm
->eap_method_priv
) {
404 sm
->m
->reset(sm
, sm
->eap_method_priv
);
405 sm
->eap_method_priv
= NULL
;
407 sm
->m
= eap_sm_get_eap_methods(sm
->currentMethod
);
409 sm
->eap_method_priv
= sm
->m
->init(sm
);
410 if (sm
->eap_method_priv
== NULL
) {
411 wpa_printf(MSG_DEBUG
, "EAP: Failed to initialize EAP "
412 "method %d", sm
->currentMethod
);
414 sm
->currentMethod
= EAP_TYPE_NONE
;
417 if (sm
->currentMethod
== EAP_TYPE_IDENTITY
||
418 sm
->currentMethod
== EAP_TYPE_NOTIFICATION
)
419 sm
->methodState
= METHOD_CONTINUE
;
421 sm
->methodState
= METHOD_PROPOSED
;
429 u8
*pos
, *nak_list
= NULL
;
433 if (sm
->eap_method_priv
) {
434 sm
->m
->reset(sm
, sm
->eap_method_priv
);
435 sm
->eap_method_priv
= NULL
;
439 nak
= (struct eap_hdr
*) sm
->eapRespData
;
440 if (nak
&& sm
->eapRespDataLen
> sizeof(*nak
)) {
441 len
= ntohs(nak
->length
);
442 if (len
> sm
->eapRespDataLen
)
443 len
= sm
->eapRespDataLen
;
444 pos
= (u8
*) (nak
+ 1);
446 if (*pos
== EAP_TYPE_NAK
) {
452 eap_sm_Policy_update(sm
, nak_list
, len
);
456 SM_STATE(EAP
, SELECT_ACTION
)
458 SM_ENTRY(EAP
, SELECT_ACTION
);
460 sm
->decision
= eap_sm_Policy_getDecision(sm
);
464 SM_STATE(EAP
, TIMEOUT_FAILURE
)
466 SM_ENTRY(EAP
, TIMEOUT_FAILURE
);
468 eapol_set_bool(sm
, EAPOL_eapTimeout
, TRUE
);
472 SM_STATE(EAP
, FAILURE
)
474 SM_ENTRY(EAP
, FAILURE
);
476 free(sm
->eapReqData
);
477 sm
->eapReqData
= eap_sm_buildFailure(sm
, sm
->currentId
,
479 if (sm
->eapReqData
) {
480 eapol_set_eapReqData(sm
, sm
->eapReqData
, sm
->eapReqDataLen
);
481 free(sm
->eapReqData
);
482 sm
->eapReqData
= NULL
;
483 sm
->eapReqDataLen
= 0;
485 free(sm
->lastReqData
);
486 sm
->lastReqData
= NULL
;
487 sm
->lastReqDataLen
= 0;
488 eapol_set_bool(sm
, EAPOL_eapFail
, TRUE
);
492 SM_STATE(EAP
, SUCCESS
)
494 SM_ENTRY(EAP
, SUCCESS
);
496 free(sm
->eapReqData
);
497 sm
->eapReqData
= eap_sm_buildSuccess(sm
, sm
->currentId
,
499 if (sm
->eapReqData
) {
500 eapol_set_eapReqData(sm
, sm
->eapReqData
, sm
->eapReqDataLen
);
501 free(sm
->eapReqData
);
502 sm
->eapReqData
= NULL
;
503 sm
->eapReqDataLen
= 0;
505 free(sm
->lastReqData
);
506 sm
->lastReqData
= NULL
;
507 sm
->lastReqDataLen
= 0;
508 if (sm
->eapKeyData
) {
509 eapol_set_eapKeyData(sm
, sm
->eapKeyData
, sm
->eapKeyDataLen
);
511 eapol_set_bool(sm
, EAPOL_eapSuccess
, TRUE
);
517 if (eapol_get_bool(sm
, EAPOL_eapRestart
) &&
518 eapol_get_bool(sm
, EAPOL_portEnabled
))
519 SM_ENTER_GLOBAL(EAP
, INITIALIZE
);
520 else if (!eapol_get_bool(sm
, EAPOL_portEnabled
))
521 SM_ENTER_GLOBAL(EAP
, DISABLED
);
522 else if (sm
->num_rounds
> EAP_MAX_AUTH_ROUNDS
) {
523 if (sm
->num_rounds
== EAP_MAX_AUTH_ROUNDS
+ 1) {
524 wpa_printf(MSG_DEBUG
, "EAP: more than %d "
525 "authentication rounds - abort",
526 EAP_MAX_AUTH_ROUNDS
);
528 SM_ENTER_GLOBAL(EAP
, FAILURE
);
530 } else switch (sm
->EAP_state
) {
532 if (sm
->backend_auth
) {
534 SM_ENTER(EAP
, SELECT_ACTION
);
535 else if (sm
->rxResp
&&
536 (sm
->respMethod
== EAP_TYPE_NAK
||
537 sm
->respMethod
== EAP_TYPE_EXPANDED_NAK
))
540 SM_ENTER(EAP
, PICK_UP_METHOD
);
542 SM_ENTER(EAP
, SELECT_ACTION
);
545 case EAP_PICK_UP_METHOD
:
546 if (sm
->currentMethod
== EAP_TYPE_NONE
) {
547 SM_ENTER(EAP
, SELECT_ACTION
);
549 SM_ENTER(EAP
, METHOD_RESPONSE
);
553 if (eapol_get_bool(sm
, EAPOL_portEnabled
))
554 SM_ENTER(EAP
, INITIALIZE
);
557 if (sm
->retransWhile
== 0)
558 SM_ENTER(EAP
, RETRANSMIT
);
559 else if (eapol_get_bool(sm
, EAPOL_eapResp
))
560 SM_ENTER(EAP
, RECEIVED
);
563 if (sm
->retransCount
> sm
->MaxRetrans
)
564 SM_ENTER(EAP
, TIMEOUT_FAILURE
);
569 if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
570 (sm
->respMethod
== EAP_TYPE_NAK
||
571 sm
->respMethod
== EAP_TYPE_EXPANDED_NAK
)
572 && (sm
->methodState
== METHOD_PROPOSED
))
574 else if (sm
->rxResp
&& (sm
->respId
== sm
->currentId
) &&
575 (sm
->respMethod
== sm
->currentMethod
))
576 SM_ENTER(EAP
, INTEGRITY_CHECK
);
578 SM_ENTER(EAP
, DISCARD
);
583 case EAP_SEND_REQUEST
:
586 case EAP_INTEGRITY_CHECK
:
588 SM_ENTER(EAP
, DISCARD
);
590 SM_ENTER(EAP
, METHOD_RESPONSE
);
592 case EAP_METHOD_REQUEST
:
593 SM_ENTER(EAP
, SEND_REQUEST
);
595 case EAP_METHOD_RESPONSE
:
596 if (sm
->methodState
== METHOD_END
)
597 SM_ENTER(EAP
, SELECT_ACTION
);
599 SM_ENTER(EAP
, METHOD_REQUEST
);
601 case EAP_PROPOSE_METHOD
:
602 SM_ENTER(EAP
, METHOD_REQUEST
);
605 SM_ENTER(EAP
, SELECT_ACTION
);
607 case EAP_SELECT_ACTION
:
608 if (sm
->decision
== DECISION_FAILURE
)
609 SM_ENTER(EAP
, FAILURE
);
610 else if (sm
->decision
== DECISION_SUCCESS
)
611 SM_ENTER(EAP
, SUCCESS
);
613 SM_ENTER(EAP
, PROPOSE_METHOD
);
615 case EAP_TIMEOUT_FAILURE
:
625 static int eap_sm_calculateTimeout(struct eap_sm
*sm
, int retransCount
,
626 int eapSRTT
, int eapRTTVAR
,
629 /* For now, retransmission is done in EAPOL state machines, so make
630 * sure EAP state machine does not end up trying to retransmit packets.
636 static void eap_sm_parseEapResp(struct eap_sm
*sm
, u8
*resp
, size_t len
)
641 /* parse rxResp, respId, respMethod */
644 sm
->respMethod
= EAP_TYPE_NONE
;
646 if (resp
== NULL
|| len
< sizeof(*hdr
))
649 hdr
= (struct eap_hdr
*) resp
;
650 plen
= ntohs(hdr
->length
);
652 wpa_printf(MSG_DEBUG
, "EAP: Ignored truncated EAP-Packet "
653 "(len=%lu plen=%lu)", (unsigned long) len
,
654 (unsigned long) plen
);
658 sm
->respId
= hdr
->identifier
;
660 if (hdr
->code
== EAP_CODE_RESPONSE
)
663 if (len
> sizeof(*hdr
))
664 sm
->respMethod
= *((u8
*) (hdr
+ 1));
666 wpa_printf(MSG_DEBUG
, "EAP: parseEapResp: rxResp=%d respId=%d "
667 "respMethod=%d", sm
->rxResp
, sm
->respId
, sm
->respMethod
);
671 static u8
* eap_sm_buildSuccess(struct eap_sm
*sm
, int id
, size_t *len
)
673 struct eap_hdr
*resp
;
674 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Success (id=%d)", id
);
676 *len
= sizeof(*resp
);
680 resp
->code
= EAP_CODE_SUCCESS
;
681 resp
->identifier
= id
;
682 resp
->length
= htons(*len
);
688 static u8
* eap_sm_buildFailure(struct eap_sm
*sm
, int id
, size_t *len
)
690 struct eap_hdr
*resp
;
691 wpa_printf(MSG_DEBUG
, "EAP: Building EAP-Failure (id=%d)", id
);
693 *len
= sizeof(*resp
);
697 resp
->code
= EAP_CODE_FAILURE
;
698 resp
->identifier
= id
;
699 resp
->length
= htons(*len
);
705 static int eap_sm_nextId(struct eap_sm
*sm
, int id
)
708 /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
711 if (id
!= sm
->lastId
)
714 return (id
+ 1) & 0xff;
718 void eap_sm_process_nak(struct eap_sm
*sm
, u8
*nak_list
, size_t len
)
722 wpa_printf(MSG_MSGDUMP
, "EAP: processing NAK (current EAP method "
723 "index %d)", sm
->user_eap_method_index
);
725 wpa_hexdump(MSG_MSGDUMP
, "EAP: configured methods",
726 sm
->user
->methods
, EAP_MAX_METHODS
);
727 wpa_hexdump(MSG_MSGDUMP
, "EAP: list of methods supported by the peer",
730 i
= sm
->user_eap_method_index
;
731 while (i
< EAP_MAX_METHODS
&& sm
->user
->methods
[i
] != EAP_TYPE_NONE
) {
732 for (j
= 0; j
< len
; j
++) {
733 if (nak_list
[j
] == sm
->user
->methods
[i
]) {
744 /* not found - remove from the list */
745 memmove(&sm
->user
->methods
[i
], &sm
->user
->methods
[i
+ 1],
746 EAP_MAX_METHODS
- i
- 1);
747 sm
->user
->methods
[EAP_MAX_METHODS
- 1] = EAP_TYPE_NONE
;
750 wpa_hexdump(MSG_MSGDUMP
, "EAP: new list of configured methods",
751 sm
->user
->methods
, EAP_MAX_METHODS
);
755 static void eap_sm_Policy_update(struct eap_sm
*sm
, u8
*nak_list
, size_t len
)
757 if (nak_list
== NULL
|| sm
== NULL
|| sm
->user
== NULL
)
760 if (sm
->user
->phase2
) {
761 wpa_printf(MSG_DEBUG
, "EAP: EAP-Nak received after Phase2 user"
762 " info was selected - reject");
763 sm
->decision
= DECISION_FAILURE
;
767 eap_sm_process_nak(sm
, nak_list
, len
);
771 static EapType
eap_sm_Policy_getNextMethod(struct eap_sm
*sm
)
775 /* In theory, there should be no problems with starting
776 * re-authentication with something else than EAP-Request/Identity and
777 * this does indeed work with wpa_supplicant. However, at least Funk
778 * Supplicant seemed to ignore re-auth if it skipped
779 * EAP-Request/Identity.
780 * Re-auth sets currentId == -1, so that can be used here to select
781 * whether Identity needs to be requested again. */
782 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
783 next
= EAP_TYPE_IDENTITY
;
784 sm
->update_user
= TRUE
;
785 } else if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
786 sm
->user
->methods
[sm
->user_eap_method_index
] !=
788 next
= sm
->user
->methods
[sm
->user_eap_method_index
++];
790 next
= EAP_TYPE_NONE
;
792 wpa_printf(MSG_DEBUG
, "EAP: getNextMethod: type %d", next
);
797 static int eap_sm_Policy_getDecision(struct eap_sm
*sm
)
799 if (sm
->m
&& sm
->currentMethod
!= EAP_TYPE_IDENTITY
&&
800 sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
801 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method succeeded -> "
803 sm
->update_user
= TRUE
;
804 return DECISION_SUCCESS
;
807 if (sm
->m
&& sm
->m
->isDone(sm
, sm
->eap_method_priv
) &&
808 !sm
->m
->isSuccess(sm
, sm
->eap_method_priv
)) {
809 wpa_printf(MSG_DEBUG
, "EAP: getDecision: method failed -> "
811 sm
->update_user
= TRUE
;
812 return DECISION_FAILURE
;
815 if ((sm
->user
== NULL
|| sm
->update_user
) && sm
->identity
) {
816 if (eap_user_get(sm
, sm
->identity
, sm
->identity_len
, 0) != 0) {
817 wpa_printf(MSG_DEBUG
, "EAP: getDecision: user not "
818 "found from database -> FAILURE");
819 return DECISION_FAILURE
;
821 sm
->update_user
= FALSE
;
824 if (sm
->user
&& sm
->user_eap_method_index
< EAP_MAX_METHODS
&&
825 sm
->user
->methods
[sm
->user_eap_method_index
] != EAP_TYPE_NONE
) {
826 wpa_printf(MSG_DEBUG
, "EAP: getDecision: another method "
827 "available -> CONTINUE");
828 return DECISION_CONTINUE
;
831 if (sm
->identity
== NULL
|| sm
->currentId
== -1) {
832 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no identity known "
834 return DECISION_CONTINUE
;
837 wpa_printf(MSG_DEBUG
, "EAP: getDecision: no more methods available -> "
839 return DECISION_FAILURE
;
843 static Boolean
eap_sm_Policy_doPickUp(struct eap_sm
*sm
, EapType method
)
845 return method
== EAP_TYPE_IDENTITY
? TRUE
: FALSE
;
849 int eap_sm_step(struct eap_sm
*sm
)
857 } while (sm
->changed
);
862 u8
eap_get_type(const char *name
)
865 for (i
= 0; i
< NUM_EAP_METHODS
; i
++) {
866 if (strcmp(eap_methods
[i
]->name
, name
) == 0)
867 return eap_methods
[i
]->method
;
869 return EAP_TYPE_NONE
;
873 void eap_set_eapRespData(struct eap_sm
*sm
, const u8
*eapRespData
,
874 size_t eapRespDataLen
)
878 free(sm
->eapRespData
);
879 sm
->eapRespData
= malloc(eapRespDataLen
);
880 if (sm
->eapRespData
== NULL
)
882 memcpy(sm
->eapRespData
, eapRespData
, eapRespDataLen
);
883 sm
->eapRespDataLen
= eapRespDataLen
;
884 wpa_hexdump(MSG_MSGDUMP
, "EAP: EAP-Response received",
885 eapRespData
, eapRespDataLen
);
889 static void eap_user_free(struct eap_user
*user
)
893 free(user
->password
);
894 user
->password
= NULL
;
899 struct eap_sm
* eap_sm_init(void *eapol_ctx
, struct eapol_callbacks
*eapol_cb
,
900 struct eap_config
*eap_conf
)
904 sm
= malloc(sizeof(*sm
));
907 memset(sm
, 0, sizeof(*sm
));
908 sm
->eapol_ctx
= eapol_ctx
;
909 sm
->eapol_cb
= eapol_cb
;
911 sm
->ssl_ctx
= eap_conf
->ssl_ctx
;
912 sm
->eap_sim_db_priv
= eap_conf
->eap_sim_db_priv
;
913 sm
->backend_auth
= eap_conf
->backend_auth
;
915 wpa_printf(MSG_DEBUG
, "EAP: State machine created");
921 void eap_sm_deinit(struct eap_sm
*sm
)
925 wpa_printf(MSG_DEBUG
, "EAP: State machine removed");
926 if (sm
->m
&& sm
->eap_method_priv
)
927 sm
->m
->reset(sm
, sm
->eap_method_priv
);
928 free(sm
->eapReqData
);
929 free(sm
->eapKeyData
);
930 free(sm
->lastReqData
);
931 free(sm
->eapRespData
);
933 eap_user_free(sm
->user
);
938 void eap_sm_notify_cached(struct eap_sm
*sm
)
943 sm
->EAP_state
= EAP_SUCCESS
;