~ubuntu-branches/ubuntu/gutsy/wpasupplicant/gutsy

« back to all changes in this revision

Viewing changes to wpa_supplicant/eapol_sm.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler, Alexander Sack
  • Date: 2007-08-26 16:06:57 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070826160657-2m8pxoweuxe8f93t
Tags: 0.6.0+0.5.8-0ubuntu1
* New upstream release
* remove patch 11_erroneous_manpage_ref, applied upstream
* remove patch 25_wpas_dbus_unregister_iface_fix, applied upstream

[ Alexander Sack ]
* bumping upstream version to replace development version 0.6.0 with
  this package from stable release branch.
* attempt to fix wierd timeout and high latency issues by going
  back to stable upstream version (0.5.9) (LP: #140763,
  LP: #141233).

Show diffs side-by-side

added added

removed removed

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