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

📄 lcp.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 Link Control Protocol (LCP)

//  Include Files

#include "windows.h"
#include "cclib.h"
#include "memory.h"
#include "cxport.h"
#include "crypt.h"

#include "ndis.h"
#include "ndiswan.h"

// PPP Include Files

#include "protocol.h"
#include "ppp.h"
#include "mac.h"
#include "lcp.h"
#include "auth.h"
#include "ras.h"
#include "ncp.h"
#include "pppserver.h"

void lcpIdleDisconnectTimerStop(IN  PLCPContext	pContext);
void lcpIdleDisconnectTimerStart(IN  PLCPContext pContext, IN  DWORD DurationMs);
void lcpSetIdleDisconnectMs(IN	PVOID	context, IN  DWORD   dwIdleDisconnectMs);

void
pppLcpCloseCompleteCallback(
	PLCPContext c_p)
//
//	This function is called when the LCP FSM transitions to the closed state.
//	It completes any pending close requests.
//
{
    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: +pppLcpCloseCompleteCallback\n" )));

	pppExecuteCompleteCallbacks(&c_p->pPendingCloseCompleteList);

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: -pppLcpCloseCompleteCallback\n" )));
}

void
pppLcp_GetLinkInfoCompleteCallback(
	IN	PLCPContext             pContext,
	IN	NDIS_WAN_GET_LINK_INFO *pInfo,
	IN	NDIS_STATUS             Status
	)
//
//	Called after the MAC layer indicates that it is up
//  and we retrieve MAC settings.
//
{
	pppSession_t      *pSession = (pppSession_t *)(pContext->session);
	OptionRequireLevel orlLocalMRU,
		               orlLocalAuth,
		               orlPFC,
					   orlACFC;
	USHORT             DefaultMTU;

	DefaultMTU = PPP_DEFAULT_MTU;
	if (_tcscmp(pSession->rasEntry.szDeviceType, RASDT_Vpn) == 0)
		DefaultMTU = PPP_DEFAULT_VPN_MTU;

	pContext->linkMaxSendPPPInfoFieldSize = DefaultMTU;
	pContext->linkMaxRecvPPPInfoFieldSize = DefaultMTU;

	if (Status == NDIS_STATUS_SUCCESS)
	{
		//
		// The MaxSend/RecvFrameSizes returned by the miniport must be reduced
		// by 2 bytes to account for the PPP protocol field in order to compute
		// the maximum PPP info field size.
		//
		pContext->linkMaxSendPPPInfoFieldSize = (USHORT)pInfo->MaxSendFrameSize - 2;
		pContext->linkMaxRecvPPPInfoFieldSize = (USHORT)pInfo->MaxRecvFrameSize - 2;
	}

	lcpOptionValueReset(pContext);

	// If our desired MaxRecvFrameSize is not the default MRU (1500),
	// then we want to negotiate this with the peer.  That is, we
	// want to tell our peer what size packets we can handle.

	orlLocalMRU = ORL_Allowed;
	if (pContext->local.MRU != PPP_DEFAULT_MTU)
		orlLocalMRU = ORL_Wanted;

	orlPFC = ORL_Unsupported;
	if (pContext->FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)
		orlPFC = ORL_Wanted;

	orlACFC = ORL_Unsupported;
	if (pContext->FramingBits & PPP_COMPRESS_ADDRESS_CONTROL)
		orlACFC = ORL_Wanted;

	PppFsmOptionsSetORLs(pContext->pFsm,
				LCP_OPT_MRU,           orlLocalMRU,  ORL_Allowed,
				LCP_OPT_PFC,           orlPFC,       orlPFC,
				LCP_OPT_ACFC,          orlACFC,      orlACFC,
				-1);

	if (pSession->bIsServer)
	{
		orlLocalAuth = ORL_Allowed;
		if (PPPServerGetSessionAuthenticationRequired(pSession))
			orlLocalAuth = ORL_Required;

		PppFsmOptionsSetORLs(pContext->pFsm,
				LCP_OPT_AUTH_PROTOCOL, orlLocalAuth,  ORL_Unsupported,
			    -1);
	}

	if (pContext->bMACLayerUp)
		PppFsmLowerLayerUp(pContext->pFsm);
}

void
pppLcp_LowerLayerUp(
	IN	PVOID	context)
//
//	This function will be called when the MAC layer is up
//
{
	PLCPContext	    pContext = (PLCPContext)context;
	pppSession_t    *pSession = (pppSession_t *)(pContext->session);
	WCHAR			wszRegKey[MAX_PATH + 1];

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: +pppLcp_LowerLayerUp\n" )));

	pContext->bMACLayerUp = TRUE;

	//
	//	Get Mac parameters
	//

	pppMac_GetFramingInfo(pSession->macCntxt, &pContext->FramingBits, &pContext->DesiredACCM);

	//
	//	Override the global miniport value with the per-line
	//	registry setting value if present.
	//
	wsprintf(&wszRegKey[0], L"Comm\\ppp\\Parms\\Line\\%s", pContext->session->rasEntry.szDeviceName);
	(void) ReadRegistryValues(HKEY_LOCAL_MACHINE, wszRegKey,
									L"ACCM",	REG_DWORD, 0, &pContext->DesiredACCM, sizeof(DWORD),
									NULL);

	pppMac_GetLinkInfo(pSession->macCntxt, pppLcp_GetLinkInfoCompleteCallback, pContext);

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: -pppLcp_LowerLayerUp\n" )));
}

void
pppLcp_LowerLayerDown(
	IN	PVOID	context)
//
//	This function will be called when the auth layer is down
//
{
	PLCPContext	pContext = (PLCPContext)context;

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: +pppLcp_LowerLayerDown\n" )));

	pContext->bMACLayerUp = FALSE;

	PppFsmLowerLayerDown(pContext->pFsm);

	if( pContext->pFsm->state == PFS_Initial )
	{
		// Complete any pending close requests
		pppLcpCloseCompleteCallback(pContext);
	}

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: -pppLcp_LowerLayerDown\n" )));
}

static DWORD
lcpSendPacket(
	PVOID context,
	USHORT ProtocolWord,
	PBYTE	pData,
	DWORD	cbData)
{
	PLCPContext	pContext = (PLCPContext)context;
	pppSession_t    *pSession = (pppSession_t *)(pContext->session);
	DWORD			dwResult;

	dwResult = pppSendData(pSession, ProtocolWord, pData, cbData);

	return dwResult;
}

static void
lcpConfigureMACLayer(
	PLCPContext pContext )
//
//	Called to configure the MAC layer with either:
//    1. parameters negotiated by LCP (if LCP is Opened), OR
//    2. default LCP settings (prior to LCP entering the Opened state)
//
{
	pppSession_t           *pSession = (pppSession_t *)(pContext->session);
	NDIS_WAN_SET_LINK_INFO	LinkInfo;

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: +lcpConfigureMACLayer\n" )));

	memset ((char *)&LinkInfo, 0, sizeof(LinkInfo));

	if (pContext->pFsm->state == PFS_Opened)
	{
		// Update MAC Settings with negotiated values
		//
		LinkInfo.MaxSendFrameSize = pContext->peer.MRU;
		LinkInfo.SendACCM = pContext->peer.ACCM;
		LinkInfo.SendFramingBits = PPP_FRAMING;
		if( pContext->peer.bPFC)
			LinkInfo.SendFramingBits |= PPP_COMPRESS_PROTOCOL_FIELD;
		if( pContext->peer.bACFC)
			LinkInfo.SendFramingBits |= PPP_COMPRESS_ADDRESS_CONTROL;

		LinkInfo.MaxRecvFrameSize = pContext->local.MRU;
		LinkInfo.RecvACCM = pContext->local.ACCM;
		LinkInfo.RecvFramingBits = PPP_FRAMING;
		if( pContext->local.bPFC)
			LinkInfo.RecvFramingBits |= PPP_COMPRESS_PROTOCOL_FIELD;
		if( pContext->local.bACFC)
			LinkInfo.RecvFramingBits |= PPP_COMPRESS_ADDRESS_CONTROL;
	}
	else
	{
		//
		// Prior to entering the Opened state, LCP default settings
		// are in effect (regardless of what our current in-negotiation
		// context values may be at the moment).
		//
		LinkInfo.MaxSendFrameSize = PPP_DEFAULT_MTU;
		if (pContext->linkMaxSendPPPInfoFieldSize < PPP_DEFAULT_MTU)
			LinkInfo.MaxSendFrameSize = pContext->linkMaxSendPPPInfoFieldSize;

		LinkInfo.SendACCM = LCP_DEFAULT_ACCM;
		LinkInfo.SendFramingBits = PPP_FRAMING;

		LinkInfo.MaxRecvFrameSize = pContext->linkMaxRecvPPPInfoFieldSize;
		LinkInfo.RecvACCM = LCP_DEFAULT_ACCM;
		LinkInfo.RecvFramingBits = PPP_FRAMING;
	}

    // Set MAC Layer

	pppMac_SetLink(pSession->macCntxt, &LinkInfo );
}

