hostapd: Update vendor branch to 0.6.10
[dragonfly.git] / contrib / hostapd / src / eapol_supp / eapol_supp_sm.c
1 /*
2  * EAPOL supplicant state machines
3  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.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
15 #include "includes.h"
16
17 #include "common.h"
18 #include "eapol_supp_sm.h"
19 #include "eap_peer/eap.h"
20 #include "eloop.h"
21 #include "eapol_common.h"
22 #include "md5.h"
23 #include "rc4.h"
24 #include "state_machine.h"
25 #include "wpabuf.h"
26
27 #define STATE_MACHINE_DATA struct eapol_sm
28 #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
29
30
31 /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
32
33 /**
34  * struct eapol_sm - Internal data for EAPOL state machines
35  */
36 struct eapol_sm {
37         /* Timers */
38         unsigned int authWhile;
39         unsigned int heldWhile;
40         unsigned int startWhen;
41         unsigned int idleWhile; /* for EAP state machine */
42         int timer_tick_enabled;
43
44         /* Global variables */
45         Boolean eapFail;
46         Boolean eapolEap;
47         Boolean eapSuccess;
48         Boolean initialize;
49         Boolean keyDone;
50         Boolean keyRun;
51         PortControl portControl;
52         Boolean portEnabled;
53         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
54         Boolean portValid;
55         Boolean suppAbort;
56         Boolean suppFail;
57         Boolean suppStart;
58         Boolean suppSuccess;
59         Boolean suppTimeout;
60
61         /* Supplicant PAE state machine */
62         enum {
63                 SUPP_PAE_UNKNOWN = 0,
64                 SUPP_PAE_DISCONNECTED = 1,
65                 SUPP_PAE_LOGOFF = 2,
66                 SUPP_PAE_CONNECTING = 3,
67                 SUPP_PAE_AUTHENTICATING = 4,
68                 SUPP_PAE_AUTHENTICATED = 5,
69                 /* unused(6) */
70                 SUPP_PAE_HELD = 7,
71                 SUPP_PAE_RESTART = 8,
72                 SUPP_PAE_S_FORCE_AUTH = 9,
73                 SUPP_PAE_S_FORCE_UNAUTH = 10
74         } SUPP_PAE_state; /* dot1xSuppPaeState */
75         /* Variables */
76         Boolean userLogoff;
77         Boolean logoffSent;
78         unsigned int startCount;
79         Boolean eapRestart;
80         PortControl sPortMode;
81         /* Constants */
82         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
83         unsigned int startPeriod; /* dot1xSuppStartPeriod */
84         unsigned int maxStart; /* dot1xSuppMaxStart */
85
86         /* Key Receive state machine */
87         enum {
88                 KEY_RX_UNKNOWN = 0,
89                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
90         } KEY_RX_state;
91         /* Variables */
92         Boolean rxKey;
93
94         /* Supplicant Backend state machine */
95         enum {
96                 SUPP_BE_UNKNOWN = 0,
97                 SUPP_BE_INITIALIZE = 1,
98                 SUPP_BE_IDLE = 2,
99                 SUPP_BE_REQUEST = 3,
100                 SUPP_BE_RECEIVE = 4,
101                 SUPP_BE_RESPONSE = 5,
102                 SUPP_BE_FAIL = 6,
103                 SUPP_BE_TIMEOUT = 7, 
104                 SUPP_BE_SUCCESS = 8
105         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
106         /* Variables */
107         Boolean eapNoResp;
108         Boolean eapReq;
109         Boolean eapResp;
110         /* Constants */
111         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
112
113         /* Statistics */
114         unsigned int dot1xSuppEapolFramesRx;
115         unsigned int dot1xSuppEapolFramesTx;
116         unsigned int dot1xSuppEapolStartFramesTx;
117         unsigned int dot1xSuppEapolLogoffFramesTx;
118         unsigned int dot1xSuppEapolRespFramesTx;
119         unsigned int dot1xSuppEapolReqIdFramesRx;
120         unsigned int dot1xSuppEapolReqFramesRx;
121         unsigned int dot1xSuppInvalidEapolFramesRx;
122         unsigned int dot1xSuppEapLengthErrorFramesRx;
123         unsigned int dot1xSuppLastEapolFrameVersion;
124         unsigned char dot1xSuppLastEapolFrameSource[6];
125
126         /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
127         Boolean changed;
128         struct eap_sm *eap;
129         struct eap_peer_config *config;
130         Boolean initial_req;
131         u8 *last_rx_key;
132         size_t last_rx_key_len;
133         struct wpabuf *eapReqData; /* for EAP */
134         Boolean altAccept; /* for EAP */
135         Boolean altReject; /* for EAP */
136         Boolean replay_counter_valid;
137         u8 last_replay_counter[16];
138         struct eapol_config conf;
139         struct eapol_ctx *ctx;
140         enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
141                 cb_status;
142         Boolean cached_pmk;
143
144         Boolean unicast_key_received, broadcast_key_received;
145 };
146
147
148 #define IEEE8021X_REPLAY_COUNTER_LEN 8
149 #define IEEE8021X_KEY_SIGN_LEN 16
150 #define IEEE8021X_KEY_IV_LEN 16
151
152 #define IEEE8021X_KEY_INDEX_FLAG 0x80
153 #define IEEE8021X_KEY_INDEX_MASK 0x03
154
155 #ifdef _MSC_VER
156 #pragma pack(push, 1)
157 #endif /* _MSC_VER */
158
159 struct ieee802_1x_eapol_key {
160         u8 type;
161         /* Note: key_length is unaligned */
162         u8 key_length[2];
163         /* does not repeat within the life of the keying material used to
164          * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
165         u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
166         u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
167         u8 key_index; /* key flag in the most significant bit:
168                        * 0 = broadcast (default key),
169                        * 1 = unicast (key mapping key); key index is in the
170                        * 7 least significant bits */
171         /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
172          * the key */
173         u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
174
175         /* followed by key: if packet body length = 44 + key length, then the
176          * key field (of key_length bytes) contains the key in encrypted form;
177          * if packet body length = 44, key field is absent and key_length
178          * represents the number of least significant octets from
179          * MS-MPPE-Send-Key attribute to be used as the keying material;
180          * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
181 } STRUCT_PACKED;
182
183 #ifdef _MSC_VER
184 #pragma pack(pop)
185 #endif /* _MSC_VER */
186
187
188 static void eapol_sm_txLogoff(struct eapol_sm *sm);
189 static void eapol_sm_txStart(struct eapol_sm *sm);
190 static void eapol_sm_processKey(struct eapol_sm *sm);
191 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
192 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
193 static void eapol_sm_abortSupp(struct eapol_sm *sm);
194 static void eapol_sm_abort_cached(struct eapol_sm *sm);
195 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
196
197
198 /* Port Timers state machine - implemented as a function that will be called
199  * once a second as a registered event loop timeout */
200 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
201 {
202         struct eapol_sm *sm = timeout_ctx;
203
204         if (sm->authWhile > 0) {
205                 sm->authWhile--;
206                 if (sm->authWhile == 0)
207                         wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
208         }
209         if (sm->heldWhile > 0) {
210                 sm->heldWhile--;
211                 if (sm->heldWhile == 0)
212                         wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
213         }
214         if (sm->startWhen > 0) {
215                 sm->startWhen--;
216                 if (sm->startWhen == 0)
217                         wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
218         }
219         if (sm->idleWhile > 0) {
220                 sm->idleWhile--;
221                 if (sm->idleWhile == 0)
222                         wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
223         }
224
225         if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
226                 eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
227                                        sm);
228         } else {
229                 wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
230                 sm->timer_tick_enabled = 0;
231         }
232         eapol_sm_step(sm);
233 }
234
235
236 static void eapol_enable_timer_tick(struct eapol_sm *sm)
237 {
238         if (sm->timer_tick_enabled)
239                 return;
240         wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
241         sm->timer_tick_enabled = 1;
242         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
243         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
244 }
245
246
247 SM_STATE(SUPP_PAE, LOGOFF)
248 {
249         SM_ENTRY(SUPP_PAE, LOGOFF);
250         eapol_sm_txLogoff(sm);
251         sm->logoffSent = TRUE;
252         sm->suppPortStatus = Unauthorized;
253 }
254
255
256 SM_STATE(SUPP_PAE, DISCONNECTED)
257 {
258         SM_ENTRY(SUPP_PAE, DISCONNECTED);
259         sm->sPortMode = Auto;
260         sm->startCount = 0;
261         sm->logoffSent = FALSE;
262         sm->suppPortStatus = Unauthorized;
263         sm->suppAbort = TRUE;
264
265         sm->unicast_key_received = FALSE;
266         sm->broadcast_key_received = FALSE;
267 }
268
269
270 SM_STATE(SUPP_PAE, CONNECTING)
271 {
272         int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
273         SM_ENTRY(SUPP_PAE, CONNECTING);
274         if (send_start) {
275                 sm->startWhen = sm->startPeriod;
276                 sm->startCount++;
277         } else {
278                 /*
279                  * Do not send EAPOL-Start immediately since in most cases,
280                  * Authenticator is going to start authentication immediately
281                  * after association and an extra EAPOL-Start is just going to
282                  * delay authentication. Use a short timeout to send the first
283                  * EAPOL-Start if Authenticator does not start authentication.
284                  */
285 #ifdef CONFIG_WPS
286                 /* Reduce latency on starting WPS negotiation. */
287                 sm->startWhen = 1;
288 #else /* CONFIG_WPS */
289                 sm->startWhen = 3;
290 #endif /* CONFIG_WPS */
291         }
292         eapol_enable_timer_tick(sm);
293         sm->eapolEap = FALSE;
294         if (send_start)
295                 eapol_sm_txStart(sm);
296 }
297
298
299 SM_STATE(SUPP_PAE, AUTHENTICATING)
300 {
301         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
302         sm->startCount = 0;
303         sm->suppSuccess = FALSE;
304         sm->suppFail = FALSE;
305         sm->suppTimeout = FALSE;
306         sm->keyRun = FALSE;
307         sm->keyDone = FALSE;
308         sm->suppStart = TRUE;
309 }
310
311
312 SM_STATE(SUPP_PAE, HELD)
313 {
314         SM_ENTRY(SUPP_PAE, HELD);
315         sm->heldWhile = sm->heldPeriod;
316         eapol_enable_timer_tick(sm);
317         sm->suppPortStatus = Unauthorized;
318         sm->cb_status = EAPOL_CB_FAILURE;
319 }
320
321
322 SM_STATE(SUPP_PAE, AUTHENTICATED)
323 {
324         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
325         sm->suppPortStatus = Authorized;
326         sm->cb_status = EAPOL_CB_SUCCESS;
327 }
328
329
330 SM_STATE(SUPP_PAE, RESTART)
331 {
332         SM_ENTRY(SUPP_PAE, RESTART);
333         sm->eapRestart = TRUE;
334 }
335
336
337 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
338 {
339         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
340         sm->suppPortStatus = Authorized;
341         sm->sPortMode = ForceAuthorized;
342 }
343
344
345 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
346 {
347         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
348         sm->suppPortStatus = Unauthorized;
349         sm->sPortMode = ForceUnauthorized;
350         eapol_sm_txLogoff(sm);
351 }
352
353
354 SM_STEP(SUPP_PAE)
355 {
356         if ((sm->userLogoff && !sm->logoffSent) &&
357             !(sm->initialize || !sm->portEnabled))
358                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
359         else if (((sm->portControl == Auto) &&
360                   (sm->sPortMode != sm->portControl)) ||
361                  sm->initialize || !sm->portEnabled)
362                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
363         else if ((sm->portControl == ForceAuthorized) &&
364                  (sm->sPortMode != sm->portControl) &&
365                  !(sm->initialize || !sm->portEnabled))
366                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
367         else if ((sm->portControl == ForceUnauthorized) &&
368                  (sm->sPortMode != sm->portControl) &&
369                  !(sm->initialize || !sm->portEnabled))
370                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
371         else switch (sm->SUPP_PAE_state) {
372         case SUPP_PAE_UNKNOWN:
373                 break;
374         case SUPP_PAE_LOGOFF:
375                 if (!sm->userLogoff)
376                         SM_ENTER(SUPP_PAE, DISCONNECTED);
377                 break;
378         case SUPP_PAE_DISCONNECTED:
379                 SM_ENTER(SUPP_PAE, CONNECTING);
380                 break;
381         case SUPP_PAE_CONNECTING:
382                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
383                         SM_ENTER(SUPP_PAE, CONNECTING);
384                 else if (sm->startWhen == 0 &&
385                          sm->startCount >= sm->maxStart &&
386                          sm->portValid)
387                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
388                 else if (sm->eapSuccess || sm->eapFail)
389                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
390                 else if (sm->eapolEap)
391                         SM_ENTER(SUPP_PAE, RESTART);
392                 else if (sm->startWhen == 0 &&
393                          sm->startCount >= sm->maxStart &&
394                          !sm->portValid)
395                         SM_ENTER(SUPP_PAE, HELD);
396                 break;
397         case SUPP_PAE_AUTHENTICATING:
398                 if (sm->eapSuccess && !sm->portValid &&
399                     sm->conf.accept_802_1x_keys &&
400                     sm->conf.required_keys == 0) {
401                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
402                                    "plaintext connection; no EAPOL-Key frames "
403                                    "required");
404                         sm->portValid = TRUE;
405                         if (sm->ctx->eapol_done_cb)
406                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
407                 }
408                 if (sm->eapSuccess && sm->portValid)
409                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
410                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
411                         SM_ENTER(SUPP_PAE, HELD);
412                 else if (sm->suppTimeout)
413                         SM_ENTER(SUPP_PAE, CONNECTING);
414                 break;
415         case SUPP_PAE_HELD:
416                 if (sm->heldWhile == 0)
417                         SM_ENTER(SUPP_PAE, CONNECTING);
418                 else if (sm->eapolEap)
419                         SM_ENTER(SUPP_PAE, RESTART);
420                 break;
421         case SUPP_PAE_AUTHENTICATED:
422                 if (sm->eapolEap && sm->portValid)
423                         SM_ENTER(SUPP_PAE, RESTART);
424                 else if (!sm->portValid)
425                         SM_ENTER(SUPP_PAE, DISCONNECTED);
426                 break;
427         case SUPP_PAE_RESTART:
428                 if (!sm->eapRestart)
429                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
430                 break;
431         case SUPP_PAE_S_FORCE_AUTH:
432                 break;
433         case SUPP_PAE_S_FORCE_UNAUTH:
434                 break;
435         }
436 }
437
438
439 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
440 {
441         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
442 }
443
444
445 SM_STATE(KEY_RX, KEY_RECEIVE)
446 {
447         SM_ENTRY(KEY_RX, KEY_RECEIVE);
448         eapol_sm_processKey(sm);
449         sm->rxKey = FALSE;
450 }
451
452
453 SM_STEP(KEY_RX)
454 {
455         if (sm->initialize || !sm->portEnabled)
456                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
457         switch (sm->KEY_RX_state) {
458         case KEY_RX_UNKNOWN:
459                 break;
460         case KEY_RX_NO_KEY_RECEIVE:
461                 if (sm->rxKey)
462                         SM_ENTER(KEY_RX, KEY_RECEIVE);
463                 break;
464         case KEY_RX_KEY_RECEIVE:
465                 if (sm->rxKey)
466                         SM_ENTER(KEY_RX, KEY_RECEIVE);
467                 break;
468         }
469 }
470
471
472 SM_STATE(SUPP_BE, REQUEST)
473 {
474         SM_ENTRY(SUPP_BE, REQUEST);
475         sm->authWhile = 0;
476         sm->eapReq = TRUE;
477         eapol_sm_getSuppRsp(sm);
478 }
479
480
481 SM_STATE(SUPP_BE, RESPONSE)
482 {
483         SM_ENTRY(SUPP_BE, RESPONSE);
484         eapol_sm_txSuppRsp(sm);
485         sm->eapResp = FALSE;
486 }
487
488
489 SM_STATE(SUPP_BE, SUCCESS)
490 {
491         SM_ENTRY(SUPP_BE, SUCCESS);
492         sm->keyRun = TRUE;
493         sm->suppSuccess = TRUE;
494
495         if (eap_key_available(sm->eap)) {
496                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
497                  * counter */
498                 sm->replay_counter_valid = FALSE;
499         }
500 }
501
502
503 SM_STATE(SUPP_BE, FAIL)
504 {
505         SM_ENTRY(SUPP_BE, FAIL);
506         sm->suppFail = TRUE;
507 }
508
509
510 SM_STATE(SUPP_BE, TIMEOUT)
511 {
512         SM_ENTRY(SUPP_BE, TIMEOUT);
513         sm->suppTimeout = TRUE;
514 }
515
516
517 SM_STATE(SUPP_BE, IDLE)
518 {
519         SM_ENTRY(SUPP_BE, IDLE);
520         sm->suppStart = FALSE;
521         sm->initial_req = TRUE;
522 }
523
524
525 SM_STATE(SUPP_BE, INITIALIZE)
526 {
527         SM_ENTRY(SUPP_BE, INITIALIZE);
528         eapol_sm_abortSupp(sm);
529         sm->suppAbort = FALSE;
530 }
531
532
533 SM_STATE(SUPP_BE, RECEIVE)
534 {
535         SM_ENTRY(SUPP_BE, RECEIVE);
536         sm->authWhile = sm->authPeriod;
537         eapol_enable_timer_tick(sm);
538         sm->eapolEap = FALSE;
539         sm->eapNoResp = FALSE;
540         sm->initial_req = FALSE;
541 }
542
543
544 SM_STEP(SUPP_BE)
545 {
546         if (sm->initialize || sm->suppAbort)
547                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
548         else switch (sm->SUPP_BE_state) {
549         case SUPP_BE_UNKNOWN:
550                 break;
551         case SUPP_BE_REQUEST:
552                 /*
553                  * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
554                  * and SUCCESS based on eapFail and eapSuccess, respectively.
555                  * However, IEEE Std 802.1X-2004 is also specifying that
556                  * eapNoResp should be set in conjuction with eapSuccess and
557                  * eapFail which would mean that more than one of the
558                  * transitions here would be activated at the same time.
559                  * Skipping RESPONSE and/or RECEIVE states in these cases can
560                  * cause problems and the direct transitions to do not seem
561                  * correct. Because of this, the conditions for these
562                  * transitions are verified only after eapNoResp. They are
563                  * unlikely to be used since eapNoResp should always be set if
564                  * either of eapSuccess or eapFail is set.
565                  */
566                 if (sm->eapResp && sm->eapNoResp) {
567                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
568                                    "eapResp and eapNoResp set?!");
569                 }
570                 if (sm->eapResp)
571                         SM_ENTER(SUPP_BE, RESPONSE);
572                 else if (sm->eapNoResp)
573                         SM_ENTER(SUPP_BE, RECEIVE);
574                 else if (sm->eapFail)
575                         SM_ENTER(SUPP_BE, FAIL);
576                 else if (sm->eapSuccess)
577                         SM_ENTER(SUPP_BE, SUCCESS);
578                 break;
579         case SUPP_BE_RESPONSE:
580                 SM_ENTER(SUPP_BE, RECEIVE);
581                 break;
582         case SUPP_BE_SUCCESS:
583                 SM_ENTER(SUPP_BE, IDLE);
584                 break;
585         case SUPP_BE_FAIL:
586                 SM_ENTER(SUPP_BE, IDLE);
587                 break;
588         case SUPP_BE_TIMEOUT:
589                 SM_ENTER(SUPP_BE, IDLE);
590                 break;
591         case SUPP_BE_IDLE:
592                 if (sm->eapFail && sm->suppStart)
593                         SM_ENTER(SUPP_BE, FAIL);
594                 else if (sm->eapolEap && sm->suppStart)
595                         SM_ENTER(SUPP_BE, REQUEST);
596                 else if (sm->eapSuccess && sm->suppStart)
597                         SM_ENTER(SUPP_BE, SUCCESS);
598                 break;
599         case SUPP_BE_INITIALIZE:
600                 SM_ENTER(SUPP_BE, IDLE);
601                 break;
602         case SUPP_BE_RECEIVE:
603                 if (sm->eapolEap)
604                         SM_ENTER(SUPP_BE, REQUEST);
605                 else if (sm->eapFail)
606                         SM_ENTER(SUPP_BE, FAIL);
607                 else if (sm->authWhile == 0)
608                         SM_ENTER(SUPP_BE, TIMEOUT);
609                 else if (sm->eapSuccess)
610                         SM_ENTER(SUPP_BE, SUCCESS);
611                 break;
612         }
613 }
614
615
616 static void eapol_sm_txLogoff(struct eapol_sm *sm)
617 {
618         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
619         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
620                             IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
621         sm->dot1xSuppEapolLogoffFramesTx++;
622         sm->dot1xSuppEapolFramesTx++;
623 }
624
625
626 static void eapol_sm_txStart(struct eapol_sm *sm)
627 {
628         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
629         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
630                             IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
631         sm->dot1xSuppEapolStartFramesTx++;
632         sm->dot1xSuppEapolFramesTx++;
633 }
634
635
636 #define IEEE8021X_ENCR_KEY_LEN 32
637 #define IEEE8021X_SIGN_KEY_LEN 32
638
639 struct eap_key_data {
640         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
641         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
642 };
643
644
645 static void eapol_sm_processKey(struct eapol_sm *sm)
646 {
647         struct ieee802_1x_hdr *hdr;
648         struct ieee802_1x_eapol_key *key;
649         struct eap_key_data keydata;
650         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
651         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
652         int key_len, res, sign_key_len, encr_key_len;
653         u16 rx_key_length;
654
655         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
656         if (sm->last_rx_key == NULL)
657                 return;
658
659         if (!sm->conf.accept_802_1x_keys) {
660                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
661                            " even though this was not accepted - "
662                            "ignoring this packet");
663                 return;
664         }
665
666         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
667         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
668         if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
669                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
670                 return;
671         }
672         rx_key_length = WPA_GET_BE16(key->key_length);
673         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
674                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
675                    hdr->version, hdr->type, be_to_host16(hdr->length),
676                    key->type, rx_key_length, key->key_index);
677
678         eapol_sm_notify_lower_layer_success(sm, 1);
679         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
680         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
681         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
682         if (res < 0) {
683                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
684                            "decrypting EAPOL-Key keys");
685                 return;
686         }
687         if (res == 16) {
688                 /* LEAP derives only 16 bytes of keying material. */
689                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
690                 if (res) {
691                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
692                                    "master key for decrypting EAPOL-Key keys");
693                         return;
694                 }
695                 sign_key_len = 16;
696                 encr_key_len = 16;
697                 os_memcpy(keydata.sign_key, keydata.encr_key, 16);
698         } else if (res) {
699                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
700                            "data for decrypting EAPOL-Key keys (res=%d)", res);
701                 return;
702         }
703
704         /* The key replay_counter must increase when same master key */
705         if (sm->replay_counter_valid &&
706             os_memcmp(sm->last_replay_counter, key->replay_counter,
707                       IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
708                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
709                            "not increase - ignoring key");
710                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
711                             sm->last_replay_counter,
712                             IEEE8021X_REPLAY_COUNTER_LEN);
713                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
714                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
715                 return;
716         }
717
718         /* Verify key signature (HMAC-MD5) */
719         os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
720         os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
721         hmac_md5(keydata.sign_key, sign_key_len,
722                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
723                  key->key_signature);
724         if (os_memcmp(orig_key_sign, key->key_signature,
725                       IEEE8021X_KEY_SIGN_LEN) != 0) {
726                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
727                            "EAPOL-Key packet");
728                 os_memcpy(key->key_signature, orig_key_sign,
729                           IEEE8021X_KEY_SIGN_LEN);
730                 return;
731         }
732         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
733
734         key_len = be_to_host16(hdr->length) - sizeof(*key);
735         if (key_len > 32 || rx_key_length > 32) {
736                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
737                            key_len ? key_len : rx_key_length);
738                 return;
739         }
740         if (key_len == rx_key_length) {
741                 os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
742                 os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
743                           encr_key_len);
744                 os_memcpy(datakey, key + 1, key_len);
745                 rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
746                          datakey, key_len);
747                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
748                                 datakey, key_len);
749         } else if (key_len == 0) {
750                 /*
751                  * IEEE 802.1X-2004 specifies that least significant Key Length
752                  * octets from MS-MPPE-Send-Key are used as the key if the key
753                  * data is not present. This seems to be meaning the beginning
754                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
755                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
756                  * Anyway, taking the beginning of the keying material from EAP
757                  * seems to interoperate with Authenticators.
758                  */
759                 key_len = rx_key_length;
760                 os_memcpy(datakey, keydata.encr_key, key_len);
761                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
762                                 "material data encryption key",
763                                 datakey, key_len);
764         } else {
765                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
766                            "(key_length=%d)", key_len, rx_key_length);
767                 return;
768         }
769
770         sm->replay_counter_valid = TRUE;
771         os_memcpy(sm->last_replay_counter, key->replay_counter,
772                   IEEE8021X_REPLAY_COUNTER_LEN);
773
774         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
775                    "len %d",
776                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
777                    "unicast" : "broadcast",
778                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
779
780         if (sm->ctx->set_wep_key &&
781             sm->ctx->set_wep_key(sm->ctx->ctx,
782                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
783                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
784                                  datakey, key_len) < 0) {
785                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
786                            " driver.");
787         } else {
788                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
789                         sm->unicast_key_received = TRUE;
790                 else
791                         sm->broadcast_key_received = TRUE;
792
793                 if ((sm->unicast_key_received ||
794                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
795                     (sm->broadcast_key_received ||
796                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
797                 {
798                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
799                                    "frames received");
800                         sm->portValid = TRUE;
801                         if (sm->ctx->eapol_done_cb)
802                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
803                 }
804         }
805 }
806
807
808 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
809 {
810         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
811         /* EAP layer processing; no special code is needed, since Supplicant
812          * Backend state machine is waiting for eapNoResp or eapResp to be set
813          * and these are only set in the EAP state machine when the processing
814          * has finished. */
815 }
816
817
818 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
819 {
820         struct wpabuf *resp;
821
822         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
823         resp = eap_get_eapRespData(sm->eap);
824         if (resp == NULL) {
825                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
826                            "not available");
827                 return;
828         }
829
830         /* Send EAP-Packet from the EAP layer to the Authenticator */
831         sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
832                             IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
833                             wpabuf_len(resp));
834
835         /* eapRespData is not used anymore, so free it here */
836         wpabuf_free(resp);
837
838         if (sm->initial_req)
839                 sm->dot1xSuppEapolReqIdFramesRx++;
840         else
841                 sm->dot1xSuppEapolReqFramesRx++;
842         sm->dot1xSuppEapolRespFramesTx++;
843         sm->dot1xSuppEapolFramesTx++;
844 }
845
846
847 static void eapol_sm_abortSupp(struct eapol_sm *sm)
848 {
849         /* release system resources that may have been allocated for the
850          * authentication session */
851         os_free(sm->last_rx_key);
852         sm->last_rx_key = NULL;
853         wpabuf_free(sm->eapReqData);
854         sm->eapReqData = NULL;
855         eap_sm_abort(sm->eap);
856 }
857
858
859 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
860 {
861         eapol_sm_step(timeout_ctx);
862 }
863
864
865 /**
866  * eapol_sm_step - EAPOL state machine step function
867  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
868  *
869  * This function is called to notify the state machine about changed external
870  * variables. It will step through the EAPOL state machines in loop to process
871  * all triggered state changes.
872  */
873 void eapol_sm_step(struct eapol_sm *sm)
874 {
875         int i;
876
877         /* In theory, it should be ok to run this in loop until !changed.
878          * However, it is better to use a limit on number of iterations to
879          * allow events (e.g., SIGTERM) to stop the program cleanly if the
880          * state machine were to generate a busy loop. */
881         for (i = 0; i < 100; i++) {
882                 sm->changed = FALSE;
883                 SM_STEP_RUN(SUPP_PAE);
884                 SM_STEP_RUN(KEY_RX);
885                 SM_STEP_RUN(SUPP_BE);
886                 if (eap_peer_sm_step(sm->eap))
887                         sm->changed = TRUE;
888                 if (!sm->changed)
889                         break;
890         }
891
892         if (sm->changed) {
893                 /* restart EAPOL state machine step from timeout call in order
894                  * to allow other events to be processed. */
895                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
896                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
897         }
898
899         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
900                 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
901                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
902                 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
903         }
904 }
905
906
907 #ifdef CONFIG_CTRL_IFACE
908 static const char *eapol_supp_pae_state(int state)
909 {
910         switch (state) {
911         case SUPP_PAE_LOGOFF:
912                 return "LOGOFF";
913         case SUPP_PAE_DISCONNECTED:
914                 return "DISCONNECTED";
915         case SUPP_PAE_CONNECTING:
916                 return "CONNECTING";
917         case SUPP_PAE_AUTHENTICATING:
918                 return "AUTHENTICATING";
919         case SUPP_PAE_HELD:
920                 return "HELD";
921         case SUPP_PAE_AUTHENTICATED:
922                 return "AUTHENTICATED";
923         case SUPP_PAE_RESTART:
924                 return "RESTART";
925         default:
926                 return "UNKNOWN";
927         }
928 }
929
930
931 static const char *eapol_supp_be_state(int state)
932 {
933         switch (state) {
934         case SUPP_BE_REQUEST:
935                 return "REQUEST";
936         case SUPP_BE_RESPONSE:
937                 return "RESPONSE";
938         case SUPP_BE_SUCCESS:
939                 return "SUCCESS";
940         case SUPP_BE_FAIL:
941                 return "FAIL";
942         case SUPP_BE_TIMEOUT:
943                 return "TIMEOUT";
944         case SUPP_BE_IDLE:
945                 return "IDLE";
946         case SUPP_BE_INITIALIZE:
947                 return "INITIALIZE";
948         case SUPP_BE_RECEIVE:
949                 return "RECEIVE";
950         default:
951                 return "UNKNOWN";
952         }
953 }
954
955
956 static const char * eapol_port_status(PortStatus status)
957 {
958         if (status == Authorized)
959                 return "Authorized";
960         else
961                 return "Unauthorized";
962 }
963 #endif /* CONFIG_CTRL_IFACE */
964
965
966 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
967 static const char * eapol_port_control(PortControl ctrl)
968 {
969         switch (ctrl) {
970         case Auto:
971                 return "Auto";
972         case ForceUnauthorized:
973                 return "ForceUnauthorized";
974         case ForceAuthorized:
975                 return "ForceAuthorized";
976         default:
977                 return "Unknown";
978         }
979 }
980 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
981
982
983 /**
984  * eapol_sm_configure - Set EAPOL variables
985  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
986  * @heldPeriod: dot1xSuppHeldPeriod
987  * @authPeriod: dot1xSuppAuthPeriod
988  * @startPeriod: dot1xSuppStartPeriod
989  * @maxStart: dot1xSuppMaxStart
990  *
991  * Set configurable EAPOL state machine variables. Each variable can be set to
992  * the given value or ignored if set to -1 (to set only some of the variables).
993  */
994 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
995                         int startPeriod, int maxStart)
996 {
997         if (sm == NULL)
998                 return;
999         if (heldPeriod >= 0)
1000                 sm->heldPeriod = heldPeriod;
1001         if (authPeriod >= 0)
1002                 sm->authPeriod = authPeriod;
1003         if (startPeriod >= 0)
1004                 sm->startPeriod = startPeriod;
1005         if (maxStart >= 0)
1006                 sm->maxStart = maxStart;
1007 }
1008
1009
1010 #ifdef CONFIG_CTRL_IFACE
1011 /**
1012  * eapol_sm_get_status - Get EAPOL state machine status
1013  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1014  * @buf: Buffer for status information
1015  * @buflen: Maximum buffer length
1016  * @verbose: Whether to include verbose status information
1017  * Returns: Number of bytes written to buf.
1018  *
1019  * Query EAPOL state machine for status information. This function fills in a
1020  * text area with current status information from the EAPOL state machine. If
1021  * the buffer (buf) is not large enough, status information will be truncated
1022  * to fit the buffer.
1023  */
1024 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
1025                         int verbose)
1026 {
1027         int len, ret;
1028         if (sm == NULL)
1029                 return 0;
1030
1031         len = os_snprintf(buf, buflen,
1032                           "Supplicant PAE state=%s\n"
1033                           "suppPortStatus=%s\n",
1034                           eapol_supp_pae_state(sm->SUPP_PAE_state),
1035                           eapol_port_status(sm->suppPortStatus));
1036         if (len < 0 || (size_t) len >= buflen)
1037                 return 0;
1038
1039         if (verbose) {
1040                 ret = os_snprintf(buf + len, buflen - len,
1041                                   "heldPeriod=%u\n"
1042                                   "authPeriod=%u\n"
1043                                   "startPeriod=%u\n"
1044                                   "maxStart=%u\n"
1045                                   "portControl=%s\n"
1046                                   "Supplicant Backend state=%s\n",
1047                                   sm->heldPeriod,
1048                                   sm->authPeriod,
1049                                   sm->startPeriod,
1050                                   sm->maxStart,
1051                                   eapol_port_control(sm->portControl),
1052                                   eapol_supp_be_state(sm->SUPP_BE_state));
1053                 if (ret < 0 || (size_t) ret >= buflen - len)
1054                         return len;
1055                 len += ret;
1056         }
1057
1058         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
1059
1060         return len;
1061 }
1062
1063
1064 /**
1065  * eapol_sm_get_mib - Get EAPOL state machine MIBs
1066  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1067  * @buf: Buffer for MIB information
1068  * @buflen: Maximum buffer length
1069  * Returns: Number of bytes written to buf.
1070  *
1071  * Query EAPOL state machine for MIB information. This function fills in a
1072  * text area with current MIB information from the EAPOL state machine. If
1073  * the buffer (buf) is not large enough, MIB information will be truncated to
1074  * fit the buffer.
1075  */
1076 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
1077 {
1078         size_t len;
1079         int ret;
1080
1081         if (sm == NULL)
1082                 return 0;
1083         ret = os_snprintf(buf, buflen,
1084                           "dot1xSuppPaeState=%d\n"
1085                           "dot1xSuppHeldPeriod=%u\n"
1086                           "dot1xSuppAuthPeriod=%u\n"
1087                           "dot1xSuppStartPeriod=%u\n"
1088                           "dot1xSuppMaxStart=%u\n"
1089                           "dot1xSuppSuppControlledPortStatus=%s\n"
1090                           "dot1xSuppBackendPaeState=%d\n",
1091                           sm->SUPP_PAE_state,
1092                           sm->heldPeriod,
1093                           sm->authPeriod,
1094                           sm->startPeriod,
1095                           sm->maxStart,
1096                           sm->suppPortStatus == Authorized ?
1097                           "Authorized" : "Unauthorized",
1098                           sm->SUPP_BE_state);
1099
1100         if (ret < 0 || (size_t) ret >= buflen)
1101                 return 0;
1102         len = ret;
1103
1104         ret = os_snprintf(buf + len, buflen - len,
1105                           "dot1xSuppEapolFramesRx=%u\n"
1106                           "dot1xSuppEapolFramesTx=%u\n"
1107                           "dot1xSuppEapolStartFramesTx=%u\n"
1108                           "dot1xSuppEapolLogoffFramesTx=%u\n"
1109                           "dot1xSuppEapolRespFramesTx=%u\n"
1110                           "dot1xSuppEapolReqIdFramesRx=%u\n"
1111                           "dot1xSuppEapolReqFramesRx=%u\n"
1112                           "dot1xSuppInvalidEapolFramesRx=%u\n"
1113                           "dot1xSuppEapLengthErrorFramesRx=%u\n"
1114                           "dot1xSuppLastEapolFrameVersion=%u\n"
1115                           "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1116                           sm->dot1xSuppEapolFramesRx,
1117                           sm->dot1xSuppEapolFramesTx,
1118                           sm->dot1xSuppEapolStartFramesTx,
1119                           sm->dot1xSuppEapolLogoffFramesTx,
1120                           sm->dot1xSuppEapolRespFramesTx,
1121                           sm->dot1xSuppEapolReqIdFramesRx,
1122                           sm->dot1xSuppEapolReqFramesRx,
1123                           sm->dot1xSuppInvalidEapolFramesRx,
1124                           sm->dot1xSuppEapLengthErrorFramesRx,
1125                           sm->dot1xSuppLastEapolFrameVersion,
1126                           MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1127
1128         if (ret < 0 || (size_t) ret >= buflen - len)
1129                 return len;
1130         len += ret;
1131
1132         return len;
1133 }
1134 #endif /* CONFIG_CTRL_IFACE */
1135
1136
1137 /**
1138  * eapol_sm_rx_eapol - Process received EAPOL frames
1139  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1140  * @src: Source MAC address of the EAPOL packet
1141  * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
1142  * @len: Length of the EAPOL frame
1143  * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
1144  * -1 failure
1145  */
1146 int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
1147                       size_t len)
1148 {
1149         const struct ieee802_1x_hdr *hdr;
1150         const struct ieee802_1x_eapol_key *key;
1151         int data_len;
1152         int res = 1;
1153         size_t plen;
1154
1155         if (sm == NULL)
1156                 return 0;
1157         sm->dot1xSuppEapolFramesRx++;
1158         if (len < sizeof(*hdr)) {
1159                 sm->dot1xSuppInvalidEapolFramesRx++;
1160                 return 0;
1161         }
1162         hdr = (const struct ieee802_1x_hdr *) buf;
1163         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1164         os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1165         if (hdr->version < EAPOL_VERSION) {
1166                 /* TODO: backwards compatibility */
1167         }
1168         plen = be_to_host16(hdr->length);
1169         if (plen > len - sizeof(*hdr)) {
1170                 sm->dot1xSuppEapLengthErrorFramesRx++;
1171                 return 0;
1172         }
1173 #ifdef CONFIG_WPS
1174         if (sm->conf.workaround &&
1175             plen < len - sizeof(*hdr) &&
1176             hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
1177             len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
1178                 const struct eap_hdr *ehdr =
1179                         (const struct eap_hdr *) (hdr + 1);
1180                 u16 elen;
1181
1182                 elen = be_to_host16(ehdr->length);
1183                 if (elen > plen && elen <= len - sizeof(*hdr)) {
1184                         /*
1185                          * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
1186                          * packets with too short EAPOL header length field
1187                          * (14 octets). This is fixed in firmware Ver.1.49.
1188                          * As a workaround, fix the EAPOL header based on the
1189                          * correct length in the EAP packet.
1190                          */
1191                         wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
1192                                    "payload length based on EAP header: "
1193                                    "%d -> %d", (int) plen, elen);
1194                         plen = elen;
1195                 }
1196         }
1197 #endif /* CONFIG_WPS */
1198         data_len = plen + sizeof(*hdr);
1199
1200         switch (hdr->type) {
1201         case IEEE802_1X_TYPE_EAP_PACKET:
1202                 if (sm->cached_pmk) {
1203                         /* Trying to use PMKSA caching, but Authenticator did
1204                          * not seem to have a matching entry. Need to restart
1205                          * EAPOL state machines.
1206                          */
1207                         eapol_sm_abort_cached(sm);
1208                 }
1209                 wpabuf_free(sm->eapReqData);
1210                 sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
1211                 if (sm->eapReqData) {
1212                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1213                                    "frame");
1214                         sm->eapolEap = TRUE;
1215                         eapol_sm_step(sm);
1216                 }
1217                 break;
1218         case IEEE802_1X_TYPE_EAPOL_KEY:
1219                 if (plen < sizeof(*key)) {
1220                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1221                                    "frame received");
1222                         break;
1223                 }
1224                 key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
1225                 if (key->type == EAPOL_KEY_TYPE_WPA ||
1226                     key->type == EAPOL_KEY_TYPE_RSN) {
1227                         /* WPA Supplicant takes care of this frame. */
1228                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1229                                    "frame in EAPOL state machines");
1230                         res = 0;
1231                         break;
1232                 }
1233                 if (key->type != EAPOL_KEY_TYPE_RC4) {
1234                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1235                                    "EAPOL-Key type %d", key->type);
1236                         break;
1237                 }
1238                 os_free(sm->last_rx_key);
1239                 sm->last_rx_key = os_malloc(data_len);
1240                 if (sm->last_rx_key) {
1241                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1242                                    "frame");
1243                         os_memcpy(sm->last_rx_key, buf, data_len);
1244                         sm->last_rx_key_len = data_len;
1245                         sm->rxKey = TRUE;
1246                         eapol_sm_step(sm);
1247                 }
1248                 break;
1249         default:
1250                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1251                            hdr->type);
1252                 sm->dot1xSuppInvalidEapolFramesRx++;
1253                 break;
1254         }
1255
1256         return res;
1257 }
1258
1259
1260 /**
1261  * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
1262  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1263  *
1264  * Notify EAPOL state machine about transmitted EAPOL packet from an external
1265  * component, e.g., WPA. This will update the statistics.
1266  */
1267 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1268 {
1269         if (sm)
1270                 sm->dot1xSuppEapolFramesTx++;
1271 }
1272
1273
1274 /**
1275  * eapol_sm_notify_portEnabled - Notification about portEnabled change
1276  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1277  * @enabled: New portEnabled value
1278  *
1279  * Notify EAPOL state machine about new portEnabled value.
1280  */
1281 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1282 {
1283         if (sm == NULL)
1284                 return;
1285         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1286                    "portEnabled=%d", enabled);
1287         sm->portEnabled = enabled;
1288         eapol_sm_step(sm);
1289 }
1290
1291
1292 /**
1293  * eapol_sm_notify_portValid - Notification about portValid change
1294  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1295  * @valid: New portValid value
1296  *
1297  * Notify EAPOL state machine about new portValid value.
1298  */
1299 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1300 {
1301         if (sm == NULL)
1302                 return;
1303         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1304                    "portValid=%d", valid);
1305         sm->portValid = valid;
1306         eapol_sm_step(sm);
1307 }
1308
1309
1310 /**
1311  * eapol_sm_notify_eap_success - Notification of external EAP success trigger
1312  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1313  * @success: %TRUE = set success, %FALSE = clear success
1314  *
1315  * Notify the EAPOL state machine that external event has forced EAP state to
1316  * success (success = %TRUE). This can be cleared by setting success = %FALSE.
1317  *
1318  * This function is called to update EAP state when WPA-PSK key handshake has
1319  * been completed successfully since WPA-PSK does not use EAP state machine.
1320  */
1321 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1322 {
1323         if (sm == NULL)
1324                 return;
1325         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1326                    "EAP success=%d", success);
1327         sm->eapSuccess = success;
1328         sm->altAccept = success;
1329         if (success)
1330                 eap_notify_success(sm->eap);
1331         eapol_sm_step(sm);
1332 }
1333
1334
1335 /**
1336  * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
1337  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1338  * @fail: %TRUE = set failure, %FALSE = clear failure
1339  *
1340  * Notify EAPOL state machine that external event has forced EAP state to
1341  * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
1342  */
1343 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1344 {
1345         if (sm == NULL)
1346                 return;
1347         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1348                    "EAP fail=%d", fail);
1349         sm->eapFail = fail;
1350         sm->altReject = fail;
1351         eapol_sm_step(sm);
1352 }
1353
1354
1355 /**
1356  * eapol_sm_notify_config - Notification of EAPOL configuration change
1357  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1358  * @config: Pointer to current network EAP configuration
1359  * @conf: Pointer to EAPOL configuration data
1360  *
1361  * Notify EAPOL state machine that configuration has changed. config will be
1362  * stored as a backpointer to network configuration. This can be %NULL to clear
1363  * the stored pointed. conf will be copied to local EAPOL/EAP configuration
1364  * data. If conf is %NULL, this part of the configuration change will be
1365  * skipped.
1366  */
1367 void eapol_sm_notify_config(struct eapol_sm *sm,
1368                             struct eap_peer_config *config,
1369                             const struct eapol_config *conf)
1370 {
1371         if (sm == NULL)
1372                 return;
1373
1374         sm->config = config;
1375
1376         if (conf == NULL)
1377                 return;
1378
1379         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1380         sm->conf.required_keys = conf->required_keys;
1381         sm->conf.fast_reauth = conf->fast_reauth;
1382         sm->conf.workaround = conf->workaround;
1383         if (sm->eap) {
1384                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1385                 eap_set_workaround(sm->eap, conf->workaround);
1386                 eap_set_force_disabled(sm->eap, conf->eap_disabled);
1387         }
1388 }
1389
1390
1391 /**
1392  * eapol_sm_get_key - Get master session key (MSK) from EAP
1393  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1394  * @key: Pointer for key buffer
1395  * @len: Number of bytes to copy to key
1396  * Returns: 0 on success (len of key available), maximum available key len
1397  * (>0) if key is available but it is shorter than len, or -1 on failure.
1398  *
1399  * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
1400  * is available only after a successful authentication.
1401  */
1402 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1403 {
1404         const u8 *eap_key;
1405         size_t eap_len;
1406
1407         if (sm == NULL || !eap_key_available(sm->eap)) {
1408                 wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
1409                 return -1;
1410         }
1411         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1412         if (eap_key == NULL) {
1413                 wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
1414                 return -1;
1415         }
1416         if (len > eap_len) {
1417                 wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
1418                            "available (len=%lu)",
1419                            (unsigned long) len, (unsigned long) eap_len);
1420                 return eap_len;
1421         }
1422         os_memcpy(key, eap_key, len);
1423         wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
1424                    (unsigned long) len);
1425         return 0;
1426 }
1427
1428
1429 /**
1430  * eapol_sm_notify_logoff - Notification of logon/logoff commands
1431  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1432  * @logoff: Whether command was logoff
1433  *
1434  * Notify EAPOL state machines that user requested logon/logoff.
1435  */
1436 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1437 {
1438         if (sm) {
1439                 sm->userLogoff = logoff;
1440                 eapol_sm_step(sm);
1441         }
1442 }
1443
1444
1445 /**
1446  * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
1447  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1448  *
1449  * Notify EAPOL state machines that PMKSA caching was successful. This is used
1450  * to move EAPOL and EAP state machines into authenticated/successful state.
1451  */
1452 void eapol_sm_notify_cached(struct eapol_sm *sm)
1453 {
1454         if (sm == NULL)
1455                 return;
1456         wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
1457         sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1458         sm->suppPortStatus = Authorized;
1459         sm->portValid = TRUE;
1460         eap_notify_success(sm->eap);
1461         eapol_sm_step(sm);
1462 }
1463
1464
1465 /**
1466  * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
1467  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1468  * @attempt: Whether PMKSA caching is tried
1469  *
1470  * Notify EAPOL state machines whether PMKSA caching is used.
1471  */
1472 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1473 {
1474         if (sm == NULL)
1475                 return;
1476         if (attempt) {
1477                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1478                 sm->cached_pmk = TRUE;
1479         } else {
1480                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1481                 sm->cached_pmk = FALSE;
1482         }
1483 }
1484
1485
1486 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1487 {
1488         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1489                    "doing full EAP authentication");
1490         if (sm == NULL)
1491                 return;
1492         sm->cached_pmk = FALSE;
1493         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1494         sm->suppPortStatus = Unauthorized;
1495
1496         /* Make sure we do not start sending EAPOL-Start frames first, but
1497          * instead move to RESTART state to start EAPOL authentication. */
1498         sm->startWhen = 3;
1499         eapol_enable_timer_tick(sm);
1500
1501         if (sm->ctx->aborted_cached)
1502                 sm->ctx->aborted_cached(sm->ctx->ctx);
1503 }
1504
1505
1506 /**
1507  * eapol_sm_register_scard_ctx - Notification of smart card context
1508  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1509  * @ctx: Context data for smart card operations
1510  *
1511  * Notify EAPOL state machines of context data for smart card operations. This
1512  * context data will be used as a parameter for scard_*() functions.
1513  */
1514 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1515 {
1516         if (sm) {
1517                 sm->ctx->scard_ctx = ctx;
1518                 eap_register_scard_ctx(sm->eap, ctx);
1519         }
1520 }
1521
1522
1523 /**
1524  * eapol_sm_notify_portControl - Notification of portControl changes
1525  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1526  * @portControl: New value for portControl variable
1527  *
1528  * Notify EAPOL state machines that portControl variable has changed.
1529  */
1530 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1531 {
1532         if (sm == NULL)
1533                 return;
1534         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1535                    "portControl=%s", eapol_port_control(portControl));
1536         sm->portControl = portControl;
1537         eapol_sm_step(sm);
1538 }
1539
1540
1541 /**
1542  * eapol_sm_notify_ctrl_attached - Notification of attached monitor
1543  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1544  *
1545  * Notify EAPOL state machines that a monitor was attached to the control
1546  * interface to trigger re-sending of pending requests for user input.
1547  */
1548 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1549 {
1550         if (sm == NULL)
1551                 return;
1552         eap_sm_notify_ctrl_attached(sm->eap);
1553 }
1554
1555
1556 /**
1557  * eapol_sm_notify_ctrl_response - Notification of received user input
1558  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1559  *
1560  * Notify EAPOL state machines that a control response, i.e., user
1561  * input, was received in order to trigger retrying of a pending EAP request.
1562  */
1563 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1564 {
1565         if (sm == NULL)
1566                 return;
1567         if (sm->eapReqData && !sm->eapReq) {
1568                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1569                            "input) notification - retrying pending EAP "
1570                            "Request");
1571                 sm->eapolEap = TRUE;
1572                 sm->eapReq = TRUE;
1573                 eapol_sm_step(sm);
1574         }
1575 }
1576
1577
1578 /**
1579  * eapol_sm_request_reauth - Request reauthentication
1580  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1581  *
1582  * This function can be used to request EAPOL reauthentication, e.g., when the
1583  * current PMKSA entry is nearing expiration.
1584  */
1585 void eapol_sm_request_reauth(struct eapol_sm *sm)
1586 {
1587         if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
1588                 return;
1589         eapol_sm_txStart(sm);
1590 }
1591
1592
1593 /**
1594  * eapol_sm_notify_lower_layer_success - Notification of lower layer success
1595  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1596  * @in_eapol_sm: Whether the caller is already running inside EAPOL state
1597  * machine loop (eapol_sm_step())
1598  *
1599  * Notify EAPOL (and EAP) state machines that a lower layer has detected a
1600  * successful authentication. This is used to recover from dropped EAP-Success
1601  * messages.
1602  */
1603 void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
1604 {
1605         if (sm == NULL)
1606                 return;
1607         eap_notify_lower_layer_success(sm->eap);
1608         if (!in_eapol_sm)
1609                 eapol_sm_step(sm);
1610 }
1611
1612
1613 /**
1614  * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
1615  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1616  */
1617 void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
1618 {
1619         if (sm)
1620                 eap_invalidate_cached_session(sm->eap);
1621 }
1622
1623
1624 static struct eap_peer_config * eapol_sm_get_config(void *ctx)
1625 {
1626         struct eapol_sm *sm = ctx;
1627         return sm ? sm->config : NULL;
1628 }
1629
1630
1631 static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
1632 {
1633         struct eapol_sm *sm = ctx;
1634         if (sm == NULL || sm->eapReqData == NULL)
1635                 return NULL;
1636
1637         return sm->eapReqData;
1638 }
1639
1640
1641 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1642 {
1643         struct eapol_sm *sm = ctx;
1644         if (sm == NULL)
1645                 return FALSE;
1646         switch (variable) {
1647         case EAPOL_eapSuccess:
1648                 return sm->eapSuccess;
1649         case EAPOL_eapRestart:
1650                 return sm->eapRestart;
1651         case EAPOL_eapFail:
1652                 return sm->eapFail;
1653         case EAPOL_eapResp:
1654                 return sm->eapResp;
1655         case EAPOL_eapNoResp:
1656                 return sm->eapNoResp;
1657         case EAPOL_eapReq:
1658                 return sm->eapReq;
1659         case EAPOL_portEnabled:
1660                 return sm->portEnabled;
1661         case EAPOL_altAccept:
1662                 return sm->altAccept;
1663         case EAPOL_altReject:
1664                 return sm->altReject;
1665         }
1666         return FALSE;
1667 }
1668
1669
1670 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1671                               Boolean value)
1672 {
1673         struct eapol_sm *sm = ctx;
1674         if (sm == NULL)
1675                 return;
1676         switch (variable) {
1677         case EAPOL_eapSuccess:
1678                 sm->eapSuccess = value;
1679                 break;
1680         case EAPOL_eapRestart:
1681                 sm->eapRestart = value;
1682                 break;
1683         case EAPOL_eapFail:
1684                 sm->eapFail = value;
1685                 break;
1686         case EAPOL_eapResp:
1687                 sm->eapResp = value;
1688                 break;
1689         case EAPOL_eapNoResp:
1690                 sm->eapNoResp = value;
1691                 break;
1692         case EAPOL_eapReq:
1693                 sm->eapReq = value;
1694                 break;
1695         case EAPOL_portEnabled:
1696                 sm->portEnabled = value;
1697                 break;
1698         case EAPOL_altAccept:
1699                 sm->altAccept = value;
1700                 break;
1701         case EAPOL_altReject:
1702                 sm->altReject = value;
1703                 break;
1704         }
1705 }
1706
1707
1708 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1709 {
1710         struct eapol_sm *sm = ctx;
1711         if (sm == NULL)
1712                 return 0;
1713         switch (variable) {
1714         case EAPOL_idleWhile:
1715                 return sm->idleWhile;
1716         }
1717         return 0;
1718 }
1719
1720
1721 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1722                              unsigned int value)
1723 {
1724         struct eapol_sm *sm = ctx;
1725         if (sm == NULL)
1726                 return;
1727         switch (variable) {
1728         case EAPOL_idleWhile:
1729                 sm->idleWhile = value;
1730                 eapol_enable_timer_tick(sm);
1731                 break;
1732         }
1733 }
1734
1735
1736 static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
1737 {
1738 #ifndef CONFIG_NO_CONFIG_BLOBS
1739         struct eapol_sm *sm = ctx;
1740         if (sm && sm->ctx && sm->ctx->set_config_blob)
1741                 sm->ctx->set_config_blob(sm->ctx->ctx, blob);
1742 #endif /* CONFIG_NO_CONFIG_BLOBS */
1743 }
1744
1745
1746 static const struct wpa_config_blob *
1747 eapol_sm_get_config_blob(void *ctx, const char *name)
1748 {
1749 #ifndef CONFIG_NO_CONFIG_BLOBS
1750         struct eapol_sm *sm = ctx;
1751         if (sm && sm->ctx && sm->ctx->get_config_blob)
1752                 return sm->ctx->get_config_blob(sm->ctx->ctx, name);
1753         else
1754                 return NULL;
1755 #else /* CONFIG_NO_CONFIG_BLOBS */
1756         return NULL;
1757 #endif /* CONFIG_NO_CONFIG_BLOBS */
1758 }
1759
1760
1761 static void eapol_sm_notify_pending(void *ctx)
1762 {
1763         struct eapol_sm *sm = ctx;
1764         if (sm == NULL)
1765                 return;
1766         if (sm->eapReqData && !sm->eapReq) {
1767                 wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
1768                            "state machine - retrying pending EAP Request");
1769                 sm->eapolEap = TRUE;
1770                 sm->eapReq = TRUE;
1771                 eapol_sm_step(sm);
1772         }
1773 }
1774
1775
1776 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
1777 static void eapol_sm_eap_param_needed(void *ctx, const char *field,
1778                                       const char *txt)
1779 {
1780         struct eapol_sm *sm = ctx;
1781         wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
1782         if (sm->ctx->eap_param_needed)
1783                 sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
1784 }
1785 #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1786 #define eapol_sm_eap_param_needed NULL
1787 #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
1788
1789
1790 static struct eapol_callbacks eapol_cb =
1791 {
1792         eapol_sm_get_config,
1793         eapol_sm_get_bool,
1794         eapol_sm_set_bool,
1795         eapol_sm_get_int,
1796         eapol_sm_set_int,
1797         eapol_sm_get_eapReqData,
1798         eapol_sm_set_config_blob,
1799         eapol_sm_get_config_blob,
1800         eapol_sm_notify_pending,
1801         eapol_sm_eap_param_needed
1802 };
1803
1804
1805 /**
1806  * eapol_sm_init - Initialize EAPOL state machine
1807  * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
1808  * and EAPOL state machine will free it in eapol_sm_deinit()
1809  * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
1810  *
1811  * Allocate and initialize an EAPOL state machine.
1812  */
1813 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
1814 {
1815         struct eapol_sm *sm;
1816         struct eap_config conf;
1817         sm = os_zalloc(sizeof(*sm));
1818         if (sm == NULL)
1819                 return NULL;
1820         sm->ctx = ctx;
1821
1822         sm->portControl = Auto;
1823
1824         /* Supplicant PAE state machine */
1825         sm->heldPeriod = 60;
1826         sm->startPeriod = 30;
1827         sm->maxStart = 3;
1828
1829         /* Supplicant Backend state machine */
1830         sm->authPeriod = 30;
1831
1832         os_memset(&conf, 0, sizeof(conf));
1833 #ifdef EAP_TLS_OPENSSL
1834         conf.opensc_engine_path = ctx->opensc_engine_path;
1835         conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
1836         conf.pkcs11_module_path = ctx->pkcs11_module_path;
1837 #endif /* EAP_TLS_OPENSSL */
1838         conf.wps = ctx->wps;
1839
1840         sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
1841         if (sm->eap == NULL) {
1842                 os_free(sm);
1843                 return NULL;
1844         }
1845
1846         /* Initialize EAPOL state machines */
1847         sm->initialize = TRUE;
1848         eapol_sm_step(sm);
1849         sm->initialize = FALSE;
1850         eapol_sm_step(sm);
1851
1852         sm->timer_tick_enabled = 1;
1853         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1854
1855         return sm;
1856 }
1857
1858
1859 /**
1860  * eapol_sm_deinit - Deinitialize EAPOL state machine
1861  * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
1862  *
1863  * Deinitialize and free EAPOL state machine.
1864  */
1865 void eapol_sm_deinit(struct eapol_sm *sm)
1866 {
1867         if (sm == NULL)
1868                 return;
1869         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
1870         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1871         eap_peer_sm_deinit(sm->eap);
1872         os_free(sm->last_rx_key);
1873         wpabuf_free(sm->eapReqData);
1874         os_free(sm->ctx);
1875         os_free(sm);
1876 }