1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125 |
- /*
- * EAPOL supplicant state machines
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
- #include "includes.h"
- #include "common.h"
- #include "state_machine.h"
- #include "wpabuf.h"
- #include "eloop.h"
- #include "crypto/crypto.h"
- #include "crypto/md5.h"
- #include "common/eapol_common.h"
- #include "eap_peer/eap.h"
- #include "eap_peer/eap_proxy.h"
- #include "eapol_supp_sm.h"
- #define STATE_MACHINE_DATA struct eapol_sm
- #define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
- /* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
- /**
- * struct eapol_sm - Internal data for EAPOL state machines
- */
- struct eapol_sm {
- /* Timers */
- unsigned int authWhile;
- unsigned int heldWhile;
- unsigned int startWhen;
- unsigned int idleWhile; /* for EAP state machine */
- int timer_tick_enabled;
- /* Global variables */
- Boolean eapFail;
- Boolean eapolEap;
- Boolean eapSuccess;
- Boolean initialize;
- Boolean keyDone;
- Boolean keyRun;
- PortControl portControl;
- Boolean portEnabled;
- PortStatus suppPortStatus; /* dot1xSuppControlledPortStatus */
- Boolean portValid;
- Boolean suppAbort;
- Boolean suppFail;
- Boolean suppStart;
- Boolean suppSuccess;
- Boolean suppTimeout;
- /* Supplicant PAE state machine */
- enum {
- SUPP_PAE_UNKNOWN = 0,
- SUPP_PAE_DISCONNECTED = 1,
- SUPP_PAE_LOGOFF = 2,
- SUPP_PAE_CONNECTING = 3,
- SUPP_PAE_AUTHENTICATING = 4,
- SUPP_PAE_AUTHENTICATED = 5,
- /* unused(6) */
- SUPP_PAE_HELD = 7,
- SUPP_PAE_RESTART = 8,
- SUPP_PAE_S_FORCE_AUTH = 9,
- SUPP_PAE_S_FORCE_UNAUTH = 10
- } SUPP_PAE_state; /* dot1xSuppPaeState */
- /* Variables */
- Boolean userLogoff;
- Boolean logoffSent;
- unsigned int startCount;
- Boolean eapRestart;
- PortControl sPortMode;
- /* Constants */
- unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
- unsigned int startPeriod; /* dot1xSuppStartPeriod */
- unsigned int maxStart; /* dot1xSuppMaxStart */
- /* Key Receive state machine */
- enum {
- KEY_RX_UNKNOWN = 0,
- KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
- } KEY_RX_state;
- /* Variables */
- Boolean rxKey;
- /* Supplicant Backend state machine */
- enum {
- SUPP_BE_UNKNOWN = 0,
- SUPP_BE_INITIALIZE = 1,
- SUPP_BE_IDLE = 2,
- SUPP_BE_REQUEST = 3,
- SUPP_BE_RECEIVE = 4,
- SUPP_BE_RESPONSE = 5,
- SUPP_BE_FAIL = 6,
- SUPP_BE_TIMEOUT = 7,
- SUPP_BE_SUCCESS = 8
- } SUPP_BE_state; /* dot1xSuppBackendPaeState */
- /* Variables */
- Boolean eapNoResp;
- Boolean eapReq;
- Boolean eapResp;
- /* Constants */
- unsigned int authPeriod; /* dot1xSuppAuthPeriod */
- /* Statistics */
- unsigned int dot1xSuppEapolFramesRx;
- unsigned int dot1xSuppEapolFramesTx;
- unsigned int dot1xSuppEapolStartFramesTx;
- unsigned int dot1xSuppEapolLogoffFramesTx;
- unsigned int dot1xSuppEapolRespFramesTx;
- unsigned int dot1xSuppEapolReqIdFramesRx;
- unsigned int dot1xSuppEapolReqFramesRx;
- unsigned int dot1xSuppInvalidEapolFramesRx;
- unsigned int dot1xSuppEapLengthErrorFramesRx;
- unsigned int dot1xSuppLastEapolFrameVersion;
- unsigned char dot1xSuppLastEapolFrameSource[6];
- /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
- Boolean changed;
- struct eap_sm *eap;
- struct eap_peer_config *config;
- Boolean initial_req;
- u8 *last_rx_key;
- size_t last_rx_key_len;
- struct wpabuf *eapReqData; /* for EAP */
- Boolean altAccept; /* for EAP */
- Boolean altReject; /* for EAP */
- Boolean eapTriggerStart;
- Boolean replay_counter_valid;
- u8 last_replay_counter[16];
- struct eapol_config conf;
- struct eapol_ctx *ctx;
- enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
- cb_status;
- Boolean cached_pmk;
- Boolean unicast_key_received, broadcast_key_received;
- Boolean force_authorized_update;
- #ifdef CONFIG_EAP_PROXY
- Boolean use_eap_proxy;
- struct eap_proxy_sm *eap_proxy;
- #endif /* CONFIG_EAP_PROXY */
- };
- static void eapol_sm_txLogoff(struct eapol_sm *sm);
- static void eapol_sm_txStart(struct eapol_sm *sm);
- static void eapol_sm_processKey(struct eapol_sm *sm);
- static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
- static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
- static void eapol_sm_abortSupp(struct eapol_sm *sm);
- static void eapol_sm_abort_cached(struct eapol_sm *sm);
- static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
- static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
- static void eapol_sm_set_port_unauthorized(struct eapol_sm *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_sm *sm = timeout_ctx;
- if (sm->authWhile > 0) {
- sm->authWhile--;
- if (sm->authWhile == 0)
- wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
- }
- if (sm->heldWhile > 0) {
- sm->heldWhile--;
- if (sm->heldWhile == 0)
- wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
- }
- if (sm->startWhen > 0) {
- sm->startWhen--;
- if (sm->startWhen == 0)
- wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
- }
- if (sm->idleWhile > 0) {
- sm->idleWhile--;
- if (sm->idleWhile == 0)
- wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
- }
- if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
- eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
- sm);
- } else {
- wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
- sm->timer_tick_enabled = 0;
- }
- eapol_sm_step(sm);
- }
- static void eapol_enable_timer_tick(struct eapol_sm *sm)
- {
- if (sm->timer_tick_enabled)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
- sm->timer_tick_enabled = 1;
- eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
- }
- SM_STATE(SUPP_PAE, LOGOFF)
- {
- SM_ENTRY(SUPP_PAE, LOGOFF);
- eapol_sm_txLogoff(sm);
- sm->logoffSent = TRUE;
- eapol_sm_set_port_unauthorized(sm);
- }
- SM_STATE(SUPP_PAE, DISCONNECTED)
- {
- SM_ENTRY(SUPP_PAE, DISCONNECTED);
- sm->sPortMode = Auto;
- sm->startCount = 0;
- sm->eapTriggerStart = FALSE;
- sm->logoffSent = FALSE;
- eapol_sm_set_port_unauthorized(sm);
- sm->suppAbort = TRUE;
- sm->unicast_key_received = FALSE;
- sm->broadcast_key_received = FALSE;
- /*
- * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
- * allows the timer tick to be stopped more quickly when the port is
- * not enabled. Since this variable is used only within HELD state,
- * clearing it on initialization does not change actual state machine
- * behavior.
- */
- sm->heldWhile = 0;
- }
- SM_STATE(SUPP_PAE, CONNECTING)
- {
- int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
- SM_ENTRY(SUPP_PAE, CONNECTING);
- if (sm->eapTriggerStart)
- send_start = 1;
- sm->eapTriggerStart = FALSE;
- if (send_start) {
- sm->startWhen = sm->startPeriod;
- sm->startCount++;
- } else {
- /*
- * Do not send EAPOL-Start immediately since in most cases,
- * Authenticator is going to start authentication immediately
- * after association and an extra EAPOL-Start is just going to
- * delay authentication. Use a short timeout to send the first
- * EAPOL-Start if Authenticator does not start authentication.
- */
- if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
- /* Reduce latency on starting WPS negotiation. */
- wpa_printf(MSG_DEBUG,
- "EAPOL: Using shorter startWhen for WPS");
- sm->startWhen = 1;
- } else {
- sm->startWhen = 2;
- }
- }
- eapol_enable_timer_tick(sm);
- sm->eapolEap = FALSE;
- if (send_start)
- eapol_sm_txStart(sm);
- }
- SM_STATE(SUPP_PAE, AUTHENTICATING)
- {
- SM_ENTRY(SUPP_PAE, AUTHENTICATING);
- sm->startCount = 0;
- sm->suppSuccess = FALSE;
- sm->suppFail = FALSE;
- sm->suppTimeout = FALSE;
- sm->keyRun = FALSE;
- sm->keyDone = FALSE;
- sm->suppStart = TRUE;
- }
- SM_STATE(SUPP_PAE, HELD)
- {
- SM_ENTRY(SUPP_PAE, HELD);
- sm->heldWhile = sm->heldPeriod;
- eapol_enable_timer_tick(sm);
- eapol_sm_set_port_unauthorized(sm);
- sm->cb_status = EAPOL_CB_FAILURE;
- }
- SM_STATE(SUPP_PAE, AUTHENTICATED)
- {
- SM_ENTRY(SUPP_PAE, AUTHENTICATED);
- eapol_sm_set_port_authorized(sm);
- sm->cb_status = EAPOL_CB_SUCCESS;
- }
- SM_STATE(SUPP_PAE, RESTART)
- {
- SM_ENTRY(SUPP_PAE, RESTART);
- sm->eapRestart = TRUE;
- }
- SM_STATE(SUPP_PAE, S_FORCE_AUTH)
- {
- SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
- eapol_sm_set_port_authorized(sm);
- sm->sPortMode = ForceAuthorized;
- }
- SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
- {
- SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
- eapol_sm_set_port_unauthorized(sm);
- sm->sPortMode = ForceUnauthorized;
- eapol_sm_txLogoff(sm);
- }
- SM_STEP(SUPP_PAE)
- {
- if ((sm->userLogoff && !sm->logoffSent) &&
- !(sm->initialize || !sm->portEnabled))
- SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
- else if (((sm->portControl == Auto) &&
- (sm->sPortMode != sm->portControl)) ||
- sm->initialize || !sm->portEnabled)
- SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
- else if ((sm->portControl == ForceAuthorized) &&
- (sm->sPortMode != sm->portControl) &&
- !(sm->initialize || !sm->portEnabled))
- SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
- else if ((sm->portControl == ForceUnauthorized) &&
- (sm->sPortMode != sm->portControl) &&
- !(sm->initialize || !sm->portEnabled))
- SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
- else switch (sm->SUPP_PAE_state) {
- case SUPP_PAE_UNKNOWN:
- break;
- case SUPP_PAE_LOGOFF:
- if (!sm->userLogoff)
- SM_ENTER(SUPP_PAE, DISCONNECTED);
- break;
- case SUPP_PAE_DISCONNECTED:
- SM_ENTER(SUPP_PAE, CONNECTING);
- break;
- case SUPP_PAE_CONNECTING:
- if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
- SM_ENTER(SUPP_PAE, CONNECTING);
- else if (sm->startWhen == 0 &&
- sm->startCount >= sm->maxStart &&
- sm->portValid)
- SM_ENTER(SUPP_PAE, AUTHENTICATED);
- else if (sm->eapSuccess || sm->eapFail)
- SM_ENTER(SUPP_PAE, AUTHENTICATING);
- else if (sm->eapolEap)
- SM_ENTER(SUPP_PAE, RESTART);
- else if (sm->startWhen == 0 &&
- sm->startCount >= sm->maxStart &&
- !sm->portValid)
- SM_ENTER(SUPP_PAE, HELD);
- break;
- case SUPP_PAE_AUTHENTICATING:
- if (sm->eapSuccess && !sm->portValid &&
- sm->conf.accept_802_1x_keys &&
- sm->conf.required_keys == 0) {
- wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
- "plaintext connection; no EAPOL-Key frames "
- "required");
- sm->portValid = TRUE;
- if (sm->ctx->eapol_done_cb)
- sm->ctx->eapol_done_cb(sm->ctx->ctx);
- }
- if (sm->eapSuccess && sm->portValid)
- SM_ENTER(SUPP_PAE, AUTHENTICATED);
- else if (sm->eapFail || (sm->keyDone && !sm->portValid))
- SM_ENTER(SUPP_PAE, HELD);
- else if (sm->suppTimeout)
- SM_ENTER(SUPP_PAE, CONNECTING);
- else if (sm->eapTriggerStart)
- SM_ENTER(SUPP_PAE, CONNECTING);
- break;
- case SUPP_PAE_HELD:
- if (sm->heldWhile == 0)
- SM_ENTER(SUPP_PAE, CONNECTING);
- else if (sm->eapolEap)
- SM_ENTER(SUPP_PAE, RESTART);
- break;
- case SUPP_PAE_AUTHENTICATED:
- if (sm->eapolEap && sm->portValid)
- SM_ENTER(SUPP_PAE, RESTART);
- else if (!sm->portValid)
- SM_ENTER(SUPP_PAE, DISCONNECTED);
- break;
- case SUPP_PAE_RESTART:
- if (!sm->eapRestart)
- SM_ENTER(SUPP_PAE, AUTHENTICATING);
- break;
- case SUPP_PAE_S_FORCE_AUTH:
- break;
- case SUPP_PAE_S_FORCE_UNAUTH:
- break;
- }
- }
- SM_STATE(KEY_RX, NO_KEY_RECEIVE)
- {
- SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
- }
- SM_STATE(KEY_RX, KEY_RECEIVE)
- {
- SM_ENTRY(KEY_RX, KEY_RECEIVE);
- eapol_sm_processKey(sm);
- sm->rxKey = FALSE;
- }
- SM_STEP(KEY_RX)
- {
- if (sm->initialize || !sm->portEnabled)
- SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
- switch (sm->KEY_RX_state) {
- case KEY_RX_UNKNOWN:
- break;
- case KEY_RX_NO_KEY_RECEIVE:
- if (sm->rxKey)
- SM_ENTER(KEY_RX, KEY_RECEIVE);
- break;
- case KEY_RX_KEY_RECEIVE:
- if (sm->rxKey)
- SM_ENTER(KEY_RX, KEY_RECEIVE);
- break;
- }
- }
- SM_STATE(SUPP_BE, REQUEST)
- {
- SM_ENTRY(SUPP_BE, REQUEST);
- sm->authWhile = 0;
- sm->eapReq = TRUE;
- eapol_sm_getSuppRsp(sm);
- }
- SM_STATE(SUPP_BE, RESPONSE)
- {
- SM_ENTRY(SUPP_BE, RESPONSE);
- eapol_sm_txSuppRsp(sm);
- sm->eapResp = FALSE;
- }
- SM_STATE(SUPP_BE, SUCCESS)
- {
- SM_ENTRY(SUPP_BE, SUCCESS);
- sm->keyRun = TRUE;
- sm->suppSuccess = TRUE;
- #ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
- if (eap_proxy_key_available(sm->eap_proxy)) {
- /* New key received - clear IEEE 802.1X EAPOL-Key replay
- * counter */
- sm->replay_counter_valid = FALSE;
- }
- return;
- }
- #endif /* CONFIG_EAP_PROXY */
- if (eap_key_available(sm->eap)) {
- /* New key received - clear IEEE 802.1X EAPOL-Key replay
- * counter */
- sm->replay_counter_valid = FALSE;
- }
- }
- SM_STATE(SUPP_BE, FAIL)
- {
- SM_ENTRY(SUPP_BE, FAIL);
- sm->suppFail = TRUE;
- }
- SM_STATE(SUPP_BE, TIMEOUT)
- {
- SM_ENTRY(SUPP_BE, TIMEOUT);
- sm->suppTimeout = TRUE;
- }
- SM_STATE(SUPP_BE, IDLE)
- {
- SM_ENTRY(SUPP_BE, IDLE);
- sm->suppStart = FALSE;
- sm->initial_req = TRUE;
- }
- SM_STATE(SUPP_BE, INITIALIZE)
- {
- SM_ENTRY(SUPP_BE, INITIALIZE);
- eapol_sm_abortSupp(sm);
- sm->suppAbort = FALSE;
- /*
- * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
- * allows the timer tick to be stopped more quickly when the port is
- * not enabled. Since this variable is used only within RECEIVE state,
- * clearing it on initialization does not change actual state machine
- * behavior.
- */
- sm->authWhile = 0;
- }
- SM_STATE(SUPP_BE, RECEIVE)
- {
- SM_ENTRY(SUPP_BE, RECEIVE);
- sm->authWhile = sm->authPeriod;
- eapol_enable_timer_tick(sm);
- sm->eapolEap = FALSE;
- sm->eapNoResp = FALSE;
- sm->initial_req = FALSE;
- }
- SM_STEP(SUPP_BE)
- {
- if (sm->initialize || sm->suppAbort)
- SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
- else switch (sm->SUPP_BE_state) {
- case SUPP_BE_UNKNOWN:
- break;
- case SUPP_BE_REQUEST:
- /*
- * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
- * and SUCCESS based on eapFail and eapSuccess, respectively.
- * However, IEEE Std 802.1X-2004 is also specifying that
- * eapNoResp should be set in conjunction with eapSuccess and
- * eapFail which would mean that more than one of the
- * transitions here would be activated at the same time.
- * Skipping RESPONSE and/or RECEIVE states in these cases can
- * cause problems and the direct transitions to do not seem
- * correct. Because of this, the conditions for these
- * transitions are verified only after eapNoResp. They are
- * unlikely to be used since eapNoResp should always be set if
- * either of eapSuccess or eapFail is set.
- */
- if (sm->eapResp && sm->eapNoResp) {
- wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
- "eapResp and eapNoResp set?!");
- }
- if (sm->eapResp)
- SM_ENTER(SUPP_BE, RESPONSE);
- else if (sm->eapNoResp)
- SM_ENTER(SUPP_BE, RECEIVE);
- else if (sm->eapFail)
- SM_ENTER(SUPP_BE, FAIL);
- else if (sm->eapSuccess)
- SM_ENTER(SUPP_BE, SUCCESS);
- break;
- case SUPP_BE_RESPONSE:
- SM_ENTER(SUPP_BE, RECEIVE);
- break;
- case SUPP_BE_SUCCESS:
- SM_ENTER(SUPP_BE, IDLE);
- break;
- case SUPP_BE_FAIL:
- SM_ENTER(SUPP_BE, IDLE);
- break;
- case SUPP_BE_TIMEOUT:
- SM_ENTER(SUPP_BE, IDLE);
- break;
- case SUPP_BE_IDLE:
- if (sm->eapFail && sm->suppStart)
- SM_ENTER(SUPP_BE, FAIL);
- else if (sm->eapolEap && sm->suppStart)
- SM_ENTER(SUPP_BE, REQUEST);
- else if (sm->eapSuccess && sm->suppStart)
- SM_ENTER(SUPP_BE, SUCCESS);
- break;
- case SUPP_BE_INITIALIZE:
- SM_ENTER(SUPP_BE, IDLE);
- break;
- case SUPP_BE_RECEIVE:
- if (sm->eapolEap)
- SM_ENTER(SUPP_BE, REQUEST);
- else if (sm->eapFail)
- SM_ENTER(SUPP_BE, FAIL);
- else if (sm->authWhile == 0)
- SM_ENTER(SUPP_BE, TIMEOUT);
- else if (sm->eapSuccess)
- SM_ENTER(SUPP_BE, SUCCESS);
- break;
- }
- }
- static void eapol_sm_txLogoff(struct eapol_sm *sm)
- {
- wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
- sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
- IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
- sm->dot1xSuppEapolLogoffFramesTx++;
- sm->dot1xSuppEapolFramesTx++;
- }
- static void eapol_sm_txStart(struct eapol_sm *sm)
- {
- wpa_printf(MSG_DEBUG, "EAPOL: txStart");
- sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
- IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
- sm->dot1xSuppEapolStartFramesTx++;
- sm->dot1xSuppEapolFramesTx++;
- }
- #define IEEE8021X_ENCR_KEY_LEN 32
- #define IEEE8021X_SIGN_KEY_LEN 32
- struct eap_key_data {
- u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
- u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
- };
- static void eapol_sm_processKey(struct eapol_sm *sm)
- {
- #ifndef CONFIG_FIPS
- struct ieee802_1x_hdr *hdr;
- struct ieee802_1x_eapol_key *key;
- struct eap_key_data keydata;
- u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
- u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
- int key_len, res, sign_key_len, encr_key_len;
- u16 rx_key_length;
- size_t plen;
- wpa_printf(MSG_DEBUG, "EAPOL: processKey");
- if (sm->last_rx_key == NULL)
- return;
- if (!sm->conf.accept_802_1x_keys) {
- wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
- " even though this was not accepted - "
- "ignoring this packet");
- return;
- }
- if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
- return;
- hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
- key = (struct ieee802_1x_eapol_key *) (hdr + 1);
- plen = be_to_host16(hdr->length);
- if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
- wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
- return;
- }
- rx_key_length = WPA_GET_BE16(key->key_length);
- wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
- "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
- hdr->version, hdr->type, be_to_host16(hdr->length),
- key->type, rx_key_length, key->key_index);
- eapol_sm_notify_lower_layer_success(sm, 1);
- sign_key_len = IEEE8021X_SIGN_KEY_LEN;
- encr_key_len = IEEE8021X_ENCR_KEY_LEN;
- res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
- if (res < 0) {
- wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
- "decrypting EAPOL-Key keys");
- return;
- }
- if (res == 16) {
- /* LEAP derives only 16 bytes of keying material. */
- res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
- if (res) {
- wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
- "master key for decrypting EAPOL-Key keys");
- return;
- }
- sign_key_len = 16;
- encr_key_len = 16;
- os_memcpy(keydata.sign_key, keydata.encr_key, 16);
- } else if (res) {
- wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
- "data for decrypting EAPOL-Key keys (res=%d)", res);
- return;
- }
- /* The key replay_counter must increase when same master key */
- if (sm->replay_counter_valid &&
- os_memcmp(sm->last_replay_counter, key->replay_counter,
- IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
- wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
- "not increase - ignoring key");
- wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
- sm->last_replay_counter,
- IEEE8021X_REPLAY_COUNTER_LEN);
- wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
- key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
- return;
- }
- /* Verify key signature (HMAC-MD5) */
- os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
- os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
- hmac_md5(keydata.sign_key, sign_key_len,
- sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
- key->key_signature);
- if (os_memcmp_const(orig_key_sign, key->key_signature,
- IEEE8021X_KEY_SIGN_LEN) != 0) {
- wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
- "EAPOL-Key packet");
- os_memcpy(key->key_signature, orig_key_sign,
- IEEE8021X_KEY_SIGN_LEN);
- return;
- }
- wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
- key_len = plen - sizeof(*key);
- if (key_len > 32 || rx_key_length > 32) {
- wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
- key_len ? key_len : rx_key_length);
- return;
- }
- if (key_len == rx_key_length) {
- os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
- os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
- encr_key_len);
- os_memcpy(datakey, key + 1, key_len);
- rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
- datakey, key_len);
- wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
- datakey, key_len);
- } else if (key_len == 0) {
- /*
- * IEEE 802.1X-2004 specifies that least significant Key Length
- * octets from MS-MPPE-Send-Key are used as the key if the key
- * data is not present. This seems to be meaning the beginning
- * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
- * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
- * Anyway, taking the beginning of the keying material from EAP
- * seems to interoperate with Authenticators.
- */
- key_len = rx_key_length;
- os_memcpy(datakey, keydata.encr_key, key_len);
- wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
- "material data encryption key",
- datakey, key_len);
- } else {
- wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
- "(key_length=%d)", key_len, rx_key_length);
- return;
- }
- sm->replay_counter_valid = TRUE;
- os_memcpy(sm->last_replay_counter, key->replay_counter,
- IEEE8021X_REPLAY_COUNTER_LEN);
- wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
- "len %d",
- key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
- "unicast" : "broadcast",
- key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
- if (sm->ctx->set_wep_key &&
- sm->ctx->set_wep_key(sm->ctx->ctx,
- key->key_index & IEEE8021X_KEY_INDEX_FLAG,
- key->key_index & IEEE8021X_KEY_INDEX_MASK,
- datakey, key_len) < 0) {
- wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
- " driver.");
- } else {
- if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
- sm->unicast_key_received = TRUE;
- else
- sm->broadcast_key_received = TRUE;
- if ((sm->unicast_key_received ||
- !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
- (sm->broadcast_key_received ||
- !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
- {
- wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
- "frames received");
- sm->portValid = TRUE;
- if (sm->ctx->eapol_done_cb)
- sm->ctx->eapol_done_cb(sm->ctx->ctx);
- }
- }
- #endif /* CONFIG_FIPS */
- }
- static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
- {
- wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
- /* EAP layer processing; no special code is needed, since Supplicant
- * Backend state machine is waiting for eapNoResp or eapResp to be set
- * and these are only set in the EAP state machine when the processing
- * has finished. */
- }
- static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
- {
- struct wpabuf *resp;
- wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
- #ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
- /* Get EAP Response from EAP Proxy */
- resp = eap_proxy_get_eapRespData(sm->eap_proxy);
- if (resp == NULL) {
- wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP Proxy "
- "response data not available");
- return;
- }
- } else
- #endif /* CONFIG_EAP_PROXY */
- resp = eap_get_eapRespData(sm->eap);
- if (resp == NULL) {
- wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
- "not available");
- return;
- }
- /* Send EAP-Packet from the EAP layer to the Authenticator */
- sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
- IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
- wpabuf_len(resp));
- /* eapRespData is not used anymore, so free it here */
- wpabuf_free(resp);
- if (sm->initial_req)
- sm->dot1xSuppEapolReqIdFramesRx++;
- else
- sm->dot1xSuppEapolReqFramesRx++;
- sm->dot1xSuppEapolRespFramesTx++;
- sm->dot1xSuppEapolFramesTx++;
- }
- static void eapol_sm_abortSupp(struct eapol_sm *sm)
- {
- /* release system resources that may have been allocated for the
- * authentication session */
- os_free(sm->last_rx_key);
- sm->last_rx_key = NULL;
- wpabuf_free(sm->eapReqData);
- sm->eapReqData = NULL;
- eap_sm_abort(sm->eap);
- }
- static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
- {
- eapol_sm_step(timeout_ctx);
- }
- static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
- {
- int cb;
- cb = sm->suppPortStatus != Authorized || sm->force_authorized_update;
- sm->force_authorized_update = FALSE;
- sm->suppPortStatus = Authorized;
- if (cb && sm->ctx->port_cb)
- sm->ctx->port_cb(sm->ctx->ctx, 1);
- }
- static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
- {
- int cb;
- cb = sm->suppPortStatus != Unauthorized || sm->force_authorized_update;
- sm->force_authorized_update = FALSE;
- sm->suppPortStatus = Unauthorized;
- if (cb && sm->ctx->port_cb)
- sm->ctx->port_cb(sm->ctx->ctx, 0);
- }
- /**
- * eapol_sm_step - EAPOL state machine step function
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * This function is called to notify the state machine about changed external
- * variables. It will step through the EAPOL state machines in loop to process
- * all triggered state changes.
- */
- void eapol_sm_step(struct eapol_sm *sm)
- {
- int i;
- /* In theory, it should be ok to run this in loop until !changed.
- * However, it is better to use a limit on number of iterations to
- * allow events (e.g., SIGTERM) to stop the program cleanly if the
- * state machine were to generate a busy loop. */
- for (i = 0; i < 100; i++) {
- sm->changed = FALSE;
- SM_STEP_RUN(SUPP_PAE);
- SM_STEP_RUN(KEY_RX);
- SM_STEP_RUN(SUPP_BE);
- #ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
- /* Drive the EAP proxy state machine */
- if (eap_proxy_sm_step(sm->eap_proxy, sm->eap))
- sm->changed = TRUE;
- } else
- #endif /* CONFIG_EAP_PROXY */
- if (eap_peer_sm_step(sm->eap))
- sm->changed = TRUE;
- if (!sm->changed)
- break;
- }
- if (sm->changed) {
- /* restart EAPOL state machine step from timeout call in order
- * to allow other events to be processed. */
- eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
- eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
- }
- if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
- enum eapol_supp_result result;
- if (sm->cb_status == EAPOL_CB_SUCCESS)
- result = EAPOL_SUPP_RESULT_SUCCESS;
- else if (eap_peer_was_failure_expected(sm->eap))
- result = EAPOL_SUPP_RESULT_EXPECTED_FAILURE;
- else
- result = EAPOL_SUPP_RESULT_FAILURE;
- sm->cb_status = EAPOL_CB_IN_PROGRESS;
- sm->ctx->cb(sm, result, sm->ctx->cb_ctx);
- }
- }
- #ifdef CONFIG_CTRL_IFACE
- static const char *eapol_supp_pae_state(int state)
- {
- switch (state) {
- case SUPP_PAE_LOGOFF:
- return "LOGOFF";
- case SUPP_PAE_DISCONNECTED:
- return "DISCONNECTED";
- case SUPP_PAE_CONNECTING:
- return "CONNECTING";
- case SUPP_PAE_AUTHENTICATING:
- return "AUTHENTICATING";
- case SUPP_PAE_HELD:
- return "HELD";
- case SUPP_PAE_AUTHENTICATED:
- return "AUTHENTICATED";
- case SUPP_PAE_RESTART:
- return "RESTART";
- default:
- return "UNKNOWN";
- }
- }
- static const char *eapol_supp_be_state(int state)
- {
- switch (state) {
- case SUPP_BE_REQUEST:
- return "REQUEST";
- case SUPP_BE_RESPONSE:
- return "RESPONSE";
- case SUPP_BE_SUCCESS:
- return "SUCCESS";
- case SUPP_BE_FAIL:
- return "FAIL";
- case SUPP_BE_TIMEOUT:
- return "TIMEOUT";
- case SUPP_BE_IDLE:
- return "IDLE";
- case SUPP_BE_INITIALIZE:
- return "INITIALIZE";
- case SUPP_BE_RECEIVE:
- return "RECEIVE";
- default:
- return "UNKNOWN";
- }
- }
- static const char * eapol_port_status(PortStatus status)
- {
- if (status == Authorized)
- return "Authorized";
- else
- return "Unauthorized";
- }
- #endif /* CONFIG_CTRL_IFACE */
- #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
- static const char * eapol_port_control(PortControl ctrl)
- {
- switch (ctrl) {
- case Auto:
- return "Auto";
- case ForceUnauthorized:
- return "ForceUnauthorized";
- case ForceAuthorized:
- return "ForceAuthorized";
- default:
- return "Unknown";
- }
- }
- #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
- /**
- * eapol_sm_configure - Set EAPOL variables
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @heldPeriod: dot1xSuppHeldPeriod
- * @authPeriod: dot1xSuppAuthPeriod
- * @startPeriod: dot1xSuppStartPeriod
- * @maxStart: dot1xSuppMaxStart
- *
- * Set configurable EAPOL state machine variables. Each variable can be set to
- * the given value or ignored if set to -1 (to set only some of the variables).
- */
- void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
- int startPeriod, int maxStart)
- {
- if (sm == NULL)
- return;
- if (heldPeriod >= 0)
- sm->heldPeriod = heldPeriod;
- if (authPeriod >= 0)
- sm->authPeriod = authPeriod;
- if (startPeriod >= 0)
- sm->startPeriod = startPeriod;
- if (maxStart >= 0)
- sm->maxStart = maxStart;
- }
- /**
- * eapol_sm_get_method_name - Get EAPOL method name
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * Returns: Static string containing name of current eap method or NULL
- */
- const char * eapol_sm_get_method_name(struct eapol_sm *sm)
- {
- if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
- sm->suppPortStatus != Authorized)
- return NULL;
- return eap_sm_get_method_name(sm->eap);
- }
- #ifdef CONFIG_CTRL_IFACE
- /**
- * eapol_sm_get_status - Get EAPOL state machine status
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @buf: Buffer for status information
- * @buflen: Maximum buffer length
- * @verbose: Whether to include verbose status information
- * Returns: Number of bytes written to buf.
- *
- * Query EAPOL state machine for status information. This function fills in a
- * text area with current status information from the EAPOL state machine. If
- * the buffer (buf) is not large enough, status information will be truncated
- * to fit the buffer.
- */
- int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
- int verbose)
- {
- int len, ret;
- if (sm == NULL)
- return 0;
- len = os_snprintf(buf, buflen,
- "Supplicant PAE state=%s\n"
- "suppPortStatus=%s\n",
- eapol_supp_pae_state(sm->SUPP_PAE_state),
- eapol_port_status(sm->suppPortStatus));
- if (os_snprintf_error(buflen, len))
- return 0;
- if (verbose) {
- ret = os_snprintf(buf + len, buflen - len,
- "heldPeriod=%u\n"
- "authPeriod=%u\n"
- "startPeriod=%u\n"
- "maxStart=%u\n"
- "portControl=%s\n"
- "Supplicant Backend state=%s\n",
- sm->heldPeriod,
- sm->authPeriod,
- sm->startPeriod,
- sm->maxStart,
- eapol_port_control(sm->portControl),
- eapol_supp_be_state(sm->SUPP_BE_state));
- if (os_snprintf_error(buflen - len, ret))
- return len;
- len += ret;
- }
- #ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy)
- len += eap_proxy_sm_get_status(sm->eap_proxy,
- buf + len, buflen - len,
- verbose);
- else
- #endif /* CONFIG_EAP_PROXY */
- len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
- return len;
- }
- /**
- * eapol_sm_get_mib - Get EAPOL state machine MIBs
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @buf: Buffer for MIB information
- * @buflen: Maximum buffer length
- * Returns: Number of bytes written to buf.
- *
- * Query EAPOL state machine for MIB information. This function fills in a
- * text area with current MIB information from the EAPOL state machine. If
- * the buffer (buf) is not large enough, MIB information will be truncated to
- * fit the buffer.
- */
- int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
- {
- size_t len;
- int ret;
- if (sm == NULL)
- return 0;
- ret = os_snprintf(buf, buflen,
- "dot1xSuppPaeState=%d\n"
- "dot1xSuppHeldPeriod=%u\n"
- "dot1xSuppAuthPeriod=%u\n"
- "dot1xSuppStartPeriod=%u\n"
- "dot1xSuppMaxStart=%u\n"
- "dot1xSuppSuppControlledPortStatus=%s\n"
- "dot1xSuppBackendPaeState=%d\n",
- sm->SUPP_PAE_state,
- sm->heldPeriod,
- sm->authPeriod,
- sm->startPeriod,
- sm->maxStart,
- sm->suppPortStatus == Authorized ?
- "Authorized" : "Unauthorized",
- sm->SUPP_BE_state);
- if (os_snprintf_error(buflen, ret))
- return 0;
- len = ret;
- ret = os_snprintf(buf + len, buflen - len,
- "dot1xSuppEapolFramesRx=%u\n"
- "dot1xSuppEapolFramesTx=%u\n"
- "dot1xSuppEapolStartFramesTx=%u\n"
- "dot1xSuppEapolLogoffFramesTx=%u\n"
- "dot1xSuppEapolRespFramesTx=%u\n"
- "dot1xSuppEapolReqIdFramesRx=%u\n"
- "dot1xSuppEapolReqFramesRx=%u\n"
- "dot1xSuppInvalidEapolFramesRx=%u\n"
- "dot1xSuppEapLengthErrorFramesRx=%u\n"
- "dot1xSuppLastEapolFrameVersion=%u\n"
- "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
- sm->dot1xSuppEapolFramesRx,
- sm->dot1xSuppEapolFramesTx,
- sm->dot1xSuppEapolStartFramesTx,
- sm->dot1xSuppEapolLogoffFramesTx,
- sm->dot1xSuppEapolRespFramesTx,
- sm->dot1xSuppEapolReqIdFramesRx,
- sm->dot1xSuppEapolReqFramesRx,
- sm->dot1xSuppInvalidEapolFramesRx,
- sm->dot1xSuppEapLengthErrorFramesRx,
- sm->dot1xSuppLastEapolFrameVersion,
- MAC2STR(sm->dot1xSuppLastEapolFrameSource));
- if (os_snprintf_error(buflen - len, ret))
- return len;
- len += ret;
- return len;
- }
- #endif /* CONFIG_CTRL_IFACE */
- /**
- * eapol_sm_rx_eapol - Process received EAPOL frames
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @src: Source MAC address of the EAPOL packet
- * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
- * @len: Length of the EAPOL frame
- * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
- * -1 failure
- */
- int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
- size_t len)
- {
- const struct ieee802_1x_hdr *hdr;
- const struct ieee802_1x_eapol_key *key;
- int data_len;
- int res = 1;
- size_t plen;
- if (sm == NULL)
- return 0;
- sm->dot1xSuppEapolFramesRx++;
- if (len < sizeof(*hdr)) {
- sm->dot1xSuppInvalidEapolFramesRx++;
- return 0;
- }
- hdr = (const struct ieee802_1x_hdr *) buf;
- sm->dot1xSuppLastEapolFrameVersion = hdr->version;
- os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
- if (hdr->version < EAPOL_VERSION) {
- /* TODO: backwards compatibility */
- }
- plen = be_to_host16(hdr->length);
- if (plen > len - sizeof(*hdr)) {
- sm->dot1xSuppEapLengthErrorFramesRx++;
- return 0;
- }
- #ifdef CONFIG_WPS
- if (sm->conf.wps && sm->conf.workaround &&
- plen < len - sizeof(*hdr) &&
- hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
- len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
- const struct eap_hdr *ehdr =
- (const struct eap_hdr *) (hdr + 1);
- u16 elen;
- elen = be_to_host16(ehdr->length);
- if (elen > plen && elen <= len - sizeof(*hdr)) {
- /*
- * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
- * packets with too short EAPOL header length field
- * (14 octets). This is fixed in firmware Ver.1.49.
- * As a workaround, fix the EAPOL header based on the
- * correct length in the EAP packet.
- */
- wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
- "payload length based on EAP header: "
- "%d -> %d", (int) plen, elen);
- plen = elen;
- }
- }
- #endif /* CONFIG_WPS */
- data_len = plen + sizeof(*hdr);
- switch (hdr->type) {
- case IEEE802_1X_TYPE_EAP_PACKET:
- if (sm->conf.workaround) {
- /*
- * An AP has been reported to send out EAP message with
- * undocumented code 10 at some point near the
- * completion of EAP authentication. This can result in
- * issues with the unexpected EAP message triggering
- * restart of EAPOL authentication. Avoid this by
- * skipping the message without advancing the state
- * machine.
- */
- const struct eap_hdr *ehdr =
- (const struct eap_hdr *) (hdr + 1);
- if (plen >= sizeof(*ehdr) && ehdr->code == 10) {
- wpa_printf(MSG_DEBUG, "EAPOL: Ignore EAP packet with unknown code 10");
- break;
- }
- }
- if (sm->cached_pmk) {
- /* Trying to use PMKSA caching, but Authenticator did
- * not seem to have a matching entry. Need to restart
- * EAPOL state machines.
- */
- eapol_sm_abort_cached(sm);
- }
- wpabuf_free(sm->eapReqData);
- sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
- if (sm->eapReqData) {
- wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
- "frame");
- sm->eapolEap = TRUE;
- #ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
- eap_proxy_packet_update(
- sm->eap_proxy,
- wpabuf_mhead_u8(sm->eapReqData),
- wpabuf_len(sm->eapReqData));
- wpa_printf(MSG_DEBUG, "EAPOL: eap_proxy "
- "EAP Req updated");
- }
- #endif /* CONFIG_EAP_PROXY */
- eapol_sm_step(sm);
- }
- break;
- case IEEE802_1X_TYPE_EAPOL_KEY:
- if (plen < sizeof(*key)) {
- wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
- "frame received");
- break;
- }
- key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
- if (key->type == EAPOL_KEY_TYPE_WPA ||
- key->type == EAPOL_KEY_TYPE_RSN) {
- /* WPA Supplicant takes care of this frame. */
- wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
- "frame in EAPOL state machines");
- res = 0;
- break;
- }
- if (key->type != EAPOL_KEY_TYPE_RC4) {
- wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
- "EAPOL-Key type %d", key->type);
- break;
- }
- os_free(sm->last_rx_key);
- sm->last_rx_key = os_malloc(data_len);
- if (sm->last_rx_key) {
- wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
- "frame");
- os_memcpy(sm->last_rx_key, buf, data_len);
- sm->last_rx_key_len = data_len;
- sm->rxKey = TRUE;
- eapol_sm_step(sm);
- }
- break;
- #ifdef CONFIG_MACSEC
- case IEEE802_1X_TYPE_EAPOL_MKA:
- wpa_printf(MSG_EXCESSIVE,
- "EAPOL type %d will be handled by MKA",
- hdr->type);
- break;
- #endif /* CONFIG_MACSEC */
- default:
- wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
- hdr->type);
- sm->dot1xSuppInvalidEapolFramesRx++;
- break;
- }
- return res;
- }
- /**
- * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machine about transmitted EAPOL packet from an external
- * component, e.g., WPA. This will update the statistics.
- */
- void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
- {
- if (sm)
- sm->dot1xSuppEapolFramesTx++;
- }
- /**
- * eapol_sm_notify_portEnabled - Notification about portEnabled change
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @enabled: New portEnabled value
- *
- * Notify EAPOL state machine about new portEnabled value.
- */
- void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
- "portEnabled=%d", enabled);
- if (sm->portEnabled != enabled)
- sm->force_authorized_update = TRUE;
- sm->portEnabled = enabled;
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_notify_portValid - Notification about portValid change
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @valid: New portValid value
- *
- * Notify EAPOL state machine about new portValid value.
- */
- void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
- "portValid=%d", valid);
- sm->portValid = valid;
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_notify_eap_success - Notification of external EAP success trigger
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @success: %TRUE = set success, %FALSE = clear success
- *
- * Notify the EAPOL state machine that external event has forced EAP state to
- * success (success = %TRUE). This can be cleared by setting success = %FALSE.
- *
- * This function is called to update EAP state when WPA-PSK key handshake has
- * been completed successfully since WPA-PSK does not use EAP state machine.
- */
- void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
- "EAP success=%d", success);
- sm->eapSuccess = success;
- sm->altAccept = success;
- if (success)
- eap_notify_success(sm->eap);
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @fail: %TRUE = set failure, %FALSE = clear failure
- *
- * Notify EAPOL state machine that external event has forced EAP state to
- * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
- */
- void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
- "EAP fail=%d", fail);
- sm->eapFail = fail;
- sm->altReject = fail;
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_notify_config - Notification of EAPOL configuration change
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @config: Pointer to current network EAP configuration
- * @conf: Pointer to EAPOL configuration data
- *
- * Notify EAPOL state machine that configuration has changed. config will be
- * stored as a backpointer to network configuration. This can be %NULL to clear
- * the stored pointed. conf will be copied to local EAPOL/EAP configuration
- * data. If conf is %NULL, this part of the configuration change will be
- * skipped.
- */
- void eapol_sm_notify_config(struct eapol_sm *sm,
- struct eap_peer_config *config,
- const struct eapol_config *conf)
- {
- if (sm == NULL)
- return;
- sm->config = config;
- #ifdef CONFIG_EAP_PROXY
- sm->use_eap_proxy = eap_proxy_notify_config(sm->eap_proxy, config) > 0;
- #endif /* CONFIG_EAP_PROXY */
- if (conf == NULL)
- return;
- sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
- sm->conf.required_keys = conf->required_keys;
- sm->conf.fast_reauth = conf->fast_reauth;
- sm->conf.workaround = conf->workaround;
- sm->conf.wps = conf->wps;
- #ifdef CONFIG_EAP_PROXY
- if (sm->use_eap_proxy) {
- /* Using EAP Proxy, so skip EAP state machine update */
- return;
- }
- #endif /* CONFIG_EAP_PROXY */
- if (sm->eap) {
- eap_set_fast_reauth(sm->eap, conf->fast_reauth);
- eap_set_workaround(sm->eap, conf->workaround);
- eap_set_force_disabled(sm->eap, conf->eap_disabled);
- eap_set_external_sim(sm->eap, conf->external_sim);
- }
- }
- /**
- * eapol_sm_get_key - Get master session key (MSK) from EAP
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @key: Pointer for key buffer
- * @len: Number of bytes to copy to key
- * Returns: 0 on success (len of key available), maximum available key len
- * (>0) if key is available but it is shorter than len, or -1 on failure.
- *
- * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
- * is available only after a successful authentication.
- */
- int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
- {
- const u8 *eap_key;
- size_t eap_len;
- #ifdef CONFIG_EAP_PROXY
- if (sm && sm->use_eap_proxy) {
- /* Get key from EAP proxy */
- if (sm == NULL || !eap_proxy_key_available(sm->eap_proxy)) {
- wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
- return -1;
- }
- eap_key = eap_proxy_get_eapKeyData(sm->eap_proxy, &eap_len);
- if (eap_key == NULL) {
- wpa_printf(MSG_DEBUG, "EAPOL: Failed to get "
- "eapKeyData");
- return -1;
- }
- goto key_fetched;
- }
- #endif /* CONFIG_EAP_PROXY */
- if (sm == NULL || !eap_key_available(sm->eap)) {
- wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
- return -1;
- }
- eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
- if (eap_key == NULL) {
- wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
- return -1;
- }
- #ifdef CONFIG_EAP_PROXY
- key_fetched:
- #endif /* CONFIG_EAP_PROXY */
- if (len > eap_len) {
- wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
- "available (len=%lu)",
- (unsigned long) len, (unsigned long) eap_len);
- return eap_len;
- }
- os_memcpy(key, eap_key, len);
- wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
- (unsigned long) len);
- return 0;
- }
- /**
- * eapol_sm_get_session_id - Get EAP Session-Id
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @len: Pointer to variable that will be set to number of bytes in the session
- * Returns: Pointer to the EAP Session-Id or %NULL on failure
- *
- * The Session-Id is available only after a successful authentication.
- */
- const u8 * eapol_sm_get_session_id(struct eapol_sm *sm, size_t *len)
- {
- if (sm == NULL || !eap_key_available(sm->eap)) {
- wpa_printf(MSG_DEBUG, "EAPOL: EAP Session-Id not available");
- return NULL;
- }
- return eap_get_eapSessionId(sm->eap, len);
- }
- /**
- * eapol_sm_notify_logoff - Notification of logon/logoff commands
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @logoff: Whether command was logoff
- *
- * Notify EAPOL state machines that user requested logon/logoff.
- */
- void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
- {
- if (sm) {
- sm->userLogoff = logoff;
- if (!logoff) {
- /* If there is a delayed txStart queued, start now. */
- sm->startWhen = 0;
- }
- eapol_sm_step(sm);
- }
- }
- /**
- * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines that PMKSA caching was successful. This is used
- * to move EAPOL and EAP state machines into authenticated/successful state.
- */
- void eapol_sm_notify_cached(struct eapol_sm *sm)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
- sm->eapSuccess = TRUE;
- eap_notify_success(sm->eap);
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines if PMKSA caching is used.
- */
- void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
- sm->cached_pmk = TRUE;
- }
- static void eapol_sm_abort_cached(struct eapol_sm *sm)
- {
- wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
- "doing full EAP authentication");
- if (sm == NULL)
- return;
- sm->cached_pmk = FALSE;
- sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
- eapol_sm_set_port_unauthorized(sm);
- /* Make sure we do not start sending EAPOL-Start frames first, but
- * instead move to RESTART state to start EAPOL authentication. */
- sm->startWhen = 3;
- eapol_enable_timer_tick(sm);
- if (sm->ctx->aborted_cached)
- sm->ctx->aborted_cached(sm->ctx->ctx);
- }
- /**
- * eapol_sm_register_scard_ctx - Notification of smart card context
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @ctx: Context data for smart card operations
- *
- * Notify EAPOL state machines of context data for smart card operations. This
- * context data will be used as a parameter for scard_*() functions.
- */
- void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
- {
- if (sm) {
- sm->ctx->scard_ctx = ctx;
- eap_register_scard_ctx(sm->eap, ctx);
- }
- }
- /**
- * eapol_sm_notify_portControl - Notification of portControl changes
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @portControl: New value for portControl variable
- *
- * Notify EAPOL state machines that portControl variable has changed.
- */
- void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
- {
- if (sm == NULL)
- return;
- wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
- "portControl=%s", eapol_port_control(portControl));
- sm->portControl = portControl;
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_notify_ctrl_attached - Notification of attached monitor
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines that a monitor was attached to the control
- * interface to trigger re-sending of pending requests for user input.
- */
- void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
- {
- if (sm == NULL)
- return;
- eap_sm_notify_ctrl_attached(sm->eap);
- }
- /**
- * eapol_sm_notify_ctrl_response - Notification of received user input
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Notify EAPOL state machines that a control response, i.e., user
- * input, was received in order to trigger retrying of a pending EAP request.
- */
- void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
- {
- if (sm == NULL)
- return;
- if (sm->eapReqData && !sm->eapReq) {
- wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
- "input) notification - retrying pending EAP "
- "Request");
- sm->eapolEap = TRUE;
- sm->eapReq = TRUE;
- eapol_sm_step(sm);
- }
- }
- /**
- * eapol_sm_request_reauth - Request reauthentication
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * This function can be used to request EAPOL reauthentication, e.g., when the
- * current PMKSA entry is nearing expiration.
- */
- void eapol_sm_request_reauth(struct eapol_sm *sm)
- {
- if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
- return;
- eapol_sm_txStart(sm);
- }
- /**
- * eapol_sm_notify_lower_layer_success - Notification of lower layer success
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- * @in_eapol_sm: Whether the caller is already running inside EAPOL state
- * machine loop (eapol_sm_step())
- *
- * Notify EAPOL (and EAP) state machines that a lower layer has detected a
- * successful authentication. This is used to recover from dropped EAP-Success
- * messages.
- */
- void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
- {
- if (sm == NULL)
- return;
- eap_notify_lower_layer_success(sm->eap);
- if (!in_eapol_sm)
- eapol_sm_step(sm);
- }
- /**
- * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- */
- void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
- {
- if (sm)
- eap_invalidate_cached_session(sm->eap);
- }
- static struct eap_peer_config * eapol_sm_get_config(void *ctx)
- {
- struct eapol_sm *sm = ctx;
- return sm ? sm->config : NULL;
- }
- static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
- {
- struct eapol_sm *sm = ctx;
- if (sm == NULL || sm->eapReqData == NULL)
- return NULL;
- return sm->eapReqData;
- }
- static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
- {
- struct eapol_sm *sm = ctx;
- if (sm == NULL)
- return FALSE;
- switch (variable) {
- case EAPOL_eapSuccess:
- return sm->eapSuccess;
- case EAPOL_eapRestart:
- return sm->eapRestart;
- case EAPOL_eapFail:
- return sm->eapFail;
- case EAPOL_eapResp:
- return sm->eapResp;
- case EAPOL_eapNoResp:
- return sm->eapNoResp;
- case EAPOL_eapReq:
- return sm->eapReq;
- case EAPOL_portEnabled:
- return sm->portEnabled;
- case EAPOL_altAccept:
- return sm->altAccept;
- case EAPOL_altReject:
- return sm->altReject;
- case EAPOL_eapTriggerStart:
- return sm->eapTriggerStart;
- }
- return FALSE;
- }
- static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
- Boolean value)
- {
- struct eapol_sm *sm = ctx;
- if (sm == NULL)
- return;
- switch (variable) {
- case EAPOL_eapSuccess:
- sm->eapSuccess = value;
- break;
- case EAPOL_eapRestart:
- sm->eapRestart = value;
- break;
- case EAPOL_eapFail:
- sm->eapFail = value;
- break;
- case EAPOL_eapResp:
- sm->eapResp = value;
- break;
- case EAPOL_eapNoResp:
- sm->eapNoResp = value;
- break;
- case EAPOL_eapReq:
- sm->eapReq = value;
- break;
- case EAPOL_portEnabled:
- sm->portEnabled = value;
- break;
- case EAPOL_altAccept:
- sm->altAccept = value;
- break;
- case EAPOL_altReject:
- sm->altReject = value;
- break;
- case EAPOL_eapTriggerStart:
- sm->eapTriggerStart = value;
- break;
- }
- }
- static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
- {
- struct eapol_sm *sm = ctx;
- if (sm == NULL)
- return 0;
- switch (variable) {
- case EAPOL_idleWhile:
- return sm->idleWhile;
- }
- return 0;
- }
- static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
- unsigned int value)
- {
- struct eapol_sm *sm = ctx;
- if (sm == NULL)
- return;
- switch (variable) {
- case EAPOL_idleWhile:
- sm->idleWhile = value;
- if (sm->idleWhile > 0)
- eapol_enable_timer_tick(sm);
- break;
- }
- }
- static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
- {
- #ifndef CONFIG_NO_CONFIG_BLOBS
- struct eapol_sm *sm = ctx;
- if (sm && sm->ctx && sm->ctx->set_config_blob)
- sm->ctx->set_config_blob(sm->ctx->ctx, blob);
- #endif /* CONFIG_NO_CONFIG_BLOBS */
- }
- static const struct wpa_config_blob *
- eapol_sm_get_config_blob(void *ctx, const char *name)
- {
- #ifndef CONFIG_NO_CONFIG_BLOBS
- struct eapol_sm *sm = ctx;
- if (sm && sm->ctx && sm->ctx->get_config_blob)
- return sm->ctx->get_config_blob(sm->ctx->ctx, name);
- else
- return NULL;
- #else /* CONFIG_NO_CONFIG_BLOBS */
- return NULL;
- #endif /* CONFIG_NO_CONFIG_BLOBS */
- }
- static void eapol_sm_notify_pending(void *ctx)
- {
- struct eapol_sm *sm = ctx;
- if (sm == NULL)
- return;
- if (sm->eapReqData && !sm->eapReq) {
- wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
- "state machine - retrying pending EAP Request");
- sm->eapolEap = TRUE;
- sm->eapReq = TRUE;
- eapol_sm_step(sm);
- }
- }
- #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
- static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
- const char *txt)
- {
- struct eapol_sm *sm = ctx;
- wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
- if (sm->ctx->eap_param_needed)
- sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
- }
- #else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
- #define eapol_sm_eap_param_needed NULL
- #endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
- static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
- const char *altsubject[],
- int num_altsubject, const char *cert_hash,
- const struct wpabuf *cert)
- {
- struct eapol_sm *sm = ctx;
- if (sm->ctx->cert_cb)
- sm->ctx->cert_cb(sm->ctx->ctx, depth, subject, altsubject,
- num_altsubject, cert_hash, cert);
- }
- static void eapol_sm_notify_status(void *ctx, const char *status,
- const char *parameter)
- {
- struct eapol_sm *sm = ctx;
- if (sm->ctx->status_cb)
- sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
- }
- static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
- {
- struct eapol_sm *sm = ctx;
- if (sm->ctx->set_anon_id)
- sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
- }
- static struct eapol_callbacks eapol_cb =
- {
- eapol_sm_get_config,
- eapol_sm_get_bool,
- eapol_sm_set_bool,
- eapol_sm_get_int,
- eapol_sm_set_int,
- eapol_sm_get_eapReqData,
- eapol_sm_set_config_blob,
- eapol_sm_get_config_blob,
- eapol_sm_notify_pending,
- eapol_sm_eap_param_needed,
- eapol_sm_notify_cert,
- eapol_sm_notify_status,
- eapol_sm_set_anon_id
- };
- /**
- * eapol_sm_init - Initialize EAPOL state machine
- * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
- * and EAPOL state machine will free it in eapol_sm_deinit()
- * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
- *
- * Allocate and initialize an EAPOL state machine.
- */
- struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
- {
- struct eapol_sm *sm;
- struct eap_config conf;
- sm = os_zalloc(sizeof(*sm));
- if (sm == NULL)
- return NULL;
- sm->ctx = ctx;
- sm->portControl = Auto;
- /* Supplicant PAE state machine */
- sm->heldPeriod = 60;
- sm->startPeriod = 30;
- sm->maxStart = 3;
- /* Supplicant Backend state machine */
- sm->authPeriod = 30;
- os_memset(&conf, 0, sizeof(conf));
- conf.opensc_engine_path = ctx->opensc_engine_path;
- conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
- conf.pkcs11_module_path = ctx->pkcs11_module_path;
- conf.openssl_ciphers = ctx->openssl_ciphers;
- conf.wps = ctx->wps;
- conf.cert_in_cb = ctx->cert_in_cb;
- sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
- if (sm->eap == NULL) {
- os_free(sm);
- return NULL;
- }
- #ifdef CONFIG_EAP_PROXY
- sm->use_eap_proxy = FALSE;
- sm->eap_proxy = eap_proxy_init(sm, &eapol_cb, sm->ctx->msg_ctx);
- if (sm->eap_proxy == NULL) {
- wpa_printf(MSG_ERROR, "Unable to initialize EAP Proxy");
- }
- #endif /* CONFIG_EAP_PROXY */
- /* Initialize EAPOL state machines */
- sm->force_authorized_update = TRUE;
- sm->initialize = TRUE;
- eapol_sm_step(sm);
- sm->initialize = FALSE;
- eapol_sm_step(sm);
- sm->timer_tick_enabled = 1;
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
- return sm;
- }
- /**
- * eapol_sm_deinit - Deinitialize EAPOL state machine
- * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
- *
- * Deinitialize and free EAPOL state machine.
- */
- void eapol_sm_deinit(struct eapol_sm *sm)
- {
- if (sm == NULL)
- return;
- eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
- eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
- eap_peer_sm_deinit(sm->eap);
- #ifdef CONFIG_EAP_PROXY
- eap_proxy_deinit(sm->eap_proxy);
- #endif /* CONFIG_EAP_PROXY */
- os_free(sm->last_rx_key);
- wpabuf_free(sm->eapReqData);
- os_free(sm->ctx);
- os_free(sm);
- }
- void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
- struct ext_password_data *ext)
- {
- if (sm && sm->eap)
- eap_sm_set_ext_pw_ctx(sm->eap, ext);
- }
- int eapol_sm_failed(struct eapol_sm *sm)
- {
- if (sm == NULL)
- return 0;
- return !sm->eapSuccess && sm->eapFail;
- }
- int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len)
- {
- #ifdef CONFIG_EAP_PROXY
- if (sm->eap_proxy == NULL)
- return -1;
- return eap_proxy_get_imsi(sm->eap_proxy, imsi, len);
- #else /* CONFIG_EAP_PROXY */
- return -1;
- #endif /* CONFIG_EAP_PROXY */
- }
- void eapol_sm_erp_flush(struct eapol_sm *sm)
- {
- if (sm)
- eap_peer_erp_free_keys(sm->eap);
- }
|