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