Coverage Report

Created: 2025-04-24 06:18

/src/hostap/src/eapol_auth/eapol_auth_sm.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * IEEE 802.1X-2004 Authenticator - EAPOL state machine
3
 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "includes.h"
10
11
#include "common.h"
12
#include "eloop.h"
13
#include "state_machine.h"
14
#include "common/eapol_common.h"
15
#include "eap_common/eap_defs.h"
16
#include "eap_common/eap_common.h"
17
#include "eap_server/eap.h"
18
#include "eapol_auth_sm.h"
19
#include "eapol_auth_sm_i.h"
20
21
#define STATE_MACHINE_DATA struct eapol_state_machine
22
0
#define STATE_MACHINE_DEBUG_PREFIX "IEEE 802.1X"
23
#define STATE_MACHINE_ADDR sm->addr
24
25
static const struct eapol_callbacks eapol_cb;
26
27
/* EAPOL state machines are described in IEEE Std 802.1X-2004, Chap. 8.2 */
28
29
0
#define setPortAuthorized() \
30
0
sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 1)
31
0
#define setPortUnauthorized() \
32
0
sm->eapol->cb.set_port_authorized(sm->eapol->conf.ctx, sm->sta, 0)
33
34
/* procedures */
35
0
#define txCannedFail() eapol_auth_tx_canned_eap(sm, 0)
36
0
#define txCannedSuccess() eapol_auth_tx_canned_eap(sm, 1)
37
0
#define txReq() eapol_auth_tx_req(sm)
38
0
#define abortAuth() sm->eapol->cb.abort_auth(sm->eapol->conf.ctx, sm->sta)
39
#define txKey() sm->eapol->cb.tx_key(sm->eapol->conf.ctx, sm->sta)
40
#define processKey() do { } while (0)
41
42
43
static void eapol_sm_step_run(struct eapol_state_machine *sm);
44
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
45
static void eapol_auth_initialize(struct eapol_state_machine *sm);
46
static void eapol_auth_conf_free(struct eapol_auth_config *conf);
47
48
49
static void eapol_auth_logger(struct eapol_authenticator *eapol,
50
            const u8 *addr, eapol_logger_level level,
51
            const char *txt)
52
0
{
53
0
  if (eapol->cb.logger == NULL)
54
0
    return;
55
0
  eapol->cb.logger(eapol->conf.ctx, addr, level, txt);
56
0
}
57
58
59
PRINTF_FORMAT(4, 5)
60
static void eapol_auth_vlogger(struct eapol_authenticator *eapol,
61
             const u8 *addr, eapol_logger_level level,
62
             const char *fmt, ...)
63
0
{
64
0
  char *format;
65
0
  int maxlen;
66
0
  va_list ap;
67
68
0
  if (eapol->cb.logger == NULL)
69
0
    return;
70
71
0
  maxlen = os_strlen(fmt) + 100;
72
0
  format = os_malloc(maxlen);
73
0
  if (!format)
74
0
    return;
75
76
0
  va_start(ap, fmt);
77
0
  vsnprintf(format, maxlen, fmt, ap);
78
0
  va_end(ap);
79
80
0
  eapol_auth_logger(eapol, addr, level, format);
81
82
0
  os_free(format);
83
0
}
84
85
86
static void eapol_auth_tx_canned_eap(struct eapol_state_machine *sm,
87
             int success)
88
0
{
89
0
  struct eap_hdr eap;
90
91
0
  os_memset(&eap, 0, sizeof(eap));
92
93
0
  eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
94
0
  eap.identifier = ++sm->last_eap_id;
95
0
  eap.length = host_to_be16(sizeof(eap));
96
97
0
  eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
98
0
         "Sending canned EAP packet %s (identifier %d)",
99
0
         success ? "SUCCESS" : "FAILURE", eap.identifier);
100
0
  sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
101
0
         IEEE802_1X_TYPE_EAP_PACKET,
102
0
         (u8 *) &eap, sizeof(eap));
103
0
  sm->dot1xAuthEapolFramesTx++;
104
0
}
105
106
107
static void eapol_auth_tx_req(struct eapol_state_machine *sm)
108
0
{
109
0
  if (sm->eap_if->eapReqData == NULL ||
110
0
      wpabuf_len(sm->eap_if->eapReqData) < sizeof(struct eap_hdr)) {
111
0
    eapol_auth_logger(sm->eapol, sm->addr,
112
0
          EAPOL_LOGGER_DEBUG,
113
0
          "TxReq called, but there is no EAP request "
114
0
          "from authentication server");
115
0
    return;
116
0
  }
117
118
0
  if (sm->flags & EAPOL_SM_WAIT_START) {
119
0
    wpa_printf(MSG_DEBUG, "EAPOL: Drop EAPOL TX to " MACSTR
120
0
         " while waiting for EAPOL-Start",
121
0
         MAC2STR(sm->addr));
122
0
    return;
123
0
  }
124
125
0
  sm->last_eap_id = eap_get_id(sm->eap_if->eapReqData);
126
0
  eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_DEBUG,
127
0
         "Sending EAP Packet (identifier %d)",
128
0
         sm->last_eap_id);
129
0
  sm->eapol->cb.eapol_send(sm->eapol->conf.ctx, sm->sta,
130
0
         IEEE802_1X_TYPE_EAP_PACKET,
131
0
         wpabuf_head(sm->eap_if->eapReqData),
132
0
         wpabuf_len(sm->eap_if->eapReqData));
133
0
  sm->dot1xAuthEapolFramesTx++;
134
0
  if (eap_get_type(sm->eap_if->eapReqData) == EAP_TYPE_IDENTITY)
135
0
    sm->dot1xAuthEapolReqIdFramesTx++;
136
0
  else
137
0
    sm->dot1xAuthEapolReqFramesTx++;
138
0
}
139
140
141
/**
142
 * eapol_port_timers_tick - Port Timers state machine
143
 * @eloop_ctx: struct eapol_state_machine *
144
 * @timeout_ctx: Not used
145
 *
146
 * This statemachine is implemented as a function that will be called
147
 * once a second as a registered event loop timeout.
148
 */
149
static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
150
0
{
151
0
  struct eapol_state_machine *state = timeout_ctx;
152
153
0
  if (state->aWhile > 0) {
154
0
    state->aWhile--;
155
0
    if (state->aWhile == 0) {
156
0
      wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
157
0
           " - aWhile --> 0",
158
0
           MAC2STR(state->addr));
159
0
    }
160
0
  }
