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