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