2 * WPA Supplicant / EAP state machines (RFC 4137)
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.
22 #include "wpa_supplicant.h"
23 #include "config_ssid.h"
26 #include "pcsc_funcs.h"
30 #define EAP_MAX_AUTH_ROUNDS 50
34 extern const struct eap_method eap_method_md5;
37 extern const struct eap_method eap_method_tls;
40 extern const struct eap_method eap_method_mschapv2;
43 extern const struct eap_method eap_method_peap;
46 extern const struct eap_method eap_method_ttls;
49 extern const struct eap_method eap_method_gtc;
52 extern const struct eap_method eap_method_otp;
55 extern const struct eap_method eap_method_sim;
58 extern const struct eap_method eap_method_leap;
61 extern const struct eap_method eap_method_psk;
64 extern const struct eap_method eap_method_aka;
67 extern const struct eap_method eap_method_fast;
70 extern const struct eap_method eap_method_pax;
73 static const struct eap_method *eap_methods[] =
115 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
119 * eap_sm_get_eap_methods - Get EAP method based on type number
120 * @method: EAP type number
121 * Returns: Pointer to EAP method of %NULL if not found
123 const struct eap_method * eap_sm_get_eap_methods(int method)
126 for (i = 0; i < NUM_EAP_METHODS; i++) {
127 if (eap_methods[i]->method == method)
128 return eap_methods[i];
134 static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
135 static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
136 static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
138 static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len);
139 static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
140 static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len);
141 static const char * eap_sm_method_state_txt(int state);
142 static const char * eap_sm_decision_txt(int decision);
145 /* Definitions for clarifying state machine implementation */
146 #define SM_STATE(machine, state) \
147 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
150 #define SM_ENTRY(machine, state) \
151 if (!global || sm->machine ## _state != machine ## _ ## state) { \
152 sm->changed = TRUE; \
153 wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
155 sm->machine ## _state = machine ## _ ## state;
157 #define SM_ENTER(machine, state) \
158 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
159 #define SM_ENTER_GLOBAL(machine, state) \
160 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
162 #define SM_STEP(machine) \
163 static void sm_ ## machine ## _Step(struct eap_sm *sm)
165 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
168 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
170 return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
174 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
177 sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
181 static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
183 return sm->eapol_cb->get_int(sm->eapol_ctx, var);
187 static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
190 sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
194 static u8 * eapol_get_eapReqData(struct eap_sm *sm, size_t *len)
196 return sm->eapol_cb->get_eapReqData(sm->eapol_ctx, len);
200 static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
202 if (sm->m == NULL || sm->eap_method_priv == NULL)
205 wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
206 "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
207 sm->m->deinit(sm, sm->eap_method_priv);
208 sm->eap_method_priv = NULL;
213 SM_STATE(EAP, INITIALIZE)
215 SM_ENTRY(EAP, INITIALIZE);
216 if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
217 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
218 wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
219 "fast reauthentication");
220 sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
222 eap_deinit_prev_method(sm, "INITIALIZE");
224 sm->selectedMethod = EAP_TYPE_NONE;
225 sm->methodState = METHOD_NONE;
226 sm->allowNotifications = TRUE;
227 sm->decision = DECISION_FAIL;
228 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
229 eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
230 eapol_set_bool(sm, EAPOL_eapFail, FALSE);
231 free(sm->eapKeyData);
232 sm->eapKeyData = NULL;
233 sm->eapKeyAvailable = FALSE;
234 eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
235 sm->lastId = -1; /* new session - make sure this does not match with
236 * the first EAP-Packet */
238 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
239 * seemed to be able to trigger cases where both were set and if EAPOL
240 * state machine uses eapNoResp first, it may end up not sending a real
241 * reply correctly. This occurred when the workaround in FAIL state set
242 * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
245 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
246 eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
251 SM_STATE(EAP, DISABLED)
253 SM_ENTRY(EAP, DISABLED);
264 SM_STATE(EAP, RECEIVED)
266 const u8 *eapReqData;
267 size_t eapReqDataLen;
269 SM_ENTRY(EAP, RECEIVED);
270 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
271 /* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
272 eap_sm_parseEapReq(sm, eapReqData, eapReqDataLen);
277 SM_STATE(EAP, GET_METHOD)
279 SM_ENTRY(EAP, GET_METHOD);
280 if (eap_sm_allowMethod(sm, sm->reqMethod)) {
282 if (sm->fast_reauth &&
283 sm->m && sm->m->method == sm->reqMethod &&
284 sm->m->has_reauth_data &&
285 sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
286 wpa_printf(MSG_DEBUG, "EAP: using previous method data"
287 " for fast re-authentication");
290 eap_deinit_prev_method(sm, "GET_METHOD");
291 sm->selectedMethod = sm->reqMethod;
293 sm->m = eap_sm_get_eap_methods(sm->selectedMethod);
295 wpa_printf(MSG_DEBUG, "EAP: initialize selected EAP "
297 sm->selectedMethod, sm->m->name);
299 sm->eap_method_priv = sm->m->init_for_reauth(
300 sm, sm->eap_method_priv);
302 sm->eap_method_priv = sm->m->init(sm);
303 if (sm->eap_method_priv == NULL) {
304 struct wpa_ssid *config = eap_get_config(sm);
305 wpa_msg(sm->msg_ctx, MSG_INFO,
306 "EAP: Failed to initialize EAP method "
308 sm->selectedMethod, sm->m->name);
310 sm->methodState = METHOD_NONE;
311 sm->selectedMethod = EAP_TYPE_NONE;
312 if (sm->reqMethod == EAP_TYPE_TLS &&
314 (config->pending_req_pin ||
315 config->pending_req_passphrase)) {
317 * Return without generating Nak in
318 * order to allow entering of PIN code
319 * or passphrase to retry the current
322 wpa_printf(MSG_DEBUG, "EAP: Pending "
323 "PIN/passphrase request - "
328 sm->methodState = METHOD_INIT;
329 wpa_msg(sm->msg_ctx, MSG_INFO,
331 "EAP method %d (%s) selected",
332 sm->selectedMethod, sm->m->name);
338 free(sm->eapRespData);
339 sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen);
343 SM_STATE(EAP, METHOD)
346 size_t eapReqDataLen;
347 struct eap_method_ret ret;
349 SM_ENTRY(EAP, METHOD);
351 wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
355 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
357 /* Get ignore, methodState, decision, allowNotifications, and
359 memset(&ret, 0, sizeof(ret));
360 ret.ignore = sm->ignore;
361 ret.methodState = sm->methodState;
362 ret.decision = sm->decision;
363 ret.allowNotifications = sm->allowNotifications;
364 free(sm->eapRespData);
365 sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
366 eapReqData, eapReqDataLen,
367 &sm->eapRespDataLen);
368 wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
369 "methodState=%s decision=%s",
370 ret.ignore ? "TRUE" : "FALSE",
371 eap_sm_method_state_txt(ret.methodState),
372 eap_sm_decision_txt(ret.decision));
374 sm->ignore = ret.ignore;
377 sm->methodState = ret.methodState;
378 sm->decision = ret.decision;
379 sm->allowNotifications = ret.allowNotifications;
381 if (sm->m->isKeyAvailable && sm->m->getKey &&
382 sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
383 free(sm->eapKeyData);
384 sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
390 SM_STATE(EAP, SEND_RESPONSE)
392 SM_ENTRY(EAP, SEND_RESPONSE);
393 free(sm->lastRespData);
394 if (sm->eapRespData) {
396 memcpy(sm->last_md5, sm->req_md5, 16);
397 sm->lastId = sm->reqId;
398 sm->lastRespData = malloc(sm->eapRespDataLen);
399 if (sm->lastRespData) {
400 memcpy(sm->lastRespData, sm->eapRespData,
402 sm->lastRespDataLen = sm->eapRespDataLen;
404 eapol_set_bool(sm, EAPOL_eapResp, TRUE);
406 sm->lastRespData = NULL;
407 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
408 eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
412 SM_STATE(EAP, DISCARD)
414 SM_ENTRY(EAP, DISCARD);
415 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
416 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
420 SM_STATE(EAP, IDENTITY)
422 const u8 *eapReqData;
423 size_t eapReqDataLen;
425 SM_ENTRY(EAP, IDENTITY);
426 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
427 eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);
428 free(sm->eapRespData);
429 sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,
430 &sm->eapRespDataLen, 0);
434 SM_STATE(EAP, NOTIFICATION)
436 const u8 *eapReqData;
437 size_t eapReqDataLen;
439 SM_ENTRY(EAP, NOTIFICATION);
440 eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
441 eap_sm_processNotify(sm, eapReqData, eapReqDataLen);
442 free(sm->eapRespData);
443 sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,
444 &sm->eapRespDataLen);
448 SM_STATE(EAP, RETRANSMIT)
450 SM_ENTRY(EAP, RETRANSMIT);
451 free(sm->eapRespData);
452 if (sm->lastRespData) {
453 sm->eapRespData = malloc(sm->lastRespDataLen);
454 if (sm->eapRespData) {
455 memcpy(sm->eapRespData, sm->lastRespData,
456 sm->lastRespDataLen);
457 sm->eapRespDataLen = sm->lastRespDataLen;
460 sm->eapRespData = NULL;
464 SM_STATE(EAP, SUCCESS)
466 SM_ENTRY(EAP, SUCCESS);
467 if (sm->eapKeyData != NULL)
468 sm->eapKeyAvailable = TRUE;
469 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
472 * RFC 4137 does not clear eapReq here, but this seems to be required
473 * to avoid processing the same request twice when state machine is
476 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
479 * RFC 4137 does not set eapNoResp here, but this seems to be required
480 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
481 * addition, either eapResp or eapNoResp is required to be set after
482 * processing the received EAP frame.
484 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
486 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
487 "EAP authentication completed successfully");
491 SM_STATE(EAP, FAILURE)
493 SM_ENTRY(EAP, FAILURE);
494 eapol_set_bool(sm, EAPOL_eapFail, TRUE);
497 * RFC 4137 does not clear eapReq here, but this seems to be required
498 * to avoid processing the same request twice when state machine is
501 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
504 * RFC 4137 does not set eapNoResp here. However, either eapResp or
505 * eapNoResp is required to be set after processing the received EAP
508 eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
510 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
511 "EAP authentication failed");
515 static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
518 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
519 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
520 * RFC 4137 require that reqId == lastId. In addition, it looks like
521 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
523 * Accept this kind of Id if EAP workarounds are enabled. These are
524 * unauthenticated plaintext messages, so this should have minimal
525 * security implications (bit easier to fake EAP-Success/Failure).
527 if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
528 reqId == ((lastId + 2) & 0xff))) {
529 wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
530 "identifier field in EAP Success: "
531 "reqId=%d lastId=%d (these are supposed to be "
532 "same)", reqId, lastId);
535 wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
536 "lastId=%d", reqId, lastId);
545 if (eapol_get_bool(sm, EAPOL_eapRestart) &&
546 eapol_get_bool(sm, EAPOL_portEnabled))
547 SM_ENTER_GLOBAL(EAP, INITIALIZE);
548 else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
549 SM_ENTER_GLOBAL(EAP, DISABLED);
550 else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
551 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
552 wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
553 "authentication rounds - abort",
554 EAP_MAX_AUTH_ROUNDS);
556 SM_ENTER_GLOBAL(EAP, FAILURE);
558 } else switch (sm->EAP_state) {
563 if (eapol_get_bool(sm, EAPOL_portEnabled) &&
565 SM_ENTER(EAP, INITIALIZE);
568 if (eapol_get_bool(sm, EAPOL_eapReq))
569 SM_ENTER(EAP, RECEIVED);
570 else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
571 sm->decision != DECISION_FAIL) ||
572 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
573 sm->decision == DECISION_UNCOND_SUCC))
574 SM_ENTER(EAP, SUCCESS);
575 else if (eapol_get_bool(sm, EAPOL_altReject) ||
576 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
577 sm->decision != DECISION_UNCOND_SUCC) ||
578 (eapol_get_bool(sm, EAPOL_altAccept) &&
579 sm->methodState != METHOD_CONT &&
580 sm->decision == DECISION_FAIL))
581 SM_ENTER(EAP, FAILURE);
582 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
583 sm->leap_done && sm->decision != DECISION_FAIL &&
584 sm->methodState == METHOD_DONE)
585 SM_ENTER(EAP, SUCCESS);
586 else if (sm->selectedMethod == EAP_TYPE_PEAP &&
587 sm->peap_done && sm->decision != DECISION_FAIL &&
588 sm->methodState == METHOD_DONE)
589 SM_ENTER(EAP, SUCCESS);
592 duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
593 if (sm->workaround && duplicate &&
594 memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
596 * RFC 4137 uses (reqId == lastId) as the only
597 * verification for duplicate EAP requests. However,
598 * this misses cases where the AS is incorrectly using
599 * the same id again; and unfortunately, such
600 * implementations exist. Use MD5 hash as an extra
601 * verification for the packets being duplicate to
602 * workaround these issues.
604 wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
605 " but EAP packets were not identical");
606 wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
607 "is not a duplicate packet");
612 (sm->reqId == sm->lastId ||
613 eap_success_workaround(sm, sm->reqId, sm->lastId)) &&
614 sm->decision != DECISION_FAIL)
615 SM_ENTER(EAP, SUCCESS);
616 else if (sm->methodState != METHOD_CONT &&
618 sm->decision != DECISION_UNCOND_SUCC) ||
619 (sm->rxSuccess && sm->decision == DECISION_FAIL &&
620 (sm->selectedMethod != EAP_TYPE_LEAP ||
621 sm->methodState != METHOD_MAY_CONT))) &&
622 (sm->reqId == sm->lastId ||
623 eap_success_workaround(sm, sm->reqId, sm->lastId)))
624 SM_ENTER(EAP, FAILURE);
625 else if (sm->rxReq && duplicate)
626 SM_ENTER(EAP, RETRANSMIT);
627 else if (sm->rxReq && !duplicate &&
628 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
629 sm->allowNotifications)
630 SM_ENTER(EAP, NOTIFICATION);
631 else if (sm->rxReq && !duplicate &&
632 sm->selectedMethod == EAP_TYPE_NONE &&
633 sm->reqMethod == EAP_TYPE_IDENTITY)
634 SM_ENTER(EAP, IDENTITY);
635 else if (sm->rxReq && !duplicate &&
636 sm->selectedMethod == EAP_TYPE_NONE &&
637 sm->reqMethod != EAP_TYPE_IDENTITY &&
638 sm->reqMethod != EAP_TYPE_NOTIFICATION)
639 SM_ENTER(EAP, GET_METHOD);
640 else if (sm->rxReq && !duplicate &&
641 sm->reqMethod == sm->selectedMethod &&
642 sm->methodState != METHOD_DONE)
643 SM_ENTER(EAP, METHOD);
644 else if (sm->selectedMethod == EAP_TYPE_LEAP &&
645 (sm->rxSuccess || sm->rxResp))
646 SM_ENTER(EAP, METHOD);
648 SM_ENTER(EAP, DISCARD);
651 if (sm->selectedMethod == sm->reqMethod)
652 SM_ENTER(EAP, METHOD);
654 SM_ENTER(EAP, SEND_RESPONSE);
658 SM_ENTER(EAP, DISCARD);
660 SM_ENTER(EAP, SEND_RESPONSE);
662 case EAP_SEND_RESPONSE:
669 SM_ENTER(EAP, SEND_RESPONSE);
671 case EAP_NOTIFICATION:
672 SM_ENTER(EAP, SEND_RESPONSE);
675 SM_ENTER(EAP, SEND_RESPONSE);
685 static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method)
687 struct wpa_ssid *config = eap_get_config(sm);
690 if (!wpa_config_allowed_eap_method(config, method))
692 for (i = 0; i < NUM_EAP_METHODS; i++) {
693 if (eap_methods[i]->method == method)
700 static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
702 struct wpa_ssid *config = eap_get_config(sm);
703 struct eap_hdr *resp;
707 wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "
708 "allowed)", sm->reqMethod);
709 *len = sizeof(struct eap_hdr) + 1;
710 resp = malloc(*len + NUM_EAP_METHODS);
714 resp->code = EAP_CODE_RESPONSE;
715 resp->identifier = id;
716 pos = (u8 *) (resp + 1);
717 *pos++ = EAP_TYPE_NAK;
719 for (i = 0; i < NUM_EAP_METHODS; i++) {
720 if (eap_methods[i]->method != sm->reqMethod &&
721 wpa_config_allowed_eap_method(config,
722 eap_methods[i]->method)) {
723 *pos++ = eap_methods[i]->method;
729 *pos = EAP_TYPE_NONE;
732 wpa_hexdump(MSG_DEBUG, "EAP: allowed methods",
733 ((u8 *) (resp + 1)) + 1, found);
735 resp->length = host_to_be16(*len);
741 static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
744 const struct eap_hdr *hdr = (const struct eap_hdr *) req;
745 const u8 *pos = (const u8 *) (hdr + 1);
748 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
749 "EAP authentication started");
751 /* TODO: could save displayable message so that it can be shown to the
752 * user in case of interaction is required */
753 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
754 pos, be_to_host16(hdr->length) - 5);
758 static int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
763 u8 *pos = ssid->eap_methods;
765 imsi_len = sizeof(imsi);
766 if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
767 wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
771 wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
773 while (pos && *pos != EAP_TYPE_NONE) {
774 if (*pos == EAP_TYPE_AKA) {
781 free(ssid->identity);
782 ssid->identity = malloc(1 + imsi_len);
783 if (ssid->identity == NULL) {
784 wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
785 "IMSI-based identity");
789 ssid->identity[0] = aka ? '0' : '1';
790 memcpy(ssid->identity + 1, imsi, imsi_len);
791 ssid->identity_len = 1 + imsi_len;
796 static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
798 if (scard_set_pin(sm->scard_ctx, ssid->pin)) {
800 * Make sure the same PIN is not tried again in order to avoid
806 wpa_printf(MSG_WARNING, "PIN validation failed");
807 eap_sm_request_pin(sm, ssid);
811 return eap_sm_imsi_identity(sm, ssid);
816 * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
817 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
818 * @id: EAP identifier for the packet
819 * @len: Pointer to variable that will be set to the length of the response
820 * @encrypted: Whether the packet is for enrypted tunnel (EAP phase 2)
821 * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
824 * This function allocates and builds an EAP-Identity/Response packet for the
825 * current network. The caller is responsible for freeing the returned data.
827 u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
830 struct wpa_ssid *config = eap_get_config(sm);
831 struct eap_hdr *resp;
836 if (config == NULL) {
837 wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
838 "was not available");
842 if (sm->m && sm->m->get_identity &&
843 (identity = sm->m->get_identity(sm, sm->eap_method_priv,
844 &identity_len)) != NULL) {
845 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
846 "identity", identity, identity_len);
847 } else if (!encrypted && config->anonymous_identity) {
848 identity = config->anonymous_identity;
849 identity_len = config->anonymous_identity_len;
850 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
851 identity, identity_len);
853 identity = config->identity;
854 identity_len = config->identity_len;
855 wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
856 identity, identity_len);
859 if (identity == NULL) {
860 wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
861 "configuration was not available");
863 if (eap_sm_get_scard_identity(sm, config) < 0)
865 identity = config->identity;
866 identity_len = config->identity_len;
867 wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
868 "IMSI", identity, identity_len);
870 eap_sm_request_identity(sm, config);
876 *len = sizeof(struct eap_hdr) + 1 + identity_len;
881 resp->code = EAP_CODE_RESPONSE;
882 resp->identifier = id;
883 resp->length = host_to_be16(*len);
884 pos = (u8 *) (resp + 1);
885 *pos++ = EAP_TYPE_IDENTITY;
886 memcpy(pos, identity, identity_len);
892 static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
894 const struct eap_hdr *hdr = (const struct eap_hdr *) req;
900 pos = (const u8 *) (hdr + 1);
903 msg_len = be_to_host16(hdr->length);
907 wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
910 msg = malloc(msg_len + 1);
913 for (i = 0; i < msg_len; i++)
914 msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
916 wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
917 WPA_EVENT_EAP_NOTIFICATION, msg);
922 static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
924 struct eap_hdr *resp;
927 wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
928 *len = sizeof(struct eap_hdr) + 1;
933 resp->code = EAP_CODE_RESPONSE;
934 resp->identifier = id;
935 resp->length = host_to_be16(*len);
936 pos = (u8 *) (resp + 1);
937 *pos = EAP_TYPE_NOTIFICATION;
943 static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
945 const struct eap_hdr *hdr;
948 sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
950 sm->reqMethod = EAP_TYPE_NONE;
952 if (req == NULL || len < sizeof(*hdr))
955 hdr = (const struct eap_hdr *) req;
956 plen = be_to_host16(hdr->length);
958 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
959 "(len=%lu plen=%lu)",
960 (unsigned long) len, (unsigned long) plen);
964 sm->reqId = hdr->identifier;
966 if (sm->workaround) {
967 md5_vector(1, (const u8 **) &req, &len, sm->req_md5);
971 case EAP_CODE_REQUEST:
973 if (plen > sizeof(*hdr))
974 sm->reqMethod = *((u8 *) (hdr + 1));
975 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request method=%d "
976 "id=%d", sm->reqMethod, sm->reqId);
978 case EAP_CODE_RESPONSE:
979 if (sm->selectedMethod == EAP_TYPE_LEAP) {
981 if (plen > sizeof(*hdr))
982 sm->reqMethod = *((u8 *) (hdr + 1));
983 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
984 "LEAP method=%d id=%d",
985 sm->reqMethod, sm->reqId);
988 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
990 case EAP_CODE_SUCCESS:
991 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
992 sm->rxSuccess = TRUE;
994 case EAP_CODE_FAILURE:
995 wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
996 sm->rxFailure = TRUE;
999 wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
1000 "code %d", hdr->code);
1007 * eap_sm_init - Allocate and initialize EAP state machine
1008 * @eapol_ctx: Context data to be used with eapol_cb calls
1009 * @eapol_cb: Pointer to EAPOL callback functions
1010 * @msg_ctx: Context data for wpa_msg() calls
1011 * @conf: EAP configuration
1012 * Returns: Pointer to the allocated EAP state machine or %NULL on failure
1014 * This function allocates and initializes an EAP state machine. In addition,
1015 * this initializes TLS library for the new EAP state machine.
1017 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
1018 void *msg_ctx, struct eap_config *conf)
1021 struct tls_config tlsconf;
1023 sm = malloc(sizeof(*sm));
1026 memset(sm, 0, sizeof(*sm));
1027 sm->eapol_ctx = eapol_ctx;
1028 sm->eapol_cb = eapol_cb;
1029 sm->msg_ctx = msg_ctx;
1030 sm->ClientTimeout = 60;
1032 memset(&tlsconf, 0, sizeof(tlsconf));
1033 tlsconf.opensc_engine_path = conf->opensc_engine_path;
1034 tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
1035 tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
1036 sm->ssl_ctx = tls_init(&tlsconf);
1037 if (sm->ssl_ctx == NULL) {
1038 wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
1049 * eap_sm_deinit - Deinitialize and free an EAP state machine
1050 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1052 * This function deinitializes EAP state machine and frees all allocated
1055 void eap_sm_deinit(struct eap_sm *sm)
1059 eap_deinit_prev_method(sm, "EAP deinit");
1060 free(sm->lastRespData);
1061 free(sm->eapRespData);
1062 free(sm->eapKeyData);
1063 tls_deinit(sm->ssl_ctx);
1069 * eap_sm_step - Step EAP state machine
1070 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1071 * Returns: 1 if EAP state was changed or 0 if not
1073 * This function advances EAP state machine to a new state to match with the
1074 * current variables. This should be called whenever variables used by the EAP
1075 * state machine have changed.
1077 int eap_sm_step(struct eap_sm *sm)
1081 sm->changed = FALSE;
1085 } while (sm->changed);
1091 * eap_sm_abort - Abort EAP authentication
1092 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1094 * Release system resources that have been allocated for the authentication
1095 * session without fully deinitializing the EAP state machine.
1097 void eap_sm_abort(struct eap_sm *sm)
1099 free(sm->eapRespData);
1100 sm->eapRespData = NULL;
1101 free(sm->eapKeyData);
1102 sm->eapKeyData = NULL;
1106 static const char * eap_sm_state_txt(int state)
1109 case EAP_INITIALIZE:
1110 return "INITIALIZE";
1117 case EAP_GET_METHOD:
1118 return "GET_METHOD";
1121 case EAP_SEND_RESPONSE:
1122 return "SEND_RESPONSE";
1127 case EAP_NOTIFICATION:
1128 return "NOTIFICATION";
1129 case EAP_RETRANSMIT:
1130 return "RETRANSMIT";
1141 static const char * eap_sm_method_state_txt(int state)
1150 case METHOD_MAY_CONT:
1160 static const char * eap_sm_decision_txt(int decision)
1165 case DECISION_COND_SUCC:
1167 case DECISION_UNCOND_SUCC:
1168 return "UNCOND_SUCC";
1176 * eap_sm_get_status - Get EAP state machine status
1177 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1178 * @buf: buffer for status information
1179 * @buflen: maximum buffer length
1180 * @verbose: whether to include verbose status information
1181 * Returns: number of bytes written to buf.
1183 * Query EAP state machine for status information. This function fills in a
1184 * text area with current status information from the EAPOL state machine. If
1185 * the buffer (buf) is not large enough, status information will be truncated
1186 * to fit the buffer.
1188 int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
1195 len = snprintf(buf, buflen,
1197 eap_sm_state_txt(sm->EAP_state));
1199 if (sm->selectedMethod != EAP_TYPE_NONE) {
1204 const struct eap_method *m =
1205 eap_sm_get_eap_methods(sm->selectedMethod);
1211 len += snprintf(buf + len, buflen - len,
1212 "selectedMethod=%d (EAP-%s)\n",
1213 sm->selectedMethod, name);
1215 if (sm->m && sm->m->get_status) {
1216 len += sm->m->get_status(sm, sm->eap_method_priv,
1217 buf + len, buflen - len,
1223 len += snprintf(buf + len, buflen - len,
1227 "ClientTimeout=%d\n",
1229 eap_sm_method_state_txt(sm->methodState),
1230 eap_sm_decision_txt(sm->decision),
1239 TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
1241 } eap_ctrl_req_type;
1243 static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
1244 eap_ctrl_req_type type, const char *msg,
1253 if (config == NULL || sm == NULL)
1260 config->pending_req_identity++;
1265 config->pending_req_password++;
1267 case TYPE_NEW_PASSWORD:
1268 field = "NEW_PASSWORD";
1269 txt = "New Password";
1270 config->pending_req_new_password++;
1275 config->pending_req_pin++;
1280 tmp = malloc(msglen + 3);
1284 memcpy(tmp + 1, msg, msglen);
1285 tmp[msglen + 1] = ']';
1286 tmp[msglen + 2] = '\0';
1288 free(config->pending_req_otp);
1289 config->pending_req_otp = tmp;
1290 config->pending_req_otp_len = msglen + 3;
1292 if (config->pending_req_otp == NULL)
1294 txt = config->pending_req_otp;
1297 case TYPE_PASSPHRASE:
1298 field = "PASSPHRASE";
1299 txt = "Private key passphrase";
1300 config->pending_req_passphrase++;
1306 buflen = 100 + strlen(txt) + config->ssid_len;
1307 buf = malloc(buflen);
1310 len = snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
1311 field, config->id, txt);
1312 if (config->ssid && buflen > len + config->ssid_len) {
1313 memcpy(buf + len, config->ssid, config->ssid_len);
1314 len += config->ssid_len;
1317 wpa_msg(sm->msg_ctx, MSG_INFO, "%s", buf);
1323 * eap_sm_request_identity - Request identity from user (ctrl_iface)
1324 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1325 * @config: Pointer to the current network configuration
1327 * EAP methods can call this function to request identity information for the
1328 * current network. This is normally called when the identity is not included
1329 * in the network configuration. The request will be sent to monitor programs
1330 * through the control interface.
1332 void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
1334 eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
1339 * eap_sm_request_password - Request password from user (ctrl_iface)
1340 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1341 * @config: Pointer to the current network configuration
1343 * EAP methods can call this function to request password information for the
1344 * current network. This is normally called when the password is not included
1345 * in the network configuration. The request will be sent to monitor programs
1346 * through the control interface.
1348 void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
1350 eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
1355 * eap_sm_request_new_password - Request new password from user (ctrl_iface)
1356 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1357 * @config: Pointer to the current network configuration
1359 * EAP methods can call this function to request new password information for
1360 * the current network. This is normally called when the EAP method indicates
1361 * that the current password has expired and password change is required. The
1362 * request will be sent to monitor programs through the control interface.
1364 void eap_sm_request_new_password(struct eap_sm *sm, struct wpa_ssid *config)
1366 eap_sm_request(sm, config, TYPE_NEW_PASSWORD, NULL, 0);
1371 * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
1372 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1373 * @config: Pointer to the current network configuration
1375 * EAP methods can call this function to request SIM or smart card PIN
1376 * information for the current network. This is normally called when the PIN is
1377 * not included in the network configuration. The request will be sent to
1378 * monitor programs through the control interface.
1380 void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config)
1382 eap_sm_request(sm, config, TYPE_PIN, NULL, 0);
1387 * eap_sm_request_otp - Request one time password from user (ctrl_iface)
1388 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1389 * @config: Pointer to the current network configuration
1390 * @msg: Message to be displayed to the user when asking for OTP
1391 * @msg_len: Length of the user displayable message
1393 * EAP methods can call this function to request open time password (OTP) for
1394 * the current network. The request will be sent to monitor programs through
1395 * the control interface.
1397 void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
1398 const char *msg, size_t msg_len)
1400 eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
1405 * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
1406 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1407 * @config: Pointer to the current network configuration
1409 * EAP methods can call this function to request passphrase for a private key
1410 * for the current network. This is normally called when the passphrase is not
1411 * included in the network configuration. The request will be sent to monitor
1412 * programs through the control interface.
1414 void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config)
1416 eap_sm_request(sm, config, TYPE_PASSPHRASE, NULL, 0);
1421 * eap_sm_notify_ctrl_attached - Notification of attached monitor
1422 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1424 * Notify EAP state machines that a monitor was attached to the control
1425 * interface to trigger re-sending of pending requests for user input.
1427 void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
1429 struct wpa_ssid *config = eap_get_config(sm);
1434 /* Re-send any pending requests for user data since a new control
1435 * interface was added. This handles cases where the EAP authentication
1436 * starts immediately after system startup when the user interface is
1437 * not yet running. */
1438 if (config->pending_req_identity)
1439 eap_sm_request_identity(sm, config);
1440 if (config->pending_req_password)
1441 eap_sm_request_password(sm, config);
1442 if (config->pending_req_new_password)
1443 eap_sm_request_new_password(sm, config);
1444 if (config->pending_req_otp)
1445 eap_sm_request_otp(sm, config, NULL, 0);
1446 if (config->pending_req_pin)
1447 eap_sm_request_pin(sm, config);
1448 if (config->pending_req_passphrase)
1449 eap_sm_request_passphrase(sm, config);
1454 * eap_get_type - Get EAP type for the given EAP method name
1455 * @name: EAP method name, e.g., TLS
1456 * Returns: EAP method type or %EAP_TYPE_NONE if not found
1458 * This function maps EAP type names into EAP type numbers based on the list of
1459 * EAP methods included in the build.
1461 u8 eap_get_type(const char *name)
1464 for (i = 0; i < NUM_EAP_METHODS; i++) {
1465 if (strcmp(eap_methods[i]->name, name) == 0)
1466 return eap_methods[i]->method;
1468 return EAP_TYPE_NONE;
1473 * eap_get_name - Get EAP method name for the given EAP type
1474 * @type: EAP method type
1475 * Returns: EAP method name, e.g., TLS, or %NULL if not found
1477 * This function maps EAP type numbers into EAP type names based on the list of
1478 * EAP methods included in the build.
1480 const char * eap_get_name(EapType type)
1483 for (i = 0; i < NUM_EAP_METHODS; i++) {
1484 if (eap_methods[i]->method == type)
1485 return eap_methods[i]->name;
1492 * eap_get_names - Get space separated list of names for supported EAP methods
1493 * @buf: Buffer for names
1494 * @buflen: Buffer length
1495 * Returns: Number of characters written into buf (not including nul
1498 size_t eap_get_names(char *buf, size_t buflen)
1506 for (i = 0; i < NUM_EAP_METHODS; i++) {
1507 pos += snprintf(pos, end - pos, "%s%s",
1508 i == 0 ? "" : " ", eap_methods[i]->name);
1515 static int eap_allowed_phase2_type(int type)
1517 return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
1518 type != EAP_TYPE_FAST;
1523 * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
1524 * @name: EAP method name, e.g., MD5
1525 * Returns: EAP method type or %EAP_TYPE_NONE if not found
1527 * This function maps EAP type names into EAP type numbers that are allowed for
1528 * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
1529 * EAP-PEAP, EAP-TTLS, and EAP-FAST.
1531 u8 eap_get_phase2_type(const char *name)
1533 u8 type = eap_get_type(name);
1534 if (eap_allowed_phase2_type(type))
1536 return EAP_TYPE_NONE;
1541 * eap_get_phase2_types - Get list of allowed EAP phase 2 types
1542 * @config: Pointer to a network configuration
1543 * @count: Pointer to variable filled with number of returned EAP types
1544 * Returns: Pointer to allocated type list or %NULL on failure
1546 * This function generates an array of allowed EAP phase 2 (tunneled) types for
1547 * the given network configuration.
1549 u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
1555 buf = malloc(NUM_EAP_METHODS);
1559 for (i = 0; i < NUM_EAP_METHODS; i++) {
1560 method = eap_methods[i]->method;
1561 if (eap_allowed_phase2_type(method)) {
1562 if (method == EAP_TYPE_TLS && config &&
1563 config->private_key2 == NULL)
1565 buf[*count] = method;
1575 * eap_set_fast_reauth - Update fast_reauth setting
1576 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1577 * @enabled: 1 = fast reauthentication is enabled, 0 = disabled
1579 void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
1581 sm->fast_reauth = enabled;
1586 * eap_set_workaround - Update EAP workarounds setting
1587 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1588 * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
1590 void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
1592 sm->workaround = workaround;
1597 * eap_get_config - Get current network configuration
1598 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1599 * Returns: Pointer to the current network configuration or %NULL if not found
1601 struct wpa_ssid * eap_get_config(struct eap_sm *sm)
1603 return sm->eapol_cb->get_config(sm->eapol_ctx);
1608 * eap_key_available - Get key availability (eapKeyAvailable variable)
1609 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1610 * Returns: 1 if EAP keying material is available, 0 if not
1612 int eap_key_available(struct eap_sm *sm)
1614 return sm ? sm->eapKeyAvailable : 0;
1619 * eap_notify_success - Notify EAP state machine about external success trigger
1620 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1622 * This function is called when external event, e.g., successful completion of
1623 * WPA-PSK key handshake, is indicating that EAP state machine should move to
1624 * success state. This is mainly used with security modes that do not use EAP
1625 * state machine (e.g., WPA-PSK).
1627 void eap_notify_success(struct eap_sm *sm)
1630 sm->decision = DECISION_COND_SUCC;
1631 sm->EAP_state = EAP_SUCCESS;
1635 * eap_notify_lower_layer_success - Notification of lower layer success
1636 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1638 * Notify EAP state machines that a lower layer has detected a successful
1639 * authentication. This is used to recover from dropped EAP-Success messages.
1641 void eap_notify_lower_layer_success(struct eap_sm *sm)
1646 if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
1647 sm->decision == DECISION_FAIL ||
1648 (sm->methodState != METHOD_MAY_CONT &&
1649 sm->methodState != METHOD_DONE))
1652 if (sm->eapKeyData != NULL)
1653 sm->eapKeyAvailable = TRUE;
1654 eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
1655 wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
1656 "EAP authentication completed successfully (based on lower "
1662 * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
1663 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1664 * @len: Pointer to variable that will be set to number of bytes in the key
1665 * Returns: Pointer to the EAP keying data or %NULL on failure
1667 * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
1668 * key is available only after a successful authentication. EAP state machine
1669 * continues to manage the key data and the caller must not change or free the
1672 const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
1674 if (sm == NULL || sm->eapKeyData == NULL) {
1679 *len = sm->eapKeyDataLen;
1680 return sm->eapKeyData;
1685 * eap_get_eapKeyData - Get EAP response data
1686 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1687 * @len: Pointer to variable that will be set to the length of the response
1688 * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
1690 * Fetch EAP response (eapRespData) from the EAP state machine. This data is
1691 * available when EAP state machine has processed an incoming EAP request. The
1692 * EAP state machine does not maintain a reference to the response after this
1693 * function is called and the caller is responsible for freeing the data.
1695 u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
1699 if (sm == NULL || sm->eapRespData == NULL) {
1704 resp = sm->eapRespData;
1705 *len = sm->eapRespDataLen;
1706 sm->eapRespData = NULL;
1707 sm->eapRespDataLen = 0;
1714 * eap_sm_register_scard_ctx - Notification of smart card context
1715 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1716 * @ctx: context data for smart card operations
1718 * Notify EAP state machines of context data for smart card operations. This
1719 * context data will be used as a parameter for scard_*() functions.
1721 void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
1724 sm->scard_ctx = ctx;
1729 * eap_hdr_validate - Validate EAP header
1730 * @eap_type: Expected EAP type number
1731 * @msg: EAP frame (starting with EAP header)
1732 * @msglen: Length of msg
1733 * @plen: Pointer for return payload length
1734 * Returns: Pointer to EAP payload (after type field), or %NULL on failure
1736 * This is a helper function for EAP method implementations. This is usually
1737 * called in the beginning of struct eap_method::process() function.
1739 const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
1742 const struct eap_hdr *hdr;
1746 hdr = (const struct eap_hdr *) msg;
1747 pos = (const u8 *) (hdr + 1);
1748 if (msglen < sizeof(*hdr) + 1 || *pos != eap_type) {
1749 wpa_printf(MSG_INFO, "EAP: Invalid frame type");
1752 len = be_to_host16(hdr->length);
1753 if (len < sizeof(*hdr) + 1 || len > msglen) {
1754 wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
1757 *plen = len - sizeof(*hdr) - 1;
1763 * eap_set_config_blob - Set or add a named configuration blob
1764 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1765 * @blob: New value for the blob
1767 * Adds a new configuration blob or replaces the current value of an existing
1770 void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
1772 sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
1777 * eap_get_config_blob - Get a named configuration blob
1778 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1779 * @name: Name of the blob
1780 * Returns: Pointer to blob data or %NULL if not found
1782 const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
1785 return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
1790 * eap_set_force_disabled - Set force_disabled flag
1791 * @sm: Pointer to EAP state machine allocated with eap_sm_init()
1792 * @disabled: 1 = EAP disabled, 0 = EAP enabled
1794 * This function is used to force EAP state machine to be disabled when it is
1795 * not in use (e.g., with WPA-PSK or plaintext connections).
1797 void eap_set_force_disabled(struct eap_sm *sm, int disabled)
1799 sm->force_disabled = disabled;