⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 layerfsm.c

📁 WinCE5.0部分核心源码
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// 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 + -