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

📄 option.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 Option Negotiation Implementation
//


//  Include Files

#include "windows.h"
#include "types.h"
#include "layerfsm.h"
#include "debug.h"
#include "raserror.h"

#define MALLOC(size)	LocalAlloc(LPTR, (size))
#define FREE(ptr)		LocalFree(ptr)

void
OptionContextInitialize(
	POptionContext				pContext,
	PSTR						szProtocolName,
	OPTION_RESET_PEER_OPT_CB	CbResetPeerOptions,
	PVOID						CbContext)
//
//	Initialize an option negotiation context structure.
//
{
	pContext->szProtocolName = szProtocolName;
	pContext->pOptionList = NULL;
	pContext->CbResetPeerOptions = CbResetPeerOptions;
	pContext->CbContext = CbContext;
	pContext->dwMaxFailure = DEFAULT_MAX_FAILURE;	
	pContext->dwConsecutiveFailureCount = 0;	
}

void
OptionContextCleanup(
	POptionContext pContext)
//
//	Release all the resources allocated for an option negotiation context
//
{
	POptionInfo pInfo,
				pNext;

	if (pContext)
	{
		for (pInfo = pContext->pOptionList; pInfo; pInfo = pNext)
		{
			pNext = pInfo->next;
			FREE(pInfo);
		}
	}
}

DWORD
OptionInfoAdd(
	POptionContext			pContext,
	POptionDescriptor		pDescriptor,
	OptionRequireLevel		orlLocal,
	OptionRequireLevel		orlPeer
	)
//
//	Add an option to the list of options known by the context.
//
{
	POptionInfo pInfo, *ppInfo;
	DWORD		dwResult = NO_ERROR;

	pInfo = (POptionInfo)MALLOC(sizeof(OptionInfo));
	if (pInfo == NULL)
	{
		dwResult = ERROR_OUTOFMEMORY;
	}
	else
	{
		pInfo->pDescriptor = pDescriptor;
		pInfo->orlLocal = orlLocal;
		pInfo->orlPeer = orlPeer;
		pInfo->onsLocal = ONS_Initial;

		// Add the new node to the end of the Option List

		for (ppInfo = &pContext->pOptionList; *ppInfo; ppInfo = &(*ppInfo)->next)
			;

		pInfo->next = NULL;
		*ppInfo = pInfo;
	}

	return dwResult;
}

POptionInfo
OptionInfoFind(
	POptionContext			pContext,
	BYTE					type)
//
//	Find the option info for the specified type.
//
//	Return NULL if type not found.
//
{
	POptionInfo pInfo;

	for (pInfo = pContext->pOptionList;
		 pInfo;
		 pInfo = pInfo->next)
	{
		if (pInfo->pDescriptor->type == type)
			break;
	}

	return pInfo;
}

DWORD
OptionSetORL(
	POptionContext			pContext,
	BYTE					type,
	OptionRequireLevel		orlLocal,
	OptionRequireLevel		orlPeer
	)
//
//	Set the ORLs for the specified option
//
{
	POptionInfo pInfo;
	DWORD		dwResult = NO_ERROR;

	pInfo = OptionInfoFind(pContext, type);
	if (pInfo)
	{
		pInfo->orlLocal = orlLocal;
		pInfo->orlPeer = orlPeer;
	}
	else
	{
		dwResult = ERROR_INVALID_PARAMETER;
	}

	return dwResult;
}

DWORD
OptionResponseAdd(
	IN	OUT	PBYTE	pResponse,
	IN		DWORD	cbResponse,
	IN		BYTE	code,					// ACK, NAK, REJ
	IN		BYTE	optionType,				// protocol specific option type identifier
	IN		PBYTE	pOptData,	OPTIONAL
	IN		DWORD	cbOptData)
//
//	Add an option to a response packet being built.
//
//	If the response packet is already a NAK or REJ, then don't add
//	any ACKs to it.
//	If the  response packet is already a REJ, the only add more REJs
//	to it.
//
{
	BYTE	codeCurrent = pResponse[0];
	DWORD	dwResult = NO_ERROR;
	DWORD  offset;
	DWORD	lenOpt;

	ASSERT(cbOptData < 254);

	if (code < codeCurrent)
	{
		// Don't add the option to the response, since
		// we are already doing a REJ or a NAK of other options.
	}
	else
	{
		if (code > codeCurrent)
		{
			// Reset the packet to the new code
			pResponse[0] = code;
			pResponse[2] = 0;
			pResponse[3] = 4;
		}

		// Add the option to the list of options in the response

		offset = (pResponse[2] << 8) | pResponse[3];

		lenOpt = 2 + cbOptData;

		if (offset + lenOpt < cbResponse)
		{
			pResponse[offset] = optionType;
			pResponse[offset + 1] = (BYTE)lenOpt;
			memcpy(pResponse + offset + 2, pOptData, cbOptData);

			offset += lenOpt;
			pResponse[2] = (BYTE)(offset >> 8);
			pResponse[3] = (BYTE)offset;
		}
		else
		{
			dwResult = ERROR_INSUFFICIENT_BUFFER;
		}
	}

	return dwResult;
}

DWORD
OptionsWalk(
	IN		PBYTE		   pOptions,
	IN		DWORD		   cbOptions,
	IN	OUT	POptionContext pContext,	OPTIONAL
	IN		DWORD		  (*pOptionCb)(POptionContext pContext, POptionHeader pOption) OPTIONAL)
//
//	Walk through the options contained within a frame, calling the
//	specified function on each option.
//	If the options are invalid in any way, return ERROR_PPP_INVALID_PACKET.
//
{
    POptionHeader  pOption;
	DWORD		   dwResult = NO_ERROR;
	BOOL		   frameOptionSizesOk = TRUE;	

	for (pOption = (POptionHeader)pOptions;
	     cbOptions;
		 pOption = (POptionHeader)((PBYTE)pOption + pOption->Len))
	{
		if ((cbOptions < 2)
		||  (pOption->Len < 2)
		||  (pOption->Len > cbOptions ))
		{
			// Invalid frame, either:
			//  1. Insufficient size for the option header (Type + Len)
			//  2. option length is too small (less than option header size)
			//  3. option length is too large (greater than remaining bytes in frame)
			dwResult = ERROR_PPP_INVALID_PACKET;
			break;
		}

		if (pOptionCb)
		{
			dwResult = pOptionCb(pContext, pOption);
			if (dwResult != NO_ERROR)
				break;
		}
		cbOptions -= pOption->Len;
	}

	return dwResult;
}

#ifdef DEBUG
void
OptionDebugAppendOptionList(
	IN		POptionContext pContext,
	IN		PSTR	pBuffer,
	IN		PBYTE	pOptions,
	IN		DWORD	cbOptions)
//
//	Append to pBuffer an option list in ASCII readable text.
//
{
    POptionHeader  pOption;
	BOOL		   frameOptionSizesOk = TRUE;
	POptionInfo	   pInfo;

	pBuffer += strlen(pBuffer);
	for (pOption = (POptionHeader)pOptions;
	     cbOptions;
		 pOption = (POptionHeader)((PBYTE)pOption + pOption->Len))
	{
		if ((cbOptions < 2)
		||  (pOption->Len < 2)
		||  (pOption->Len > cbOptions ))
		{
			pBuffer += sprintf(pBuffer, "ERROR - BAD OPTION Len=%u cbOptions=%u ", pOption->Len, cbOptions);
			break;
		}

		pInfo = OptionInfoFind(pContext, pOption->Type);
		if (pInfo)
		{
			pBuffer += sprintf(pBuffer, " %hs", pInfo->pDescriptor->szName);
		}
		else
		{
			pBuffer += sprintf(pBuffer, " [%u]", pOption->Type);
		}
		if (pOption->Len > OPTION_HEADER_LENGTH)
		{
			BYTE  cbOptData = pOption->Len - OPTION_HEADER_LENGTH;
			PBYTE pOptData = (PBYTE)pOption + OPTION_HEADER_LENGTH;

			*(pBuffer++) = '=';
			if (pInfo && pInfo->pDescriptor->OptionToStrCb)
			{
				pInfo->pDescriptor->OptionToStrCb(pContext->CbContext, pInfo, pOptData, cbOptData, &pBuffer);
			}
			else
			{
				// Just do hex dump of option data
				while (cbOptData--)
				{
					pBuffer += sprintf(pBuffer, "%02X", *pOptData++);
				}
			}
		}

		cbOptions -= pOption->Len;
	}
}
#endif


DWORD
OptionRequest(
	IN	OUT	POptionContext pContext,
	IN		POptionHeader  pOption)
