/* * fsm.cc - Self explanitory * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: fsm.cc,v 1.1 2004/03/11 03:59:31 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include "fsm.h" #include "config.h" extern void DialReport(DialResponse_t *); const char *fsmStateName[] = { "INITIAL", "STARTING", "CLOSED", "STOPPED", "CLOSING", "STOPPING", "REQSENT", "ACKRCVD", "ACKSENT", "OPENED" }; ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CFsmProtocol::CFsmProtocol() : CTimedProtocol() { DebugEnter("CFsmProtocol::CFsmProtocol()"); state = ST_INITIAL; cntConfig = cntTerminate = 0; maxConfig = 10; maxTerminate = 2; cntFailure = maxFailure = 5; m_restartTime = 3; modePassive = modeRestart = 0; DebugVoidReturn; } CFsmProtocol::~CFsmProtocol() { } /* * CFsmProtocol::Up() - The lower layer has come up */ void CFsmProtocol::Up() { Log(LF_DEBUG|LF_STATE, "Got FSA event [Up]"); switch (state) { case ST_INITIAL: SetState(ST_CLOSED); DisableTimer(); break; case ST_STARTING: SetState(ST_REQSENT); EnableTimer(); cntFailure = maxFailure = 5; InitRestartCount(); SndConfReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> Up!", m_protocolName, fsmStateName[state]); break; } } /* * CFsmProtocol::Down() - The lower layer has gone down */ void CFsmProtocol::Down() { Log(LF_DEBUG|LF_STATE, "Got FSA event [Down], current state[%s]", fsmStateName[state]); switch(state) { case ST_CLOSED: SetState(ST_INITIAL); DisableTimer(); break; case ST_STOPPED: SetState(ST_STARTING); DisableTimer(); ThisLayerStarted(); break; case ST_CLOSING: SetState(ST_INITIAL); DisableTimer(); break; case ST_STOPPING: case ST_REQSENT: case ST_ACKRCVD: case ST_ACKSENT: SetState(ST_STARTING); DisableTimer(); break; case ST_OPENED: SetState(ST_STARTING); DisableTimer(); ThisLayerDown(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> Down!", m_protocolName, fsmStateName[state]); } } /* * CFsmProtocol::Open() - The state machine has been opened */ void CFsmProtocol::Open() { Log(LF_DEBUG|LF_STATE, "Got FSA event [Open]"); switch(state) { case ST_INITIAL: SetState(ST_STARTING); DisableTimer(); ThisLayerStarted(); break; case ST_STARTING: break; case ST_CLOSED: SetState(ST_REQSENT); EnableTimer(); InitRestartCount(); SndConfReq(); break; case ST_STOPPED: case ST_STOPPING: case ST_OPENED: // Restart option as suggested in RFC 1661 if(modeRestart) { Down(); Up(); } break; case ST_CLOSING: SetState(ST_STOPPING); EnableTimer(); // Restart option as suggested in RFC 1661 if(modeRestart) { Down(); Up(); } break; case ST_REQSENT: case ST_ACKRCVD: case ST_ACKSENT: break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> Open!", m_protocolName, fsmStateName[state]); } } /* * CFsmProtocol::Close() - The state machine has been closed */ void CFsmProtocol::Close(const char *why) { Log(LF_DEBUG|LF_STATE, "Got FSA event [Close]"); #if 0 if (reason) { DialResponse_t dr; dr.call = call; dr.status = status; strcpy(dr.msg, reason); DialReport(&dr); } #endif switch(state) { case ST_INITIAL: case ST_CLOSED: case ST_CLOSING: break; case ST_STARTING: SetState(ST_INITIAL); DisableTimer(); ThisLayerFinished(why); break; case ST_STOPPED: SetState(ST_CLOSED); DisableTimer(); break; case ST_STOPPING: SetState(ST_CLOSING); EnableTimer(); break; case ST_REQSENT: case ST_ACKRCVD: case ST_ACKSENT: SetState(ST_CLOSING); EnableTimer(); InitRestartCount(); SndTermReq(); break; case ST_OPENED: SetState(ST_CLOSING); EnableTimer(); ThisLayerDown(); InitRestartCount(); SndTermReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> Close!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::TimerExpired() { DebugEnter("CFsmProtocol::TimerExpired()"); if(!cntTerminate || !cntFailure || !cntConfig) { Expire(); DebugVoidReturn; } Log(LF_DEBUG|LF_STATE, "Got FSA event [TO+]"); switch(state) { case ST_CLOSING: case ST_STOPPING: SndTermReq(); EnableTimer(); break; case ST_REQSENT: case ST_ACKSENT: EnableTimer(); SndConfReq(); break; case ST_ACKRCVD: SetState(ST_REQSENT); EnableTimer(); SndConfReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> TimerExpired!", m_protocolName, fsmStateName[state]); } DebugVoidReturn; } void CFsmProtocol::Expire() { Log(LF_DEBUG|LF_STATE, "Got FSA event [TO-]"); switch(state) { case ST_CLOSING: SetState(ST_CLOSED); DisableTimer(); ThisLayerFinished("timed out"); break; case ST_STOPPING: SetState(ST_STOPPED); DisableTimer(); ThisLayerFinished("timed out"); break; case ST_REQSENT: case ST_ACKSENT: case ST_ACKRCVD: SetState(ST_STOPPED); DisableTimer(); ThisLayerFinished("timed out"); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> Expire!", m_protocolName, fsmStateName[state]); } } void CFsmProtocol::RcvGoodConfReq() { Log(LF_DEBUG|LF_STATE, "Got FSA event [RCR+]"); switch(state) { case ST_CLOSED: SndTermAck(); break; case ST_STOPPED: SetState(ST_ACKSENT); EnableTimer(); InitRestartCount(); SndConfReq(); SndConfAck(); break; case ST_CLOSING: case ST_STOPPING: break; case ST_REQSENT: SetState(ST_ACKSENT); EnableTimer(); SndConfAck(); break; case ST_ACKRCVD: SetState(ST_OPENED); DisableTimer(); SndConfAck(); ThisLayerUp(); /* must be after SndConfAck, as it triggers other layers to begin sending packets */ break; case ST_ACKSENT: SetState(ST_ACKSENT); EnableTimer(); SndConfAck(); break; case ST_OPENED: SetState(ST_ACKSENT); EnableTimer(); ThisLayerDown(); SndConfReq(); SndConfAck(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvGoodConfReq!", m_protocolName, fsmStateName[state]); } } void CFsmProtocol::RcvBadConfReq() { Log(LF_DEBUG|LF_STATE, "Got FSA event [RCR-]"); if(!cntFailure) { Log(LF_DEBUG|LF_PROTO, "FSA exceed maxFailure(%d)", maxFailure); ThisLayerDown(); DebugVoidReturn; } if (cntFailure) cntFailure--; switch(state) { case ST_CLOSED: SndTermAck(); break; case ST_STOPPED: SetState(ST_REQSENT); EnableTimer(); InitRestartCount(); SndConfReq(); SndConfNak(); break; case ST_CLOSING: case ST_STOPPING: break; case ST_REQSENT: case ST_ACKRCVD: SndConfNak(); break; case ST_ACKSENT: SetState(ST_REQSENT); EnableTimer(); SndConfNak(); break; case ST_OPENED: SetState(ST_REQSENT); EnableTimer(); ThisLayerDown(); SndConfReq(); SndConfNak(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvBadConfReq!", m_protocolName, fsmStateName[state]); } } void CFsmProtocol::RcvConfAck(CPppPacket *pkt) { if(pkt == pkt); // Suppress warning Log(LF_INFO|LF_STATE, "Got FSA event [RCA]"); switch(state) { case ST_CLOSED: case ST_STOPPED: SndTermAck(); break; case ST_CLOSING: case ST_STOPPING: break; case ST_REQSENT: SetState(ST_ACKRCVD); EnableTimer(); InitRestartCount(); break; case ST_ACKRCVD: SetState(ST_REQSENT); EnableTimer(); SndConfReq(); break; case ST_ACKSENT: SetState(ST_OPENED); DisableTimer(); InitRestartCount(); ThisLayerUp(); break; case ST_OPENED: SetState(ST_REQSENT); EnableTimer(); ThisLayerDown(); SndConfReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvConfAck!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::RcvConfNak(CPppPacket *pkt) { if(pkt == pkt); // Suppress warning Log(LF_INFO|LF_STATE, "Got FSA event [RCN]"); switch(state) { case ST_CLOSED: case ST_STOPPED: SndTermAck(); break; case ST_CLOSING: case ST_STOPPING: break; case ST_REQSENT: InitRestartCount(); EnableTimer(); SndConfReq(); break; case ST_ACKRCVD: SetState(ST_REQSENT); EnableTimer(); SndConfReq(); break; case ST_ACKSENT: InitRestartCount(); EnableTimer(); SndConfReq(); break; case ST_OPENED: SetState(ST_REQSENT); EnableTimer(); ThisLayerDown(); SndConfReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvConfNak!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::RcvTermReq() { Log(LF_INFO|LF_STATE, "Got FSA event [RTR]"); switch(state) { case ST_CLOSED: case ST_STOPPED: case ST_CLOSING: case ST_STOPPING: case ST_REQSENT: SndTermAck(); break; case ST_ACKRCVD: case ST_ACKSENT: SetState(ST_REQSENT); EnableTimer(); SndTermAck(); break; case ST_OPENED: SetState(ST_STOPPING); EnableTimer(); ThisLayerDown(); ZeroRestartCount(); SndTermAck(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvTermReq!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::RcvTermAck() { Log(LF_INFO|LF_STATE, "Got FSA event [RTA]"); switch(state) { case ST_CLOSED: case ST_STOPPED: case ST_REQSENT: case ST_ACKSENT: break; case ST_CLOSING: SetState(ST_CLOSED); DisableTimer(); ThisLayerFinished("terminate requested"); break; case ST_STOPPING: SetState(ST_STOPPED); DisableTimer(); ThisLayerFinished("terminate requested"); break; case ST_ACKRCVD: SetState(ST_REQSENT); EnableTimer(); break; case ST_OPENED: SetState(ST_REQSENT); EnableTimer(); ThisLayerDown(); SndConfReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvTermAck!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::RcvUnknownCode(CPppPacket *pkt) { Log(LF_DEBUG|LF_STATE, "Got FSA event [RUC]"); switch(state) { case ST_CLOSED: case ST_STOPPED: case ST_CLOSING: case ST_STOPPING: case ST_REQSENT: case ST_ACKRCVD: case ST_ACKSENT: case ST_OPENED: SndCodeReject(pkt); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvUnknownCode!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::RcvCodeReject(CPppPacket *pkt) { if(pkt == pkt); // Supress warning Log(LF_INFO|LF_STATE, "Got FSA event [RXJ+]"); switch(state) { case ST_CLOSED: case ST_STOPPED: case ST_CLOSING: case ST_STOPPING: case ST_REQSENT: case ST_ACKSENT: case ST_OPENED: break; case ST_ACKRCVD: SetState(ST_REQSENT); EnableTimer(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvCodeReject!", m_protocolName, fsmStateName[state]); } } /* * */ void CFsmProtocol::RcvFatalReject() { Log(LF_INFO|LF_STATE, "Got FSA event [RXJ-]"); switch(state) { case ST_CLOSING: SetState(ST_CLOSED); DisableTimer(); ThisLayerFinished("received fatal reject"); break; case ST_CLOSED: DisableTimer(); ThisLayerFinished("received fatal reject"); break; case ST_STOPPED: DisableTimer(); ThisLayerFinished("received fatal reject"); break; case ST_STOPPING: case ST_REQSENT: case ST_ACKRCVD: case ST_ACKSENT: SetState(ST_STOPPED); DisableTimer(); ThisLayerFinished("received fatal reject"); break; case ST_OPENED: SetState(ST_STOPPING); EnableTimer(); ThisLayerDown(); InitRestartCount(); SndTermReq(); break; default: Log(LF_WARN|LF_STATE, "%s: FSA Invalid state transtition %s -> RcvFatalReject!", m_protocolName, fsmStateName[state]); } } void CFsmProtocol::RcvEchoReq(CPppPacket *pkt) { switch(state) { case ST_OPENED: SndEchoReply(pkt); default: break; } }