161
162
0
  if (state->quietWhile > 0) {
163
0
    state->quietWhile--;
164
0
    if (state->quietWhile == 0) {
165
0
      wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
166
0
           " - quietWhile --> 0",
167
0
           MAC2STR(state->addr));
168
0
    }
169
0
  }
170
171
0
  if (state->reAuthWhen > 0) {
172
0
    state->reAuthWhen--;
173
0
    if (state->reAuthWhen == 0) {
174
0
      wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
175
0
           " - reAuthWhen --> 0",
176
0
           MAC2STR(state->addr));
177
0
    }
178
0
  }
179
180
0
  if (state->eap_if->retransWhile > 0) {
181
0
    state->eap_if->retransWhile--;
182
0
    if (state->eap_if->retransWhile == 0) {
183
0
      wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR
184
0
           " - (EAP) retransWhile --> 0",
185
0
           MAC2STR(state->addr));
186
0
    }
187
0
  }
188
189
0
  eapol_sm_step_run(state);
190
191
0
  eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
192
0
}
193
194
195
196
/* Authenticator PAE state machine */
197
198
SM_STATE(AUTH_PAE, INITIALIZE)
199
0
{
200
0
  SM_ENTRY_MA(AUTH_PAE, INITIALIZE, auth_pae);
201
0
  sm->portMode = Auto;
202
203
  /*
204
   * Clearing keyRun here is not specified in IEEE Std 802.1X-2004, but
205
   * it looks like this would be logical thing to do here since the
206
   * EAPOL-Key exchange is not possible in this state. It is possible to
207
   * get here on disconnection event without advancing to the
208
   * AUTHENTICATING state to clear keyRun before the IEEE 802.11 RSN
209
   * authenticator state machine runs and that may advance from
210
   * AUTHENTICATION2 to INITPMK if keyRun = true has been left from the
211
   * last association. This can be avoided by clearing keyRun here.
212
   */
213
0
  sm->keyRun = false;
214
0
}
215
216
217
SM_STATE(AUTH_PAE, DISCONNECTED)
218
0
{
219
0
  int from_initialize = sm->auth_pae_state == AUTH_PAE_INITIALIZE;
220
0
  bool pre_auth_logoff = sm->auth_pae_state == AUTH_PAE_ABORTING &&
221
0
    sm->eapolLogoff && !sm->authenticated;
222
0
  bool logoff = sm->eapolLogoff;
223
224
0
  if (sm->eapolLogoff) {
225
0
    if (sm->auth_pae_state == AUTH_PAE_CONNECTING)
226
0
      sm->authEapLogoffsWhileConnecting++;
227
0
    else if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED)
228
0
      sm->authAuthEapLogoffWhileAuthenticated++;
229
0
  }
230
231
0
  SM_ENTRY_MA(AUTH_PAE, DISCONNECTED, auth_pae);
232
233
0
  sm->authPortStatus = Unauthorized;
234
0
  setPortUnauthorized();
235
0
  sm->reAuthCount = 0;
236
0
  sm->eapolLogoff = false;
237
0
  if (!from_initialize && !pre_auth_logoff) {
238
0
    if (sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
239
0
             sm->flags & EAPOL_SM_PREAUTH,
240
0
             logoff)) {
241
0
      wpa_printf(MSG_DEBUG,
242
0
           "EAPOL: Do not restart since lower layers will disconnect the port after EAPOL-Logoff");
243
0
      sm->stopped = true;
244
0
    }
245
0
  }
246
0
}
247
248
249
SM_STATE(AUTH_PAE, RESTART)
250
0
{
251
0
  if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATED) {
252
0
    if (sm->reAuthenticate)
253
0
      sm->authAuthReauthsWhileAuthenticated++;
254
0
    if (sm->eapolStart)
255
0
      sm->authAuthEapStartsWhileAuthenticated++;
256
0
    if (sm->eapolLogoff)
257
0
      sm->authAuthEapLogoffWhileAuthenticated++;
258
0
  }
259
260
0
  SM_ENTRY_MA(AUTH_PAE, RESTART, auth_pae);
261
262
0
  sm->eap_if->eapRestart = true;
263
0
}
264
265
266
SM_STATE(AUTH_PAE, CONNECTING)
267
0
{
268
0
  if (sm->auth_pae_state != AUTH_PAE_CONNECTING)
269
0
    sm->authEntersConnecting++;
270
271
0
  SM_ENTRY_MA(AUTH_PAE, CONNECTING, auth_pae);
272
273
0
  sm->reAuthenticate = false;
274
0
  sm->reAuthCount++;
275
0
}
276
277
278
SM_STATE(AUTH_PAE, HELD)
279
0
{
280
0
  if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authFail)
281
0
    sm->authAuthFailWhileAuthenticating++;
282
283
0
  SM_ENTRY_MA(AUTH_PAE, HELD, auth_pae);
284
285
0
  sm->authPortStatus = Unauthorized;
286
0
  setPortUnauthorized();
287
0
  sm->quietWhile = sm->quietPeriod;
288
0
  sm->eapolLogoff = false;
289
290
0
  eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_WARNING,
291
0
         "authentication failed - EAP type: %d (%s)",
292
0
         sm->eap_type_authsrv,
293
0
         eap_server_get_name(0, sm->eap_type_authsrv));
294
0
  if (sm->eap_type_authsrv != sm->eap_type_supp) {
295
0
    eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
296
0
           "Supplicant used different EAP type: "
297
0
           "%d (%s)", sm->eap_type_supp,
298
0
           eap_server_get_name(0, sm->eap_type_supp));
299
0
  }
300
0
  sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 0,
301
0
             sm->flags & EAPOL_SM_PREAUTH, false);
302
0
}
303
304
305
SM_STATE(AUTH_PAE, AUTHENTICATED)
306
0
{
307
0
  char *extra = "";
308
309
0
  if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
310
0
    sm->authAuthSuccessesWhileAuthenticating++;
311
312
0
  SM_ENTRY_MA(AUTH_PAE, AUTHENTICATED, auth_pae);
313
314
0
  sm->authPortStatus = Authorized;
315
0
  setPortAuthorized();
316
0
  sm->reAuthCount = 0;
317
0
  if (sm->flags & EAPOL_SM_PREAUTH)
318
0
    extra = " (pre-authentication)";
319
0
  else if (sm->flags & EAPOL_SM_FROM_PMKSA_CACHE)
320
0
    extra = " (PMKSA cache)";
321
0
  eapol_auth_vlogger(sm->eapol, sm->addr, EAPOL_LOGGER_INFO,
322
0
         "authenticated - EAP type: %d (%s)%s",
323
0
         sm->eap_type_authsrv,
324
0
         eap_server_get_name(0, sm->eap_type_authsrv),
325
0
         extra);
326
0
  if (sm->authSuccess)
327
0
    sm->authenticated++;
328
0
  sm->eapol->cb.finished(sm->eapol->conf.ctx, sm->sta, 1,
329
0
             sm->flags & EAPOL_SM_PREAUTH, false);
330
0
}
331
332
333
SM_STATE(AUTH_PAE, AUTHENTICATING)
334
0
{
335
0
  SM_ENTRY_MA(AUTH_PAE, AUTHENTICATING, auth_pae);
336
337
0
  sm->eapolStart = false;
338
0
  sm->authSuccess = false;
339
0
  sm->authFail = false;
340
0
  sm->authTimeout = false;
341
0
  sm->authStart = true;
342
0
  sm->keyRun = false;
343
0
  sm->keyDone = false;
344
0
}
345
346
347
SM_STATE(AUTH_PAE, ABORTING)
348
0
{
349
0
  if (sm->auth_pae_state == AUTH_PAE_AUTHENTICATING) {
350
0
    if (sm->authTimeout)
351
0
      sm->authAuthTimeoutsWhileAuthenticating++;
352
0
    if (sm->eapolStart)
353
0
      sm->authAuthEapStartsWhileAuthenticating++;
354
0
    if (sm->eapolLogoff)
355
0
      sm->authAuthEapLogoffWhileAuthenticating++;
356
0
  }
357
358
0
  SM_ENTRY_MA(AUTH_PAE, ABORTING, auth_pae);
359
360
0
  sm->authAbort = true;
361
0
  sm->keyRun = false;
362
0
  sm->keyDone = false;
363
0
}
364
365
366
SM_STATE(AUTH_PAE, FORCE_AUTH)
367
0
{
368
0
  SM_ENTRY_MA(AUTH_PAE, FORCE_AUTH, auth_pae);
369
370
0
  sm->authPortStatus = Authorized;
371
0
  setPortAuthorized();
372
0
  sm->portMode = ForceAuthorized;
373
0
  sm->eapolStart = false;
374
0
  txCannedSuccess();
375
0
}
376
377
378
SM_STATE(AUTH_PAE, FORCE_UNAUTH)
379
0
{
380
0
  SM_ENTRY_MA(AUTH_PAE, FORCE_UNAUTH, auth_pae);
381
382
0
  sm->authPortStatus = Unauthorized;
383
0
  setPortUnauthorized();
384
0
  sm->portMode = ForceUnauthorized;
385
0
  sm->eapolStart = false;
386
0
  txCannedFail();
387
0
}
388
389
390
SM_STEP(AUTH_PAE)
391
0
{
392
0
  if ((sm->portControl == Auto && sm->portMode != sm->portControl) ||
393
0
      sm->initialize || !sm->eap_if->portEnabled)
394
0
    SM_ENTER_GLOBAL(AUTH_PAE, INITIALIZE);
395
0
  else if (sm->portControl == ForceAuthorized &&
396
0
     sm->portMode != sm->portControl &&
397
0
     !(sm->initialize || !sm->eap_if->portEnabled))
398
0
    SM_ENTER_GLOBAL(AUTH_PAE, FORCE_AUTH);
399
0
  else if (sm->portControl == ForceUnauthorized &&
400
0
     sm->portMode != sm->portControl &&
401
0
     !(sm->initialize || !sm->eap_if->portEnabled))
402
0
    SM_ENTER_GLOBAL(AUTH_PAE, FORCE_UNAUTH);
403
0
  else {
404
0
    switch (sm->auth_pae_state) {
405
0
    case AUTH_PAE_INITIALIZE:
406
0
      SM_ENTER(AUTH_PAE, DISCONNECTED);
407
0
      break;
408
0
    case AUTH_PAE_DISCONNECTED:
409
0
      if (!sm->stopped)
410
0
        SM_ENTER(AUTH_PAE, RESTART);
411
0
      break;
412
0
    case AUTH_PAE_RESTART:
413
0
      if (!sm->eap_if->eapRestart)
414
0
        SM_ENTER(AUTH_PAE, CONNECTING);
415
0
      break;
416
0
    case AUTH_PAE_HELD:
417
0
      if (sm->quietWhile == 0)
418
0
        SM_ENTER(AUTH_PAE, RESTART);
419
0
      break;
420
0
    case AUTH_PAE_CONNECTING:
421
0
      if (sm->eapolLogoff || sm->reAuthCount > sm->reAuthMax)
422
0
        SM_ENTER(AUTH_PAE, DISCONNECTED);
423
0
      else if ((sm->eap_if->eapReq &&
424
0
          sm->reAuthCount <= sm->reAuthMax) ||
425
0
         sm->eap_if->eapSuccess || sm->eap_if->eapFail)
426
0
        SM_ENTER(AUTH_PAE, AUTHENTICATING);
427
0
      break;
428
0
    case AUTH_PAE_AUTHENTICATED:
429
0
      if (sm->eapolStart || sm->reAuthenticate)
430
0
        SM_ENTER(AUTH_PAE, RESTART);
431
0
      else if (sm->eapolLogoff || !sm->portValid)
432
0
        SM_ENTER(AUTH_PAE, DISCONNECTED);
433
0
      break;
434
0
    case AUTH_PAE_AUTHENTICATING:
435
0
      if (sm->authSuccess && sm->portValid)
436
0
        SM_ENTER(AUTH_PAE, AUTHENTICATED);
437
0
      else if (sm->authFail ||
438
0
         (sm->keyDone && !sm->portValid))
439
0
        SM_ENTER(AUTH_PAE, HELD);
440
0
      else if (sm->eapolStart || sm->eapolLogoff ||
441
0
         sm->authTimeout)
442
0
        SM_ENTER(AUTH_PAE, ABORTING);
443
0
      break;
444
0
    case AUTH_PAE_ABORTING:
445
0
      if (sm->eapolLogoff && !sm->authAbort)
446
0
        SM_ENTER(AUTH_PAE, DISCONNECTED);
447
0
      else if (!sm->eapolLogoff && !sm->authAbort)
448
0
        SM_ENTER(AUTH_PAE, RESTART);
449
0
      break;
450
0
    case AUTH_PAE_FORCE_AUTH:
451
0
      if (sm->eapolStart)
452
0
        SM_ENTER(AUTH_PAE, FORCE_AUTH);
453
0
      break;
454
0
    case AUTH_PAE_FORCE_UNAUTH:
455
0
      if (sm->eapolStart)
456
0
        SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
457
0
      break;
458
0
    }
459
0
  }
460
0
}
461
462
463
464
/* Backend Authentication state machine */
465
466
SM_STATE(BE_AUTH, INITIALIZE)
467
0
{
468
0
  SM_ENTRY_MA(BE_AUTH, INITIALIZE, be_auth);
469
470
0
  abortAuth();
471
0
  sm->eap_if->eapNoReq = false;
472
0
  sm->authAbort = false;
473
0
}
474
475
476
SM_STATE(BE_AUTH, REQUEST)
477
0
{
478
0
  SM_ENTRY_MA(BE_AUTH, REQUEST, be_auth);
479
480
0
  txReq();
481
0
  sm->eap_if->eapReq = false;
482
0
  sm->backendOtherRequestsToSupplicant++;
483
484
  /*
485
   * Clearing eapolEap here is not specified in IEEE Std 802.1X-2004, but
486
   * it looks like this would be logical thing to do there since the old
487
   * EAP response would not be valid anymore after the new EAP request
488
   * was sent out.
489
   *
490
   * A race condition has been reported, in which hostapd ended up
491
   * sending out EAP-Response/Identity as a response to the first
492
   * EAP-Request from the main EAP method. This can be avoided by
493
   * clearing eapolEap here.
494
   */
495
0
  sm->eapolEap = false;
496
0
}
497
498
499
SM_STATE(BE_AUTH, RESPONSE)
500
0
{
501
0
  SM_ENTRY_MA(BE_AUTH, RESPONSE, be_auth);
502
503
0
  sm->authTimeout = false;
504
0
  sm->eapolEap = false;
505
0
  sm->eap_if->eapNoReq = false;
506
0
  sm->aWhile = sm->serverTimeout;
507
0
  sm->eap_if->eapResp = true;
508
  /* sendRespToServer(); */
509
0
  sm->backendResponses++;
510
0
}
511
512
513
SM_STATE(BE_AUTH, SUCCESS)
514
0
{
515
0
  SM_ENTRY_MA(BE_AUTH, SUCCESS, be_auth);
516
517
0
  txReq();
518
0
  sm->authSuccess = true;
519
0
  sm->keyRun = true;
520
0
}
521
522
523
SM_STATE(BE_AUTH, FAIL)
524
0
{
525
0
  SM_ENTRY_MA(BE_AUTH, FAIL, be_auth);
526
527
0
  txReq();
528
0
  sm->authFail = true;
529
0
}
530
531
532
SM_STATE(BE_AUTH, TIMEOUT)
533
0
{
534
0
  SM_ENTRY_MA(BE_AUTH, TIMEOUT, be_auth);
535
536
0
  sm->authTimeout = true;
537
0
}
538
539
540
SM_STATE(BE_AUTH, IDLE)
541
0
{
542
0
  SM_ENTRY_MA(BE_AUTH, IDLE, be_auth);
543
544
0
  sm->authStart = false;
545
0
}
546
547
548
SM_STATE(BE_AUTH, IGNORE)
549
0
{
550
0
  SM_ENTRY_MA(BE_AUTH, IGNORE, be_auth);
551
552
0
  sm->eap_if->eapNoReq = false;
553
0
}
554
555
556
SM_STEP(BE_AUTH)
557
0
{
558
0
  if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
559
0
    SM_ENTER_GLOBAL(BE_AUTH, INITIALIZE);
560
0
    return;
561
0
  }
