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