static  DWORD
lcpUp(
	PVOID context)
//
//	This is called when the FSM enters the Opened state
//
{
	PLCPContext	pContext = (PLCPContext)context;
	pppSession_t    *pSession = (pppSession_t *)(pContext->session);

	lcpConfigureMACLayer( pContext );

    // Indicate to Session Manager and upper layer that we are UP.
    // RAS state AllDevicesConnected - doesn't seem quite right 
    // but is best fit.

    pppChangeOfState( pSession, RASCS_AllDevicesConnected, 0 );

	// Inform higher layer (AUTH) that LCP is up
	AuthLowerLayerUp(pSession->authCntxt);

	// Start the Idle Disconnect Timer as appropriate
	lcpSetIdleDisconnectMs(pContext, pContext->dwIdleDisconnectMs);

	return NO_ERROR;
}

static  DWORD
lcpDown(
	PVOID context)
//
//	This is called when the FSM leaves the Opened state
//
{
	PLCPContext	     pContext = (PLCPContext)context;
	pppSession_t    *pSession = (pppSession_t *)(pContext->session);

	lcpIdleDisconnectTimerStop(pContext);

	lcpOptionValueReset(pContext);

	// Set MAC layer settings to defaults
	lcpConfigureMACLayer( pContext );

	// Indicate to upper (auth) layer we are down
	AuthLowerLayerDown(pSession->authCntxt);

	return NO_ERROR;
}

static  DWORD
lcpStarted(
	PVOID context)
{
	PLCPContext	pContext = (PLCPContext)context;

    DEBUGMSG( ZONE_LCP, ( TEXT( "PPP: LCP STARTED\n" )));

	return NO_ERROR;
}

static  DWORD
lcpFinished(
	PVOID context)
//
//	Called when the FSM enters the Closed or Stopped state from a higher state,
//  or enters the Initial state from the Starting state.
//
{
	PLCPContext	pContext = (PLCPContext)context;

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: +lcpFinished\n" )));

	//
	// Take the MAC layer down
	// Note that this will result in the RASCS_Disconnected state being
	// entered when LINECALLSTATE_DISCONNECTED  is indicated by the miniport.
	//
	pppMac_CallClose(pContext->session->macCntxt, NULL, NULL);

	if( pContext->pFsm->state == PFS_Initial )
	{
		// Complete any pending close requests
		pppLcpCloseCompleteCallback(pContext);
	}

    DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: -lcpFinished\n" )));

	return NO_ERROR;
}

DWORD
lcpSessionLock(
	PVOID context)
//
//	This is called by the FSM when it needs to lock the session
//	because a timer has expired.
//
{
	PLCPContext	pContext = (PLCPContext)context;

	pppLock(pContext->session);

	return NO_ERROR;
}

DWORD
lcpSessionUnlock(
	PVOID context)
//
//	This is called by the FSM when it needs to unlock the session
//	after a prior call to lock it due to timer expiry.
//
{
	PLCPContext	pContext = (PLCPContext)context;

	pppUnLock(pContext->session);

	return NO_ERROR;
}

void
LcpProtocolRejected(
	IN	PVOID	context)
//
//  Called when we receive a protocol reject packet from
//  the peer in which they are rejecting the LCP protocol.
//
{
	PLCPContext	    pContext = (PLCPContext)context;

	//
	// A protocol reject of an LCP packet is a major error, can't do
	// anything without LCP!
	//
	DEBUGMSG(ZONE_ERROR, (TEXT("PPP: ERROR - LCP protocol REJECTED\n")));
	PppFsmProtocolRejected( pContext->pFsm );
}

void
lcpRxProtocolReject(
	IN	PVOID	context,
	IN	BYTE	code,
	IN  BYTE    id,
	IN	PBYTE	pData,
	IN	DWORD	cbData)