562
563
0
  switch (sm->be_auth_state) {
564
0
  case BE_AUTH_INITIALIZE:
565
0
    SM_ENTER(BE_AUTH, IDLE);
566
0
    break;
567
0
  case BE_AUTH_REQUEST:
568
0
    if (sm->eapolEap)
569
0
      SM_ENTER(BE_AUTH, RESPONSE);
570
0
    else if (sm->eap_if->eapReq)
571
0
      SM_ENTER(BE_AUTH, REQUEST);
572
0
    else if (sm->eap_if->eapTimeout)
573
0
      SM_ENTER(BE_AUTH, TIMEOUT);
574
0
    break;
575
0
  case BE_AUTH_RESPONSE:
576
0
    if (sm->eap_if->eapNoReq)
577
0
      SM_ENTER(BE_AUTH, IGNORE);
578
0
    if (sm->eap_if->eapReq) {
579
0
      sm->backendAccessChallenges++;
580
0
      SM_ENTER(BE_AUTH, REQUEST);
581
0
    } else if (sm->aWhile == 0)
582
0
      SM_ENTER(BE_AUTH, TIMEOUT);
583
0
    else if (sm->eap_if->eapFail) {
584
0
      sm->backendAuthFails++;
585
0
      SM_ENTER(BE_AUTH, FAIL);
586
0
    } else if (sm->eap_if->eapSuccess) {
587
0
      sm->backendAuthSuccesses++;
588
0
      SM_ENTER(BE_AUTH, SUCCESS);
589
0
    }
590
0
    break;
591
0
  case BE_AUTH_SUCCESS:
592
0
    SM_ENTER(BE_AUTH, IDLE);
593
0
    break;
594
0
  case BE_AUTH_FAIL:
595
0
    SM_ENTER(BE_AUTH, IDLE);
596
0
    break;
597
0
  case BE_AUTH_TIMEOUT:
598
0
    SM_ENTER(BE_AUTH, IDLE);
599
0
    break;
600
0
  case BE_AUTH_IDLE:
601
0
    if (sm->eap_if->eapFail && sm->authStart)
602
0
      SM_ENTER(BE_AUTH, FAIL);
603
0
    else if (sm->eap_if->eapReq && sm->authStart)
604
0
      SM_ENTER(BE_AUTH, REQUEST);
605
0
    else if (sm->eap_if->eapSuccess && sm->authStart)
606
0
      SM_ENTER(BE_AUTH, SUCCESS);
607
0
    break;
608
0
  case BE_AUTH_IGNORE:
609
0
    if (sm->eapolEap)
610
0
      SM_ENTER(BE_AUTH, RESPONSE);
611
0
    else if (sm->eap_if->eapReq)
612
0
      SM_ENTER(BE_AUTH, REQUEST);
613
0
    else if (sm->eap_if->eapTimeout)
614
0
      SM_ENTER(BE_AUTH, TIMEOUT);
615
0
    break;
616
0
  }
