📄 lcp.c
字号:
lcpIdleDisconnectTimerStart(
IN PLCPContext pContext,
IN DWORD DurationMs)
{
if (DurationMs && pContext->pFsm->state == PFS_Opened)
{
CTEStartTimer(&pContext->IdleDisconnectTimer, DurationMs, lcpIdleDisconnectTimerCb, (PVOID)pContext);
}
}
void
lcpIdleDisconnectTimerCb(
CTETimer *timer,
PVOID context)
//
// This function is called periodically to check to see if we are receiving traffic from the
// peer. We take action based upon how much time has elapsed since the last traffic received:
//
// Elapsed Time Action
// ------------ ------
// 0 to dwIdleDisconnectMs/2 Restart timer for dwIdleDisconnectMs/2
// dwIdleDisconnect/2 to dwIdleDisconnect Send Echo Request, start timer for dwEchoRequestIntervalMs
// > dwIdleDisconnect Terminate link
//
{
PLCPContext pContext = (PLCPContext)context;
BOOL bTerminateConnection = FALSE;
DWORD CurrentTime = GetTickCount();
DWORD TimeSinceLastRxData;
pppLock(pContext->session);
if (pContext->session->bRxData)
{
pContext->session->bRxData = FALSE;
pContext->LastRxDataTime = CurrentTime;
// Line is receiving, restart timer
lcpIdleDisconnectTimerStart(pContext, pContext->dwIdleDisconnectMs / 2);
}
else
{
// Didn't receive anything lately
TimeSinceLastRxData = CurrentTime - pContext->LastRxDataTime;
if (TimeSinceLastRxData <= pContext->dwIdleDisconnectMs)
{
// We haven't been idle for too long, send echo request
lcpEchoRequestSend(pContext);
lcpIdleDisconnectTimerStart(pContext, pContext->dwEchoRequestIntervalMs);
}
else
{
// Idle for too long, disconnect
DEBUGMSG(ZONE_WARN, (L"PPP: WARNING - No RX data from peer for %u ms, terminating connection\n", pContext->dwIdleDisconnectMs));
pContext->session->bDisconnectDueToUnresponsivePeer = TRUE;
pppLcp_Close(pContext, NULL, NULL);
}
}
pppUnLock(pContext->session);
}
void
lcpSetIdleDisconnectMs(
IN PVOID context,
IN DWORD dwIdleDisconnectMs)
{
PLCPContext pContext = (PLCPContext)context;
lcpIdleDisconnectTimerStop(pContext);
pContext->dwIdleDisconnectMs = dwIdleDisconnectMs;
pContext->LastRxDataTime = GetTickCount();
lcpIdleDisconnectTimerStart(pContext, pContext->dwIdleDisconnectMs / 2);
}
void
lcpRxDiscardRequest(
IN PVOID context,
IN BYTE code,
IN BYTE id,
IN PBYTE pData,
IN DWORD cbData)
{
}
PppFsmExtensionMessageDescriptor lcpExtensionMessageDescriptor[] =
{
{LCP_PROTOCOL_REJECT, "Protocol-Reject", lcpRxProtocolReject},
{LCP_ECHO_REQUEST, "Echo-Request", lcpRxEchoRequest},
{LCP_ECHO_REPLY, "Echo-Reply", lcpRxEchoReply},
{LCP_DISCARD_REQUEST, "Discard-Request", lcpRxDiscardRequest},
{0, NULL, NULL}
};
//
// cbMaxTxPacket derivation for LCP:
// 6 bytes standard PPP packet header
// 4 bytes MRU option
// 6 bytes ACCM option
// 5 bytes auth option
// 6 bytes magic number option
// 2 bytes pfc option
// 2 bytes acfc option
//
static PppFsmDescriptor lcpFsmData =
{
"LCP", // szProtocolName
PPP_PROTOCOL_LCP, // ProtocolWord
64, // cbMaxTxPacket
lcpUp,
lcpDown,
lcpStarted,
lcpFinished,
lcpSendPacket,
lcpSessionLock,
lcpSessionUnlock,
&lcpExtensionMessageDescriptor[0] // Extension message handlers for LCP
};
void
pppLcp_Open(
IN PLCPContext pContext)
//
// Get the LCP FSM into the opened state, ready to establish connections when the
// MAC layer is up.
//
{
PppFsmOpen(pContext->pFsm);
}
void
pppLcp_Close(
IN PLCPContext pContext,
IN void (*pLcpCloseCompleteCallback)(PVOID),
IN PVOID pCallbackData)
//
// Get LCP into the initial state, i.e. closed and MAC layer down.
// When PFS_Initial is achieved, invoke the pLcpCloseCompleteCallback function.
//
{
DWORD dwResult;
DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: +pppLcp_Close\n" )));
// Signal the state machine to
// get to the initial state. The state machine will
// call pppLcpCloseCompleteCallback when that state
// is achieved, and that function will call the
// pLcpCloseCompleteCallback handler.
//
DEBUGMSG(ZONE_LCP, (TEXT( "PPP: PppFsmClose LCP\n" )));
PppFsmClose(pContext->pFsm);
if( pContext->pFsm->state == PFS_Initial )
{
// All done
if (pLcpCloseCompleteCallback)
pLcpCloseCompleteCallback(pCallbackData);
}
else
{
// Can be in one of the following states:
// PFS_Closed (MAC layer is still up)
// PFS_Closing (MAC layer is up, waiting for terminate-ack)
//
// Allocate and add the close request to the queue of
// pending close requests.
//
dwResult = pppInsertCompleteCallbackRequest(&pContext->pPendingCloseCompleteList, pLcpCloseCompleteCallback, pCallbackData);
if (ERROR_SUCCESS != dwResult)
{
// Unable to allocate callback structure. Perform callback immediately as if LCP was down (no graceful LCP shutdown).
if (pLcpCloseCompleteCallback)
pLcpCloseCompleteCallback(pCallbackData);
}
else
{
if (pContext->pFsm->state == PFS_Closed)
{
// Need to terminate MAC layer to get to Initial state
pppMac_CallClose(pContext->session->macCntxt, NULL, NULL);
// When lcpLowerLayerDown is called, we will enter the PFS_Initial state and
// process pPendingCloseCompleteList
}
else // PFS_Closing state
{
// lcpFinished will be called when the state machine transitions from:
// PFS_Closing to PFS_Initial (on a Down indication) or
// PFS_Closing to PFS_Closed (on receive-terminate-ack)
}
}
}
DEBUGMSG(ZONE_FUNCTION, (TEXT( "PPP: -pppLcp_Close\n" )));
}
void
pppLcp_Rejected(
IN PVOID context )
//
// Called when the peer rejects the LCP protocol.
// The link will be terminated.
//
{
PLCPContext pContext = (PLCPContext)context;
PppFsmProtocolRejected(pContext->pFsm);
}
static BOOLEAN
StringIsInMultiSz(
IN PWSTR sz,
IN PWSTR multisz)
//
// Return TRUE if sz is one of the strings in multisz.
//
{
BOOLEAN bFound = FALSE;
while (*multisz != L'\0')
{
if (wcsicmp(sz, multisz) == 0)
{
bFound = TRUE;
break;
}
multisz += wcslen(multisz) + 1;
}
return bFound;
}
DWORD
LcpOpen(
IN PVOID context)
//
// Called when RasIoControl is invoked to cause us to open LCP.
//
{
PLCPContext pContext = (PLCPContext)context;
DEBUGMSG(ZONE_LCP, (TEXT("PPP: Open LCP\n")));
return PppFsmOpen(pContext->pFsm);
}
DWORD
LcpClose(
IN PVOID context)
//
// Called when RasIoControl is invoked to cause us to open LCP.
//
{
PLCPContext pContext = (PLCPContext)context;
DEBUGMSG(ZONE_LCP, (TEXT("PPP: Close LCP\n")));
return PppFsmClose(pContext->pFsm);
}
DWORD
LcpRenegotiate(
IN PVOID context)
//
// Called when RasIoControl is invoked to cause us to renegotiate
// our LCP parameters, typically after we have modified one of
// the settings.
//
{
PLCPContext pContext = (PLCPContext)context;
DEBUGMSG(ZONE_LCP, (TEXT("PPP: Renegotiate LCP\n")));
return PppFsmRenegotiate(pContext->pFsm);
}
DWORD
LcpGetParameter(
IN PVOID context,
IN OUT PRASCNTL_LAYER_PARAMETER pParm,
IN OUT PDWORD pcbParm)
//
// Called by RasIoControl to get a particular LCP parameter.
//
{
PLCPContext pContext = (PLCPContext)context;
DWORD dwResult = ERROR_SUCCESS;
lcpOptValue_t *pValues = &pContext->local;
pParm->dwValueType = RASCNTL_LAYER_PARAMETER_TYPE_DWORD;
pParm->dwValueSize = sizeof(DWORD);
switch (pParm->dwParameterId)
{
case LCP_OPT_MRU:
pParm->dwValue = pValues->MRU;
break;
case LCP_OPT_ACCM:
pParm->dwValue = pValues->ACCM;
break;
case LCP_OPT_AUTH_PROTOCOL:
pParm->dwValue = pValues->Auth.Protocol;
break;
case LCP_OPT_MAGIC_NUMBER:
pParm->dwValue = pValues->MagicNumber;
break;
case LCP_OPT_PFC:
pParm->dwValue = pValues->bPFC;
break;
case LCP_OPT_ACFC:
pParm->dwValue = pValues->bACFC;
break;
default:
dwResult = ERROR_INVALID_PARAMETER;
break;
}
return dwResult;
}
DWORD
LcpSetParameter(
IN PVOID context,
IN PRASCNTL_LAYER_PARAMETER pParm,
IN DWORD cbParm)
//
// Called by RasIoControl to set a particular LCP parameter.
//
{
PLCPContext pContext = (PLCPContext)context;
DWORD dwResult = ERROR_SUCCESS;
lcpOptValue_t *pValues = &pContext->local;
switch (pParm->dwParameterId)
{
case LCP_OPT_MRU:
pValues->MRU = (USHORT)pParm->dwValue;;
break;
case LCP_OPT_ACCM:
pContext->DesiredACCM = pParm->dwValue;
break;
case LCP_OPT_AUTH_PROTOCOL:
pValues->Auth.Protocol = (USHORT)pParm->dwValue;
break;
case LCP_OPT_MAGIC_NUMBER:
pValues->MagicNumber = pParm->dwValue;
break;
case LCP_OPT_PFC:
pValues->bPFC = pParm->dwValue;
break;
case LCP_OPT_ACFC:
pValues->bACFC = pParm->dwValue;
break;
default:
dwResult = ERROR_INVALID_PARAMETER;
break;
}
return dwResult;
}
PROTOCOL_DESCRIPTOR pppLcpProtocolDescriptor =
{
pppLcpRcvData,
LcpProtocolRejected,
LcpOpen,
LcpClose,
LcpRenegotiate,
LcpGetParameter,
LcpSetParameter
};
DWORD
pppLcp_InstanceCreate(
IN PVOID session,
OUT PVOID *ReturnedContext)
//
// Called during session creation to allocate and initialize the IPCP protocol
// context.
//
{
pppSession_t *pSession = (pppSession_t *)session;
RASPENTRY *pRasEntry = &pSession->rasEntry;
PLCPContext pContext;
DWORD dwResult = NO_ERROR;
WCHAR wmszIdleDeviceTypes[MAX_PATH];
DEBUGMSG( ZONE_LCP | ZONE_FUNCTION, (TEXT( "pppLcp_InstanceCreate\r\n" )));
ASSERT( session );
do
{
pContext = (PLCPContext)pppAlloc(pSession, sizeof(*pContext), TEXT( "IPCP CONTEXT" ) );
if( pContext == NULL )
{
DEBUGMSG( ZONE_LCP, (TEXT( "PPP: ERROR: NO MEMORY for IPCP context\r\n" )) );
dwResult = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Register LCP context and protocol decriptor with session
dwResult = PPPSessionRegisterProtocol(pSession, PPP_PROTOCOL_LCP, &pppLcpProtocolDescriptor, pContext);
if (dwResult != NO_ERROR)
break;
// Initialize context
pContext->session = session;
pContext->pPendingCloseCompleteList = NULL;
CTEInitTimer(&pContext->IdleDisconnectTimer);
pContext->dwIdleDisconnectMs = DEFAULT_IDLE_DISCONNECT_MS;
pContext->dwEchoRequestIntervalMs = DEFAULT_ECHO_REQUEST_INTERVAL_MS;
memset(wmszIdleDeviceTypes, 0, sizeof(wmszIdleDeviceTypes));
wcscpy(wmszIdleDeviceTypes, RASDT_PPPoE);
(void)ReadRegistryValues(HKEY_LOCAL_MACHINE, TEXT("Comm\\ppp\\Parms"),
RAS_VALUENAME_LCP_IDLE_DISCONNECT_MS, REG_DWORD, 0, &pContext->dwIdleDisconnectMs, sizeof(DWORD),
RAS_VALUENAME_LCP_ECHO_REQUEST_INTERVAL_MS, REG_DWORD, 0, &pContext->dwEchoRequestIntervalMs, sizeof(DWORD),
RAS_VALUENAME_LCP_IDLE_DEVICE_TYPES, REG_MULTI_SZ, 0, &wmszIdleDeviceTypes[0], sizeof(wmszIdleDeviceTypes),
NULL);
if (!StringIsInMultiSz(pRasEntry->szDeviceType, wmszIdleDeviceTypes))
{
// Disable Idle Disconnect detection for this connection
pContext->dwIdleDisconnectMs = 0;
}
// Create Fsm
pContext->pFsm = PppFsmNew(&lcpFsmData, lcpResetPeerOptionValuesCb, pContext);
if (pContext->pFsm == NULL)
{
dwResult = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Configure option values
lcpOptionInit(pContext);
// Put the FSM into the opened state, ready to go when the lower layer comes up
PppFsmOpen(pContext->pFsm);
} while (FALSE);
if (dwResult != NO_ERROR)
{
pppFree(pSession, pContext, TEXT( "LCP CONTEXT" ));
pContext = NULL;
}
*ReturnedContext = pContext;
return dwResult;
}
void
pppLcp_InstanceDelete(
IN PVOID context )
//
// Called during session deletion to free the IPCP protocol context
// created by pppLcp_InstanceCreate.
//
{
PLCPContext pContext = (PLCPContext)context;
DEBUGMSG(ZONE_FUNCTION, (TEXT("+pppLcp_InstanceDelete\r\n" )));
if (context)
{
DEBUGMSG(ZONE_LCP, (TEXT( "PPP: Close LCP\n" )));
lcpIdleDisconnectTimerStop(pContext);
PppFsmClose(pContext->pFsm);
PppFsmDelete(pContext->pFsm);
pppFree( pContext->session, pContext, TEXT( "LCP CONTEXT" ) );
}
DEBUGMSG(ZONE_FUNCTION, (TEXT("-pppLcp_InstanceDelete\r\n" )));
}
DWORD
pppLcp_QueryParameter(
IN PVOID context,
IN BOOL bLocal,
IN DWORD type,
OUT PVOID pValue,
IN OUT PDWORD pcbValue)
//
// Query the value of a parameter negotiated by LCP
//
{
PLCPContext pContext = (PLCPContext)context;
DWORD dwResult = NO_ERROR;
lcpOptValue_t *pValues = bLocal ? &pContext->local : &pContext->peer;
PVOID pCurValue;
DWORD dwSize;
switch(type)
{
case LCP_OPT_MRU:
dwSize = sizeof(pValues->MRU);
pCurValue = &pValues->MRU;
break;
case LCP_OPT_AUTH_PROTOCOL:
dwSize = sizeof(lcpAuthValue_t);
pCurValue = &pValues->Auth;
break;
default:
dwResult = ERROR_INVALID_PARAMETER;
break;
}
if (dwResult == NO_ERROR)
{
if (*pcbValue < dwSize)
dwResult = ERROR_INSUFFICIENT_BUFFER;
else
memcpy(pValue, pCurValue, dwSize);
*pcbValue = dwSize;
}
return dwResult;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -