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