//
//	The peer is requesting a value for the option via a configure-request.
//
{
	DWORD		dwResult = NO_ERROR;
	POptionInfo pInfo;
	BYTE		type = pOption->Type;
	BYTE		len  = pOption->Len;
	BYTE		code;
	PBYTE		pOptData = (PBYTE)pOption + OPTION_HEADER_LENGTH;
	DWORD		cbOptData = len - OPTION_HEADER_LENGTH;

	//
	//	Any length errors should have been caught already.
	//
	ASSERT(len >= OPTION_HEADER_LENGTH);

	pInfo = OptionInfoFind(pContext, type);

	if (pInfo == NULL || pInfo->orlPeer == ORL_Unsupported)
	{
		//
		//	We don't support this option, inform the peer via a reject.
		//
		code = PPP_CONFIGURE_REJ;
	}
	else if (pInfo->pDescriptor->fixedLength != OPTION_VARIABLE_LENGTH
	&&       pInfo->pDescriptor->fixedLength != cbOptData)
	{
		//
		//	Option length is invalid. Pretty hopeless situation if the peer is unable to
		//	set the option length to the value we expect.
		//
		DEBUGMSG(ZONE_WARN, (TEXT("PPP: WARNING - Protocol %hs Option %hs length is %u, expected %u\n"),
			pContext->szProtocolName, pInfo->pDescriptor->szName, len, pInfo->pDescriptor->fixedLength));
		code = PPP_CONFIGURE_REJ;
	}
	else
	{
		pInfo->bRequested = TRUE;

		pInfo->pDescriptor->RequestOptionCb(pContext->CbContext, pInfo, &code, &pOptData, &cbOptData);

		if (code == PPP_CONFIGURE_NAK
		&&  pContext->dwConsecutiveFailureCount >= pContext->dwMaxFailure)
		{
			DEBUGMSG(ZONE_WARN, (TEXT("PPP: WARNING - Protocol %hs Failing to converge, REJecting Option %hs instead of NAKing\n"),
				pContext->szProtocolName, pInfo->pDescriptor->szName));
			code = PPP_CONFIGURE_REJ;
			pOptData = (PBYTE)pOption + OPTION_HEADER_LENGTH;
			cbOptData = len - OPTION_HEADER_LENGTH;
		}
	}

	//
	//	Update the response
	//
	dwResult = OptionResponseAdd(pContext->pResponse, pContext->cbResponse, code, type, pOptData, cbOptData);

	return dwResult;
}

DWORD
OptionAcked(
	IN	OUT	POptionContext pContext,
	IN		POptionHeader  pOption)
//
//	The value for the option has been accepted from the negotiations,
//	and we can now make it go into effect.
//
{
	DWORD       dwResult = NO_ERROR;
	POptionInfo pInfo;
	BYTE		type = pOption->Type;
	BYTE		len  = pOption->Len;

	//
	//	Any length errors should have been caught already.
	//
	ASSERT(len >= OPTION_HEADER_LENGTH);

	pInfo = OptionInfoFind(pContext, type);
	//
	//	All the options in an ACK message should be ones that we sent
	//	in a config-request.  And we should only be sending options
	//	that we support in a config-request.  Hence info should always
	//	be found for an option here.
	//
	ASSERT(pInfo && pInfo->onsLocal == ONS_Requested);

	if (pInfo)
	{
		ASSERT(pInfo->pDescriptor->fixedLength == OPTION_VARIABLE_LENGTH || pInfo->pDescriptor->fixedLength == len - OPTION_HEADER_LENGTH);
		pInfo->onsLocal = ONS_Acked;

		if (pInfo->pDescriptor->AckOptionCb)
			dwResult = pInfo->pDescriptor->AckOptionCb(pContext->CbContext, pInfo, (PBYTE)pOption + OPTION_HEADER_LENGTH, len - OPTION_HEADER_LENGTH);
	}

	return dwResult;
}

DWORD
OptionNak(
	IN	OUT	POptionContext pContext,
	IN		POptionHeader  pOption)
//
//	The peer is suggesting a value for the option.
//
{
	DWORD       dwResult = NO_ERROR;
	POptionInfo pInfo;
	BYTE		type = pOption->Type;
	BYTE		len  = pOption->Len;
	PBYTE		pOptData = (PBYTE)pOption + OPTION_HEADER_LENGTH;
	DWORD		cbOptData = len - OPTION_HEADER_LENGTH;

	//
	//	Any length errors should have been caught already.
	//
	ASSERT(len >= OPTION_HEADER_LENGTH);

	pInfo = OptionInfoFind(pContext, type);
	//
	//	A NAK can to either suggest an alternative value for an option
	//	that was present in the configure request, or can be requesting
	//	the negotiation of an option that was not present in the configure-request.
	//	In the latter case, we may not support that option at all, so
	//  pInfo will be NULL and we just ignore the peer on that option.
	//

	if (pInfo && pInfo->orlLocal != ORL_Unsupported)
	{
		if (pInfo->pDescriptor->fixedLength != OPTION_VARIABLE_LENGTH
		&&  pInfo->pDescriptor->fixedLength != cbOptData)
		{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -