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