]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/eapol_sm.c
This commit was generated by cvs2svn to compensate for changes in r147013,
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / eapol_sm.c
1 /*
2  * WPA Supplicant / EAPOL state machines
3  * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  *
9  * Alternatively, this software may be distributed under the terms of BSD
10  * license.
11  *
12  * See README and COPYING for more details.
13  */
14
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "common.h"
20 #include "eapol_sm.h"
21 #include "eap.h"
22 #include "eloop.h"
23 #include "wpa_supplicant.h"
24 #include "l2_packet.h"
25 #include "wpa.h"
26 #include "md5.h"
27 #include "rc4.h"
28
29
30 /* IEEE 802.1aa/D6.1 - Supplicant */
31
32 struct eapol_sm {
33         /* Timers */
34         unsigned int authWhile;
35         unsigned int heldWhile;
36         unsigned int startWhen;
37         unsigned int idleWhile; /* for EAP state machine */
38
39         /* Global variables */
40         Boolean eapFail;
41         Boolean eapolEap;
42         Boolean eapSuccess;
43         Boolean initialize;
44         Boolean keyDone;
45         Boolean keyRun;
46         PortControl portControl;
47         Boolean portEnabled;
48         PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
49         Boolean portValid;
50         Boolean suppAbort;
51         Boolean suppFail;
52         Boolean suppStart;
53         Boolean suppSuccess;
54         Boolean suppTimeout;
55
56         /* Supplicant PAE state machine */
57         enum {
58                 SUPP_PAE_UNKNOWN = 0,
59                 SUPP_PAE_DISCONNECTED = 1,
60                 SUPP_PAE_LOGOFF = 2,
61                 SUPP_PAE_CONNECTING = 3,
62                 SUPP_PAE_AUTHENTICATING = 4,
63                 SUPP_PAE_AUTHENTICATED = 5,
64                 /* unused(6) */
65                 SUPP_PAE_HELD = 7,
66                 SUPP_PAE_RESTART = 8,
67                 SUPP_PAE_S_FORCE_AUTH = 9,
68                 SUPP_PAE_S_FORCE_UNAUTH = 10
69         } SUPP_PAE_state; /* dot1xSuppPaeState */
70         /* Variables */
71         Boolean userLogoff;
72         Boolean logoffSent;
73         unsigned int startCount;
74         Boolean eapRestart;
75         PortControl sPortMode;
76         /* Constants */
77         unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
78         unsigned int startPeriod; /* dot1xSuppStartPeriod */
79         unsigned int maxStart; /* dot1xSuppMaxStart */
80
81         /* Key Receive state machine */
82         enum {
83                 KEY_RX_UNKNOWN = 0,
84                 KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
85         } KEY_RX_state;
86         /* Variables */
87         Boolean rxKey;
88
89         /* Supplicant Backend state machine */
90         enum {
91                 SUPP_BE_UNKNOWN = 0,
92                 SUPP_BE_INITIALIZE = 1,
93                 SUPP_BE_IDLE = 2,
94                 SUPP_BE_REQUEST = 3,
95                 SUPP_BE_RECEIVE = 4,
96                 SUPP_BE_RESPONSE = 5,
97                 SUPP_BE_FAIL = 6,
98                 SUPP_BE_TIMEOUT = 7, 
99                 SUPP_BE_SUCCESS = 8
100         } SUPP_BE_state; /* dot1xSuppBackendPaeState */
101         /* Variables */
102         Boolean eapNoResp;
103         Boolean eapReq;
104         Boolean eapResp;
105         /* Constants */
106         unsigned int authPeriod; /* dot1xSuppAuthPeriod */
107
108         /* Statistics */
109         unsigned int dot1xSuppEapolFramesRx;
110         unsigned int dot1xSuppEapolFramesTx;
111         unsigned int dot1xSuppEapolStartFramesTx;
112         unsigned int dot1xSuppEapolLogoffFramesTx;
113         unsigned int dot1xSuppEapolRespFramesTx;
114         unsigned int dot1xSuppEapolReqIdFramesRx;
115         unsigned int dot1xSuppEapolReqFramesRx;
116         unsigned int dot1xSuppInvalidEapolFramesRx;
117         unsigned int dot1xSuppEapLengthErrorFramesRx;
118         unsigned int dot1xSuppLastEapolFrameVersion;
119         unsigned char dot1xSuppLastEapolFrameSource[6];
120
121         /* Miscellaneous variables (not defined in IEEE 802.1aa/D6.1) */
122         Boolean changed;
123         struct eap_sm *eap;
124         struct wpa_ssid *config;
125         Boolean initial_req;
126         u8 *last_rx_key;
127         size_t last_rx_key_len;
128         u8 *eapReqData; /* for EAP */
129         size_t eapReqDataLen; /* for EAP */
130         Boolean altAccept; /* for EAP */
131         Boolean altReject; /* for EAP */
132         Boolean replay_counter_valid;
133         u8 last_replay_counter[16];
134         struct eapol_config conf;
135         struct eapol_ctx *ctx;
136         enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
137                 cb_status;
138         Boolean cached_pmk;
139
140         Boolean unicast_key_received, broadcast_key_received;
141 };
142
143
144 static void eapol_sm_txLogoff(struct eapol_sm *sm);
145 static void eapol_sm_txStart(struct eapol_sm *sm);
146 static void eapol_sm_processKey(struct eapol_sm *sm);
147 static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
148 static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
149 static void eapol_sm_abortSupp(struct eapol_sm *sm);
150 static void eapol_sm_abort_cached(struct eapol_sm *sm);
151 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
152
153 static struct eapol_callbacks eapol_cb;
154
155
156 /* Definitions for clarifying state machine implementation */
157 #define SM_STATE(machine, state) \
158 static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_sm *sm, \
159         int global)
160
161 #define SM_ENTRY(machine, state) \
162 if (!global || sm->machine ## _state != machine ## _ ## state) { \
163         sm->changed = TRUE; \
164         wpa_printf(MSG_DEBUG, "EAPOL: " #machine " entering state " #state); \
165 } \
166 sm->machine ## _state = machine ## _ ## state;
167
168 #define SM_ENTER(machine, state) \
169 sm_ ## machine ## _ ## state ## _Enter(sm, 0)
170 #define SM_ENTER_GLOBAL(machine, state) \
171 sm_ ## machine ## _ ## state ## _Enter(sm, 1)
172
173 #define SM_STEP(machine) \
174 static void sm_ ## machine ## _Step(struct eapol_sm *sm)
175
176 #define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
177
178
179 /* Port Timers state machine - implemented as a function that will be called
180  * once a second as a registered event loop timeout */
181 static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
182 {
183         struct eapol_sm *sm = timeout_ctx;
184
185         if (sm->authWhile > 0)
186                 sm->authWhile--;
187         if (sm->heldWhile > 0)
188                 sm->heldWhile--;
189         if (sm->startWhen > 0)
190                 sm->startWhen--;
191         if (sm->idleWhile > 0)
192                 sm->idleWhile--;
193         wpa_printf(MSG_MSGDUMP, "EAPOL: Port Timers tick - authWhile=%d "
194                    "heldWhile=%d startWhen=%d idleWhile=%d",
195                    sm->authWhile, sm->heldWhile, sm->startWhen, sm->idleWhile);
196
197         eapol_sm_step(sm);
198
199         eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, 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 }
210
211
212 SM_STATE(SUPP_PAE, DISCONNECTED)
213 {
214         SM_ENTRY(SUPP_PAE, DISCONNECTED);
215         sm->sPortMode = Auto;
216         sm->startCount = 0;
217         sm->logoffSent = FALSE;
218         sm->suppPortStatus = Unauthorized;
219         sm->suppAbort = TRUE;
220
221         sm->unicast_key_received = FALSE;
222         sm->broadcast_key_received = FALSE;
223 }
224
225
226 SM_STATE(SUPP_PAE, CONNECTING)
227 {
228         SM_ENTRY(SUPP_PAE, CONNECTING);
229         sm->startWhen = sm->startPeriod;
230         sm->startCount++;
231         sm->eapolEap = FALSE;
232         eapol_sm_txStart(sm);
233 }
234
235
236 SM_STATE(SUPP_PAE, AUTHENTICATING)
237 {
238         SM_ENTRY(SUPP_PAE, AUTHENTICATING);
239         sm->startCount = 0;
240         sm->suppSuccess = FALSE;
241         sm->suppFail = FALSE;
242         sm->suppTimeout = FALSE;
243         sm->keyRun = FALSE;
244         sm->keyDone = FALSE;
245         sm->suppStart = TRUE;
246 }
247
248
249 SM_STATE(SUPP_PAE, HELD)
250 {
251         SM_ENTRY(SUPP_PAE, HELD);
252         sm->heldWhile = sm->heldPeriod;
253         sm->suppPortStatus = Unauthorized;
254         sm->cb_status = EAPOL_CB_FAILURE;
255 }
256
257
258 SM_STATE(SUPP_PAE, AUTHENTICATED)
259 {
260         SM_ENTRY(SUPP_PAE, AUTHENTICATED);
261         sm->suppPortStatus = Authorized;
262         sm->cb_status = EAPOL_CB_SUCCESS;
263 }
264
265
266 SM_STATE(SUPP_PAE, RESTART)
267 {
268         SM_ENTRY(SUPP_PAE, RESTART);
269         sm->eapRestart = TRUE;
270 }
271
272
273 SM_STATE(SUPP_PAE, S_FORCE_AUTH)
274 {
275         SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
276         sm->suppPortStatus = Authorized;
277         sm->sPortMode = ForceAuthorized;
278 }
279
280
281 SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
282 {
283         SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
284         sm->suppPortStatus = Unauthorized;
285         sm->sPortMode = ForceUnauthorized;
286         eapol_sm_txLogoff(sm);
287 }
288
289
290 SM_STEP(SUPP_PAE)
291 {
292         if ((sm->userLogoff && !sm->logoffSent) &&
293             !(sm->initialize || !sm->portEnabled))
294                 SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
295         else if (((sm->portControl == Auto) &&
296                   (sm->sPortMode != sm->portControl)) ||
297                  sm->initialize || !sm->portEnabled)
298                 SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
299         else if ((sm->portControl == ForceAuthorized) &&
300                  (sm->sPortMode != sm->portControl) &&
301                  !(sm->initialize || !sm->portEnabled))
302                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
303         else if ((sm->portControl == ForceUnauthorized) &&
304                  (sm->sPortMode != sm->portControl) &&
305                  !(sm->initialize || !sm->portEnabled))
306                 SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
307         else switch (sm->SUPP_PAE_state) {
308         case SUPP_PAE_UNKNOWN:
309                 break;
310         case SUPP_PAE_LOGOFF:
311                 if (!sm->userLogoff)
312                         SM_ENTER(SUPP_PAE, DISCONNECTED);
313                 break;
314         case SUPP_PAE_DISCONNECTED:
315                 SM_ENTER(SUPP_PAE, CONNECTING);
316                 break;
317         case SUPP_PAE_CONNECTING:
318                 if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
319                         SM_ENTER(SUPP_PAE, CONNECTING);
320                 else if (sm->startWhen == 0 &&
321                          sm->startCount >= sm->maxStart &&
322                          sm->portValid)
323                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
324                 else if (sm->eapSuccess || sm->eapFail)
325                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
326                 else if (sm->eapolEap)
327                         SM_ENTER(SUPP_PAE, RESTART);
328                 else if (sm->startWhen == 0 &&
329                          sm->startCount >= sm->maxStart &&
330                          !sm->portValid)
331                         SM_ENTER(SUPP_PAE, HELD);
332                 break;
333         case SUPP_PAE_AUTHENTICATING:
334                 if (sm->eapSuccess && !sm->portValid &&
335                     sm->conf.accept_802_1x_keys &&
336                     sm->conf.required_keys == 0) {
337                         wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
338                                    "plaintext connection; no EAPOL-Key frames "
339                                    "required");
340                         sm->portValid = TRUE;
341                         if (sm->ctx->eapol_done_cb)
342                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
343                 }
344                 if (sm->eapSuccess && sm->portValid)
345                         SM_ENTER(SUPP_PAE, AUTHENTICATED);
346                 else if (sm->eapFail || (sm->keyDone && !sm->portValid))
347                         SM_ENTER(SUPP_PAE, HELD);
348                 else if (sm->suppTimeout)
349                         SM_ENTER(SUPP_PAE, CONNECTING);
350                 break;
351         case SUPP_PAE_HELD:
352                 if (sm->heldWhile == 0)
353                         SM_ENTER(SUPP_PAE, CONNECTING);
354                 else if (sm->eapolEap)
355                         SM_ENTER(SUPP_PAE, RESTART);
356                 break;
357         case SUPP_PAE_AUTHENTICATED:
358                 if (sm->eapolEap && sm->portValid)
359                         SM_ENTER(SUPP_PAE, RESTART);
360                 else if (!sm->portValid)
361                         SM_ENTER(SUPP_PAE, DISCONNECTED);
362                 break;
363         case SUPP_PAE_RESTART:
364                 if (!sm->eapRestart)
365                         SM_ENTER(SUPP_PAE, AUTHENTICATING);
366                 break;
367         case SUPP_PAE_S_FORCE_AUTH:
368                 break;
369         case SUPP_PAE_S_FORCE_UNAUTH:
370                 break;
371         }
372 }
373
374
375 SM_STATE(KEY_RX, NO_KEY_RECEIVE)
376 {
377         SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
378 }
379
380
381 SM_STATE(KEY_RX, KEY_RECEIVE)
382 {
383         SM_ENTRY(KEY_RX, KEY_RECEIVE);
384         eapol_sm_processKey(sm);
385         sm->rxKey = FALSE;
386 }
387
388
389 SM_STEP(KEY_RX)
390 {
391         if (sm->initialize || !sm->portEnabled)
392                 SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
393         switch (sm->KEY_RX_state) {
394         case KEY_RX_UNKNOWN:
395                 break;
396         case KEY_RX_NO_KEY_RECEIVE:
397                 if (sm->rxKey)
398                         SM_ENTER(KEY_RX, KEY_RECEIVE);
399                 break;
400         case KEY_RX_KEY_RECEIVE:
401                 if (sm->rxKey)
402                         SM_ENTER(KEY_RX, KEY_RECEIVE);
403                 break;
404         }
405 }
406
407
408 SM_STATE(SUPP_BE, REQUEST)
409 {
410         SM_ENTRY(SUPP_BE, REQUEST);
411         sm->authWhile = 0;
412         sm->eapReq = TRUE;
413         eapol_sm_getSuppRsp(sm);
414 }
415
416
417 SM_STATE(SUPP_BE, RESPONSE)
418 {
419         SM_ENTRY(SUPP_BE, RESPONSE);
420         eapol_sm_txSuppRsp(sm);
421         sm->eapResp = FALSE;
422 }
423
424
425 SM_STATE(SUPP_BE, SUCCESS)
426 {
427         SM_ENTRY(SUPP_BE, SUCCESS);
428         sm->keyRun = TRUE;
429         sm->suppSuccess = TRUE;
430
431         if (eap_key_available(sm->eap)) {
432                 /* New key received - clear IEEE 802.1X EAPOL-Key replay
433                  * counter */
434                 sm->replay_counter_valid = FALSE;
435         }
436 }
437
438
439 SM_STATE(SUPP_BE, FAIL)
440 {
441         SM_ENTRY(SUPP_BE, FAIL);
442         sm->suppFail = TRUE;
443 }
444
445
446 SM_STATE(SUPP_BE, TIMEOUT)
447 {
448         SM_ENTRY(SUPP_BE, TIMEOUT);
449         sm->suppTimeout = TRUE;
450 }
451
452
453 SM_STATE(SUPP_BE, IDLE)
454 {
455         SM_ENTRY(SUPP_BE, IDLE);
456         sm->suppStart = FALSE;
457         sm->initial_req = TRUE;
458 }
459
460
461 SM_STATE(SUPP_BE, INITIALIZE)
462 {
463         SM_ENTRY(SUPP_BE, INITIALIZE);
464         eapol_sm_abortSupp(sm);
465         sm->suppAbort = FALSE;
466 }
467
468
469 SM_STATE(SUPP_BE, RECEIVE)
470 {
471         SM_ENTRY(SUPP_BE, RECEIVE);
472         sm->authWhile = sm->authPeriod;
473         sm->eapolEap = FALSE;
474         sm->eapNoResp = FALSE;
475         sm->initial_req = FALSE;
476 }
477
478
479 SM_STEP(SUPP_BE)
480 {
481         if (sm->initialize || sm->suppAbort)
482                 SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
483         else switch (sm->SUPP_BE_state) {
484         case SUPP_BE_UNKNOWN:
485                 break;
486         case SUPP_BE_REQUEST:
487                 if (sm->eapResp && sm->eapNoResp) {
488                         wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
489                                    "eapResp and eapNoResp set?!");
490                 }
491                 if (sm->eapResp)
492                         SM_ENTER(SUPP_BE, RESPONSE);
493                 else if (sm->eapNoResp)
494                         SM_ENTER(SUPP_BE, RECEIVE);
495                 break;
496         case SUPP_BE_RESPONSE:
497                 SM_ENTER(SUPP_BE, RECEIVE);
498                 break;
499         case SUPP_BE_SUCCESS:
500                 SM_ENTER(SUPP_BE, IDLE);
501                 break;
502         case SUPP_BE_FAIL:
503                 SM_ENTER(SUPP_BE, IDLE);
504                 break;
505         case SUPP_BE_TIMEOUT:
506                 SM_ENTER(SUPP_BE, IDLE);
507                 break;
508         case SUPP_BE_IDLE:
509                 if (sm->eapFail && sm->suppStart)
510                         SM_ENTER(SUPP_BE, FAIL);
511                 else if (sm->eapolEap && sm->suppStart)
512                         SM_ENTER(SUPP_BE, REQUEST);
513                 else if (sm->eapSuccess && sm->suppStart)
514                         SM_ENTER(SUPP_BE, SUCCESS);
515                 break;
516         case SUPP_BE_INITIALIZE:
517                 SM_ENTER(SUPP_BE, IDLE);
518                 break;
519         case SUPP_BE_RECEIVE:
520                 if (sm->eapolEap)
521                         SM_ENTER(SUPP_BE, REQUEST);
522                 else if (sm->eapFail)
523                         SM_ENTER(SUPP_BE, FAIL);
524                 else if (sm->authWhile == 0)
525                         SM_ENTER(SUPP_BE, TIMEOUT);
526                 else if (sm->eapSuccess)
527                         SM_ENTER(SUPP_BE, SUCCESS);
528                 break;
529         }
530 }
531
532
533 static void eapol_sm_txLogoff(struct eapol_sm *sm)
534 {
535         wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
536         sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAPOL_LOGOFF,
537                             (u8 *) "", 0);
538         sm->dot1xSuppEapolLogoffFramesTx++;
539         sm->dot1xSuppEapolFramesTx++;
540 }
541
542
543 static void eapol_sm_txStart(struct eapol_sm *sm)
544 {
545         wpa_printf(MSG_DEBUG, "EAPOL: txStart");
546         sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAPOL_START,
547                             (u8 *) "", 0);
548         sm->dot1xSuppEapolStartFramesTx++;
549         sm->dot1xSuppEapolFramesTx++;
550 }
551
552
553 #define IEEE8021X_ENCR_KEY_LEN 32
554 #define IEEE8021X_SIGN_KEY_LEN 32
555
556 struct eap_key_data {
557         u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
558         u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
559 };
560
561
562 static void eapol_sm_processKey(struct eapol_sm *sm)
563 {
564         struct ieee802_1x_hdr *hdr;
565         struct ieee802_1x_eapol_key *key;
566         struct eap_key_data keydata;
567         u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
568         u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
569         int key_len, res, sign_key_len, encr_key_len;
570
571         wpa_printf(MSG_DEBUG, "EAPOL: processKey");
572         if (sm->last_rx_key == NULL)
573                 return;
574
575         if (!sm->conf.accept_802_1x_keys) {
576                 wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
577                            " even though this was not accepted - "
578                            "ignoring this packet");
579                 return;
580         }
581
582         hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
583         key = (struct ieee802_1x_eapol_key *) (hdr + 1);
584         if (sizeof(*hdr) + be_to_host16(hdr->length) > sm->last_rx_key_len) {
585                 wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
586                 return;
587         }
588         wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
589                    "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
590                    hdr->version, hdr->type, be_to_host16(hdr->length),
591                    key->type, be_to_host16(key->key_length), key->key_index);
592
593         sign_key_len = IEEE8021X_SIGN_KEY_LEN;
594         encr_key_len = IEEE8021X_ENCR_KEY_LEN;
595         res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
596         if (res < 0) {
597                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
598                            "decrypting EAPOL-Key keys");
599                 return;
600         }
601         if (res == 16) {
602                 /* LEAP derives only 16 bytes of keying material. */
603                 res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
604                 if (res) {
605                         wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
606                                    "master key for decrypting EAPOL-Key keys");
607                         return;
608                 }
609                 sign_key_len = 16;
610                 encr_key_len = 16;
611                 memcpy(keydata.sign_key, keydata.encr_key, 16);
612         } else if (res) {
613                 wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
614                            "data for decrypting EAPOL-Key keys (res=%d)", res);
615                 return;
616         }
617
618         /* The key replay_counter must increase when same master key */
619         if (sm->replay_counter_valid &&
620             memcmp(sm->last_replay_counter, key->replay_counter,
621                    IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
622                 wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
623                            "not increase - ignoring key");
624                 wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
625                             sm->last_replay_counter,
626                             IEEE8021X_REPLAY_COUNTER_LEN);
627                 wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
628                             key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
629                 return;
630         }
631
632         /* Verify key signature (HMAC-MD5) */
633         memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
634         memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
635         hmac_md5(keydata.sign_key, sign_key_len,
636                  sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
637                  key->key_signature);
638         if (memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN)
639             != 0) {
640                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
641                            "EAPOL-Key packet");
642                 memcpy(key->key_signature, orig_key_sign,
643                        IEEE8021X_KEY_SIGN_LEN);
644                 return;
645         }
646         wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
647
648         key_len = be_to_host16(hdr->length) - sizeof(*key);
649         if (key_len > 32 || be_to_host16(key->key_length) > 32) {
650                 wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
651                            key_len ? key_len : be_to_host16(key->key_length));
652                 return;
653         }
654         if (key_len == be_to_host16(key->key_length)) {
655                 memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
656                 memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
657                        encr_key_len);
658                 memcpy(datakey, key + 1, key_len);
659                 rc4(datakey, key_len, ekey,
660                     IEEE8021X_KEY_IV_LEN + encr_key_len);
661                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
662                                 datakey, key_len);
663         } else if (key_len == 0) {
664                 /* IEEE 802.1X-REV specifies that least significant Key Length
665                  * octets from MS-MPPE-Send-Key are used as the key if the key
666                  * data is not present. This seems to be meaning the beginning
667                  * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
668                  * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
669                  * Anyway, taking the beginning of the keying material from EAP
670                  * seems to interoperate with Authenticators. */
671                 key_len = be_to_host16(key->key_length);
672                 memcpy(datakey, keydata.encr_key, key_len);
673                 wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
674                                 "material data encryption key",
675                                 datakey, key_len);
676         } else {
677                 wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
678                            "(key_length=%d)", key_len,
679                            be_to_host16(key->key_length));
680                 return;
681         }
682
683         sm->replay_counter_valid = TRUE;
684         memcpy(sm->last_replay_counter, key->replay_counter,
685                IEEE8021X_REPLAY_COUNTER_LEN);
686
687         wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
688                    "len %d",
689                    key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
690                    "unicast" : "broadcast",
691                    key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
692
693         if (sm->ctx->set_wep_key &&
694             sm->ctx->set_wep_key(sm->ctx->ctx,
695                                  key->key_index & IEEE8021X_KEY_INDEX_FLAG,
696                                  key->key_index & IEEE8021X_KEY_INDEX_MASK,
697                                  datakey, key_len) < 0) {
698                 wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
699                            " driver.");
700         } else {
701                 if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
702                         sm->unicast_key_received = TRUE;
703                 else
704                         sm->broadcast_key_received = TRUE;
705
706                 if ((sm->unicast_key_received ||
707                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
708                     (sm->broadcast_key_received ||
709                      !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
710                 {
711                         wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
712                                    "frames received");
713                         sm->portValid = TRUE;
714                         if (sm->ctx->eapol_done_cb)
715                                 sm->ctx->eapol_done_cb(sm->ctx->ctx);
716                 }
717         }
718 }
719
720
721 static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
722 {
723         wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
724         /* EAP layer processing; no special code is needed, since Supplicant
725          * Backend state machine is waiting for eapNoResp or eapResp to be set
726          * and these are only set in the EAP state machine when the processing
727          * has finished. */
728 }
729
730
731 static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
732 {
733         u8 *resp;
734         size_t resp_len;
735
736         wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
737         resp = eap_get_eapRespData(sm->eap, &resp_len);
738         if (resp == NULL) {
739                 wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
740                            "not available");
741                 return;
742         }
743
744         /* Send EAP-Packet from the EAP layer to the Authenticator */
745         sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAP_PACKET,
746                             resp, resp_len);
747
748         /* eapRespData is not used anymore, so free it here */
749         free(resp);
750
751         if (sm->initial_req)
752                 sm->dot1xSuppEapolReqIdFramesRx++;
753         else
754                 sm->dot1xSuppEapolReqFramesRx++;
755         sm->dot1xSuppEapolRespFramesTx++;
756         sm->dot1xSuppEapolFramesTx++;
757 }
758
759
760 static void eapol_sm_abortSupp(struct eapol_sm *sm)
761 {
762         /* release system resources that may have been allocated for the
763          * authentication session */
764         free(sm->last_rx_key);
765         sm->last_rx_key = NULL;
766         free(sm->eapReqData);
767         sm->eapReqData = NULL;
768         eap_sm_abort(sm->eap);
769 }
770
771
772 struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
773 {
774         struct eapol_sm *sm;
775         sm = malloc(sizeof(*sm));
776         if (sm == NULL)
777                 return NULL;
778         memset(sm, 0, sizeof(*sm));
779         sm->ctx = ctx;
780
781         sm->portControl = Auto;
782
783         /* Supplicant PAE state machine */
784         sm->heldPeriod = 60;
785         sm->startPeriod = 30;
786         sm->maxStart = 3;
787
788         /* Supplicant Backend state machine */
789         sm->authPeriod = 30;
790
791         sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx);
792         if (sm->eap == NULL) {
793                 free(sm);
794                 return NULL;
795         }
796
797         /* Initialize EAPOL state machines */
798         sm->initialize = TRUE;
799         eapol_sm_step(sm);
800         sm->initialize = FALSE;
801         eapol_sm_step(sm);
802
803         eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
804
805         return sm;
806 }
807
808
809 void eapol_sm_deinit(struct eapol_sm *sm)
810 {
811         if (sm == NULL)
812                 return;
813         eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
814         eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
815         eap_sm_deinit(sm->eap);
816         free(sm->last_rx_key);
817         free(sm->eapReqData);
818         free(sm->ctx);
819         free(sm);
820 }
821
822
823 static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
824 {
825         eapol_sm_step(timeout_ctx);
826 }
827
828
829 void eapol_sm_step(struct eapol_sm *sm)
830 {
831         int i;
832
833         /* In theory, it should be ok to run this in loop until !changed.
834          * However, it is better to use a limit on number of iterations to
835          * allow events (e.g., SIGTERM) to stop the program cleanly if the
836          * state machine were to generate a busy loop. */
837         for (i = 0; i < 100; i++) {
838                 sm->changed = FALSE;
839                 SM_STEP_RUN(SUPP_PAE);
840                 SM_STEP_RUN(KEY_RX);
841                 SM_STEP_RUN(SUPP_BE);
842                 if (eap_sm_step(sm->eap))
843                         sm->changed = TRUE;
844         }
845
846         if (sm->changed) {
847                 /* restart EAPOL state machine step from timeout call in order
848                  * to allow other events to be processed. */
849                 eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
850                 eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
851         }
852
853         if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
854                 int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
855                 sm->cb_status = EAPOL_CB_IN_PROGRESS;
856                 sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
857         }
858 }
859
860
861 static const char *eapol_supp_pae_state(int state)
862 {
863         switch (state) {
864         case SUPP_PAE_LOGOFF:
865                 return "LOGOFF";
866         case SUPP_PAE_DISCONNECTED:
867                 return "DISCONNECTED";
868         case SUPP_PAE_CONNECTING:
869                 return "CONNECTING";
870         case SUPP_PAE_AUTHENTICATING:
871                 return "AUTHENTICATING";
872         case SUPP_PAE_HELD:
873                 return "HELD";
874         case SUPP_PAE_AUTHENTICATED:
875                 return "AUTHENTICATED";
876         case SUPP_PAE_RESTART:
877                 return "RESTART";
878         default:
879                 return "UNKNOWN";
880         }
881 }
882
883
884 static const char *eapol_supp_be_state(int state)
885 {
886         switch (state) {
887         case SUPP_BE_REQUEST:
888                 return "REQUEST";
889         case SUPP_BE_RESPONSE:
890                 return "RESPONSE";
891         case SUPP_BE_SUCCESS:
892                 return "SUCCESS";
893         case SUPP_BE_FAIL:
894                 return "FAIL";
895         case SUPP_BE_TIMEOUT:
896                 return "TIMEOUT";
897         case SUPP_BE_IDLE:
898                 return "IDLE";
899         case SUPP_BE_INITIALIZE:
900                 return "INITIALIZE";
901         case SUPP_BE_RECEIVE:
902                 return "RECEIVE";
903         default:
904                 return "UNKNOWN";
905         }
906 }
907
908
909 static const char * eapol_port_status(PortStatus status)
910 {
911         if (status == Authorized)
912                 return "Authorized";
913         else
914                 return "Unauthorized";
915 }
916
917
918 static const char * eapol_port_control(PortControl ctrl)
919 {
920         switch (ctrl) {
921         case Auto:
922                 return "Auto";
923         case ForceUnauthorized:
924                 return "ForceUnauthorized";
925         case ForceAuthorized:
926                 return "ForceAuthorized";
927         default:
928                 return "Unknown";
929         }
930 }
931
932
933 void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
934                         int startPeriod, int maxStart)
935 {
936         if (sm == NULL)
937                 return;
938         if (heldPeriod >= 0)
939                 sm->heldPeriod = heldPeriod;
940         if (authPeriod >= 0)
941                 sm->authPeriod = authPeriod;
942         if (startPeriod >= 0)
943                 sm->startPeriod = startPeriod;
944         if (maxStart >= 0)
945                 sm->maxStart = maxStart;
946 }
947
948
949 int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
950                         int verbose)
951 {
952         int len;
953         if (sm == NULL)
954                 return 0;
955
956         len = snprintf(buf, buflen,
957                        "Supplicant PAE state=%s\n"
958                        "suppPortStatus=%s\n",
959                        eapol_supp_pae_state(sm->SUPP_PAE_state),
960                        eapol_port_status(sm->suppPortStatus));
961
962         if (verbose) {
963                 len += snprintf(buf + len, buflen - len,
964                                 "heldPeriod=%d\n"
965                                 "authPeriod=%d\n"
966                                 "startPeriod=%d\n"
967                                 "maxStart=%d\n"
968                                 "portControl=%s\n"
969                                 "Supplicant Backend state=%s\n",
970                                 sm->heldPeriod,
971                                 sm->authPeriod,
972                                 sm->startPeriod,
973                                 sm->maxStart,
974                                 eapol_port_control(sm->portControl),
975                                 eapol_supp_be_state(sm->SUPP_BE_state));
976         }
977
978         len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
979
980         return len;
981 }
982
983
984 int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
985 {
986         int len;
987         if (sm == NULL)
988                 return 0;
989         len = snprintf(buf, buflen,
990                        "dot1xSuppPaeState=%d\n"
991                        "dot1xSuppHeldPeriod=%d\n"
992                        "dot1xSuppAuthPeriod=%d\n"
993                        "dot1xSuppStartPeriod=%d\n"
994                        "dot1xSuppMaxStart=%d\n"
995                        "dot1xSuppSuppControlledPortStatus=%s\n"
996                        "dot1xSuppBackendPaeState=%d\n"
997                        "dot1xSuppEapolFramesRx=%d\n"
998                        "dot1xSuppEapolFramesTx=%d\n"
999                        "dot1xSuppEapolStartFramesTx=%d\n"
1000                        "dot1xSuppEapolLogoffFramesTx=%d\n"
1001                        "dot1xSuppEapolRespFramesTx=%d\n"
1002                        "dot1xSuppEapolReqIdFramesRx=%d\n"
1003                        "dot1xSuppEapolReqFramesRx=%d\n"
1004                        "dot1xSuppInvalidEapolFramesRx=%d\n"
1005                        "dot1xSuppEapLengthErrorFramesRx=%d\n"
1006                        "dot1xSuppLastEapolFrameVersion=%d\n"
1007                        "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
1008                        sm->SUPP_PAE_state,
1009                        sm->heldPeriod,
1010                        sm->authPeriod,
1011                        sm->startPeriod,
1012                        sm->maxStart,
1013                        sm->suppPortStatus == Authorized ?
1014                        "Authorized" : "Unauthorized",
1015                        sm->SUPP_BE_state,
1016                        sm->dot1xSuppEapolFramesRx,
1017                        sm->dot1xSuppEapolFramesTx,
1018                        sm->dot1xSuppEapolStartFramesTx,
1019                        sm->dot1xSuppEapolLogoffFramesTx,
1020                        sm->dot1xSuppEapolRespFramesTx,
1021                        sm->dot1xSuppEapolReqIdFramesRx,
1022                        sm->dot1xSuppEapolReqFramesRx,
1023                        sm->dot1xSuppInvalidEapolFramesRx,
1024                        sm->dot1xSuppEapLengthErrorFramesRx,
1025                        sm->dot1xSuppLastEapolFrameVersion,
1026                        MAC2STR(sm->dot1xSuppLastEapolFrameSource));
1027         return len;
1028 }
1029
1030
1031 void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
1032 {
1033         struct ieee802_1x_hdr *hdr;
1034         struct ieee802_1x_eapol_key *key;
1035         int plen, data_len;
1036
1037         if (sm == NULL)
1038                 return;
1039         sm->dot1xSuppEapolFramesRx++;
1040         if (len < sizeof(*hdr)) {
1041                 sm->dot1xSuppInvalidEapolFramesRx++;
1042                 return;
1043         }
1044         hdr = (struct ieee802_1x_hdr *) buf;
1045         sm->dot1xSuppLastEapolFrameVersion = hdr->version;
1046         memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
1047         if (hdr->version < EAPOL_VERSION) {
1048                 /* TODO: backwards compatibility */
1049         }
1050         plen = be_to_host16(hdr->length);
1051         if (plen > len - sizeof(*hdr)) {
1052                 sm->dot1xSuppEapLengthErrorFramesRx++;
1053                 return;
1054         }
1055         data_len = plen + sizeof(*hdr);
1056
1057         switch (hdr->type) {
1058         case IEEE802_1X_TYPE_EAP_PACKET:
1059                 if (sm->cached_pmk) {
1060                         /* Trying to use PMKSA caching, but Authenticator did
1061                          * not seem to have a matching entry. Need to restart
1062                          * EAPOL state machines.
1063                          */
1064                         eapol_sm_abort_cached(sm);
1065                 }
1066                 free(sm->eapReqData);
1067                 sm->eapReqDataLen = plen;
1068                 sm->eapReqData = malloc(sm->eapReqDataLen);
1069                 if (sm->eapReqData) {
1070                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
1071                                    "frame");
1072                         memcpy(sm->eapReqData, (u8 *) (hdr + 1),
1073                                sm->eapReqDataLen);
1074                         sm->eapolEap = TRUE;
1075                         eapol_sm_step(sm);
1076                 }
1077                 break;
1078         case IEEE802_1X_TYPE_EAPOL_KEY:
1079                 if (plen < sizeof(*key)) {
1080                         wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
1081                                    "frame received");
1082                         break;
1083                 }
1084                 key = (struct ieee802_1x_eapol_key *) (hdr + 1);
1085                 if (key->type == EAPOL_KEY_TYPE_WPA ||
1086                     key->type == EAPOL_KEY_TYPE_RSN) {
1087                         /* WPA Supplicant takes care of this frame. */
1088                         wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
1089                                    "frame in EAPOL state machines");
1090                         break;
1091                 }
1092                 if (key->type != EAPOL_KEY_TYPE_RC4) {
1093                         wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
1094                                    "EAPOL-Key type %d", key->type);
1095                         break;
1096                 }
1097                 free(sm->last_rx_key);
1098                 sm->last_rx_key = malloc(data_len);
1099                 if (sm->last_rx_key) {
1100                         wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
1101                                    "frame");
1102                         memcpy(sm->last_rx_key, buf, data_len);
1103                         sm->last_rx_key_len = data_len;
1104                         sm->rxKey = TRUE;
1105                         eapol_sm_step(sm);
1106                 }
1107                 break;
1108         default:
1109                 wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
1110                            hdr->type);
1111                 sm->dot1xSuppInvalidEapolFramesRx++;
1112                 break;
1113         }
1114 }
1115
1116
1117 void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
1118 {
1119         if (sm)
1120                 sm->dot1xSuppEapolFramesTx++;
1121 }
1122
1123
1124 void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
1125 {
1126         if (sm == NULL)
1127                 return;
1128         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1129                    "portEnabled=%d", enabled);
1130         sm->portEnabled = enabled;
1131         eapol_sm_step(sm);
1132 }
1133
1134
1135 void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
1136 {
1137         if (sm == NULL)
1138                 return;
1139         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1140                    "portValid=%d", valid);
1141         sm->portValid = valid;
1142         eapol_sm_step(sm);
1143 }
1144
1145
1146 void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
1147 {
1148         if (sm == NULL)
1149                 return;
1150         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1151                    "EAP success=%d", success);
1152         sm->eapSuccess = success;
1153         sm->altAccept = success;
1154         if (success)
1155                 eap_notify_success(sm->eap);
1156         eapol_sm_step(sm);
1157 }
1158
1159
1160 void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
1161 {
1162         if (sm == NULL)
1163                 return;
1164         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1165                    "EAP fail=%d", fail);
1166         sm->eapFail = fail;
1167         sm->altReject = fail;
1168         eapol_sm_step(sm);
1169 }
1170
1171
1172 void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
1173                             struct eapol_config *conf)
1174 {
1175         if (sm == NULL)
1176                 return;
1177
1178         sm->config = config;
1179
1180         if (conf == NULL)
1181                 return;
1182
1183         sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
1184         sm->conf.required_keys = conf->required_keys;
1185         sm->conf.fast_reauth = conf->fast_reauth;
1186         if (sm->eap) {
1187                 eap_set_fast_reauth(sm->eap, conf->fast_reauth);
1188                 eap_set_workaround(sm->eap, conf->workaround);
1189         }
1190 }
1191
1192
1193 int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
1194 {
1195         u8 *eap_key;
1196         size_t eap_len;
1197
1198         if (sm == NULL || !eap_key_available(sm->eap))
1199                 return -1;
1200         eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
1201         if (eap_key == NULL)
1202                 return -1;
1203         if (len > eap_len)
1204                 return eap_len;
1205         memcpy(key, eap_key, len);
1206         return 0;
1207 }
1208
1209
1210 void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
1211 {
1212         if (sm) {
1213                 sm->userLogoff = logoff;
1214                 eapol_sm_step(sm);
1215         }
1216 }
1217
1218
1219 void eapol_sm_notify_cached(struct eapol_sm *sm)
1220 {
1221         if (sm == NULL)
1222                 return;
1223         sm->SUPP_PAE_state = SUPP_PAE_AUTHENTICATED;
1224         sm->suppPortStatus = Authorized;
1225         eap_notify_success(sm->eap);
1226 }
1227
1228
1229 void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
1230 {
1231         if (sm == NULL)
1232                 return;
1233         if (attempt) {
1234                 wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
1235                 sm->cached_pmk = TRUE;
1236         } else {
1237                 wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
1238                 sm->cached_pmk = FALSE;
1239         }
1240 }
1241
1242
1243 static void eapol_sm_abort_cached(struct eapol_sm *sm)
1244 {
1245         wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
1246                    "doing full EAP authentication");
1247         if (sm == NULL)
1248                 return;
1249         sm->cached_pmk = FALSE;
1250         sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
1251         sm->suppPortStatus = Unauthorized;
1252         sm->eapRestart= TRUE;
1253 }
1254
1255
1256 void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
1257 {
1258         if (sm) {
1259                 sm->ctx->scard_ctx = ctx;
1260                 eap_register_scard_ctx(sm->eap, ctx);
1261         }
1262 }
1263
1264
1265 void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
1266 {
1267         if (sm == NULL)
1268                 return;
1269         wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
1270                    "portControl=%s", eapol_port_control(portControl));
1271         sm->portControl = portControl;
1272         eapol_sm_step(sm);
1273 }
1274
1275
1276 void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
1277 {
1278         if (sm == NULL)
1279                 return;
1280         eap_sm_notify_ctrl_attached(sm->eap);
1281 }
1282
1283
1284 void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
1285 {
1286         if (sm == NULL)
1287                 return;
1288         if (sm->eapReqData && !sm->eapReq) {
1289                 wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
1290                            "input) notification - retrying pending EAP "
1291                            "Request");
1292                 sm->eapolEap = TRUE;
1293                 sm->eapReq = TRUE;
1294                 eapol_sm_step(sm);
1295         }
1296 }
1297
1298
1299 static struct wpa_ssid * eapol_sm_get_config(void *ctx)
1300 {
1301         struct eapol_sm *sm = ctx;
1302         return sm ? sm->config : NULL;
1303 }
1304
1305
1306 static u8 * eapol_sm_get_eapReqData(void *ctx, size_t *len)
1307 {
1308         struct eapol_sm *sm = ctx;
1309         if (sm == NULL || sm->eapReqData == NULL) {
1310                 *len = 0;
1311                 return NULL;
1312         }
1313
1314         *len = sm->eapReqDataLen;
1315         return sm->eapReqData;
1316 }
1317
1318
1319 static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
1320 {
1321         struct eapol_sm *sm = ctx;
1322         if (sm == NULL)
1323                 return FALSE;
1324         switch (variable) {
1325         case EAPOL_eapSuccess:
1326                 return sm->eapSuccess;
1327         case EAPOL_eapRestart:
1328                 return sm->eapRestart;
1329         case EAPOL_eapFail:
1330                 return sm->eapFail;
1331         case EAPOL_eapResp:
1332                 return sm->eapResp;
1333         case EAPOL_eapNoResp:
1334                 return sm->eapNoResp;
1335         case EAPOL_eapReq:
1336                 return sm->eapReq;
1337         case EAPOL_portEnabled:
1338                 return sm->portEnabled;
1339         case EAPOL_altAccept:
1340                 return sm->altAccept;
1341         case EAPOL_altReject:
1342                 return sm->altReject;
1343         }
1344         return FALSE;
1345 }
1346
1347
1348 static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
1349                               Boolean value)
1350 {
1351         struct eapol_sm *sm = ctx;
1352         if (sm == NULL)
1353                 return;
1354         switch (variable) {
1355         case EAPOL_eapSuccess:
1356                 sm->eapSuccess = value;
1357                 break;
1358         case EAPOL_eapRestart:
1359                 sm->eapRestart = value;
1360                 break;
1361         case EAPOL_eapFail:
1362                 sm->eapFail = value;
1363                 break;
1364         case EAPOL_eapResp:
1365                 sm->eapResp = value;
1366                 break;
1367         case EAPOL_eapNoResp:
1368                 sm->eapNoResp = value;
1369                 break;
1370         case EAPOL_eapReq:
1371                 sm->eapReq = value;
1372                 break;
1373         case EAPOL_portEnabled:
1374                 sm->portEnabled = value;
1375                 break;
1376         case EAPOL_altAccept:
1377                 sm->altAccept = value;
1378                 break;
1379         case EAPOL_altReject:
1380                 sm->altReject = value;
1381                 break;
1382         }
1383 }
1384
1385
1386 static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
1387 {
1388         struct eapol_sm *sm = ctx;
1389         if (sm == NULL)
1390                 return 0;
1391         switch (variable) {
1392         case EAPOL_idleWhile:
1393                 return sm->idleWhile;
1394         }
1395         return 0;
1396 }
1397
1398
1399 static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
1400                              unsigned int value)
1401 {
1402         struct eapol_sm *sm = ctx;
1403         if (sm == NULL)
1404                 return;
1405         switch (variable) {
1406         case EAPOL_idleWhile:
1407                 sm->idleWhile = value;
1408                 break;
1409         }
1410 }
1411
1412
1413 static struct eapol_callbacks eapol_cb =
1414 {
1415         .get_config = eapol_sm_get_config,
1416         .get_bool = eapol_sm_get_bool,
1417         .set_bool = eapol_sm_set_bool,
1418         .get_int = eapol_sm_get_int,
1419         .set_int = eapol_sm_set_int,
1420         .get_eapReqData = eapol_sm_get_eapReqData,
1421 };