📄 layerfsm.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
//
// PPP Protocol Layer Finite State Machine Implementation Module
//
#include "windows.h"
#include "types.h"
#include "protocol.h"
#include "ppp.h"
#include "raserror.h"
#include "layerfsm.h"
#include "debug.h"
#define MALLOC(size) LocalAlloc(LPTR, (size))
#define FREE(ptr) LocalFree(ptr)
void PppFsmStartTimer(PPppFsm pFsm, ULONG timeInMilliseconds);
void PppFsmNewState(IN OUT PPppFsm pFsm, IN PppFsmState newState);
#ifdef DEBUG
PSTR g_szStateName[] =
{
"Initial",
"Starting",
"Closed",
"Stopped",
"Closing",
"Stopping",
"Request-Sent",
"Ack-Received",
"Ack-Sent",
"Opened"
};
#endif
void
PppFsmActionTLU(
IN OUT PPppFsm pFsm)
//
// This-Layer-Up
//
// This action indicates to the upper layers that the automaton is
// entering the Opened state.
//
{
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionTLU %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFsm->pDescriptor->ThisLayerUpCb(pFsm->CbContext);
}
void
PppFsmActionTLD(
IN OUT PPppFsm pFsm)
//
// This-Layer-Down
//
// This action indicates to the upper layers that the automaton is
// leaving the Opened state.
//
{
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionTLD %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFsm->pDescriptor->ThisLayerDownCb(pFsm->CbContext);
}
void
PppFsmActionTLS(
IN OUT PPppFsm pFsm)
//
// This-Layer-Started
//
// This action indicates to the lower layers that the automaton is
// entering the Starting state, and the lower layer is needed for the
// link. The lower layer SHOULD respond with an Up event when the lower
// layer is available.
//
{
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionTLS %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFsm->pDescriptor->ThisLayerStartedCb(pFsm->CbContext);
}
void
PppFsmActionTLF(
IN OUT PPppFsm pFsm)
//
// This-Layer-Finished
//
// This action indicates to the lower layers that the automaton is
// entering the Initial, Closed, or Stopped states, and the lower
// layer is no longer needed for the link. The lower layer SHOULD
// respond with a Down event when the lower layer has terminated.
//
{
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionTLF %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFsm->pDescriptor->ThisLayerFinishedCb(pFsm->CbContext);
}
#ifdef DEBUG
PSTR
PacketCodeName(
IN PPppFsm pFsm,
IN BYTE code)
{
PPppFsmExtensionMessageDescriptor pMsgDescriptor;
switch(code)
{
case PPP_CONFIGURE_REQUEST: return "CR";
case PPP_CONFIGURE_ACK: return "ACK";
case PPP_CONFIGURE_NAK: return "NAK";
case PPP_CONFIGURE_REJ: return "REJ";
case PPP_TERMINATE_REQUEST: return "TERM-REQ";
case PPP_TERMINATE_ACK: return "TERM-ACK";
case PPP_CODE_REJECT: return "CODE-REJ";
default:
pMsgDescriptor = pFsm->pDescriptor->pExtensionMessageDescriptors;
if (pMsgDescriptor)
{
while (TRUE)
{
if (pMsgDescriptor->MessageRxCb == NULL)
{
// Didn't find a matching handler
pMsgDescriptor = NULL;
break;
}
if (pMsgDescriptor->code == code)
break;
pMsgDescriptor++;
}
}
if (pMsgDescriptor)
return pMsgDescriptor->szName;
else
return "???";
}
}
void
PppFsmDebugShowPacket(
IN PPppFsm pFsm,
IN PSTR szTxOrRx,
IN PBYTE pPacket,
IN DWORD cbPacket)
{
char buffer[512];
BYTE type = pPacket[0];
sprintf(buffer, "%s %s %-3s ID=%u", szTxOrRx, pFsm->pDescriptor->szProtocolName, PacketCodeName(pFsm, type), pPacket[1]);
if (PPP_CONFIGURE_REQUEST <= type && type <= PPP_CONFIGURE_REJ)
OptionDebugAppendOptionList(&pFsm->optionContext, &buffer[0], pPacket + 4, cbPacket - 4);
DEBUGMSG(1, (TEXT("PPP: %hs\n"), &buffer[0]));
}
#endif
DWORD
PppFsmSendPacket(
IN PPppFsm pFsm,
IN PBYTE pPacket,
IN DWORD cbPacket)
{
DWORD dwResult;
#ifdef DEBUG
if (ZONE_TRACE)
PppFsmDebugShowPacket(pFsm, "TX", pPacket, cbPacket);
#endif
dwResult = pFsm->pDescriptor->SendPacketCb(pFsm->CbContext, pFsm->pDescriptor->ProtocolWord, pPacket, cbPacket);
return dwResult;
}
DWORD
PppFsmActionSCR(
IN OUT PPppFsm pFsm)
//
// Called to send a configure-request packet.
//
{
DWORD dwResult,
cbCR;
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionSCR %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
cbCR = pFsm->pDescriptor->cbMaxTxPacket;
dwResult = OptionBuildConfigureRequest(&pFsm->optionContext, pFsm->idTxCR, pFsm->pRequestBuffer, &cbCR);
//
// If we were unable to build the configure request, for example because the
// peer rejected a required option, then just return the error.
// If we built it successfully, send it and start the timer.
//
if (dwResult == NO_ERROR)
{
if (pFsm->dwRestartCount > 0)
pFsm->dwRestartCount--;
pFsm->cbRequestBuffer = cbCR;
pFsm->bmActions |= ACTION_SEND_REQUEST;
PppFsmStartTimer(pFsm, pFsm->dwRestartTimerMs);
}
return dwResult;
}
void
PppFsmActionSTR(
IN OUT PPppFsm pFsm)
//
// Called to send a terminate-request packet.
//
{
PBYTE pFrame = pFsm->pRequestBuffer;
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionSTR %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
if (pFsm->dwRestartCount > 0)
pFsm->dwRestartCount--;
pFrame[0] = PPP_TERMINATE_REQUEST;
pFrame[1] = ++pFsm->idTxTR;
pFrame[2] = 0;
pFrame[3] = 4;
pFsm->cbRequestBuffer = 4;
pFsm->bmActions |= ACTION_SEND_REQUEST;
PppFsmStartTimer(pFsm, pFsm->dwRestartTimerMs);
}
void
PppFsmActionSTA(
IN OUT PPppFsm pFsm,
IN BYTE idTR)
{
PBYTE pFrame = &pFsm->abResponsePacket[0];
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionSTA %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFrame[0] = PPP_TERMINATE_ACK;
pFrame[1] = idTR;
pFrame[2] = 0;
pFrame[3] = 4;
pFsm->cbResponsePacket = 4;
pFsm->bmActions |= ACTION_SEND_RESPONSE;
}
void
PppFsmLockSession(
PPppFsm pFsm)
{
pFsm->pDescriptor->SessionLockCb(pFsm->CbContext);
}
void
PppFsmUnlockSession(
PPppFsm pFsm)
{
pFsm->pDescriptor->SessionUnlockCb(pFsm->CbContext);
}
void
PppFsmTimerExpireCb(
CTETimer *pTimer,
PVOID CbContext)
//
// Called when the timer expires, e.g. due to no response
// received for a terminate-request or a configure-request.
//
{
PPppFsm pFsm = (PPppFsm)CbContext;
PppFsmState curState,
newState;
PppFsmLockSession(pFsm);
//
// Ignore the timer if we have stopped it.
// That is, the timer thread could have fired just as/after we
// stopped it, and we can't prevent it from running,
// so we just have to ignore it.
//
if (pFsm->bTimerRunning)
{
curState = pFsm->state,
newState = pFsm->state;
pFsm->bTimerRunning = FALSE;
DEBUGMSG(ZONE_TRACE, (TEXT("PPP: EV %hs TO%c\n"),
pFsm->pDescriptor->szProtocolName, pFsm->dwRestartCount ? '+' : '-'));
switch(curState)
{
case PFS_Closing:
case PFS_Stopping:
if (pFsm->dwRestartCount > 0)
{
PppFsmActionSTR(pFsm);
}
else
{
newState = curState == PFS_Closing ? PFS_Closed : PFS_Stopped;
}
break;
case PFS_Request_Sent:
case PFS_Ack_Received:
case PFS_Ack_Sent:
if (pFsm->dwRestartCount > 0
&& PppFsmActionSCR(pFsm) == NO_ERROR)
{
if (curState == PFS_Ack_Received)
newState = PFS_Request_Sent;
}
else
{
newState = PFS_Stopped;
}
break;
}
PppFsmNewState(pFsm, newState);
}
PppFsmUnlockSession(pFsm);
}
void
PppFsmStopTimer(
PPppFsm pFsm)
{
if (pFsm->bTimerRunning)
{
CTEStopTimer(&pFsm->timer);
pFsm->bTimerRunning = FALSE;
}
}
void
PppFsmStartTimer(
PPppFsm pFsm,
ULONG timeInMilliseconds)
//
// Per IETF STD51, Section 4.1:
// "Only the Send-Configure-Request, Send-Terminate-Request, and Zero-Restart-Count actions
// start or restart the Restart timer."
//
{
PppFsmStopTimer(pFsm);
CTEStartTimer(&pFsm->timer, timeInMilliseconds, PppFsmTimerExpireCb, (PVOID)pFsm);
pFsm->bTimerRunning = TRUE;
}
PPppFsm
PppFsmNew(
IN PPppFsmDescriptor pDescriptor,
IN OPTION_RESET_PEER_OPT_CB CbResetPeerOptions,
IN PVOID CbContext)
//
// Allocate and initialize a new PppFsm structure.
//
{
PPppFsm pFsm;
DWORD dwRestartTimerSecs = 0;
pFsm = (PPppFsm)MALLOC(sizeof(PppFsm) + pDescriptor->cbMaxTxPacket);
if (pFsm)
{
pFsm->pDescriptor = pDescriptor;
pFsm->CbContext = CbContext;
pFsm->state = PFS_Initial;
pFsm->bTimerRunning = FALSE;
CTEInitTimer(&pFsm->timer);
pFsm->dwRestartTimerMs = DEFAULT_RESTART_TIMER_MS;
pFsm->dwMaxTerminate = DEFAULT_MAX_TERMINATE;
pFsm->dwMaxConfigure = DEFAULT_MAX_CONFIGURE;
pFsm->pRequestBuffer = (PBYTE)(pFsm + 1);
pFsm->idTxCR = 0xFF;
OptionContextInitialize(&pFsm->optionContext, pDescriptor->szProtocolName, CbResetPeerOptions, CbContext);
//
// Read in optional registry overrides for default settings
//
(void) ReadRegistryValues(HKEY_LOCAL_MACHINE, TEXT("Comm\\ppp\\Parms"),
RAS_VALUENAME_MAXCONFIGURE, REG_DWORD, 0, &pFsm->dwMaxConfigure, sizeof(DWORD),
RAS_VALUENAME_MAXTERMINATE, REG_DWORD, 0, &pFsm->dwMaxTerminate, sizeof(DWORD),
RAS_VALUENAME_MAXFAILURE, REG_DWORD, 0, &pFsm->optionContext.dwMaxFailure, sizeof(DWORD),
RAS_VALUENAME_RESTARTTIMER, REG_DWORD, 0, &dwRestartTimerSecs, sizeof(DWORD),
NULL);
if (dwRestartTimerSecs)
pFsm->dwRestartTimerMs = dwRestartTimerSecs * 1000;
}
return pFsm;
}
void
PppFsmDelete(
PPppFsm pFsm)
//
// Free a PppFsm previously created by PppFsmNew.
//
{
if (pFsm)
{
PppFsmStopTimer(pFsm);
OptionContextCleanup(&pFsm->optionContext);
FREE(pFsm);
}
}
DWORD
PppFsmOptionsAdd(
PPppFsm pFsm,
...)
//
// Add options to the list.
// Varargs parameters should be in groups of
// POptionDescriptor, OptionRequireLevel, OptionRequireLevel
// terminated by a NULL POptionDescriptor
//
{
DWORD dwResult = NO_ERROR;
POptionDescriptor pDescriptor;
OptionRequireLevel orlLocal;
OptionRequireLevel orlPeer;
va_list arglist;
va_start(arglist, pFsm);
do
{
pDescriptor = va_arg(arglist, POptionDescriptor);
if (pDescriptor == NULL)
break;
orlLocal = va_arg(arglist, OptionRequireLevel);
orlPeer = va_arg(arglist, OptionRequireLevel);
dwResult = OptionInfoAdd(&pFsm->optionContext, pDescriptor, orlLocal, orlPeer);
} while (dwResult == NO_ERROR);
va_end(arglist);
return dwResult;
}
DWORD
PppFsmOptionsSetORLs(
PPppFsm pFsm,
...)
//
// Set the option require list for a set of options
// Varargs parameters should be in groups of
// Option Type, OptionRequireLevel, OptionRequireLevel
// terminated by a -1 Option Type
//
{
DWORD dwResult = NO_ERROR;
int optionType;
OptionRequireLevel orlLocal;
OptionRequireLevel orlPeer;
va_list arglist;
va_start(arglist, pFsm);
while (TRUE)
{
optionType = va_arg(arglist, int);
if (optionType == -1)
break;
orlLocal = va_arg(arglist, OptionRequireLevel);
orlPeer = va_arg(arglist, OptionRequireLevel);
dwResult = OptionSetORL(&pFsm->optionContext, (BYTE)optionType, orlLocal, orlPeer);
}
va_end(arglist);
return dwResult;
}
void
PppFsmActionIRC(
IN OUT PPppFsm pFsm,
IN DWORD dwMaxTries)
//
// Initialize the restart count.
//
{
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionIRC %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFsm->dwRestartCount = dwMaxTries;
}
PppFsmActionZRC(
IN OUT PPppFsm pFsm)
//
// Zero the restart count.
//
// From IETF STD51:
// "This action enables the FSA to pause before proceeding
// to the desired final state, allowing traffic to be processed by the
// peer. In addition to zeroing the restart counter, the implementation
// MUST set the timeout period to an appropriate value."
//
// When the timer expires, it will be a TO- event because the Restart count is 0.
// This will cause the transition from the Stopping state to the Stopped state.
//
{
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmActionZRC %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
pFsm->dwRestartCount = 0;
PppFsmStartTimer(pFsm, STOP_DELAY_TIME_MS);
}
void
PppFsmNewState(
IN OUT PPppFsm pFsm,
IN PppFsmState newState)
{
PppFsmState curState = pFsm->state;
void (*pDeferredCb)(PPppFsm pFsm) = NULL;
DWORD bmActions;
ASSERT(PFS_Initial <= newState && newState <= PFS_Opened);
ASSERT(PFS_Initial <= pFsm->state && pFsm->state <= PFS_Opened);
if (newState != pFsm->state)
{
//
// Per IETF STD51, Section 4.1:
// "The Restart timer is stopped when transitioning from any state
// where the timer is running to a state where the timer is not running."
//
if (newState <= PFS_Stopped || newState == PFS_Opened)
{
// The timer is not active in these states.
PppFsmStopTimer(pFsm);
}
DEBUGMSG(ZONE_TRACE, (TEXT("PPP: %hs State %hs --> %hs\n"),
pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state], g_szStateName[newState]));
if (newState == PFS_Starting
&& (curState == PFS_Initial || curState == PFS_Stopped))
{
pDeferredCb = PppFsmActionTLS;
}
else if (newState == PFS_Opened)
{
// Transitioning to the Open state - this layer up
pDeferredCb = PppFsmActionTLU;
}
else if ((newState == PFS_Initial || newState == PFS_Closed || newState == PFS_Stopped)
&& (curState != PFS_Initial && curState != PFS_Closed && curState != PFS_Stopped))
{
//
// Transitioning from a state requiring the service of lower layers
// to a state which does not. Inform the lower layers they are no
// longer needed.
//
pDeferredCb = PppFsmActionTLF;
}
pFsm->state = newState;
}
// Process deferred send request and response actions
bmActions = pFsm->bmActions;
pFsm->bmActions = 0;
if (bmActions & ACTION_SEND_REQUEST)
PppFsmSendPacket(pFsm, pFsm->pRequestBuffer, pFsm->cbRequestBuffer);
if (bmActions & ACTION_SEND_RESPONSE)
PppFsmSendPacket(pFsm, pFsm->abResponsePacket, pFsm->cbResponsePacket);
if (pDeferredCb)
pDeferredCb(pFsm);
}
DWORD
PppFsmOpen(
PPppFsm pFsm)
{
DWORD dwResult = NO_ERROR;
PppFsmState newState = pFsm->state;
DEBUGMSG(ZONE_TRACE, (L"PPP: PppFsmOpen %hs State=%hs\n", pFsm->pDescriptor->szProtocolName, g_szStateName[pFsm->state]));
switch(pFsm->state)
{
case PFS_Initial:
newState = PFS_Starting;
break;
case PFS_Closed:
OptionResetNegotiation(&pFsm->optionContext);
PppFsmActionIRC(pFsm, pFsm->dwMaxConfigure);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -