📄 ncp.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.
//
/*****************************************************************************
*
*
* @doc
* @module ncp.c | PPP Network Control Protocol (NCP)
*
* Date: 1-10-95
*
* @comm
*/
// Include Files
#include "windows.h"
#include "cclib.h"
#include "memory.h"
#include "cxport.h"
#include "crypt.h"
#include "iphlpapi.h"
#include "winsock.h"
// VJ Compression Include Files
#include "ndis.h"
#include "tcpip.h"
#include "vjcomp.h"
// PPP Include Files
#include "protocol.h"
#include "ppp.h"
#include "auth.h"
#include "lcp.h"
#include "ipcp.h"
#include "ipv6intf.h"
#include "ipv6cp.h"
#include "ccp.h"
#include "ncp.h"
#include "mac.h"
/*++
Routine Name:
IPv6Present
Routine Description:
Determine if IPv6 is available on the system.
Arguments:
Return Value:
TRUE if IPv6 is configured, FALSE otherwise
--*/
HMODULE g_hWS2Module;
BOOL
IPv6Present()
{
SOCKET s = INVALID_SOCKET;
SOCKET (*pSocket)();
void (*pCloseSocket)();
DWORD dwResult;
dwResult = CXUtilGetProcAddresses(
TEXT("ws2.dll"), &g_hWS2Module,
TEXT("socket"), &pSocket,
TEXT("closesocket"), &pCloseSocket,
NULL);
if (dwResult == NO_ERROR)
{
// WS2 module is present and has socket/closesocket exports
// Check if v6 is running
s = pSocket(AF_INET6, SOCK_DGRAM, 0);
if (s != INVALID_SOCKET)
pCloseSocket(s);
}
else
{
DEBUGMSG(ZONE_WARN, (TEXT("PPP: WARNING - ws2.dll not available, IPV6 will not be supported\n")));
}
return s != INVALID_SOCKET;
}
////////////////////////////////////////////////////////////////////////////////
//
// Network layer idle disconnect timer support
//
void
ncpIdleDisconnectTimerStop(
IN PNCPContext pContext)
{
CTEStopTimer(&pContext->IdleIpTimer);
}
void
ncpIdleDisconnectTimerStart(
IN PNCPContext pContext,
IN DWORD DurationMs)
{
if (DurationMs && pContext->bLowerLayerUp)
{
CTEStartTimer(&pContext->IdleIpTimer, DurationMs, ncpIdleDisconnectTimerCb, (PVOID)pContext);
}
}
void
ncpIdleDisconnectTimerCb(
CTETimer *timer,
PVOID context)
//
// This function is called periodically to check to see if we are receiving network layer traffic
// from the peer. If we haven't received traffic in too long a time interval, we disconnect the link.
// Otherwise, we restart the timer.
//
{
PNCPContext pContext = (PNCPContext)context;
DWORD CurrentTime = GetTickCount();
DWORD TicksSinceLastRxIpData;
pppLock(pContext->session);
TicksSinceLastRxIpData = CurrentTime - pContext->dwLastTxRxIpDataTickCount;
if (TicksSinceLastRxIpData < pContext->dwIdleDisconnectMs)
{
// Not idle for too long, restart timer
ncpIdleDisconnectTimerStart(pContext, pContext->dwIdleDisconnectMs - TicksSinceLastRxIpData);
}
else
{
// Idle for too long, disconnect
DEBUGMSG(ZONE_PPP, (L"PPP: No RX IP data from peer for %u ms, closing connection\n", TicksSinceLastRxIpData));
pContext->session->bDisconnectDueToUnresponsivePeer = TRUE;
pppLcp_Close(pContext->session->lcpCntxt, NULL, NULL);
}
pppUnLock(pContext->session);
}
/*****************************************************************************
*
* @func DWORD | pppNcp_InstanceCreate | Creates ncp instance.
*
* @rdesc Returns error code, 0 for success, non-zero for other errors.
*
* @parm void * | SessionContext | Session context pointer.
* @parm void ** | ReturnedContext | Returned context pointer.
*
* @comm This function creates an instance of the CCP layer and returns
* a pointer to it. This pointer is used for all subsequent calls
* to this context.
*/
DWORD
pppNcp_InstanceCreate( void *SessionContext, void **ReturnedContext )
{
pppSession_t *s_p = (pppSession_t *)SessionContext;
ncpCntxt_t *c_p = NULL;
DWORD RetVal = NO_ERROR;
DWORD dwDisableIPV6;
DEBUGMSG( ZONE_NCP | ZONE_FUNCTION, (TEXT( "pppNcp_InstanceCreate\r\n" )));
do
{
c_p = (ncpCntxt_t *)pppAlloc( s_p, sizeof( ncpCntxt_t ), TEXT( "NCP CONTEXT" ) );
if( NULL == c_p )
{
DEBUGMSG(ZONE_ERROR, ( TEXT( "PPP: ERROR - Out of memory for NCP Context\n" )));
RetVal = ERROR_NOT_ENOUGH_MEMORY;
break;
}
c_p->session = s_p; // save session context
CTEInitTimer(&c_p->IdleIpTimer);
// Initialize desired Protocols
//
// TCP/IP
// Always enable TCPIP
c_p->protocol[NCP_IPCP].enabled = TRUE;
c_p->protocol[NCP_IPCP].Close = IpcpClose;
c_p->protocol[NCP_IPCP].LowerLayerUp = pppIpcp_LowerLayerUp;
c_p->protocol[NCP_IPCP].LowerLayerDown = pppIpcp_LowerLayerDown;
c_p->protocol[NCP_IPCP].SendData = pppIpcpSndData;
RetVal = pppIpcp_InstanceCreate(s_p, &(c_p->protocol[NCP_IPCP].context) );
if (RetVal != NO_ERROR)
break;
// TCP/IPV6
// Enable TCPIPV6 if the tcpipv6 stack is present
dwDisableIPV6 = FALSE;
ReadRegistryValues(HKEY_LOCAL_MACHINE, TEXT("Comm\\ppp\\Parms"),
RAS_VALUENAME_IPV6_DISABLE, REG_DWORD, 0, &dwDisableIPV6, sizeof(DWORD),
NULL);
c_p->protocol[NCP_IPV6CP].enabled = FALSE;
if (!dwDisableIPV6 && IPv6Present() && (PPPIPV6InterfaceInitialize() == NO_ERROR))
{
c_p->protocol[NCP_IPV6CP].enabled = TRUE;
c_p->protocol[NCP_IPV6CP].Close = Ipv6cpClose;
c_p->protocol[NCP_IPV6CP].LowerLayerUp = pppIpv6cp_LowerLayerUp;
c_p->protocol[NCP_IPV6CP].LowerLayerDown = pppIpv6cp_LowerLayerDown;
c_p->protocol[NCP_IPV6CP].SendData = pppIpv6cpSendData;
RetVal = pppIpv6cp_InstanceCreate(s_p, &(c_p->protocol[NCP_IPV6CP].context) );
if (RetVal != NO_ERROR)
break;
}
// CCP
// Always enable CCP to allow encryption to be negotiated,
// in case the peer requires it
c_p->protocol[NCP_CCP].enabled = TRUE;
c_p->protocol[NCP_CCP].Close = CcpClose;
c_p->protocol[NCP_CCP].LowerLayerUp = pppCcp_LowerLayerUp;
c_p->protocol[NCP_CCP].LowerLayerDown = pppCcp_LowerLayerDown;
RetVal = pppCcp_InstanceCreate( s_p, &(c_p->protocol[NCP_CCP].context));
if (RetVal != NO_ERROR)
break;
// Default to Idle disconnect timeout disabled.
c_p->dwIdleDisconnectMs = 0;
{
//
// Temporary code to read in ICS RAS timeout settings and confgure our Idle timeout appropriately.
// To be replaced with RASENTRY configuration changes in CE 5.0.
//
WCHAR wszRasEntryName1[MAX_PATH];
WCHAR wszRasEntryName2[MAX_PATH];
DWORD IdleTimeoutMS;
IdleTimeoutMS = 1000 * 60 * 30; // default 30 minute idle timeout
wszRasEntryName1[0] = 0;
wszRasEntryName2[0] = 0;
// Read ICS registry settings
(void)ReadRegistryValues(
HKEY_LOCAL_MACHINE, L"Comm\\Autodial",
L"RasEntryName1", REG_SZ, 0, (PVOID)wszRasEntryName1, sizeof(wszRasEntryName1),
L"RasEntryName2", REG_SZ, 0, (PVOID)wszRasEntryName2, sizeof(wszRasEntryName2),
L"IdleTimeoutMS", REG_DWORD, 0, (PVOID)&IdleTimeoutMS, sizeof(IdleTimeoutMS),
NULL);
// If the name of our RAS entry matches that of either ICS ras entry, then apply the timeout
if (0 == wcsicmp(wszRasEntryName1, s_p->rasDialParams.szEntryName)
|| 0 == wcsicmp(wszRasEntryName2, s_p->rasDialParams.szEntryName))
{
c_p->dwIdleDisconnectMs = IdleTimeoutMS;
}
}
} while (FALSE);
if (RetVal != NO_ERROR)
{
pppNcp_InstanceDelete(c_p);
c_p = NULL;
}
*ReturnedContext = c_p;
return RetVal;
}
/*****************************************************************************
*
* @func void | pppNcp_InstanceDelete | Deletes ncp instance.
*
* @parm void * | context | Instance context pointer.
*
* @comm This function deletes the passed in context.
*/
void
pppNcp_InstanceDelete( void *context )
{
ncpCntxt_t *c_p = (ncpCntxt_t *)context;
DEBUGMSG( ZONE_NCP | ZONE_FUNCTION, (TEXT("pppNcp_InstanceDelete 0x%X\r\n" ), context ));
if (context)
{
// Delete the NCP protocols
pppIpv6cp_InstanceDelete(c_p->protocol[NCP_IPV6CP].context );
pppIpcp_InstanceDelete(c_p->protocol[NCP_IPCP].context );
pppCcp_InstanceDelete (c_p->protocol[NCP_CCP].context );
// Free the NCP layer
c_p->session->ncpCntxt = NULL;
pppFree( c_p->session, context, TEXT( "NCP CONTEXT" ) );
}
}
void
pppNcp_IndicateConnected(
IN PVOID context)
//
// When an NCP protocol goes up it calls this function to
// determine whether to report the link as being connected.
//
// To be considered connected:
// IPCP has to be up OR IPV6CP has to be up, AND
// NEED_ENCRYPTION must be FALSE or CCP must be up
//
{
ncpCntxt_t *pContext = (ncpCntxt_t *)context;
pppSession_t *pSession = pContext->session;
RASPENTRY *pRasEntry = &pSession->rasEntry;
PIPV6Context pIPV6Context = (PIPV6Context)pContext->protocol[NCP_IPV6CP].context;
PIPCPContext pIPCPContext = (PIPCPContext)pContext->protocol[NCP_IPCP].context;
PCCPContext pCCPContext = (PCCPContext) pContext->protocol[NCP_CCP].context;
BOOL bIPV6up = pIPV6Context && pIPV6Context->pFsm->state == PFS_Opened;
BOOL bIPCPup = pIPCPContext && pIPCPContext->pFsm->state == PFS_Opened;
BOOL bCCPup = pCCPContext && pCCPContext->pFsm->state == PFS_Opened;
if ((bIPCPup || bIPV6up) && (bCCPup || !NEED_ENCRYPTION(pRasEntry)))
{
// Start the (optional) idle disconnect timer
pContext->dwLastTxRxIpDataTickCount = GetTickCount();
ncpIdleDisconnectTimerStop(pContext);
ncpIdleDisconnectTimerStart(pContext, pContext->dwIdleDisconnectMs);
pppChangeOfState( pSession, RASCS_Connected, 0 );
}
}
/*****************************************************************************
*
* @func void | pppNcp_Send | NCP send data entry point.
*
*
* @comm This function routes the IP packet to the IPCP protocol.
*/
void
pppNcp_SendIPvX(
PVOID context,
PNDIS_PACKET Packet,
IN DWORD ncpProtoId)
{
ncpCntxt_t *c_p = (ncpCntxt_t *)context; // context pntr
DEBUGMSG( ZONE_NCP | ZONE_FUNCTION, (TEXT( "pppNcp_SendIPvX( %08X %08X %08X )\r\n" ), context, Packet ));
ASSERT(ncpProtoId == NCP_IPCP || ncpProtoId == NCP_IPV6CP);
if( c_p->protocol[ncpProtoId].enabled )
{
c_p->dwLastTxRxIpDataTickCount = GetTickCount();
c_p->protocol[ncpProtoId].SendData( c_p->protocol[ncpProtoId].context, Packet);
}
else
{
DEBUGMSG(ZONE_ERROR,(TEXT( "PPP: ERROR - TX NCP - TOSS PKT - protoid %u DISABLED\n" ), ncpProtoId));
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -