📄 eapol_sm.c
字号:
/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
Module Name:
eapol_sm.c
Revision History:
Who When What
-------- ---------- ----------------------------------------------
Jan, Lee Dec --2003 modified
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include "rt61apd.h"
#include "ieee802_1x.h"
#include "eapol_sm.h"
#include "eloop.h"
#include "mac2port.h"
/* TODO:
* implement state machines: Controlled Directions and Key Receive
*/
/* EAPOL state machines are described in IEEE Std 802.1X-2001, Chap. 8.5 */
#define setPortAuthorized() \
ieee802_1x_set_sta_authorized(1)
#define setPortUnauthorized() \
ieee802_1x_set_sta_authorized(0)
/* procedures */
#define txCannedFail(x) ieee802_1x_tx_canned_eap(sm->rtapd, sm->sta, (x), 0)
#define txCannedSuccess(x) ieee802_1x_tx_canned_eap(sm->rtapd, sm->sta, (x), 1)
/* TODO: IEEE 802.1aa/D4 replaces txReqId(x) with txInitialMsg(x); value of
* initialEAPMsg should be used to select which type of EAP packet is sent;
* Currently, hostapd only supports EAP Request/Identity, so this can be
* hardcoded. */
#define txInitialMsg(x) ieee802_1x_request_identity(sm->rtapd, sm->sta, (x))
#define txReq(x) ieee802_1x_tx_req(sm->rtapd, sm->sta, (x))
#define sendRespToServer ieee802_1x_send_resp_to_server(sm->rtapd, sm->sta)
/* TODO: check if abortAuth would be needed for something */
#define abortAuth do { } while (0)
#define txKey(x) ieee802_1x_tx_key(sm->rtapd, sm->sta, (x))
/* Definitions for clarifying state machine implementation */
#define SM_STATE(machine, state) \
static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_state_machine \
*sm)
#define SM_ENTRY(machine, _state, _data) \
sm->_data.state = machine ## _ ## _state; \
if (sm->rtapd->conf->debug >= HOSTAPD_DEBUG_MINIMAL) \
DBGPRINT(RT_DEBUG_ERROR,"IEEE 802.1X: " MACSTR " " #machine " entering state " #_state \
"\n", MAC2STR(sm->sta->addr));
#define SM_ENTER(machine, state) sm_ ## machine ## _ ## state ## _Enter(sm)
#define SM_STEP(machine) \
static void sm_ ## machine ## _Step(struct eapol_state_machine *sm)
#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
/* Port Timers state machine - implemented as a function that will be called
* once a second as a registered event loop timeout */
static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
{
struct eapol_state_machine *state = timeout_ctx;
if (state->aWhile > 0)
state->aWhile--;
if (state->quietWhile > 0)
state->quietWhile--;
if (state->reAuthWhen > 0)
state->reAuthWhen--;
if (state->txWhen > 0)
state->txWhen--;
DBGPRINT(RT_DEBUG_INFO," eapol_port_timers_tick call eapol_sm_step\n");
eapol_sm_step(state);
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
}
/* Authenticator PAE state machine */
SM_STATE(AUTH_PAE, INITIALIZE)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, INITIALIZE\n");
SM_ENTRY(AUTH_PAE, INITIALIZE, auth_pae);
sm->currentId = 1;
sm->auth_pae.portMode = Auto;
}
SM_STATE(AUTH_PAE, DISCONNECTED)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, DISCONNECTED\n");
int from_initialize = sm->auth_pae.state == AUTH_PAE_INITIALIZE;
if (sm->auth_pae.state == AUTH_PAE_CONNECTING &&
sm->auth_pae.eapLogoff)
sm->auth_pae.authEapLogoffsWhileConnecting++;
SM_ENTRY(AUTH_PAE, DISCONNECTED, auth_pae);
if((sm->portStatus != Unauthorized) || (!from_initialize))
{
int lPort;
lPort = Mac2Port_FindPortByMac(sm->sta->addr);
if(lPort != -1)
{
ieee802_1x_set_sta_port_status(1, lPort);
}
Mac2Port_DelMac(sm->sta->addr);
eloop_cancel_timeout(eapol_port_timers_tick, sm->rtapd, sm);
}
sm->portStatus = Unauthorized;
setPortUnauthorized();
sm->auth_pae.eapLogoff = FALSE;
sm->auth_pae.reAuthCount = 0;
/* IEEE 802.1X state machine uses txCannedFail() always in this state.
* However, sending EAP packet with failure code seems to cause WinXP
* Supplicant to deauthenticate, which will set portEnabled = FALSE and
* state machines end back to INITIALIZE and then back here to send
* canned failure, and so on.. Avoid this by not sending failure packet
* when DISCONNECTED state is entered from INITIALIZE state. */
if (!from_initialize) {
txCannedFail(sm->currentId);
sm->currentId++;
}
}
SM_STATE(AUTH_PAE, CONNECTING)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_CONNECTING\n");
if (sm->auth_pae.state != AUTH_PAE_CONNECTING)
sm->auth_pae.authEntersConnecting++;
if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATED) {
if (sm->reAuthenticate)
sm->auth_pae.authAuthReauthsWhileAuthenticated++;
if (sm->auth_pae.eapStart)
sm->auth_pae.authAuthEapStartsWhileAuthenticated++;
if (sm->auth_pae.eapLogoff)
sm->auth_pae.authAuthEapLogoffWhileAuthenticated++;
}
SM_ENTRY(AUTH_PAE, CONNECTING, auth_pae);
sm->auth_pae.eapStart = FALSE;
sm->reAuthenticate = FALSE;
sm->txWhen = sm->auth_pae.txPeriod;
sm->auth_pae.rxInitialRsp = FALSE;
txInitialMsg(sm->currentId);
sm->auth_pae.reAuthCount++;
}
SM_STATE(AUTH_PAE, HELD)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_HELD\n");
if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authFail)
sm->auth_pae.authAuthFailWhileAuthenticating++;
SM_ENTRY(AUTH_PAE, HELD, auth_pae);
sm->portStatus = Unauthorized;
setPortUnauthorized();
{
int lPort;
lPort = Mac2Port_FindPortByMac(sm->sta->addr);
if(lPort != -1)
{
ieee802_1x_set_sta_port_status(1, lPort);
}
}
sm->quietWhile = sm->auth_pae.quietPeriod;
sm->auth_pae.eapLogoff = FALSE;
sm->currentId++;
}
SM_STATE(AUTH_PAE, AUTHENTICATED)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_AUTHENTICATED\n");
if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
sm->auth_pae.authAuthSuccessesWhileAuthenticating++;
SM_ENTRY(AUTH_PAE, AUTHENTICATED, auth_pae);
if(sm->portStatus != Authorized)
{
int lPort;
lPort = Mac2Port_FindPortByMac(sm->sta->addr);
if(lPort != -1)
{
ieee802_1x_set_sta_port_status(FALSE, lPort);
}
}
sm->portStatus = Authorized;
setPortAuthorized();
sm->auth_pae.reAuthCount = 0;
sm->currentId++;
}
SM_STATE(AUTH_PAE, AUTHENTICATING)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_AUTHENTICATING\n");
if (sm->auth_pae.state == AUTH_PAE_CONNECTING &&
sm->auth_pae.rxInitialRsp)
sm->auth_pae.authEntersAuthenticating++;
SM_ENTRY(AUTH_PAE, AUTHENTICATING, auth_pae);
sm->authSuccess = FALSE;
sm->authFail = FALSE;
sm->authTimeout = FALSE;
sm->authStart = TRUE;
}
SM_STATE(AUTH_PAE, ABORTING)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_ABORTING\n");
if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING) {
if (sm->authTimeout)
sm->auth_pae.authAuthTimeoutsWhileAuthenticating++;
if (sm->reAuthenticate)
sm->auth_pae.authAuthReauthsWhileAuthenticating++;
if (sm->auth_pae.eapStart)
sm->auth_pae.authAuthEapStartsWhileAuthenticating++;
if (sm->auth_pae.eapLogoff)
sm->auth_pae.authAuthEapLogoffWhileAuthenticating++;
}
SM_ENTRY(AUTH_PAE, ABORTING, auth_pae);
sm->authAbort = TRUE;
sm->currentId++;
}
SM_STATE(AUTH_PAE, FORCE_AUTH)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_FORCE_AUTH\n");
SM_ENTRY(AUTH_PAE, FORCE_AUTH, auth_pae);
sm->portStatus = Authorized;
setPortAuthorized();
/*强制认证状态下端口不一定学到了MAC地址*/
/*{
int lPort;
lPort = Mac2Port_FindPortByMac(sm->sta->addr);
if(lPort != -1)
{
ieee802_1x_set_sta_port_status(FALSE, lPort);
}
}*/
sm->auth_pae.portMode = ForceAuthorized;
sm->auth_pae.eapStart = FALSE;
txCannedSuccess(sm->currentId);
sm->currentId++;
}
SM_STATE(AUTH_PAE, FORCE_UNAUTH)
{
DBGPRINT(RT_DEBUG_INFO," SM_STATE, AUTH_PAE, CONNECTING_FORCE_UNAUTH\n");
SM_ENTRY(AUTH_PAE, FORCE_UNAUTH, auth_pae);
sm->portStatus = Unauthorized;
setPortUnauthorized();
/*强制非认证状态下端口不一定学到了MAC地址*/
/*{
int lPort;
lPort = Mac2Port_FindPortByMac(sm->sta->addr);
if(lPort != -1)
{
ieee802_1x_set_sta_port_status(1, lPort);
}
}*/
Mac2Port_DelMac(sm->sta->addr);
sm->auth_pae.portMode = ForceUnauthorized;
sm->auth_pae.eapStart = FALSE;
txCannedFail(sm->currentId);
sm->currentId++;
}
SM_STEP(AUTH_PAE)
{
DBGPRINT(RT_DEBUG_INFO," SM_STEP, AUTH_PAE, auth_pae.state(%d)\n",sm->auth_pae.state);
if ((sm->portControl == Auto &&
sm->auth_pae.portMode != sm->portControl) ||
sm->initialize || !sm->portEnabled)
SM_ENTER(AUTH_PAE, INITIALIZE);
else if (sm->portControl == ForceAuthorized &&
sm->auth_pae.portMode != sm->portControl &&
!(sm->initialize || !sm->portEnabled))
SM_ENTER(AUTH_PAE, FORCE_AUTH);
else if (sm->portControl == ForceUnauthorized &&
sm->auth_pae.portMode != sm->portControl &&
!(sm->initialize || !sm->portEnabled))
SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
else {
switch (sm->auth_pae.state) {
case AUTH_PAE_INITIALIZE:
SM_ENTER(AUTH_PAE, DISCONNECTED);
break;
case AUTH_PAE_DISCONNECTED:
SM_ENTER(AUTH_PAE, CONNECTING);
break;
case AUTH_PAE_HELD:
if (sm->quietWhile == 0)
SM_ENTER(AUTH_PAE, CONNECTING);
break;
case AUTH_PAE_CONNECTING:
if (sm->auth_pae.eapLogoff ||
sm->auth_pae.reAuthCount > sm->auth_pae.reAuthMax)
SM_ENTER(AUTH_PAE, DISCONNECTED);
else if (sm->auth_pae.rxInitialRsp &&
sm->auth_pae.reAuthCount <=
sm->auth_pae.reAuthMax)
SM_ENTER(AUTH_PAE, AUTHENTICATING);
else if ((sm->txWhen == 0 || sm->auth_pae.eapStart ||
sm->reAuthenticate) &&
sm->auth_pae.reAuthCount <=
sm->auth_pae.reAuthMax)
SM_ENTER(AUTH_PAE, CONNECTING);
break;
case AUTH_PAE_AUTHENTICATED:
if (sm->auth_pae.eapStart || sm->reAuthenticate)
SM_ENTER(AUTH_PAE, CONNECTING);
else if (sm->auth_pae.eapLogoff || !sm->portValid)
SM_ENTER(AUTH_PAE, DISCONNECTED);
break;
case AUTH_PAE_AUTHENTICATING:
if (sm->authSuccess && sm->portValid)
SM_ENTER(AUTH_PAE, AUTHENTICATED);
else if (sm->authFail)
SM_ENTER(AUTH_PAE, HELD);
else if (sm->reAuthenticate || sm->auth_pae.eapStart ||
sm->auth_pae.eapLogoff ||
sm->authTimeout)
SM_ENTER(AUTH_PAE, ABORTING);
break;
case AUTH_PAE_ABORTING:
if (sm->auth_pae.eapLogoff && !sm->authAbort)
SM_ENTER(AUTH_PAE, DISCONNECTED);
else if (!sm->auth_pae.eapLogoff && !sm->authAbort)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -