714 lines
22 KiB
C++
714 lines
22 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
lcp.cpp
|
|
|
|
Abstract:
|
|
|
|
Line Control Protocol.
|
|
|
|
Revision History:
|
|
|
|
07-11-00 vadimg created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
LCP_OPTIONS gLcpDefault = {
|
|
0, // Negotiation flags
|
|
LCP_DEFAULT_MRU, // Default value for MRU
|
|
0xFFFFFFFF, // Default ACCM value.
|
|
0, // no authentication ( for client )
|
|
0, // no authentication data ( for client )
|
|
NULL, // no authentication data ( for client )
|
|
0, // Magic Number.
|
|
FALSE, // Protocol field compression.
|
|
FALSE, // Address and Contorl-Field Compression.
|
|
0, // Callback Operation message field
|
|
LCP_DEFAULT_MRU, // Default value for MRRU == MRU according to RFC1717
|
|
0, // No short sequencing
|
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // No endpoint discriminator
|
|
0, // Length of Endpoint Discriminator
|
|
0 // Link Discriminator (for BAP/BACP)
|
|
};
|
|
|
|
DWORD gSizeOfOption[] = {
|
|
0, // unused
|
|
PPP_OPTION_HDR_LEN + 2, // MRU
|
|
PPP_OPTION_HDR_LEN + 4, // ACCM
|
|
PPP_OPTION_HDR_LEN + 2, // authentication
|
|
0, // Unused.
|
|
PPP_OPTION_HDR_LEN + 4, // magic number
|
|
0, // Reserved, unused
|
|
PPP_OPTION_HDR_LEN + 0, // Protocol compression
|
|
PPP_OPTION_HDR_LEN + 0, // Address/Control compression
|
|
0, // Unused
|
|
0, // Unused
|
|
0, // Unused
|
|
0, // Unused
|
|
PPP_OPTION_HDR_LEN + 1, // Callback
|
|
0, // Unused
|
|
0, // Unused
|
|
0, // Unused
|
|
PPP_OPTION_HDR_LEN + 2, // MRRU
|
|
PPP_OPTION_HDR_LEN + 0, // Short Sequence Header Format
|
|
PPP_OPTION_HDR_LEN, // Endpoint Discriminator
|
|
0, // Unused
|
|
0, // Unused
|
|
0, // Unused
|
|
PPP_OPTION_HDR_LEN + 2 // Link Discriminator (for BAP/BACP)
|
|
};
|
|
|
|
DWORD gLcpNegotiate = LCP_N_MRU | LCP_N_ACCM | LCP_N_AUTHENT | LCP_N_MAGIC | LCP_N_PFC | LCP_N_ACFC;
|
|
|
|
/***************************************************************************\
|
|
* MakeOption
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD MakeOption(LCP_OPTIONS *pOption, DWORD dwOptionCode,
|
|
PPP_OPTION *pSendOption, DWORD cbSendOption)
|
|
{
|
|
if (cbSendOption < gSizeOfOption[dwOptionCode]) {
|
|
return ERROR_BUFFER_TOO_SMALL;
|
|
}
|
|
|
|
pSendOption->Type = (BYTE)dwOptionCode;
|
|
pSendOption->Length = (BYTE)gSizeOfOption[dwOptionCode];
|
|
|
|
switch (dwOptionCode) {
|
|
case LCP_OPTION_MRU:
|
|
HostToWireFormat16((WORD)pOption->MRU, pSendOption->Data);
|
|
break;
|
|
|
|
case LCP_OPTION_ACCM:
|
|
HostToWireFormat32(pOption->ACCM, pSendOption->Data);
|
|
break;
|
|
|
|
case LCP_OPTION_AUTHENT:
|
|
if (cbSendOption < (gSizeOfOption[dwOptionCode] + pOption->APDataSize)) {
|
|
return ERROR_BUFFER_TOO_SMALL;
|
|
}
|
|
HostToWireFormat16((WORD)pOption->AP, pSendOption->Data);
|
|
CopyMemory(pSendOption->Data + 2, pOption->pAPData, pOption->APDataSize);
|
|
pSendOption->Length += (BYTE)pOption->APDataSize;
|
|
break;
|
|
|
|
case LCP_OPTION_MAGIC:
|
|
HostToWireFormat32(pOption->MagicNumber, pSendOption->Data);
|
|
break;
|
|
|
|
case LCP_OPTION_PFC:
|
|
break;
|
|
|
|
case LCP_OPTION_ACFC:
|
|
break;
|
|
|
|
case LCP_OPTION_MRRU:
|
|
HostToWireFormat16((WORD)pOption->MRRU, pSendOption->Data);
|
|
break;
|
|
|
|
default:
|
|
return ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* CheckOption
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD CheckOption(LCP_SIDE *pLcpSide, PPP_OPTION *pOption, BOOL fMakingResult)
|
|
{
|
|
DWORD dwIndex;
|
|
DWORD dwAPDataSize;
|
|
DWORD dwRetCode = CONFIG_ACK;
|
|
|
|
if (pOption->Length < gSizeOfOption[pOption->Type]) {
|
|
return CONFIG_REJ;
|
|
}
|
|
|
|
// If we do not want to negotiate the option we CONFIG_REJ it.
|
|
if (!(pLcpSide->WillNegotiate & (1 << pOption->Type))) {
|
|
return CONFIG_REJ;
|
|
}
|
|
|
|
switch (pOption->Type) {
|
|
case LCP_OPTION_MRU:
|
|
pLcpSide->Work.MRU = WireToHostFormat16(pOption->Data);
|
|
|
|
// Check to see if this value is appropriate
|
|
if (fMakingResult) {
|
|
|
|
// We cannot send packets smaller than LCP_DEFAULT_MRU
|
|
if (pLcpSide->Work.MRU < LCP_DEFAULT_MRU) {
|
|
pLcpSide->Work.MRU = pLcpSide->Want.MRU;
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
} else {
|
|
|
|
// We cannot receive bigger packets.
|
|
if (pLcpSide->Work.MRU > pLcpSide->Want.MRU) {
|
|
pLcpSide->Work.MRU = pLcpSide->Want.MRU;
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LCP_OPTION_ACCM:
|
|
pLcpSide->Work.ACCM = WireToHostFormat32(pOption->Data);
|
|
|
|
// If we are responding to a request, we accept it blindly, if we are
|
|
// processing a NAK, then the remote host may ask to escape more
|
|
// control characters than we require, but must escape at least the
|
|
// control chars that we require.
|
|
if (!fMakingResult) {
|
|
if (pLcpSide->Work.ACCM !=
|
|
(pLcpSide->Work.ACCM | pLcpSide->Want.ACCM)) {
|
|
pLcpSide->Work.ACCM |= pLcpSide->Want.ACCM;
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LCP_OPTION_AUTHENT:
|
|
pLcpSide->Work.AP = WireToHostFormat16( pOption->Data );
|
|
|
|
// If there was Authentication data.
|
|
if (pOption->Length > PPP_OPTION_HDR_LEN + 2) {
|
|
|
|
dwAPDataSize = pOption->Length - PPP_OPTION_HDR_LEN - 2;
|
|
|
|
if (dwAPDataSize != pLcpSide->Work.APDataSize) {
|
|
|
|
pLcpSide->Work.APDataSize = dwAPDataSize;
|
|
|
|
if (pLcpSide->Work.pAPData != NULL) {
|
|
Free(pLcpSide->Work.pAPData);
|
|
pLcpSide->Work.pAPData = NULL;
|
|
}
|
|
|
|
pLcpSide->Work.pAPData = (PBYTE)Alloc(pLcpSide->Work.APDataSize);
|
|
|
|
if (pLcpSide->Work.pAPData == NULL) {
|
|
pLcpSide->Work.APDataSize = 0;
|
|
return CONFIG_REJ;
|
|
}
|
|
}
|
|
|
|
CopyMemory(pLcpSide->Work.pAPData, pOption->Data + 2,
|
|
pLcpSide->Work.APDataSize);
|
|
|
|
} else {
|
|
|
|
pLcpSide->Work.APDataSize = 0;
|
|
}
|
|
|
|
switch (pLcpSide->Work.AP) {
|
|
case PPP_PAP_PROTOCOL:
|
|
if (!(pLcpSide->APsAvailable & LCP_AP_PAP)) {
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
dwRetCode = CONFIG_NAK;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case LCP_OPTION_MAGIC:
|
|
pLcpSide->Work.MagicNumber = WireToHostFormat32(pOption->Data);
|
|
|
|
if (fMakingResult) {
|
|
|
|
// Ensure that magic numbers are different and that the remote
|
|
// request does not contain a magic number of 0.
|
|
if ((pLcpSide->Work.MagicNumber == gLcp.Local.Work.MagicNumber) ||
|
|
(pLcpSide->Work.MagicNumber == 0)) {
|
|
|
|
if (pLcpSide->Work.MagicNumber == gLcp.Local.Work.MagicNumber) {
|
|
++gLcp.dwMagicNumberFailureCount;
|
|
}
|
|
|
|
pLcpSide->Work.MagicNumber = GetMagicNumber();
|
|
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
} else {
|
|
|
|
// The remote peer NAK'ed with a magic number, check to see if
|
|
// the magic number in the NAK is the same as what we NAK'ed last
|
|
if (pLcpSide->Work.MagicNumber == gLcp.Remote.Work.MagicNumber) {
|
|
|
|
++gLcp.dwMagicNumberFailureCount;
|
|
|
|
pLcpSide->Work.MagicNumber = GetMagicNumber();
|
|
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LCP_OPTION_PFC:
|
|
pLcpSide->Work.PFC = TRUE;
|
|
|
|
if (pLcpSide->Want.PFC == FALSE) {
|
|
dwRetCode = CONFIG_REJ;
|
|
}
|
|
break;
|
|
|
|
case LCP_OPTION_ACFC:
|
|
pLcpSide->Work.ACFC = TRUE;
|
|
|
|
if (pLcpSide->Want.ACFC == FALSE) {
|
|
dwRetCode = CONFIG_REJ;
|
|
}
|
|
break;
|
|
|
|
case LCP_OPTION_MRRU:
|
|
pLcpSide->Work.MRRU = WireToHostFormat16(pOption->Data);
|
|
|
|
// Check to see if this value is appropriate
|
|
if (fMakingResult) {
|
|
|
|
// We cannot send smaller reconstructed packets.
|
|
if (pLcpSide->Work.MRRU < pLcpSide->Want.MRRU) {
|
|
pLcpSide->Work.MRRU = pLcpSide->Want.MRRU;
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
} else {
|
|
|
|
// We cannot receive bigger reconstructed packets.
|
|
if (pLcpSide->Work.MRRU > pLcpSide->Want.MRRU) {
|
|
pLcpSide->Work.MRRU = pLcpSide->Want.MRRU;
|
|
dwRetCode = CONFIG_NAK;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// If we do not recognize the option we CONFIG_REJ it.
|
|
dwRetCode = CONFIG_REJ;
|
|
break;
|
|
}
|
|
|
|
return dwRetCode;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* BuildOptionList
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD BuildOptionList(BYTE *pOptions, DWORD *pcbOptions,
|
|
LCP_OPTIONS *LcpOptions, DWORD Negotiate)
|
|
{
|
|
DWORD OptionType;
|
|
DWORD dwRetCode;
|
|
DWORD cbOptionLength = *pcbOptions;
|
|
DWORD dwResult;
|
|
|
|
for (OptionType = 1; OptionType <= LCP_OPTION_LIMIT; OptionType++) {
|
|
if (Negotiate & (1 << OptionType)) {
|
|
|
|
dwResult = MakeOption(LcpOptions, OptionType,
|
|
(PPP_OPTION*)pOptions, cbOptionLength);
|
|
|
|
if (dwResult != NO_ERROR) {
|
|
return dwResult;
|
|
}
|
|
|
|
cbOptionLength -= ((PPP_OPTION*)pOptions)->Length;
|
|
pOptions += ((PPP_OPTION*)pOptions)->Length;
|
|
}
|
|
}
|
|
*pcbOptions -= cbOptionLength;
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpMakeConfigResult
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpMakeConfigResult(PPP_CONFIG *pRecvConfig, PPP_CONFIG *pSendConfig,
|
|
DWORD cbSendConfig, BOOL fRejectNaks)
|
|
{
|
|
DWORD dwDesired;
|
|
DWORD dwRetCode;
|
|
DWORD ResultType = CONFIG_ACK;
|
|
PPP_OPTION *pRecvOption = (PPP_OPTION*)pRecvConfig->Data;
|
|
PPP_OPTION *pSendOption = (PPP_OPTION*)pSendConfig->Data;
|
|
LONG lSendLength = cbSendConfig - PPP_CONFIG_HDR_LEN;
|
|
LONG lRecvLength = WireToHostFormat16(pRecvConfig->Length) - PPP_CONFIG_HDR_LEN;
|
|
|
|
// Clear negotiate mask
|
|
gLcp.Remote.Work.Negotiate = 0;
|
|
|
|
while (lRecvLength > 0) {
|
|
|
|
if (pRecvOption->Length == 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
lRecvLength -= pRecvOption->Length;
|
|
|
|
if (lRecvLength < 0 ) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
dwRetCode = CheckOption(&gLcp.Remote, pRecvOption, TRUE);
|
|
|
|
// If we were building an ACK and we got a NAK or reject OR
|
|
// we were building a NAK and we got a reject.
|
|
if ((ResultType == CONFIG_ACK && dwRetCode != CONFIG_ACK) ||
|
|
(ResultType == CONFIG_NAK && dwRetCode == CONFIG_REJ)) {
|
|
ResultType = dwRetCode;
|
|
pSendOption = (PPP_OPTION*)pSendConfig->Data;
|
|
lSendLength = cbSendConfig - PPP_CONFIG_HDR_LEN;
|
|
}
|
|
|
|
// Remember that we processed this option
|
|
if (dwRetCode != CONFIG_REJ && pRecvOption->Type <= LCP_OPTION_LIMIT) {
|
|
gLcp.Remote.Work.Negotiate |= (1 << pRecvOption->Type);
|
|
}
|
|
|
|
if (dwRetCode == ResultType) {
|
|
|
|
// If this option is to be rejected, simply copy the
|
|
// rejected option to the send buffer
|
|
if (dwRetCode == CONFIG_REJ ||
|
|
(dwRetCode == CONFIG_NAK && fRejectNaks)) {
|
|
CopyMemory(pSendOption, pRecvOption, pRecvOption->Length);
|
|
} else {
|
|
|
|
dwRetCode = MakeOption(&gLcp.Remote.Work, pRecvOption->Type,
|
|
pSendOption, lSendLength);
|
|
|
|
if (dwRetCode != NO_ERROR) {
|
|
return dwRetCode;
|
|
}
|
|
}
|
|
|
|
lSendLength -= pSendOption->Length;
|
|
|
|
pSendOption = (PPP_OPTION*)((BYTE*)pSendOption + pSendOption->Length);
|
|
}
|
|
|
|
pRecvOption = (PPP_OPTION*)((BYTE*)pRecvOption + pRecvOption->Length);
|
|
}
|
|
|
|
// If this was an NAK and we cannot send any more NAKS then we
|
|
// make this a REJECT packet
|
|
if (ResultType == CONFIG_NAK && fRejectNaks) {
|
|
pSendConfig->Code = CONFIG_REJ;
|
|
} else {
|
|
pSendConfig->Code = (BYTE)ResultType;
|
|
}
|
|
|
|
HostToWireFormat16((WORD)(cbSendConfig - lSendLength), pSendConfig->Length);
|
|
|
|
if (ResultType == CONFIG_NAK && gLcp.dwMagicNumberFailureCount > 3) {
|
|
return ERROR_PPP_LOOPBACK_DETECTED;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpMakeConfigRequest
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpMakeConfigRequest(PPP_CONFIG *pConfig, DWORD cbConfig)
|
|
{
|
|
DWORD dwRetCode;
|
|
|
|
cbConfig -= PPP_CONFIG_HDR_LEN;
|
|
|
|
dwRetCode = BuildOptionList(pConfig->Data, &cbConfig, &gLcp.Local.Work,
|
|
gLcp.Local.Work.Negotiate);
|
|
|
|
if (dwRetCode != NO_ERROR) {
|
|
return dwRetCode;
|
|
}
|
|
|
|
HostToWireFormat16((WORD)(cbConfig + PPP_CONFIG_HDR_LEN), pConfig->Length);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpConfigAckReceived
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpConfigAckReceived(PPP_CONFIG *pConfig)
|
|
{
|
|
DWORD dwRetCode;
|
|
BYTE ConfigReqSent[LCP_DEFAULT_MRU];
|
|
PPP_OPTION *pOption = (PPP_OPTION*)pConfig->Data;
|
|
DWORD cbConfigReqSent = sizeof(ConfigReqSent);
|
|
DWORD dwLength;
|
|
|
|
dwLength = WireToHostFormat16(pConfig->Length) - PPP_CONFIG_HDR_LEN;
|
|
|
|
// Get a copy of last request we sent
|
|
dwRetCode = BuildOptionList(ConfigReqSent, &cbConfigReqSent,
|
|
&gLcp.Local.Work, gLcp.Local.Work.Negotiate);
|
|
|
|
if (dwRetCode != NO_ERROR) {
|
|
return dwRetCode;
|
|
}
|
|
|
|
if (dwLength != cbConfigReqSent) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
if (memcmp(ConfigReqSent, pConfig->Data, dwLength) != 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpConfigNakReceived
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpConfigNakReceived(PPP_CONFIG *pConfig)
|
|
{
|
|
LONG cbConfig = WireToHostFormat16(pConfig->Length) - PPP_CONFIG_HDR_LEN;
|
|
PPP_OPTION *pOption = (PPP_OPTION*)pConfig->Data;
|
|
DWORD dwLastOption = 0;
|
|
DWORD dwResult;
|
|
|
|
while (cbConfig > 0) {
|
|
|
|
if (pOption->Length == 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
cbConfig -= pOption->Length;
|
|
|
|
if (cbConfig < 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
// If this option wasn't requested, mark it as negotiable.
|
|
if (pOption->Type <= LCP_OPTION_LIMIT &&
|
|
(gLcp.Local.WillNegotiate & (1 << pOption->Type)) &&
|
|
!(gLcp.Local.Work.Negotiate & (1 << pOption->Type))) {
|
|
gLcp.Local.Work.Negotiate |= (1 << pOption->Type);
|
|
}
|
|
|
|
dwLastOption = pOption->Type;
|
|
|
|
dwResult = CheckOption(&gLcp.Local, pOption, FALSE);
|
|
|
|
if (dwResult == CONFIG_REJ && pOption->Type <= LCP_OPTION_LIMIT) {
|
|
gLcp.Local.Work.Negotiate &= ~(1 << pOption->Type);
|
|
}
|
|
|
|
pOption = (PPP_OPTION*)((BYTE*)pOption + pOption->Length);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpConfigRejReceived
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpConfigRejReceived(PPP_CONFIG *pConfig)
|
|
{
|
|
LONG cbConfig = WireToHostFormat16(pConfig->Length) - PPP_CONFIG_HDR_LEN;
|
|
PPP_OPTION *pOption = (PPP_OPTION*)pConfig->Data;
|
|
DWORD dwLastOption = 0;
|
|
DWORD dwResult;
|
|
BYTE ReqOption[LCP_DEFAULT_MRU];
|
|
|
|
while (cbConfig > 0) {
|
|
|
|
if (pOption->Length == 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
cbConfig -= pOption->Length;
|
|
|
|
if (cbConfig < 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
// Can't receive an option out of order or an option that wasn't
|
|
// requested.
|
|
if (pOption->Type <= LCP_OPTION_LIMIT &&
|
|
(pOption->Type < dwLastOption ||
|
|
!(gLcp.Local.Work.Negotiate & (1 << pOption->Type)))) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
dwResult = MakeOption(&gLcp.Local.Work, pOption->Type,
|
|
(PPP_OPTION*)ReqOption, sizeof(ReqOption));
|
|
|
|
if (dwResult != NO_ERROR) {
|
|
return dwResult;
|
|
}
|
|
|
|
if (memcmp(ReqOption, pOption, pOption->Length) != 0) {
|
|
return ERROR_PPP_INVALID_PACKET;
|
|
}
|
|
|
|
dwLastOption = pOption->Type;
|
|
|
|
if (pOption->Type <= LCP_OPTION_LIMIT) {
|
|
gLcp.Local.Work.Negotiate &= ~(1 << pOption->Type);
|
|
}
|
|
|
|
pOption = (PPP_OPTION*)((BYTE*)pOption + pOption->Length);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpThisLayerUp
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpThisLayerUp(VOID)
|
|
{
|
|
if (gLcp.Local.Work.Negotiate & LCP_N_ACCM) {
|
|
gFraming.RecvAccm = gLcp.Local.Work.ACCM;
|
|
}
|
|
if (gLcp.Local.Work.Negotiate & LCP_N_PFC) {
|
|
gFraming.fRecvPfc = gLcp.Local.Work.PFC;
|
|
}
|
|
if (gLcp.Local.Work.Negotiate & LCP_N_ACFC) {
|
|
gFraming.fRecvAcfc = gLcp.Local.Work.ACFC;
|
|
}
|
|
|
|
if (gLcp.Remote.Work.Negotiate & LCP_N_ACCM) {
|
|
gFraming.SendAccm = gLcp.Remote.Work.ACCM;
|
|
}
|
|
if (gLcp.Remote.Work.Negotiate & LCP_N_PFC) {
|
|
gFraming.fSendPfc = gLcp.Remote.Work.PFC;
|
|
}
|
|
if (gLcp.Remote.Work.Negotiate & LCP_N_ACFC) {
|
|
gFraming.fSendAcfc = gLcp.Remote.Work.ACFC;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpThisLayerDown
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpThisLayerDown(VOID)
|
|
{
|
|
if (gLcp.Local.Work.Negotiate & LCP_N_ACCM) {
|
|
gFraming.RecvAccm = gLcpDefault.ACCM;
|
|
}
|
|
if (gLcp.Local.Work.Negotiate & LCP_N_PFC) {
|
|
gFraming.fRecvPfc = gLcpDefault.PFC;
|
|
}
|
|
if (gLcp.Local.Work.Negotiate & LCP_N_ACFC) {
|
|
gFraming.fRecvAcfc = gLcpDefault.ACFC;
|
|
}
|
|
|
|
if (gLcp.Remote.Work.Negotiate & LCP_N_ACCM) {
|
|
gFraming.SendAccm = gLcpDefault.ACCM;
|
|
}
|
|
if (gLcp.Remote.Work.Negotiate & LCP_N_PFC) {
|
|
gFraming.fSendPfc = gLcpDefault.PFC;
|
|
}
|
|
if (gLcp.Remote.Work.Negotiate & LCP_N_ACFC) {
|
|
gFraming.fSendAcfc = gLcpDefault.ACFC;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpEnd
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpEnd(VOID)
|
|
{
|
|
if (gLcp.Local.Work.pAPData != NULL) {
|
|
Free(gLcp.Local.Work.pAPData);
|
|
}
|
|
if (gLcp.Remote.Work.pAPData != NULL) {
|
|
Free(gLcp.Remote.Work.pAPData);
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* LcpBegin
|
|
*
|
|
\***************************************************************************/
|
|
|
|
DWORD LcpBegin(VOID)
|
|
{
|
|
CopyMemory(&gLcp.Local.Want, &gLcpDefault, sizeof(LCP_OPTIONS));
|
|
CopyMemory(&gLcp.Remote.Want, &gLcpDefault, sizeof(LCP_OPTIONS));
|
|
|
|
gLcp.Local.WillNegotiate = gLcpNegotiate;
|
|
gLcp.Remote.WillNegotiate = gLcpNegotiate;
|
|
|
|
gLcp.Remote.APsAvailable = LCP_AP_PAP;
|
|
|
|
gLcp.Local.Want.MagicNumber = GetMagicNumber();
|
|
gLcp.Remote.Want.MagicNumber = gLcp.Local.Want.MagicNumber + 1;
|
|
|
|
gLcp.Local.Want.ACCM = 0;
|
|
gLcp.Local.Want.PFC = TRUE;
|
|
gLcp.Local.Want.ACFC = TRUE;
|
|
|
|
gLcp.Remote.Want.ACCM = 0;
|
|
gLcp.Remote.Want.PFC = TRUE;
|
|
gLcp.Remote.Want.ACFC = TRUE;
|
|
|
|
gLcp.Local.Want.Negotiate = (LCP_N_MAGIC | LCP_N_ACCM | LCP_N_PFC | LCP_N_ACFC);
|
|
gLcp.Remote.Want.Negotiate = (LCP_N_MAGIC | LCP_N_ACCM | LCP_N_PFC | LCP_N_ACFC);
|
|
|
|
CopyMemory(&gLcp.Local.Work, &gLcp.Local.Want, sizeof(LCP_OPTIONS));
|
|
CopyMemory(&gLcp.Remote.Work, &gLcp.Remote.Want, sizeof(LCP_OPTIONS));
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetLcpInfo
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID GetLcpInfo(PPP_CP_INFO *pInfo)
|
|
{
|
|
ZeroMemory(pInfo, sizeof(PPP_CP_INFO));
|
|
pInfo->Protocol = PPP_LCP_PROTOCOL;
|
|
pInfo->Recognize = DISCARD_REQ;
|
|
pInfo->CP_Begin = LcpBegin;
|
|
pInfo->CP_End = LcpEnd;
|
|
pInfo->CP_ThisLayerDown = LcpThisLayerDown;
|
|
pInfo->CP_ThisLayerUp = LcpThisLayerUp;
|
|
pInfo->CP_ConfigNakReceived = LcpConfigNakReceived;
|
|
pInfo->CP_ConfigRejReceived = LcpConfigRejReceived;
|
|
pInfo->CP_ConfigAckReceived = LcpConfigAckReceived;
|
|
pInfo->CP_MakeConfigResult = LcpMakeConfigResult;
|
|
pInfo->CP_MakeConfigRequest = LcpMakeConfigRequest;
|
|
}
|
|
|