617
0
}
618
619
620
621
/* Reauthentication Timer state machine */
622
623
SM_STATE(REAUTH_TIMER, INITIALIZE)
624
0
{
625
0
  SM_ENTRY_MA(REAUTH_TIMER, INITIALIZE, reauth_timer);
626
627
0
  sm->reAuthWhen = sm->reAuthPeriod;
628
0
}
629
630
631
SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
632
0
{
633
0
  SM_ENTRY_MA(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
634
635
0
  sm->reAuthenticate = true;
636
0
  sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
637
0
          EAPOL_AUTH_REAUTHENTICATE);
638
0
}
639
640
641
SM_STEP(REAUTH_TIMER)
642
0
{
643
0
  if (sm->portControl != Auto || sm->initialize ||
644
0
      sm->authPortStatus == Unauthorized || !sm->reAuthEnabled) {
645
0
    SM_ENTER_GLOBAL(REAUTH_TIMER, INITIALIZE);
646
0
    return;
647
0
  }
648
649
0
  switch (sm->reauth_timer_state) {
650
0
  case REAUTH_TIMER_INITIALIZE:
651
0
    if (sm->reAuthWhen == 0)
652
0
      SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
653
0
    break;
654
0
  case REAUTH_TIMER_REAUTHENTICATE:
655
0
    SM_ENTER(REAUTH_TIMER, INITIALIZE);
656
0
    break;
657
0
  }
658
0
}
659
660
661
662
#ifdef CONFIG_WEP
663
664
/* Authenticator Key Transmit state machine */
665
666
SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
667
{
668
  SM_ENTRY_MA(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
669
}
670
671
672
SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
673
{
674
  SM_ENTRY_MA(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
675
676
  txKey();
677
  sm->eap_if->eapKeyAvailable = false;
678
  sm->keyDone = true;
679
}
680
681
682
SM_STEP(AUTH_KEY_TX)
683
{
684
  if (sm->initialize || sm->portControl != Auto) {
685
    SM_ENTER_GLOBAL(AUTH_KEY_TX, NO_KEY_TRANSMIT);
686
    return;
687
  }
688
689
  switch (sm->auth_key_tx_state) {
690
  case AUTH_KEY_TX_NO_KEY_TRANSMIT:
691
    if (sm->keyTxEnabled && sm->eap_if->eapKeyAvailable &&
692
        sm->keyRun && !(sm->flags & EAPOL_SM_USES_WPA))
693
      SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
694
    break;
695
  case AUTH_KEY_TX_KEY_TRANSMIT:
696
    if (!sm->keyTxEnabled || !sm->keyRun)
697
      SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
698
    else if (sm->eap_if->eapKeyAvailable)
699
      SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
700
    break;
701
  }
702
}
703
704
705
706
/* Key Receive state machine */
707
708
SM_STATE(KEY_RX, NO_KEY_RECEIVE)
709
{
710
  SM_ENTRY_MA(KEY_RX, NO_KEY_RECEIVE, key_rx);
711
}
712
713
714
SM_STATE(KEY_RX, KEY_RECEIVE)
715
{
716
  SM_ENTRY_MA(KEY_RX, KEY_RECEIVE, key_rx);
717
718
  processKey();
719
  sm->rxKey = false;
720
}
721
722
723
SM_STEP(KEY_RX)
724
{
725
  if (sm->initialize || !sm->eap_if->portEnabled) {
726
    SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
727
    return;
728
  }
729
730
  switch (sm->key_rx_state) {
731
  case KEY_RX_NO_KEY_RECEIVE:
732
    if (sm->rxKey)
733
      SM_ENTER(KEY_RX, KEY_RECEIVE);
734
    break;
735
  case KEY_RX_KEY_RECEIVE:
736
    if (sm->rxKey)
737
      SM_ENTER(KEY_RX, KEY_RECEIVE);
738
    break;
739
  }
740
}
741
742
#endif /* CONFIG_WEP */
743
744
745
746
/* Controlled Directions state machine */
747
748
SM_STATE(CTRL_DIR, FORCE_BOTH)
749
0
{
750
0
  SM_ENTRY_MA(CTRL_DIR, FORCE_BOTH, ctrl_dir);
751
0
  sm->operControlledDirections = Both;
752
0
}
753
754
755
SM_STATE(CTRL_DIR, IN_OR_BOTH)
756
0
{
757
0
  SM_ENTRY_MA(CTRL_DIR, IN_OR_BOTH, ctrl_dir);
758
0
  sm->operControlledDirections = sm->adminControlledDirections;
759
0
}
760
761
762
SM_STEP(CTRL_DIR)
763
0
{
764
0
  if (sm->initialize) {
765
0
    SM_ENTER_GLOBAL(CTRL_DIR, IN_OR_BOTH);
766
0
    return;
767
0
  }
768
769
0
  switch (sm->ctrl_dir_state) {
770
0
  case CTRL_DIR_FORCE_BOTH:
771
0
    if (sm->eap_if->portEnabled && sm->operEdge)
772
0
      SM_ENTER(CTRL_DIR, IN_OR_BOTH);
773
0
    break;
774
0
  case CTRL_DIR_IN_OR_BOTH:
775
0
    if (sm->operControlledDirections !=
776
0
        sm->adminControlledDirections)
777
0
      SM_ENTER(CTRL_DIR, IN_OR_BOTH);
778
0
    if (!sm->eap_if->portEnabled || !sm->operEdge)
779
0
      SM_ENTER(CTRL_DIR, FORCE_BOTH);
780
0
    break;
781
0
  }
782
0
}
783
784
785
786
struct eapol_state_machine *
787
eapol_auth_alloc(struct eapol_authenticator *eapol, const u8 *addr,
788
     int flags, const struct wpabuf *assoc_wps_ie,
789
     const struct wpabuf *assoc_p2p_ie, void *sta_ctx,
790
     const char *identity, const char *radius_cui)
791
0
{
792
0
  struct eapol_state_machine *sm;
793
0
  struct eap_session_data eap_sess;
794
795
0
  if (eapol == NULL)
796
0
    return NULL;
797
798
0
  sm = os_zalloc(sizeof(*sm));
799
0
  if (sm == NULL) {
800
0
    wpa_printf(MSG_DEBUG, "IEEE 802.1X state machine allocation "
801
0
         "failed");
802
0
    return NULL;
803
0
  }
804
0
  sm->radius_identifier = -1;
805
0
  os_memcpy(sm->addr, addr, ETH_ALEN);
806
0
  sm->flags = flags;
807
808
0
  sm->eapol = eapol;
809
0
  sm->sta = sta_ctx;
810
811
  /* Set default values for state machine constants */
812
0
  sm->auth_pae_state = AUTH_PAE_INITIALIZE;
813
0
  sm->quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
814
0
  sm->reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
815
816
0
  sm->be_auth_state = BE_AUTH_INITIALIZE;
817
0
  sm->serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
818
819
0
  sm->reauth_timer_state = REAUTH_TIMER_INITIALIZE;
820
0
  sm->reAuthPeriod = eapol->conf.eap_reauth_period;
821
0
  sm->reAuthEnabled = eapol->conf.eap_reauth_period > 0;
822
823
0
  sm->auth_key_tx_state = AUTH_KEY_TX_NO_KEY_TRANSMIT;
824
825
0
  sm->key_rx_state = KEY_RX_NO_KEY_RECEIVE;
826
827
0
  sm->ctrl_dir_state = CTRL_DIR_IN_OR_BOTH;
828
829
0
  sm->portControl = Auto;
830
831
#ifdef CONFIG_WEP
832
  if (!eapol->conf.wpa &&
833
      (eapol->default_wep_key || eapol->conf.individual_wep_key_len > 0))
834
    sm->keyTxEnabled = true;
835
  else
836
#endif /* CONFIG_WEP */
837
0
    sm->keyTxEnabled = false;
838
0
  if (eapol->conf.wpa)
839
0
    sm->portValid = false;
840
0
  else
841
0
    sm->portValid = true;
842
843
0
  os_memset(&eap_sess, 0, sizeof(eap_sess));
844
0
  eap_sess.assoc_wps_ie = assoc_wps_ie;
845
0
  eap_sess.assoc_p2p_ie = assoc_p2p_ie;
846
0
  eap_sess.peer_addr = addr;
847
0
  sm->eap = eap_server_sm_init(sm, &eapol_cb, eapol->conf.eap_cfg,
848
0
             &eap_sess);
849
0
  if (sm->eap == NULL) {
850
0
    eapol_auth_free(sm);
851
0
    return NULL;
852
0
  }
853
0
  sm->eap_if = eap_get_interface(sm->eap);
854
855
0
  eapol_auth_initialize(sm);
856
857
0
  if (identity) {
858
0
    sm->identity = (u8 *) os_strdup(identity);
859
0
    if (sm->identity)
860
0
      sm->identity_len = os_strlen(identity);
861
0
  }
862
0
  if (radius_cui)
863
0
    sm->radius_cui = wpabuf_alloc_copy(radius_cui,
864
0
               os_strlen(radius_cui));
865
866
0
#ifndef CONFIG_NO_RADIUS
867
0
  if (radius_gen_session_id((u8 *) &sm->acct_multi_session_id,
868
0
          sizeof(sm->acct_multi_session_id)) < 0) {
869
0
    eapol_auth_free(sm);
870
0
    return NULL;
871
0
  }
872
0
#endif /* CONFIG_NO_RADIUS */
873
874
0
  return sm;
875
0
}
876
877
878
void eapol_auth_free(struct eapol_state_machine *sm)
879
0
{
880
0
  if (sm == NULL)
881
0
    return;
882
883
0
  eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
884
0
  eloop_cancel_timeout(eapol_sm_step_cb, sm, NULL);
885
0
  if (sm->eap)
886
0
    eap_server_sm_deinit(sm->eap);
887
888
0
  wpabuf_free(sm->radius_cui);
889
0
  os_free(sm->identity);
890
0
  os_free(sm);
891
0
}
892
893
894
static int eapol_sm_sta_entry_alive(struct eapol_authenticator *eapol,
895
            const u8 *addr)
896
0
{
897
0
  return eapol->cb.sta_entry_alive(eapol->conf.ctx, addr);
898
0
}
899
900
901
static void eapol_sm_step_run(struct eapol_state_machine *sm)
902
0
{
903
0
  struct eapol_authenticator *eapol = sm->eapol;
904
0
  u8 addr[ETH_ALEN];
905
0
  unsigned int prev_auth_pae, prev_be_auth, prev_reauth_timer,
906
0
    prev_auth_key_tx, prev_key_rx, prev_ctrl_dir;
907
0
  int max_steps = 100;
908
909
0
  os_memcpy(addr, sm->addr, ETH_ALEN);
910
911
  /*
912
   * Allow EAPOL state machines to run as long as there are state
913
   * changes, but exit and return here through event loop if more than
914
   * 100 steps is needed as a precaution against infinite loops inside
915
   * eloop callback.
916
   */
917
0
restart:
918
0
  prev_auth_pae = sm->auth_pae_state;
919
0
  prev_be_auth = sm->be_auth_state;
920
0
  prev_reauth_timer = sm->reauth_timer_state;
921
0
  prev_auth_key_tx = sm->auth_key_tx_state;
922
0
  prev_key_rx = sm->key_rx_state;
923
0
  prev_ctrl_dir = sm->ctrl_dir_state;
924
925
0
  SM_STEP_RUN(AUTH_PAE);
926
0
  if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
927
0
    SM_STEP_RUN(BE_AUTH);
928
0
  if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
929
0
    SM_STEP_RUN(REAUTH_TIMER);
930
#ifdef CONFIG_WEP
931
  if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
932
    SM_STEP_RUN(AUTH_KEY_TX);
933
  if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
934
    SM_STEP_RUN(KEY_RX);
935
#endif /* CONFIG_WEP */
936
0
  if (sm->initializing || eapol_sm_sta_entry_alive(eapol, addr))
937
0
    SM_STEP_RUN(CTRL_DIR);
938
939
0
  if (prev_auth_pae != sm->auth_pae_state ||
940
0
      prev_be_auth != sm->be_auth_state ||
941
0
      prev_reauth_timer != sm->reauth_timer_state ||
942
0
      prev_auth_key_tx != sm->auth_key_tx_state ||
943
0
      prev_key_rx != sm->key_rx_state ||
944
0
      prev_ctrl_dir != sm->ctrl_dir_state) {
945
0
    if (--max_steps > 0)
946
0
      goto restart;
947
    /* Re-run from eloop timeout */
948
0
    eapol_auth_step(sm);
949
0
    return;
950
0
  }
951
952
0
  if (eapol_sm_sta_entry_alive(eapol, addr) && sm->eap) {
953
0
    if (eap_server_sm_step(sm->eap)) {
954
0
      if (--max_steps > 0)
955
0
        goto restart;
956
      /* Re-run from eloop timeout */
957
0
      eapol_auth_step(sm);
958
0
      return;
959
0
    }
960
961
    /* TODO: find a better location for this */
962
0
    if (sm->eap_if->aaaEapResp) {
963
0
      sm->eap_if->aaaEapResp = false;
964
0
      if (sm->eap_if->aaaEapRespData == NULL) {
965
0
        wpa_printf(MSG_DEBUG, "EAPOL: aaaEapResp set, "
966
0
             "but no aaaEapRespData available");
967
0
        return;
968
0
      }
969
0
      sm->eapol->cb.aaa_send(
970
0
        sm->eapol->conf.ctx, sm->sta,
971
0
        wpabuf_head(sm->eap_if->aaaEapRespData),
972
0
        wpabuf_len(sm->eap_if->aaaEapRespData));
973
0
    }
974
0
  }
975
976
0
  if (eapol_sm_sta_entry_alive(eapol, addr))
977
0
    sm->eapol->cb.eapol_event(sm->eapol->conf.ctx, sm->sta,
978
0
            EAPOL_AUTH_SM_CHANGE);
979
0
}
980
981
982
static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx)
983
0
{
984
0
  struct eapol_state_machine *sm = eloop_ctx;
985
0
  eapol_sm_step_run(sm);
986
0
}
987
988
989
/**
990
 * eapol_auth_step - Advance EAPOL state machines
991
 * @sm: EAPOL state machine
992
 *
993
 * This function is called to advance EAPOL state machines after any change
994
 * that could affect their state.
995
 */
996
void eapol_auth_step(struct eapol_state_machine *sm)
997
0
{
998
  /*
999
   * Run eapol_sm_step_run from a registered timeout to make sure that
1000
   * other possible timeouts/events are processed and to avoid long
1001
   * function call chains.
1002
   */
1003
1004
0
  eloop_register_timeout(0, 0, eapol_sm_step_cb, sm, NULL);
1005
0
}
1006
1007
1008
static void eapol_auth_initialize(struct eapol_state_machine *sm)
1009
0
{
1010
0
  sm->initializing = true;
1011
  /* Initialize the state machines by asserting initialize and then
1012
   * deasserting it after one step */
1013
0
  sm->initialize = true;
1014
0
  eapol_sm_step_run(sm);
1015
0
  sm->initialize = false;
1016
0
  eapol_sm_step_run(sm);
1017
0
  sm->initializing = false;
1018
1019
  /* Start one second tick for port timers state machine */
1020
0
  eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
1021
0
  eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
1022
0
}
1023
1024
1025
static int eapol_sm_get_eap_user(void *ctx, const u8 *identity,
1026
         size_t identity_len, int phase2,
1027
         struct eap_user *user)
1028
0
{
1029
0
  struct eapol_state_machine *sm = ctx;
1030
1031
0
  return sm->eapol->cb.get_eap_user(sm->eapol->conf.ctx, identity,
1032
0
            identity_len, phase2, user);
1033
0
}
1034
1035
1036
static const char * eapol_sm_get_eap_req_id_text(void *ctx, size_t *len)
1037
0
{
1038
0
  struct eapol_state_machine *sm = ctx;
1039
0
  *len = sm->eapol->conf.eap_req_id_text_len;
1040
0
  return sm->eapol->conf.eap_req_id_text;
1041
0
}
1042
1043
1044
static int eapol_sm_get_erp_send_reauth_start(void *ctx)
1045
0
{
1046
0
  struct eapol_state_machine *sm = ctx;
1047
0
  return sm->eapol->conf.erp_send_reauth_start;
1048
0
}
1049
1050
1051
static const char * eapol_sm_get_erp_domain(void *ctx)
1052
0
{
1053
0
  struct eapol_state_machine *sm = ctx;
1054
0
  return sm->eapol->conf.erp_domain;
1055
0
}
1056
1057
1058
static struct eap_server_erp_key * eapol_sm_erp_get_key(void *ctx,
1059
              const char *keyname)
1060
0
{
1061
0
  struct eapol_state_machine *sm = ctx;
1062
0
  return sm->eapol->cb.erp_get_key(sm->eapol->conf.ctx, keyname);
1063
0
}
1064
1065
1066
static int eapol_sm_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
1067
0
{
1068
0
  struct eapol_state_machine *sm = ctx;
1069
0
  return sm->eapol->cb.erp_add_key(sm->eapol->conf.ctx, erp);
1070
0
}
1071
1072
1073
static const struct eapol_callbacks eapol_cb =
1074
{
1075
  eapol_sm_get_eap_user,
1076
  eapol_sm_get_eap_req_id_text,
1077
  NULL,
1078
  eapol_sm_get_erp_send_reauth_start,
1079
  eapol_sm_get_erp_domain,
1080
  eapol_sm_erp_get_key,
1081
  eapol_sm_erp_add_key,
1082
};
1083
1084
1085
int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
1086
0
{
1087
0
  if (sm == NULL || ctx == NULL || ctx != sm->eap)
1088
0
    return -1;
1089
1090
0
  eap_sm_pending_cb(sm->eap);
1091
0
  eapol_auth_step(sm);
1092
1093
0
  return 0;
1094
0
}
1095
1096
1097
void eapol_auth_reauthenticate(struct eapol_state_machine *sm)
1098
0
{
1099
0
  wpa_printf(MSG_DEBUG, "EAPOL: External reauthentication trigger for "
1100
0
       MACSTR, MAC2STR(sm->addr));
1101
0
  sm->reAuthenticate = true;
1102
0
  eapol_auth_step(sm);
1103
0
}
1104
1105
1106
int eapol_auth_set_conf(struct eapol_state_machine *sm, const char *param,
1107
      const char *value)
1108
0
{
1109
0
  wpa_printf(MSG_DEBUG, "EAPOL: External configuration operation for "
1110
0
       MACSTR " - param=%s value=%s",
1111
0
       MAC2STR(sm->addr), param, value);
1112
1113
0
  if (os_strcasecmp(param, "AdminControlledDirections") == 0) {
1114
0
    if (os_strcmp(value, "Both") == 0)
1115
0
      sm->adminControlledDirections = Both;
1116
0
    else if (os_strcmp(value, "In") == 0)
1117
0
      sm->adminControlledDirections = In;
1118
0
    else
1119
0
      return -1;
1120
0
    eapol_auth_step(sm);
1121
0
    return 0;
1122
0
  }
1123
1124
0
  if (os_strcasecmp(param, "AdminControlledPortControl") == 0) {
1125
0
    if (os_strcmp(value, "ForceAuthorized") == 0)
1126
0
      sm->portControl = ForceAuthorized;
1127
0
    else if (os_strcmp(value, "ForceUnauthorized") == 0)
1128
0
      sm->portControl = ForceUnauthorized;
1129
0
    else if (os_strcmp(value, "Auto") == 0)
1130
0
      sm->portControl = Auto;
1131
0
    else
1132
0
      return -1;
1133
0
    eapol_auth_step(sm);
1134
0
    return 0;
1135
0
  }
1136
1137
0
  if (os_strcasecmp(param, "quietPeriod") == 0) {
1138
0
    sm->quietPeriod = atoi(value);
1139
0
    return 0;
1140
0
  }
1141
1142
0
  if (os_strcasecmp(param, "serverTimeout") == 0) {
1143
0
    sm->serverTimeout = atoi(value);
1144
0
    return 0;
1145
0
  }
1146
1147
0
  if (os_strcasecmp(param, "reAuthPeriod") == 0) {
1148
0
    sm->reAuthPeriod = atoi(value);
1149
0
    return 0;
1150
0
  }
1151
1152
0
  if (os_strcasecmp(param, "reAuthEnabled") == 0) {
1153
0
    if (os_strcmp(value, "TRUE") == 0)
1154
0
      sm->reAuthEnabled = true;
1155
0
    else if (os_strcmp(value, "FALSE") == 0)
1156
0
      sm->reAuthEnabled = false;
1157
0
    else
1158
0
      return -1;
1159
0
    eapol_auth_step(sm);
1160
0
    return 0;
1161
0
  }
1162
1163
0
  if (os_strcasecmp(param, "KeyTransmissionEnabled") == 0) {
1164
0
    if (os_strcmp(value, "TRUE") == 0)
1165
0
      sm->keyTxEnabled = true;
1166
0
    else if (os_strcmp(value, "FALSE") == 0)
1167
0
      sm->keyTxEnabled = false;
1168
0
    else
1169
0
      return -1;
1170
0
    eapol_auth_step(sm);
1171
0
    return 0;
1172
0
  }
1173
1174
0
  return -1;
1175
0
}
1176
1177
1178
static int eapol_auth_conf_clone(struct eapol_auth_config *dst,
1179
         struct eapol_auth_config *src)
1180
0
{
1181
0
  dst->eap_cfg = src->eap_cfg;
1182
0
  dst->ctx = src->ctx;
1183
0
  dst->eap_reauth_period = src->eap_reauth_period;
1184
0
  dst->wpa = src->wpa;
1185
#ifdef CONFIG_WEP
1186
  dst->individual_wep_key_len = src->individual_wep_key_len;
1187
#endif /* CONFIG_WEP */
1188
0
  os_free(dst->eap_req_id_text);
1189
0
  if (src->eap_req_id_text) {
1190
0
    dst->eap_req_id_text = os_memdup(src->eap_req_id_text,
1191
0
             src->eap_req_id_text_len);
1192
0
    if (dst->eap_req_id_text == NULL)
1193
0
      return -1;
1194
0
    dst->eap_req_id_text_len = src->eap_req_id_text_len;
1195
0
  } else {
1196
0
    dst->eap_req_id_text = NULL;
1197
0
    dst->eap_req_id_text_len = 0;
1198
0
  }
1199
1200
0
  os_free(dst->erp_domain);
1201
0
  if (src->erp_domain) {
1202
0
    dst->erp_domain = os_strdup(src->erp_domain);
1203
0
    if (dst->erp_domain == NULL)
1204
0
      goto fail;
1205
0
  } else {
1206
0
    dst->erp_domain = NULL;
1207
0
  }
1208
0
  dst->erp_send_reauth_start = src->erp_send_reauth_start;
1209
1210
0
  return 0;
1211
1212
0
fail:
1213
0
  eapol_auth_conf_free(dst);
1214
0
  return -1;
1215
0
}
1216
1217
1218
static void eapol_auth_conf_free(struct eapol_auth_config *conf)
1219
0
{
1220
0
  os_free(conf->eap_req_id_text);
1221
0
  conf->eap_req_id_text = NULL;
1222
0
  os_free(conf->erp_domain);
1223
0
  conf->erp_domain = NULL;
1224
0
}
1225
1226
1227
struct eapol_authenticator * eapol_auth_init(struct eapol_auth_config *conf,
1228
               struct eapol_auth_cb *cb)
1229
0
{
1230
0
  struct eapol_authenticator *eapol;
1231
1232
0
  eapol = os_zalloc(sizeof(*eapol));
1233
0
  if (eapol == NULL)
1234
0
    return NULL;
1235
1236
0
  if (eapol_auth_conf_clone(&eapol->conf, conf) < 0) {
1237
0
    os_free(eapol);
1238
0
    return NULL;
1239
0
  }
1240
1241
#ifdef CONFIG_WEP
1242
  if (conf->individual_wep_key_len > 0) {
1243
    /* use key0 in individual key and key1 in broadcast key */
1244
    eapol->default_wep_key_idx = 1;
1245
  }
1246
#endif /* CONFIG_WEP */
1247
1248
0
  eapol->cb.eapol_send = cb->eapol_send;
1249
0
  eapol->cb.aaa_send = cb->aaa_send;
1250
0
  eapol->cb.finished = cb->finished;
1251
0
  eapol->cb.get_eap_user = cb->get_eap_user;
1252
0
  eapol->cb.sta_entry_alive = cb->sta_entry_alive;
1253
0
  eapol->cb.logger = cb->logger;
1254
0
  eapol->cb.set_port_authorized = cb->set_port_authorized;
1255
0
  eapol->cb.abort_auth = cb->abort_auth;
1256
0
  eapol->cb.tx_key = cb->tx_key;
1257
0
  eapol->cb.eapol_event = cb->eapol_event;
1258
0
  eapol->cb.erp_get_key = cb->erp_get_key;
1259
0
  eapol->cb.erp_add_key = cb->erp_add_key;
1260
1261
0
  return eapol;
1262
0
}
1263
1264
1265
void eapol_auth_deinit(struct eapol_authenticator *eapol)
1266
0
{
1267
0
  if (eapol == NULL)
1268
0
    return;
1269
1270
0
  eapol_auth_conf_free(&eapol->conf);
1271
#ifdef CONFIG_WEP
1272
  os_free(eapol->default_wep_key);
1273
#endif /* CONFIG_WEP */
1274
0
  os_free(eapol);
1275
0
}