//
// Called when we receive an LCP_PROTOCOL_REJECT packet from
// the peer because they didn't like the protocol type in a
// packet we sent.
// pData will point to the packet that we sent that the peer
// doesn't like.
//
{
	PLCPContext	    pContext = (PLCPContext)context;
	pppMsg_t        msg;

	// At this point the LCP header has been removed from the received 
    // packet.  Therefore this packet is our packet from the protocol 
    // to be terminated. Decode the packet again to determine the enclosed
    // protocol and change the option header to P_PROT_REJ. Route the packet
    // with the changed Code back to the protocol to terminate it.

	msg.data = pData;
	msg.len  = cbData;

	PPPRxProtocolReject(pContext->session, &msg);
}

void
lcpRxEchoRequest(
	IN	PVOID	context,
	IN	BYTE	code,
	IN  BYTE    id,
	IN	PBYTE	pData,
	IN	DWORD	cbData)
{
	PLCPContext	    pContext = (PLCPContext)context;
	PBYTE		    pPacket = pData - PPP_PACKET_HEADER_SIZE;

	if (cbData < 4)
	{
		// 4 byte magic number field is required in an echo-request or echo-reply
		DEBUGMSG( ZONE_LCP, (TEXT( "PPP: LCP ECHO REQUEST missing magic number, cbData=%u\n"), cbData));
	}
	else
	{
		// Reception of a Magic-Number equal to the negotiated local magic number
		// indicates a looped back link.

		// Reception of a Magic-Number other than the negotiated local magic number,
		// the peer's negotiated magic number, or zero if the peer didn't negotiate one,
		// indicates a link which has been (mis)configured for communications with
		// a different peer.

		// Change packet code to echo REPLY

		pPacket[0] = LCP_ECHO_REPLY;             

		// Put in our magic number

		memcpy(pData, &pContext->local.MagicNumber, sizeof( DWORD ) );

		// Send the REPLY

		pppSendData(pContext->session, PPP_PROTOCOL_LCP, pPacket, cbData + PPP_PACKET_HEADER_SIZE);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////
//
//  Echo Request Management for dead link detection
//
//  1. If no packets of any kind are received from the peer for half a disconnect timeout interval 
//     (default 10/2 = 5 seconds), then we send an LCP echo request.
//  2. We keep sending LCP echo requests (at default 1 second intervals) until either we receive a packet
//     (echo reply or something else) or the disconnect timeout interval is reached.
//  3. If no packets of any kind are received from the peer for a full disconnect timeout interval,
//     then we terminate the link.
//
//  By default dead link detection is only enabled for PPPoE connections. The specific device types
//  for which it is enabled can be specified by setting the registry value:
//     [HKEY_LOCAL_MACHINE\Comm\Ppp\Parms]
//          "LcpIdleDeviceTypes"=multi_sz:"vpn","direct","pppoe"
//
void
lcpRxEchoReply(
	IN	PVOID	context,
	IN	BYTE	code,
	IN  BYTE    id,
	IN	PBYTE	pData,
	IN	DWORD	cbData)
{
	PLCPContext	    pContext = (PLCPContext)context;

	//
	// Let's not be picky about the ID matching that of the most recent request.
	// The peer is there and sending us messages, so that's good.
	//
	// The session will have set the bRxData flag already to indicate that we
	// have received data and thus the peer is alive, we don't need to do anything.
	//
}

void
lcpEchoRequestSend(
	PLCPContext	    pContext)
//
//  Build and send an LCP Echo Request packet.
//
{
	BYTE echoRequestPacket[8];

	//
	// Echo request format:
	//    Code   = LCP_ECHO_REQUEST (9)
	//    Id     = sequence number incremented for each echo request transmission
	//    Length = 0x0008
	//    Magic Number (4 bytes)
	//
	pContext->EchoRequestId++;
	PPP_SET_PACKET_HEADER(echoRequestPacket, LCP_ECHO_REQUEST, (BYTE)pContext->EchoRequestId, sizeof(echoRequestPacket));
	memcpy(&echoRequestPacket[4], &pContext->local.MagicNumber, sizeof(DWORD) );

	DEBUGMSG(ZONE_TRACE, (L"PPP: TX LCP Echo-Request ID=%u", pContext->EchoRequestId));

	pppSendData(pContext->session, PPP_PROTOCOL_LCP, echoRequestPacket, 8);
}

void lcpIdleDisconnectTimerCb(CTETimer *timer, PVOID     context);

void
lcpIdleDisconnectTimerStop(
	IN  PLCPContext	    pContext)
{
	CTEStopTimer(&pContext->IdleDisconnectTimer);
}

void

⌨️ 快捷键说明

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