]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/hostapd/eap.c
This commit was generated by cvs2svn to compensate for changes in r162503,
[FreeBSD/FreeBSD.git] / contrib / hostapd / eap.c
1 /*
2  * hostapd / EAP Standalone Authenticator state machine
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
4  *
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.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  *
14  * $FreeBSD$
15  */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <unistd.h>
20 #include <netinet/in.h>
21 #include <string.h>
22 #include <sys/socket.h>
23
24 #include "hostapd.h"
25 #include "eloop.h"
26 #include "sta_info.h"
27 #include "eap_i.h"
28
29 #define EAP_MAX_AUTH_ROUNDS 50
30
31 extern const struct eap_method eap_method_identity;
32 #ifdef EAP_MD5
33 extern const struct eap_method eap_method_md5;
34 #endif /* EAP_MD5 */
35 #ifdef EAP_TLS
36 extern const struct eap_method eap_method_tls;
37 #endif /* EAP_TLS */
38 #ifdef EAP_MSCHAPv2
39 extern const struct eap_method eap_method_mschapv2;
40 #endif /* EAP_MSCHAPv2 */
41 #ifdef EAP_PEAP
42 extern const struct eap_method eap_method_peap;
43 #endif /* EAP_PEAP */
44 #ifdef EAP_TLV
45 extern const struct eap_method eap_method_tlv;
46 #endif /* EAP_TLV */
47 #ifdef EAP_GTC
48 extern const struct eap_method eap_method_gtc;
49 #endif /* EAP_GTC */
50 #ifdef EAP_TTLS
51 extern const struct eap_method eap_method_ttls;
52 #endif /* EAP_TTLS */
53 #ifdef EAP_SIM
54 extern const struct eap_method eap_method_sim;
55 #endif /* EAP_SIM */
56 #ifdef EAP_PAX
57 extern const struct eap_method eap_method_pax;
58 #endif /* EAP_PAX */
59 #ifdef EAP_PSK
60 extern const struct eap_method eap_method_psk;
61 #endif /* EAP_PSK */
62
63 static const struct eap_method *eap_methods[] =
64 {
65         &eap_method_identity,
66 #ifdef EAP_MD5
67         &eap_method_md5,
68 #endif /* EAP_MD5 */
69 #ifdef EAP_TLS
70         &eap_method_tls,
71 #endif /* EAP_TLS */
72 #ifdef EAP_MSCHAPv2
73         &eap_method_mschapv2,
74 #endif /* EAP_MSCHAPv2 */
75 #ifdef EAP_PEAP
76         &eap_method_peap,
77 #endif /* EAP_PEAP */
78 #ifdef EAP_TTLS
79         &eap_method_ttls,
80 #endif /* EAP_TTLS */
81 #ifdef EAP_TLV
82         &eap_method_tlv,
83 #endif /* EAP_TLV */
84 #ifdef EAP_GTC
85         &eap_method_gtc,
86 #endif /* EAP_GTC */
87 #ifdef EAP_SIM
88         &eap_method_sim,
89 #endif /* EAP_SIM */
90 #ifdef EAP_PAX
91         &eap_method_pax,
92 #endif /* EAP_PAX */
93 #ifdef EAP_PSK
94         &eap_method_psk,
95 #endif /* EAP_PSK */
96 };
97 #define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
98
99
100 const struct eap_method * eap_sm_get_eap_methods(int method)
101 {
102         int i;
103         for (i = 0; i < NUM_EAP_METHODS; i++) {
104                 if (eap_methods[i]->method == method)
105                         return eap_methods[i];
106         }
107         return NULL;
108 }
109
110 static void eap_user_free(struct eap_user *user);
111
112
113 /* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
114
115 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
116                                    int eapSRTT, int eapRTTVAR,
117                                    int methodTimeout);
118 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len);
119 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
120 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
121 static int eap_sm_nextId(struct eap_sm *sm, int id);
122 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
123 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);
124 static int eap_sm_Policy_getDecision(struct eap_sm *sm);
125 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
126
127
128 /* Definitions for clarifying state machine implementation */
129 #define SM_STATE(machine, state) \
130 static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
131         int global)
132
133 #define SM_ENTRY(machine, state) \
134 if (!global || sm->machine ## _state != machine ## _ ## state) { \
135         sm->changed = TRUE; \
136         wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
137 } \
138 sm->machine ## _state = machine ## _ ## state;
139
140 #define SM_ENTER(machine, state) \
141 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
142 #define SM_ENTER_GLOBAL(machine, state) \
143 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
144
145 #define SM_STEP(machine) \
146 static void sm_ ## machine ## _Step(struct eap_sm *sm)
147
148 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
149
150
151 static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
152 {
153         return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
154 }
155
156
157 static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
158                            Boolean value)
159 {
160         sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
161 }
162
163
164 static void eapol_set_eapReqData(struct eap_sm *sm,
165                                  const u8 *eapReqData, size_t eapReqDataLen)
166 {
167         wpa_hexdump(MSG_MSGDUMP, "EAP: eapReqData -> EAPOL",
168                     sm->eapReqData, sm->eapReqDataLen);
169         sm->eapol_cb->set_eapReqData(sm->eapol_ctx, eapReqData, eapReqDataLen);
170 }
171
172
173 static void eapol_set_eapKeyData(struct eap_sm *sm,
174                                  const u8 *eapKeyData, size_t eapKeyDataLen)
175 {
176         wpa_hexdump(MSG_MSGDUMP, "EAP: eapKeyData -> EAPOL",
177                     sm->eapKeyData, sm->eapKeyDataLen);
178         sm->eapol_cb->set_eapKeyData(sm->eapol_ctx, eapKeyData, eapKeyDataLen);
179 }
180
181
182 int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
183                  int phase2)
184 {
185         struct eap_user *user;
186
187         if (sm == NULL || sm->eapol_cb == NULL ||
188             sm->eapol_cb->get_eap_user == NULL)
189                 return -1;
190
191         eap_user_free(sm->user);
192         sm->user = NULL;
193
194         user = malloc(sizeof(*user));
195         if (user == NULL)
196             return -1;
197         memset(user, 0, sizeof(*user));
198
199         if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
200                                        identity_len, phase2, user) != 0) {
201                 eap_user_free(user);
202                 return -1;
203         }
204
205         sm->user = user;
206         sm->user_eap_method_index = 0;
207
208         return 0;
209 }
210
211
212 SM_STATE(EAP, DISABLED)
213 {
214         SM_ENTRY(EAP, DISABLED);
215         sm->num_rounds = 0;
216 }
217
218
219 SM_STATE(EAP, INITIALIZE)
220 {
221         SM_ENTRY(EAP, INITIALIZE);
222
223         sm->currentId = -1;
224         eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
225         eapol_set_bool(sm, EAPOL_eapFail, FALSE);
226         eapol_set_bool(sm, EAPOL_eapTimeout, FALSE);
227         free(sm->eapKeyData);
228         sm->eapKeyData = NULL;
229         sm->eapKeyDataLen = 0;
230         /* eapKeyAvailable = FALSE */
231         eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
232
233         /* This is not defined in draft-ietf-eap-statemachine-05.txt, but
234          * method state needs to be reseted here so that it does not remain in
235          * success state when re-authentication starts. */
236         if (sm->m && sm->eap_method_priv) {
237                 sm->m->reset(sm, sm->eap_method_priv);
238                 sm->eap_method_priv = NULL;
239         }
240         sm->m = NULL;
241         sm->user_eap_method_index = 0;
242
243         if (sm->backend_auth) {
244                 sm->currentMethod = EAP_TYPE_NONE;
245                 /* parse rxResp, respId, respMethod */
246                 eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
247                 if (sm->rxResp) {
248                         sm->currentId = sm->respId;
249                 }
250         }
251         sm->num_rounds = 0;
252 }
253
254
255 SM_STATE(EAP, PICK_UP_METHOD)
256 {
257         SM_ENTRY(EAP, PICK_UP_METHOD);
258
259         if (eap_sm_Policy_doPickUp(sm, sm->respMethod)) {
260                 sm->currentMethod = sm->respMethod;
261                 if (sm->m && sm->eap_method_priv) {
262                         sm->m->reset(sm, sm->eap_method_priv);
263                         sm->eap_method_priv = NULL;
264                 }
265                 sm->m = eap_sm_get_eap_methods(sm->currentMethod);
266                 if (sm->m && sm->m->initPickUp) {
267                         sm->eap_method_priv = sm->m->initPickUp(sm);
268                         if (sm->eap_method_priv == NULL) {
269                                 wpa_printf(MSG_DEBUG, "EAP: Failed to "
270                                            "initialize EAP method %d",
271                                            sm->currentMethod);
272                                 sm->m = NULL;
273                                 sm->currentMethod = EAP_TYPE_NONE;
274                         }
275                 } else {
276                         sm->m = NULL;
277                         sm->currentMethod = EAP_TYPE_NONE;
278                 }
279         }
280 }
281
282
283 SM_STATE(EAP, IDLE)
284 {
285         SM_ENTRY(EAP, IDLE);
286
287         sm->retransWhile = eap_sm_calculateTimeout(sm, sm->retransCount,
288                                                    sm->eapSRTT, sm->eapRTTVAR,
289                                                    sm->methodTimeout);
290 }
291
292
293 SM_STATE(EAP, RETRANSMIT)
294 {
295         SM_ENTRY(EAP, RETRANSMIT);
296
297         /* TODO: Is this needed since EAPOL state machines take care of
298          * retransmit? */
299 }
300
301
302 SM_STATE(EAP, RECEIVED)
303 {
304         SM_ENTRY(EAP, RECEIVED);
305
306         /* parse rxResp, respId, respMethod */
307         eap_sm_parseEapResp(sm, sm->eapRespData, sm->eapRespDataLen);
308         sm->num_rounds++;
309 }
310
311
312 SM_STATE(EAP, DISCARD)
313 {
314         SM_ENTRY(EAP, DISCARD);
315         eapol_set_bool(sm, EAPOL_eapResp, FALSE);
316         eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
317 }
318
319
320 SM_STATE(EAP, SEND_REQUEST)
321 {
322         SM_ENTRY(EAP, SEND_REQUEST);
323
324         sm->retransCount = 0;
325         if (sm->eapReqData) {
326                 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
327                 free(sm->lastReqData);
328                 sm->lastReqData = sm->eapReqData;
329                 sm->lastReqDataLen = sm->eapReqDataLen;
330                 sm->eapReqData = NULL;
331                 sm->eapReqDataLen = 0;
332                 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
333                 eapol_set_bool(sm, EAPOL_eapReq, TRUE);
334         } else {
335                 wpa_printf(MSG_INFO, "EAP: SEND_REQUEST - no eapReqData");
336                 eapol_set_bool(sm, EAPOL_eapResp, FALSE);
337                 eapol_set_bool(sm, EAPOL_eapReq, FALSE);
338                 eapol_set_bool(sm, EAPOL_eapNoReq, TRUE);
339         }
340 }
341
342
343 SM_STATE(EAP, INTEGRITY_CHECK)
344 {
345         SM_ENTRY(EAP, INTEGRITY_CHECK);
346
347         if (sm->m->check) {
348                 sm->ignore = sm->m->check(sm, sm->eap_method_priv,
349                                           sm->eapRespData, sm->eapRespDataLen);
350         }
351 }
352
353
354 SM_STATE(EAP, METHOD_REQUEST)
355 {
356         SM_ENTRY(EAP, METHOD_REQUEST);
357
358         if (sm->m == NULL) {
359                 wpa_printf(MSG_DEBUG, "EAP: method not initialized");
360                 return;
361         }
362
363         sm->currentId = eap_sm_nextId(sm, sm->currentId);
364         wpa_printf(MSG_DEBUG, "EAP: building EAP-Request: Identifier %d",
365                    sm->currentId);
366         sm->lastId = sm->currentId;
367         free(sm->eapReqData);
368         sm->eapReqData = sm->m->buildReq(sm, sm->eap_method_priv,
369                                          sm->currentId, &sm->eapReqDataLen);
370         if (sm->m->getTimeout)
371                 sm->methodTimeout = sm->m->getTimeout(sm, sm->eap_method_priv);
372         else
373                 sm->methodTimeout = 0;
374 }
375
376
377 SM_STATE(EAP, METHOD_RESPONSE)
378 {
379         SM_ENTRY(EAP, METHOD_RESPONSE);
380
381         sm->m->process(sm, sm->eap_method_priv, sm->eapRespData,
382                        sm->eapRespDataLen);
383         if (sm->m->isDone(sm, sm->eap_method_priv)) {
384                 eap_sm_Policy_update(sm, NULL, 0);
385                 free(sm->eapKeyData);
386                 if (sm->m->getKey) {
387                         sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
388                                                        &sm->eapKeyDataLen);
389                 } else {
390                         sm->eapKeyData = NULL;
391                         sm->eapKeyDataLen = 0;
392                 }
393                 sm->methodState = METHOD_END;
394         } else {
395                 sm->methodState = METHOD_CONTINUE;
396         }
397 }
398
399
400 SM_STATE(EAP, PROPOSE_METHOD)
401 {
402         SM_ENTRY(EAP, PROPOSE_METHOD);
403
404         sm->currentMethod = eap_sm_Policy_getNextMethod(sm);
405         if (sm->m && sm->eap_method_priv) {
406                 sm->m->reset(sm, sm->eap_method_priv);
407                 sm->eap_method_priv = NULL;
408         }
409         sm->m = eap_sm_get_eap_methods(sm->currentMethod);
410         if (sm->m) {
411                 sm->eap_method_priv = sm->m->init(sm);
412                 if (sm->eap_method_priv == NULL) {
413                         wpa_printf(MSG_DEBUG, "EAP: Failed to initialize EAP "
414                                    "method %d", sm->currentMethod);
415                         sm->m = NULL;
416                         sm->currentMethod = EAP_TYPE_NONE;
417                 }
418         }
419         if (sm->currentMethod == EAP_TYPE_IDENTITY ||
420             sm->currentMethod == EAP_TYPE_NOTIFICATION)
421                 sm->methodState = METHOD_CONTINUE;
422         else
423                 sm->methodState = METHOD_PROPOSED;
424 }
425
426
427 SM_STATE(EAP, NAK)
428 {
429         struct eap_hdr *nak;
430         size_t len = 0;
431         u8 *pos, *nak_list = NULL;
432
433         SM_ENTRY(EAP, NAK);
434
435         if (sm->eap_method_priv) {
436                 sm->m->reset(sm, sm->eap_method_priv);
437                 sm->eap_method_priv = NULL;
438         }
439         sm->m = NULL;
440
441         nak = (struct eap_hdr *) sm->eapRespData;
442         if (nak && sm->eapRespDataLen > sizeof(*nak)) {
443                 len = ntohs(nak->length);
444                 if (len > sm->eapRespDataLen)
445                         len = sm->eapRespDataLen;
446                 pos = (u8 *) (nak + 1);
447                 len -= sizeof(*nak);
448                 if (*pos == EAP_TYPE_NAK) {
449                         pos++;
450                         len--;
451                         nak_list = pos;
452                 }
453         }
454         eap_sm_Policy_update(sm, nak_list, len);
455 }
456
457
458 SM_STATE(EAP, SELECT_ACTION)
459 {
460         SM_ENTRY(EAP, SELECT_ACTION);
461
462         sm->decision = eap_sm_Policy_getDecision(sm);
463 }
464
465
466 SM_STATE(EAP, TIMEOUT_FAILURE)
467 {
468         SM_ENTRY(EAP, TIMEOUT_FAILURE);
469
470         eapol_set_bool(sm, EAPOL_eapTimeout, TRUE);
471 }
472
473
474 SM_STATE(EAP, FAILURE)
475 {
476         SM_ENTRY(EAP, FAILURE);
477
478         free(sm->eapReqData);
479         sm->eapReqData = eap_sm_buildFailure(sm, sm->currentId,
480                                              &sm->eapReqDataLen);
481         if (sm->eapReqData) {
482                 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
483                 free(sm->eapReqData);
484                 sm->eapReqData = NULL;
485                 sm->eapReqDataLen = 0;
486         }
487         free(sm->lastReqData);
488         sm->lastReqData = NULL;
489         sm->lastReqDataLen = 0;
490         eapol_set_bool(sm, EAPOL_eapFail, TRUE);
491 }
492
493
494 SM_STATE(EAP, SUCCESS)
495 {
496         SM_ENTRY(EAP, SUCCESS);
497
498         free(sm->eapReqData);
499         sm->eapReqData = eap_sm_buildSuccess(sm, sm->currentId,
500                                              &sm->eapReqDataLen);
501         if (sm->eapReqData) {
502                 eapol_set_eapReqData(sm, sm->eapReqData, sm->eapReqDataLen);
503                 free(sm->eapReqData);
504                 sm->eapReqData = NULL;
505                 sm->eapReqDataLen = 0;
506         }
507         free(sm->lastReqData);
508         sm->lastReqData = NULL;
509         sm->lastReqDataLen = 0;
510         if (sm->eapKeyData) {
511                 eapol_set_eapKeyData(sm, sm->eapKeyData, sm->eapKeyDataLen);
512         }
513         eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
514 }
515
516
517 SM_STEP(EAP)
518 {
519         if (eapol_get_bool(sm, EAPOL_eapRestart) &&
520             eapol_get_bool(sm, EAPOL_portEnabled))
521                 SM_ENTER_GLOBAL(EAP, INITIALIZE);
522         else if (!eapol_get_bool(sm, EAPOL_portEnabled))
523                 SM_ENTER_GLOBAL(EAP, DISABLED);
524         else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
525                 if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
526                         wpa_printf(MSG_DEBUG, "EAP: more than %d "
527                                    "authentication rounds - abort",
528                                    EAP_MAX_AUTH_ROUNDS);
529                         sm->num_rounds++;
530                         SM_ENTER_GLOBAL(EAP, FAILURE);
531                 }
532         } else switch (sm->EAP_state) {
533         case EAP_INITIALIZE:
534                 if (sm->backend_auth) {
535                         if (!sm->rxResp)
536                                 SM_ENTER(EAP, SELECT_ACTION);
537                         else if (sm->rxResp &&
538                                  (sm->respMethod == EAP_TYPE_NAK ||
539                                   sm->respMethod == EAP_TYPE_EXPANDED_NAK))
540                                 SM_ENTER(EAP, NAK);
541                         else
542                                 SM_ENTER(EAP, PICK_UP_METHOD);
543                 } else {
544                         SM_ENTER(EAP, SELECT_ACTION);
545                 }
546                 break;
547         case EAP_PICK_UP_METHOD:
548                 if (sm->currentMethod == EAP_TYPE_NONE) {
549                         SM_ENTER(EAP, SELECT_ACTION);
550                 } else {
551                         SM_ENTER(EAP, METHOD_RESPONSE);
552                 }
553                 break;
554         case EAP_DISABLED:
555                 if (eapol_get_bool(sm, EAPOL_portEnabled))
556                         SM_ENTER(EAP, INITIALIZE);
557                 break;
558         case EAP_IDLE:
559                 if (sm->retransWhile == 0)
560                         SM_ENTER(EAP, RETRANSMIT);
561                 else if (eapol_get_bool(sm, EAPOL_eapResp))
562                         SM_ENTER(EAP, RECEIVED);
563                 break;
564         case EAP_RETRANSMIT:
565                 if (sm->retransCount > sm->MaxRetrans)
566                         SM_ENTER(EAP, TIMEOUT_FAILURE);
567                 else
568                         SM_ENTER(EAP, IDLE);
569                 break;
570         case EAP_RECEIVED:
571                 if (sm->rxResp && (sm->respId == sm->currentId) &&
572                     (sm->respMethod == EAP_TYPE_NAK ||
573                      sm->respMethod == EAP_TYPE_EXPANDED_NAK)
574                     && (sm->methodState == METHOD_PROPOSED))
575                         SM_ENTER(EAP, NAK);
576                 else if (sm->rxResp && (sm->respId == sm->currentId) &&
577                          (sm->respMethod == sm->currentMethod))
578                         SM_ENTER(EAP, INTEGRITY_CHECK);
579                 else
580                         SM_ENTER(EAP, DISCARD);
581                 break;
582         case EAP_DISCARD:
583                 SM_ENTER(EAP, IDLE);
584                 break;
585         case EAP_SEND_REQUEST:
586                 SM_ENTER(EAP, IDLE);
587                 break;
588         case EAP_INTEGRITY_CHECK:
589                 if (sm->ignore)
590                         SM_ENTER(EAP, DISCARD);
591                 else
592                         SM_ENTER(EAP, METHOD_RESPONSE);
593                 break;
594         case EAP_METHOD_REQUEST:
595                 SM_ENTER(EAP, SEND_REQUEST);
596                 break;
597         case EAP_METHOD_RESPONSE:
598                 if (sm->methodState == METHOD_END)
599                         SM_ENTER(EAP, SELECT_ACTION);
600                 else
601                         SM_ENTER(EAP, METHOD_REQUEST);
602                 break;
603         case EAP_PROPOSE_METHOD:
604                 SM_ENTER(EAP, METHOD_REQUEST);
605                 break;
606         case EAP_NAK:
607                 SM_ENTER(EAP, SELECT_ACTION);
608                 break;
609         case EAP_SELECT_ACTION:
610                 if (sm->decision == DECISION_FAILURE)
611                         SM_ENTER(EAP, FAILURE);
612                 else if (sm->decision == DECISION_SUCCESS)
613                         SM_ENTER(EAP, SUCCESS);
614                 else
615                         SM_ENTER(EAP, PROPOSE_METHOD);
616                 break;
617         case EAP_TIMEOUT_FAILURE:
618                 break;
619         case EAP_FAILURE:
620                 break;
621         case EAP_SUCCESS:
622                 break;
623         }
624 }
625
626
627 static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
628                                    int eapSRTT, int eapRTTVAR,
629                                    int methodTimeout)
630 {
631         /* For now, retransmission is done in EAPOL state machines, so make
632          * sure EAP state machine does not end up trying to retransmit packets.
633          */
634         return 1;
635 }
636
637
638 static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
639 {
640         struct eap_hdr *hdr;
641         size_t plen;
642
643         /* parse rxResp, respId, respMethod */
644         sm->rxResp = FALSE;
645         sm->respId = -1;
646         sm->respMethod = EAP_TYPE_NONE;
647
648         if (resp == NULL || len < sizeof(*hdr))
649                 return;
650
651         hdr = (struct eap_hdr *) resp;
652         plen = ntohs(hdr->length);
653         if (plen > len) {
654                 wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
655                            "(len=%lu plen=%lu)", (unsigned long) len,
656                            (unsigned long) plen);
657                 return;
658         }
659
660         sm->respId = hdr->identifier;
661
662         if (hdr->code == EAP_CODE_RESPONSE)
663                 sm->rxResp = TRUE;
664
665         if (len > sizeof(*hdr))
666                 sm->respMethod = *((u8 *) (hdr + 1));
667
668         wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
669                    "respMethod=%d", sm->rxResp, sm->respId, sm->respMethod);
670 }
671
672
673 static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len)
674 {
675         struct eap_hdr *resp;
676         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Success (id=%d)", id);
677
678         *len = sizeof(*resp);
679         resp = malloc(*len);
680         if (resp == NULL)
681                 return NULL;
682         resp->code = EAP_CODE_SUCCESS;
683         resp->identifier = id;
684         resp->length = htons(*len);
685
686         return (u8 *) resp;
687 }
688
689
690 static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
691 {
692         struct eap_hdr *resp;
693         wpa_printf(MSG_DEBUG, "EAP: Building EAP-Failure (id=%d)", id);
694
695         *len = sizeof(*resp);
696         resp = malloc(*len);
697         if (resp == NULL)
698                 return NULL;
699         resp->code = EAP_CODE_FAILURE;
700         resp->identifier = id;
701         resp->length = htons(*len);
702
703         return (u8 *) resp;
704 }
705
706
707 static int eap_sm_nextId(struct eap_sm *sm, int id)
708 {
709         if (id < 0) {
710                 /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
711                  * random number */
712                 id = rand() & 0xff;
713                 if (id != sm->lastId)
714                         return id;
715         }
716         return (id + 1) & 0xff;
717 }
718
719
720 void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
721 {
722         int i, j;
723
724         wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
725                    "index %d)", sm->user_eap_method_index);
726
727         wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
728                     sm->user->methods, EAP_MAX_METHODS);
729         wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
730                     nak_list, len);
731
732         i = sm->user_eap_method_index;
733         while (i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE) {
734                 for (j = 0; j < len; j++) {
735                         if (nak_list[j] == sm->user->methods[i]) {
736                                 break;
737                         }
738                 }
739
740                 if (j < len) {
741                         /* found */
742                         i++;
743                         continue;
744                 }
745
746                 /* not found - remove from the list */
747                 memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
748                         EAP_MAX_METHODS - i - 1);
749                 sm->user->methods[EAP_MAX_METHODS - 1] = EAP_TYPE_NONE;
750         }
751
752         wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
753                     sm->user->methods, EAP_MAX_METHODS);
754 }
755
756
757 static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
758 {
759         if (nak_list == NULL || sm == NULL || sm->user == NULL)
760                 return;
761
762         if (sm->user->phase2) {
763                 wpa_printf(MSG_DEBUG, "EAP: EAP-Nak received after Phase2 user"
764                            " info was selected - reject");
765                 sm->decision = DECISION_FAILURE;
766                 return;
767         }
768
769         eap_sm_process_nak(sm, nak_list, len);
770 }
771
772
773 static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
774 {
775         EapType next;
776
777         /* In theory, there should be no problems with starting
778          * re-authentication with something else than EAP-Request/Identity and
779          * this does indeed work with wpa_supplicant. However, at least Funk
780          * Supplicant seemed to ignore re-auth if it skipped
781          * EAP-Request/Identity.
782          * Re-auth sets currentId == -1, so that can be used here to select
783          * whether Identity needs to be requested again. */
784         if (sm->identity == NULL || sm->currentId == -1) {
785                 next = EAP_TYPE_IDENTITY;
786                 sm->update_user = TRUE;
787         } else if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
788                    sm->user->methods[sm->user_eap_method_index] !=
789                    EAP_TYPE_NONE) {
790                 next = sm->user->methods[sm->user_eap_method_index++];
791         } else {
792                 next = EAP_TYPE_NONE;
793         }
794         wpa_printf(MSG_DEBUG, "EAP: getNextMethod: type %d", next);
795         return next;
796 }
797
798
799 static int eap_sm_Policy_getDecision(struct eap_sm *sm)
800 {
801         if (sm->m && sm->currentMethod != EAP_TYPE_IDENTITY &&
802             sm->m->isSuccess(sm, sm->eap_method_priv)) {
803                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method succeeded -> "
804                            "SUCCESS");
805                 sm->update_user = TRUE;
806                 return DECISION_SUCCESS;
807         }
808
809         if (sm->m && sm->m->isDone(sm, sm->eap_method_priv) &&
810             !sm->m->isSuccess(sm, sm->eap_method_priv)) {
811                 wpa_printf(MSG_DEBUG, "EAP: getDecision: method failed -> "
812                            "FAILURE");
813                 sm->update_user = TRUE;
814                 return DECISION_FAILURE;
815         }
816
817         if ((sm->user == NULL || sm->update_user) && sm->identity) {
818                 if (eap_user_get(sm, sm->identity, sm->identity_len, 0) != 0) {
819                         wpa_printf(MSG_DEBUG, "EAP: getDecision: user not "
820                                    "found from database -> FAILURE");
821                         return DECISION_FAILURE;
822                 }
823                 sm->update_user = FALSE;
824         }
825
826         if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
827             sm->user->methods[sm->user_eap_method_index] != EAP_TYPE_NONE) {
828                 wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
829                            "available -> CONTINUE");
830                 return DECISION_CONTINUE;
831         }
832
833         if (sm->identity == NULL || sm->currentId == -1) {
834                 wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
835                            "yet -> CONTINUE");
836                 return DECISION_CONTINUE;
837         }
838
839         wpa_printf(MSG_DEBUG, "EAP: getDecision: no more methods available -> "
840                    "FAILURE");
841         return DECISION_FAILURE;
842 }
843
844
845 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
846 {
847         return method == EAP_TYPE_IDENTITY ? TRUE : FALSE;
848 }
849
850
851 int eap_sm_step(struct eap_sm *sm)
852 {
853         int res = 0;
854         do {
855                 sm->changed = FALSE;
856                 SM_STEP_RUN(EAP);
857                 if (sm->changed)
858                         res = 1;
859         } while (sm->changed);
860         return res;
861 }
862
863
864 u8 eap_get_type(const char *name)
865 {
866         int i;
867         for (i = 0; i < NUM_EAP_METHODS; i++) {
868                 if (strcmp(eap_methods[i]->name, name) == 0)
869                         return eap_methods[i]->method;
870         }
871         return EAP_TYPE_NONE;
872 }
873
874
875 void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
876                          size_t eapRespDataLen)
877 {
878         if (sm == NULL)
879                 return;
880         free(sm->eapRespData);
881         sm->eapRespData = malloc(eapRespDataLen);
882         if (sm->eapRespData == NULL)
883                 return;
884         memcpy(sm->eapRespData, eapRespData, eapRespDataLen);
885         sm->eapRespDataLen = eapRespDataLen;
886         wpa_hexdump(MSG_MSGDUMP, "EAP: EAP-Response received",
887                     eapRespData, eapRespDataLen);
888 }
889
890
891 static void eap_user_free(struct eap_user *user)
892 {
893         if (user == NULL)
894                 return;
895         free(user->password);
896         user->password = NULL;
897         free(user);
898 }
899
900
901 struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
902                             struct eap_config *eap_conf)
903 {
904         struct eap_sm *sm;
905
906         sm = malloc(sizeof(*sm));
907         if (sm == NULL)
908                 return NULL;
909         memset(sm, 0, sizeof(*sm));
910         sm->eapol_ctx = eapol_ctx;
911         sm->eapol_cb = eapol_cb;
912         sm->MaxRetrans = 10;
913         sm->ssl_ctx = eap_conf->ssl_ctx;
914         sm->eap_sim_db_priv = eap_conf->eap_sim_db_priv;
915         sm->backend_auth = eap_conf->backend_auth;
916
917         wpa_printf(MSG_DEBUG, "EAP: State machine created");
918
919         return sm;
920 }
921
922
923 void eap_sm_deinit(struct eap_sm *sm)
924 {
925         if (sm == NULL)
926                 return;
927         wpa_printf(MSG_DEBUG, "EAP: State machine removed");
928         if (sm->m && sm->eap_method_priv)
929                 sm->m->reset(sm, sm->eap_method_priv);
930         free(sm->eapReqData);
931         free(sm->eapKeyData);
932         free(sm->lastReqData);
933         free(sm->eapRespData);
934         free(sm->identity);
935         eap_user_free(sm->user);
936         free(sm);
937 }
938
939
940 void eap_sm_notify_cached(struct eap_sm *sm)
941 {
942         if (sm == NULL)
943                 return;
944
945         sm->EAP_state = EAP_SUCCESS;
946 }