windows-nt/Source/XPSP1/NT/net/rras/ras/ppp/engine/lcp.c

2492 lines
67 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/********************************************************************/
/** Copyright(c) 1989 Microsoft Corporation. **/
/********************************************************************/
//***
//
// Filename: lcp.c
//
// Description: Contains entry points to configure LCP.
//
// History:
// Nov 11,1993. NarenG Created original version.
//
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h> // needed for winbase.h
#include <windows.h> // Win32 base API's
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <lmcons.h>
#include <raserror.h>
#include <mprerror.h>
#include <rasman.h>
#include <rasppp.h>
#include <pppcp.h>
#include <ppp.h>
#include <smaction.h>
#include <lcp.h>
#include <timer.h>
#include <util.h>
#include <worker.h>
//
// Default values
//
const static LCP_OPTIONS LcpDefault =
{
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)
};
//
// Accept anything we understand in the NAK and in a REQ from a remote host
//
static DWORD LcpNegotiate = LCP_N_MRU | LCP_N_ACCM | LCP_N_MAGIC |
LCP_N_PFC | LCP_N_ACFC;
static DWORD SizeOfOption[] =
{
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)
};
WORD WLinkDiscriminator = 0; // Next Link Discriminator to use
BYTE BCount = 0; // To make EndpointDiscriminator different
//**
//
// Call: MakeAuthProtocolOption
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description: Given a certain authentication protocol, will construct the
// configuration option for it.
//
DWORD
MakeAuthProtocolOption(
IN LCP_SIDE * pLcpSide
)
{
switch( pLcpSide->fLastAPTried )
{
case LCP_AP_EAP:
pLcpSide->Work.AP = PPP_EAP_PROTOCOL;
if ( pLcpSide->Work.APDataSize != 0 )
{
pLcpSide->Work.APDataSize = 0;
if ( pLcpSide->Work.pAPData != NULL )
{
LOCAL_FREE( pLcpSide->Work.pAPData );
pLcpSide->Work.pAPData = NULL;
}
}
break;
case LCP_AP_CHAP_MS:
case LCP_AP_CHAP_MS_NEW:
default:
pLcpSide->Work.AP = PPP_CHAP_PROTOCOL;
if ( pLcpSide->Work.APDataSize != 1 )
{
pLcpSide->Work.APDataSize = 1;
if ( NULL != pLcpSide->Work.pAPData )
{
LOCAL_FREE( pLcpSide->Work.pAPData );
pLcpSide->Work.pAPData = NULL;
}
pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC(
LPTR,
pLcpSide->Work.APDataSize );
if ( pLcpSide->Work.pAPData == NULL )
{
pLcpSide->Work.APDataSize = 0;
return( GetLastError() );
}
}
if ( pLcpSide->fLastAPTried == LCP_AP_CHAP_MS_NEW )
{
*(pLcpSide->Work.pAPData) = PPP_CHAP_DIGEST_MSEXT_NEW;
}
else
{
*(pLcpSide->Work.pAPData) = PPP_CHAP_DIGEST_MSEXT;
}
break;
case LCP_AP_CHAP_MD5:
pLcpSide->Work.AP = PPP_CHAP_PROTOCOL;
if ( pLcpSide->Work.APDataSize != 1 )
{
pLcpSide->Work.APDataSize = 1;
if ( NULL != pLcpSide->Work.pAPData )
{
LOCAL_FREE( pLcpSide->Work.pAPData );
pLcpSide->Work.pAPData = NULL;
}
pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC(
LPTR,
pLcpSide->Work.APDataSize );
if ( pLcpSide->Work.pAPData == NULL )
{
pLcpSide->Work.APDataSize = 0;
return( GetLastError() );
}
}
*(pLcpSide->Work.pAPData) = PPP_CHAP_DIGEST_MD5;
break;
case LCP_AP_SPAP_NEW:
pLcpSide->Work.AP = PPP_SPAP_NEW_PROTOCOL;
if ( pLcpSide->Work.APDataSize != 4 )
{
pLcpSide->Work.APDataSize = 4;
if ( NULL != pLcpSide->Work.pAPData )
{
LOCAL_FREE( pLcpSide->Work.pAPData );
pLcpSide->Work.pAPData = NULL;
}
pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC(
LPTR,
pLcpSide->Work.APDataSize );
if ( pLcpSide->Work.pAPData == NULL )
{
pLcpSide->Work.APDataSize = 0;
return( GetLastError() );
}
}
HostToWireFormat32( LCP_SPAP_VERSION, pLcpSide->Work.pAPData );
break;
case LCP_AP_PAP:
pLcpSide->Work.AP = PPP_PAP_PROTOCOL;
if ( pLcpSide->Work.APDataSize != 0 )
{
pLcpSide->Work.APDataSize = 0;
if ( pLcpSide->Work.pAPData != NULL )
{
LOCAL_FREE( pLcpSide->Work.pAPData );
pLcpSide->Work.pAPData = NULL;
}
}
break;
}
return( NO_ERROR );
}
//**
//
// Call: LcpBegin
//
// Returns: NO_ERROR - Success
// non-zero error - Failure
//
//
// Description: Called once before any other call to LCP is made. Allocate
// a work buffer and initialize it.
//
DWORD
LcpBegin(
IN OUT VOID** ppWorkBuf,
IN VOID* pInfo
)
{
LCPCB * pLcpCb;
RAS_FRAMING_CAPABILITIES RasFramingCapabilities;
DWORD dwRetCode;
DWORD dwIndex;
PPPCP_INIT * pPppCpInit;
*ppWorkBuf = LOCAL_ALLOC( LPTR, sizeof( LCPCB ) );
if ( *ppWorkBuf == NULL )
{
return( GetLastError() );
}
pLcpCb = (LCPCB *)*ppWorkBuf;
pPppCpInit = (PPPCP_INIT *)pInfo;
pLcpCb->fServer = pPppCpInit->fServer;
pLcpCb->hPort = pPppCpInit->hPort;
pLcpCb->PppConfigInfo = pPppCpInit->PppConfigInfo;;
pLcpCb->fRouter = ( pPppCpInit->IfType ==
ROUTER_IF_TYPE_FULL_ROUTER );
pLcpCb->dwMagicNumberFailureCount = 0;
pLcpCb->dwMRUFailureCount = 2;
//
// Check to see if we need to override the Negotiate Multi Link
// send by the caller
// BugID: WINSE 17061 Windows Bugs: 347562
if ( PppConfigInfo.dwDontNegotiateMultiLinkOnSingleLink )
{
//remove NegotiateMultiLink from config info
PppLog( 2, "Removing NegotiateMultilink due to registry override" );
pLcpCb->PppConfigInfo.dwConfigMask &= ~PPPCFG_NegotiateMultilink;
}
//
// Set up defaults
//
CopyMemory( &(pLcpCb->Local.Want), &LcpDefault, sizeof( LCP_OPTIONS ) );
CopyMemory( &(pLcpCb->Remote.Want), &LcpDefault, sizeof( LCP_OPTIONS ) );
//
// Get Framing information from the driver.
//
dwRetCode = RasGetFramingCapabilities( pLcpCb->hPort,
&RasFramingCapabilities );
if ( dwRetCode != NO_ERROR )
{
LOCAL_FREE( *ppWorkBuf );
return( dwRetCode );
}
pLcpCb->Local.WillNegotiate = LcpNegotiate;
pLcpCb->Remote.WillNegotiate = LcpNegotiate;
pLcpCb->Local.Want.MRU = RasFramingCapabilities.RFC_MaxFrameSize;
pLcpCb->Remote.Want.MRU = RasFramingCapabilities.RFC_MaxFrameSize;
pLcpCb->Local.Want.Negotiate = LCP_N_MAGIC;
pLcpCb->Remote.Want.Negotiate = LCP_N_MAGIC;
if (RasFramingCapabilities.RFC_MaxFrameSize != LCP_DEFAULT_MRU) {
pLcpCb->Local.Want.Negotiate |= LCP_N_MRU;
pLcpCb->Remote.Want.Negotiate |= LCP_N_MRU;
}
if ( RasFramingCapabilities.RFC_FramingBits & PPP_COMPRESS_ADDRESS_CONTROL )
{
pLcpCb->Local.Want.ACFC = TRUE;
pLcpCb->Local.Want.Negotiate |= LCP_N_ACFC;
pLcpCb->Remote.Want.ACFC = TRUE;
pLcpCb->Remote.Want.Negotiate |= LCP_N_ACFC;
}
if ( RasFramingCapabilities.RFC_FramingBits & PPP_COMPRESS_PROTOCOL_FIELD )
{
pLcpCb->Local.Want.PFC = TRUE;
pLcpCb->Local.Want.Negotiate |= LCP_N_PFC;
pLcpCb->Remote.Want.PFC = TRUE;
pLcpCb->Remote.Want.Negotiate |= LCP_N_PFC;
}
if ( RasFramingCapabilities.RFC_FramingBits & PPP_ACCM_SUPPORTED )
{
pLcpCb->Local.Want.ACCM = RasFramingCapabilities.RFC_DesiredACCM;
pLcpCb->Local.Want.Negotiate |= LCP_N_ACCM;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateMultilink )
{
pLcpCb->Local.Want.dwEDLength =
( PppConfigInfo.EndPointDiscriminator[0] == 1 ) ? 21 : 7;
CopyMemory( pLcpCb->Local.Want.EndpointDiscr,
PppConfigInfo.EndPointDiscriminator,
pLcpCb->Local.Want.dwEDLength );
if ( ( pPppCpInit->dwDeviceType & RDT_Tunnel )
&& ( !pPppCpInit->fServer ) )
{
//
// If a VPN connection goes down unexpectedly, the server doesn't
// realize this for upto 2 min. When the client redials, we don't
// want the server to bundle the old link and the new one. Hence,
// we change the EndpointDiscriminator.
//
BCount++;
pLcpCb->Local.Want.EndpointDiscr[pLcpCb->Local.Want.dwEDLength-1]
+= BCount;
}
pLcpCb->Local.Want.Negotiate |= LCP_N_ENDPOINT;
pLcpCb->Remote.Want.Negotiate |= LCP_N_ENDPOINT;
pLcpCb->Local.Want.MRRU =
RasFramingCapabilities.RFC_MaxReconstructedFrameSize;
pLcpCb->Remote.Want.MRRU = 1500; // Can always handle sending 1500
pLcpCb->Local.Want.Negotiate |= LCP_N_MRRU;
pLcpCb->Remote.Want.Negotiate |= LCP_N_MRRU;
if ( RasFramingCapabilities.RFC_FramingBits &
PPP_SHORT_SEQUENCE_HDR_FORMAT )
{
pLcpCb->Local.Want.ShortSequence = TRUE;
pLcpCb->Local.Want.Negotiate |= LCP_N_SHORT_SEQ;
pLcpCb->Remote.Want.ShortSequence = TRUE;
pLcpCb->Remote.Want.Negotiate |= LCP_N_SHORT_SEQ;
}
pLcpCb->Local.WillNegotiate |= ( LCP_N_SHORT_SEQ | LCP_N_ENDPOINT |
LCP_N_MRRU );
pLcpCb->Remote.WillNegotiate |= ( LCP_N_SHORT_SEQ | LCP_N_ENDPOINT |
LCP_N_MRRU );
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateBacp )
{
pLcpCb->Local.Want.dwLinkDiscriminator = WLinkDiscriminator++;
pLcpCb->Remote.Want.dwLinkDiscriminator = 0;
pLcpCb->Local.Want.Negotiate |= LCP_N_LINK_DISCRIM;
pLcpCb->Remote.Want.Negotiate |= LCP_N_LINK_DISCRIM;
pLcpCb->Local.WillNegotiate |= LCP_N_LINK_DISCRIM;
pLcpCb->Remote.WillNegotiate |= LCP_N_LINK_DISCRIM;
}
}
//
// We always negotiate callback if this is not a callback
//
if ( !pPppCpInit->fThisIsACallback )
{
//
// If the CBCP dll is loaded
//
if ( GetCpIndexFromProtocol( PPP_CBCP_PROTOCOL ) != (DWORD)-1 )
{
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_UseLcpExtensions )
{
pLcpCb->Local.Want.Negotiate |= LCP_N_CALLBACK;
pLcpCb->Local.Want.Callback = PPP_NEGOTIATE_CALLBACK;
}
pLcpCb->Local.WillNegotiate |= LCP_N_CALLBACK;
pLcpCb->Remote.WillNegotiate |= LCP_N_CALLBACK;
}
}
//
// Figure out what authentication protocols we may use for this connection.
//
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiatePAP )
{
pLcpCb->Local.fAPsAvailable |= LCP_AP_PAP;
pLcpCb->Remote.fAPsAvailable |= LCP_AP_PAP;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateMD5CHAP )
{
pLcpCb->Remote.fAPsAvailable |= LCP_AP_CHAP_MD5;
pLcpCb->Local.fAPsAvailable |= LCP_AP_CHAP_MD5;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateMSCHAP )
{
pLcpCb->Local.fAPsAvailable |= LCP_AP_CHAP_MS;
pLcpCb->Remote.fAPsAvailable |= LCP_AP_CHAP_MS;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateEAP )
{
pLcpCb->Remote.fAPsAvailable |= LCP_AP_EAP;
pLcpCb->Local.fAPsAvailable |= LCP_AP_EAP;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateSPAP )
{
pLcpCb->Local.fAPsAvailable |= LCP_AP_SPAP_NEW;
pLcpCb->Remote.fAPsAvailable |= LCP_AP_SPAP_NEW;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_NegotiateStrongMSCHAP )
{
pLcpCb->Local.fAPsAvailable |= LCP_AP_CHAP_MS_NEW;
pLcpCb->Remote.fAPsAvailable |= LCP_AP_CHAP_MS_NEW;
}
if ( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AllowNoAuthOnDCPorts )
{
pLcpCb->Local.fAPsAvailable = 0;
pLcpCb->Remote.fAPsAvailable = 0;
}
//
// Make sure we have at least one authentication protocol if we are a
// server or a router dialing out. Fail if we are not allow no
// authentication.
//
if ( ( pLcpCb->Local.fAPsAvailable == 0 ) &&
( !( pLcpCb->PppConfigInfo.dwConfigMask &
PPPCFG_AllowNoAuthentication ) ) &&
( ( pLcpCb->fServer ) || ( pLcpCb->fRouter ) ) )
{
LOCAL_FREE( *ppWorkBuf );
return( ERROR_NO_AUTH_PROTOCOL_AVAILABLE );
}
PppLog( 2, "ConfigInfo = %x", pLcpCb->PppConfigInfo.dwConfigMask );
PppLog( 2, "APs available = %x", pLcpCb->Local.fAPsAvailable );
//
// If this is the server side or we are a router dialing out,
// we need to request an authentication protocol.
//
if ( ( pLcpCb->Local.fAPsAvailable > 0 ) &&
(( pLcpCb->fServer ) ||
( ( pLcpCb->fRouter ) &&
( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AuthenticatePeer ))))
{
pLcpCb->Local.Want.Negotiate |= LCP_N_AUTHENT;
pLcpCb->Local.WillNegotiate |= LCP_N_AUTHENT;
pLcpCb->Local.Work.APDataSize = 0;
pLcpCb->Local.Work.pAPData = NULL;
}
//
// If this is the client side and no protocol other than MSCHAP v2 and EAP
// is allowed, then we insist on being authenticated.
//
if (!( pLcpCb->fServer ))
{
if ( ( pLcpCb->Remote.fAPsAvailable & ~( LCP_AP_CHAP_MS_NEW |
LCP_AP_EAP ) ) == 0 )
{
pLcpCb->Remote.Work.APDataSize = 0;
pLcpCb->Remote.Work.pAPData = NULL;
pLcpCb->Remote.WillNegotiate |= LCP_N_AUTHENT;
pLcpCb->Remote.Want.Negotiate |= LCP_N_AUTHENT;
}
}
//
// Accept authentication if there are authentication protocols available
// If it turns out that it is a client dialing in then authentication
// will fail and we will renegotiate and this time we will reject
// authentication option. See auth.c.
//
if ( pLcpCb->Remote.fAPsAvailable > 0 )
{
pLcpCb->Remote.Work.APDataSize = 0;
pLcpCb->Remote.Work.pAPData = NULL;
pLcpCb->Remote.WillNegotiate |= LCP_N_AUTHENT;
}
return( NO_ERROR );
}
//**
//
// Call: LcpEnd
//
// Returns: NO_ERROR - Success
//
// Description: Frees the LCP work buffer.
//
DWORD
LcpEnd(
IN VOID * pWorkBuf
)
{
LCPCB * pLcpCb = (LCPCB *)pWorkBuf;
PppLog( 2, "LcpEnd");
if ( pLcpCb->Local.Work.pAPData != (PBYTE)NULL )
{
LOCAL_FREE( pLcpCb->Local.Work.pAPData );
}
if ( pLcpCb->Remote.Work.pAPData != (PBYTE)NULL )
{
LOCAL_FREE( pLcpCb->Remote.Work.pAPData );
}
if ( pWorkBuf != NULL )
{
LOCAL_FREE( pWorkBuf );
}
return( NO_ERROR );
}
//**
//
// Call: LcpReset
//
// Returns: NO_ERROR - Success
//
// Description: Called to reset the state of LCP. Will re-initialize the work
// buffer.
//
DWORD
LcpReset(
IN VOID * pWorkBuf
)
{
LCPCB * pLcpCb = (LCPCB *)pWorkBuf;
PVOID pAPData;
DWORD APDataSize;
DWORD dwIndex;
DWORD dwRetCode;
//
// Make sure we have at least one authentication protocol if we are a
// server or a router dialing out. Fail if we are not allow no
// authentication.
//
if ( ( pLcpCb->Local.fAPsAvailable == 0 ) &&
( !( pLcpCb->PppConfigInfo.dwConfigMask &
PPPCFG_AllowNoAuthentication ) ) &&
( ( pLcpCb->fServer ) || ( pLcpCb->fRouter ) ) )
{
return( ERROR_NO_AUTH_PROTOCOL_AVAILABLE );
}
pLcpCb->dwMagicNumberFailureCount = 0;
if ( pLcpCb->Local.Want.Negotiate & LCP_N_MAGIC )
{
srand( GetCurrentTime() );
//
// Shift left since rand returns a max of 0x7FFF
//
pLcpCb->Local.Want.MagicNumber = ( rand() << 16 );
pLcpCb->Local.Want.MagicNumber += rand();
//
// Make sure that this is not 0
//
if ( pLcpCb->Local.Want.MagicNumber == 0 )
{
pLcpCb->Local.Want.MagicNumber = 23;
}
pLcpCb->Remote.Want.MagicNumber = pLcpCb->Local.Want.MagicNumber + 1;
}
pAPData = pLcpCb->Local.Work.pAPData;
APDataSize = pLcpCb->Local.Work.APDataSize;
CopyMemory( &(pLcpCb->Local.Work),
&(pLcpCb->Local.Want),
sizeof(LCP_OPTIONS) );
pLcpCb->Local.Work.pAPData = pAPData;
pLcpCb->Local.Work.APDataSize = APDataSize;
pAPData = pLcpCb->Remote.Work.pAPData;
APDataSize = pLcpCb->Remote.Work.APDataSize;
CopyMemory( &(pLcpCb->Remote.Work),
&(pLcpCb->Remote.Want),
sizeof(LCP_OPTIONS));
pLcpCb->Remote.Work.pAPData = pAPData;
pLcpCb->Remote.Work.APDataSize = APDataSize;
if ( ( pLcpCb->Local.fAPsAvailable > 0 ) &&
(( pLcpCb->fServer ) ||
( ( pLcpCb->fRouter ) &&
( pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AuthenticatePeer ))))
{
//
// Start with the highest order bit which is the strongest protocol.
//
for( dwIndex = 0, pLcpCb->Local.fLastAPTried = 1;
!(( pLcpCb->Local.fLastAPTried << dwIndex ) & LCP_AP_MAX );
dwIndex++ )
{
if ( ( pLcpCb->Local.fLastAPTried << dwIndex ) &
( pLcpCb->Local.fAPsAvailable ))
{
pLcpCb->Local.fLastAPTried =
(pLcpCb->Local.fLastAPTried << dwIndex);
break;
}
}
pLcpCb->Local.fOldLastAPTried = pLcpCb->Local.fLastAPTried;
dwRetCode = MakeAuthProtocolOption( &(pLcpCb->Local) );
if ( dwRetCode != NO_ERROR )
{
return( dwRetCode );
}
}
//
// Do the same for remote.
//
if ( pLcpCb->Remote.fAPsAvailable > 0 )
{
for( dwIndex = 0, pLcpCb->Remote.fLastAPTried = LCP_AP_FIRST;
!(( pLcpCb->Remote.fLastAPTried << dwIndex ) & LCP_AP_MAX);
dwIndex++ )
{
if ( ( pLcpCb->Remote.fLastAPTried << dwIndex ) &
( pLcpCb->Remote.fAPsAvailable ) )
{
pLcpCb->Remote.fLastAPTried =
(pLcpCb->Remote.fLastAPTried << dwIndex);
//
// We need to back up one since we are the client and we haven't
// sent this yet.
//
if ( pLcpCb->Remote.fLastAPTried == LCP_AP_FIRST )
{
pLcpCb->Remote.fLastAPTried = 0;
}
else
{
pLcpCb->Remote.fLastAPTried >>= 1;
}
pLcpCb->Remote.fOldLastAPTried = pLcpCb->Remote.fLastAPTried;
break;
}
}
}
return( NO_ERROR );
}
//**
//
// Call: MakeOption
//
// Returns: NO_ERROR - Success
// ERROR_BUFFER_TOO_SMALL - Buffer passed in is not large enough.
// ERROR_INVALID_PARAMETER - Option type not recognized.
//
// Description: This is not an entry point, it is an internal procedure called
// to build a particular option.
//
DWORD
MakeOption(
IN LCP_OPTIONS * pOptionValues,
IN DWORD dwOptionType,
IN PPP_OPTION * pSendOption,
IN DWORD cbSendOption
)
{
if ( cbSendOption < SizeOfOption[ dwOptionType ] )
return( ERROR_BUFFER_TOO_SMALL );
pSendOption->Type = (BYTE)dwOptionType;
pSendOption->Length = (BYTE)(SizeOfOption[ dwOptionType ]);
switch( dwOptionType )
{
case LCP_OPTION_MRU:
HostToWireFormat16( (WORD)(pOptionValues->MRU), pSendOption->Data );
break;
case LCP_OPTION_ACCM:
HostToWireFormat32( pOptionValues->ACCM, pSendOption->Data );
break;
case LCP_OPTION_AUTHENT:
HostToWireFormat16( (WORD)pOptionValues->AP, pSendOption->Data );
//
// First check to see if we have enough space to put the
// digest algorithm
//
if (cbSendOption<(SizeOfOption[dwOptionType]+pOptionValues->APDataSize))
{
return( ERROR_BUFFER_TOO_SMALL );
}
CopyMemory( pSendOption->Data+2,
pOptionValues->pAPData,
pOptionValues->APDataSize );
pSendOption->Length += (BYTE)(pOptionValues->APDataSize);
break;
case LCP_OPTION_MAGIC:
HostToWireFormat32( pOptionValues->MagicNumber,
pSendOption->Data );
break;
case LCP_OPTION_PFC:
//
// This is a boolean option, there is no value.
//
break;
case LCP_OPTION_ACFC:
//
// This is a boolean option, there is no value.
//
break;
case LCP_OPTION_CALLBACK:
*(pSendOption->Data) = (BYTE)(pOptionValues->Callback);
break;
case LCP_OPTION_MRRU:
HostToWireFormat16( (WORD)(pOptionValues->MRRU), pSendOption->Data );
break;
case LCP_OPTION_SHORT_SEQ:
//
// This is a boolean option, there is no value.
//
break;
case LCP_OPTION_ENDPOINT:
//
// First check to see if we have enough space to put the
// discriminator
//
if ( cbSendOption < ( SizeOfOption[dwOptionType] +
pOptionValues->dwEDLength ) )
{
return( ERROR_BUFFER_TOO_SMALL );
}
CopyMemory( pSendOption->Data,
pOptionValues->EndpointDiscr,
pOptionValues->dwEDLength );
pSendOption->Length += (BYTE)( pOptionValues->dwEDLength );
break;
case LCP_OPTION_LINK_DISCRIM:
HostToWireFormat16( (WORD)(pOptionValues->dwLinkDiscriminator),
pSendOption->Data );
break;
default:
//
// If we do not recognize the option
//
return( ERROR_INVALID_PARAMETER );
}
return( NO_ERROR );
}
//**
//
// Call: CheckOption
//
// Returns: CONFIG_ACK
// CONFIG_NAK
// CONFIG_REJ
//
// Description: This is not an entry point. Called to check to see if an option
// value is valid and if it is the new value is saved in the
// work buffer.
//
DWORD
CheckOption(
IN LCPCB * pLcpCb,
IN LCP_SIDE * pLcpSide,
IN PPP_OPTION * pOption,
IN BOOL fMakingResult
)
{
DWORD dwIndex;
DWORD dwAPDataSize;
DWORD dwRetCode = CONFIG_ACK;
if ( pOption->Length < SizeOfOption[ 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 receive bigger packets.
//
if ( pLcpSide->Work.MRU > pLcpSide->Want.MRU )
{
//
// Check to see if the server nak'd. If so
// check to see if peer wants <= 1500 mru
// and if we have already sent the request
// 2 times, just ack peers mru.
//
if(pLcpSide->Work.MRU <= LCP_DEFAULT_MRU)
{
if(pLcpCb->dwMRUFailureCount > 0)
{
pLcpCb->dwMRUFailureCount--;
}
if(pLcpCb->dwMRUFailureCount == 0)
{
break;
}
}
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 ( NULL != pLcpSide->Work.pAPData )
{
LOCAL_FREE( pLcpSide->Work.pAPData );
pLcpSide->Work.pAPData = NULL;
}
pLcpSide->Work.pAPData = (PBYTE)LOCAL_ALLOC(
LPTR,
pLcpSide->Work.APDataSize );
if ( NULL == pLcpSide->Work.pAPData )
{
pLcpSide->Work.APDataSize = 0;
return( CONFIG_REJ );
}
}
CopyMemory( pLcpSide->Work.pAPData,
pOption->Data+2,
pLcpSide->Work.APDataSize );
}
else
{
pLcpSide->Work.APDataSize = 0;
}
pLcpSide->fOldLastAPTried = pLcpSide->fLastAPTried;
switch( pLcpSide->Work.AP )
{
case PPP_CHAP_PROTOCOL:
//
// If CHAP is not available
//
if ( !( pLcpSide->fAPsAvailable & ( LCP_AP_CHAP_MS |
LCP_AP_CHAP_MD5 |
LCP_AP_CHAP_MS_NEW )))
{
dwRetCode = CONFIG_NAK;
break;
}
//
// If there was no digest algorithm then we respond with the
// digest algorithm the next time. To do this we need to back up
// one in the list of APs tried so that we try this AP again.
//
if ( pOption->Length < (PPP_OPTION_HDR_LEN + 3) )
{
pLcpSide->fLastAPTried = 0;
dwRetCode = CONFIG_NAK;
break;
}
if ( *(pLcpSide->Work.pAPData) == PPP_CHAP_DIGEST_MSEXT )
{
if ( !( pLcpSide->fAPsAvailable & LCP_AP_CHAP_MS ) )
{
dwRetCode = CONFIG_NAK;
}
}
else if ( *(pLcpSide->Work.pAPData) == PPP_CHAP_DIGEST_MSEXT_NEW )
{
if ( !( pLcpSide->fAPsAvailable & LCP_AP_CHAP_MS_NEW ) )
{
dwRetCode = CONFIG_NAK;
}
}
else if ( *(pLcpSide->Work.pAPData) == PPP_CHAP_DIGEST_MD5 )
{
if ( !( pLcpSide->fAPsAvailable & LCP_AP_CHAP_MD5 ) )
{
dwRetCode = CONFIG_NAK;
}
}
else
{
dwRetCode = CONFIG_NAK;
}
break;
case PPP_PAP_PROTOCOL:
if ( !( pLcpSide->fAPsAvailable & LCP_AP_PAP ) )
{
dwRetCode = CONFIG_NAK;
}
break;
case PPP_EAP_PROTOCOL:
if ( !( pLcpSide->fAPsAvailable & LCP_AP_EAP ) )
{
dwRetCode = CONFIG_NAK;
}
break;
case PPP_SPAP_NEW_PROTOCOL:
if ( !( pLcpSide->fAPsAvailable & LCP_AP_SPAP_NEW ) )
{
dwRetCode = CONFIG_NAK;
break;
}
if ( pOption->Length < (PPP_OPTION_HDR_LEN+6) )
{
dwRetCode = CONFIG_NAK;
//
// We are a client responding to a remote CONFIG_REQ
//
if ( fMakingResult )
{
pLcpSide->fLastAPTried = ( LCP_AP_SPAP_NEW >> 1 );
}
break;
}
//
// If encryption algorithm is not 1. NAK with 1.
//
if (WireToHostFormat32(pLcpSide->Work.pAPData) != LCP_SPAP_VERSION)
{
//
// We are a client responding to a remote CONFIG_REQ
//
if ( fMakingResult )
{
pLcpSide->fLastAPTried = ( LCP_AP_SPAP_NEW >> 1 );
}
dwRetCode = CONFIG_NAK;
break;
}
break;
default:
dwRetCode = CONFIG_NAK;
break;
}
if ( dwRetCode == CONFIG_NAK )
{
//
// The fLastAPTried is set to 0, then we set to LCP_AP_FIRST
//
if ( pLcpSide->fLastAPTried == 0 )
{
pLcpSide->fLastAPTried = LCP_AP_FIRST;
}
//
// We look for the next weakest protocol available.
//
for( dwIndex = 1;
!(( pLcpSide->fLastAPTried << dwIndex ) & LCP_AP_MAX);
dwIndex++ )
{
if ( ( pLcpSide->fLastAPTried << dwIndex ) & pLcpSide->fAPsAvailable )
{
pLcpSide->fLastAPTried = (pLcpSide->fLastAPTried<<dwIndex);
break;
}
}
MakeAuthProtocolOption( pLcpSide );
}
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 == pLcpCb->Local.Work.MagicNumber)
|| ( pLcpSide->Work.MagicNumber == 0 ) )
{
if (pLcpSide->Work.MagicNumber==pLcpCb->Local.Work.MagicNumber)
{
++(pLcpCb->dwMagicNumberFailureCount);
}
//
// Shift left since rand returns a max of 0x7FFF
//
pLcpSide->Work.MagicNumber = ( rand() << 16 );
pLcpSide->Work.MagicNumber += rand();
if ( pLcpSide->Work.MagicNumber == 0 )
{
pLcpSide->Work.MagicNumber = 48;
}
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 == pLcpCb->Remote.Work.MagicNumber )
{
++(pLcpCb->dwMagicNumberFailureCount);
//
// Shift left since rand returns a max of 0x7FFF
//
pLcpSide->Work.MagicNumber = ( rand() << 16 );
pLcpSide->Work.MagicNumber += rand();
if ( pLcpSide->Work.MagicNumber == 0 )
{
pLcpSide->Work.MagicNumber = 93;
}
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_CALLBACK:
pLcpSide->Work.Callback = *(pOption->Data);
//
// If the Callback control protocol is not loaded.
//
if ( GetCpIndexFromProtocol(PPP_CBCP_PROTOCOL) == (DWORD)-1 )
{
dwRetCode = CONFIG_REJ;
}
else if ( pLcpSide->Work.Callback != PPP_NEGOTIATE_CALLBACK )
{
if ( fMakingResult )
{
//
// We only understand this option.
//
pLcpSide->Work.Callback = PPP_NEGOTIATE_CALLBACK;
dwRetCode = CONFIG_NAK;
}
else
{
//
// If we are processing a NAK from the remote peer, then we
// simply do not negotiate this option again.
//
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;
case LCP_OPTION_SHORT_SEQ:
pLcpSide->Work.ShortSequence = TRUE;
if ( pLcpSide->Want.ShortSequence == FALSE )
dwRetCode = CONFIG_REJ;
break;
case LCP_OPTION_ENDPOINT:
//
// If this option was NAKed then we do not change this value and
// simply resend the config request
//
if ( !fMakingResult )
{
break;
}
ZeroMemory( pLcpSide->Work.EndpointDiscr,
sizeof( pLcpSide->Work.EndpointDiscr ) );
//
// Make sure that the discriminator can fit into our storage allocated
// for it, otherwise simply truncate and hope that it is unique. We do
// not want to reject it since we want bundling to work.
//
if ( ( pOption->Length - PPP_OPTION_HDR_LEN ) >
sizeof(pLcpSide->Work.EndpointDiscr) )
{
pLcpSide->Work.dwEDLength = sizeof( pLcpSide->Work.EndpointDiscr );
}
else
{
pLcpSide->Work.dwEDLength = pOption->Length - PPP_OPTION_HDR_LEN;
}
CopyMemory( pLcpSide->Work.EndpointDiscr,
pOption->Data,
pLcpSide->Work.dwEDLength );
break;
case LCP_OPTION_LINK_DISCRIM:
pLcpSide->Work.dwLinkDiscriminator = WireToHostFormat16( pOption->Data );
break;
default:
//
// If we do not recognize the option we CONFIG_REJ it.
//
dwRetCode = CONFIG_REJ;
break;
}
return( dwRetCode );
}
//**
//
// Call: BuildOptionList
//
// Returns: NO_ERROR - Success
// Non-zero returns from MakeOption
//
// Description: This is not an entry point. Will build a list of options
// either for a configure request or a configure result.
//
DWORD
BuildOptionList(
IN OUT BYTE * pOptions,
IN OUT DWORD * pcbOptions,
IN LCP_OPTIONS * LcpOptions,
IN DWORD Negotiate
)
{
DWORD OptionType;
DWORD dwRetCode;
DWORD cbOptionLength = *pcbOptions;
for ( OptionType = 1;
OptionType <= LCP_OPTION_LIMIT;
OptionType++ )
{
if ( Negotiate & ( 1 << OptionType ))
{
if ( ( dwRetCode = MakeOption( LcpOptions,
OptionType,
(PPP_OPTION *)pOptions,
cbOptionLength ) ) != NO_ERROR )
return( dwRetCode );
cbOptionLength -= ((PPP_OPTION*)pOptions)->Length;
pOptions += ((PPP_OPTION*)pOptions)->Length;
}
}
*pcbOptions -= cbOptionLength;
return( NO_ERROR );
}
//**
//
// Call: LcpMakeConfigRequest
//
// Returns: NO_ERROR - Success
// Non-zero returns from BuildOptionList
//
// Description: This is a entry point that is called to make a configure
// request packet.
//
DWORD
LcpMakeConfigRequest(
IN VOID * pWorkBuffer,
IN PPP_CONFIG * pSendConfig,
IN DWORD cbSendConfig
)
{
LCPCB * pLcpCb = (LCPCB*)pWorkBuffer;
DWORD dwRetCode;
cbSendConfig -= PPP_CONFIG_HDR_LEN;
dwRetCode = BuildOptionList( pSendConfig->Data,
&cbSendConfig,
&(pLcpCb->Local.Work),
pLcpCb->Local.Work.Negotiate );
if ( dwRetCode != NO_ERROR )
return( dwRetCode );
pSendConfig->Code = CONFIG_REQ;
HostToWireFormat16( (WORD)(cbSendConfig + PPP_CONFIG_HDR_LEN),
pSendConfig->Length );
return( NO_ERROR );
}
//**
//
// Call: LcpMakeConfigResult
//
// Returns:
//
// Description:
//
DWORD
LcpMakeConfigResult(
IN VOID * pWorkBuffer,
IN PPP_CONFIG * pRecvConfig,
OUT PPP_CONFIG * pSendConfig,
IN DWORD cbSendConfig,
IN BOOL fRejectNaks
)
{
DWORD dwDesired;
DWORD dwRetCode;
LCPCB * pLcpCb = (LCPCB*)pWorkBuffer;
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
//
pLcpCb->Remote.Work.Negotiate = 0;
//
// Process options requested by remote host
//
while( lRecvLength > 0 )
{
if ( pRecvOption->Length == 0 )
return( ERROR_PPP_INVALID_PACKET );
if ( ( lRecvLength -= pRecvOption->Length ) < 0 )
return( ERROR_PPP_INVALID_PACKET );
dwRetCode = CheckOption( pLcpCb, &(pLcpCb->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 ) )
{
pLcpCb->Remote.Work.Negotiate |= ( 1 << pRecvOption->Type );
}
//
// Add the option to the list.
//
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
{
if ( ( dwRetCode = MakeOption( &(pLcpCb->Remote.Work),
pRecvOption->Type,
pSendOption,
lSendLength ) ) != 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 have 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 we want to be authenticated, but the other side doesn't try to
// authenticate us, NAK with LCP_N_AUTHENT.
//
if ( ( pLcpCb->Remote.Want.Negotiate & LCP_N_AUTHENT ) &
~( pLcpCb->Remote.Work.Negotiate ) )
{
DWORD cbOptions;
//
// We cannot send a NAK if we are sending a REJECT
//
if ( ResultType != CONFIG_REJ )
{
if ( pLcpCb->Remote.fAPsAvailable & LCP_AP_EAP )
{
pLcpCb->Remote.fLastAPTried = LCP_AP_EAP;
}
else
{
pLcpCb->Remote.fLastAPTried = LCP_AP_CHAP_MS_NEW;
}
MakeAuthProtocolOption( &(pLcpCb->Remote) );
if ( ResultType == CONFIG_ACK )
{
ResultType = CONFIG_NAK;
pSendOption = (PPP_OPTION *)(pSendConfig->Data);
lSendLength = cbSendConfig - PPP_CONFIG_HDR_LEN;
}
cbOptions = lSendLength;
dwRetCode = BuildOptionList(
(BYTE*)pSendOption,
&cbOptions,
&(pLcpCb->Remote.Work),
LCP_N_AUTHENT );
if ( dwRetCode != NO_ERROR )
{
return( dwRetCode );
}
pSendConfig->Code = CONFIG_NAK;
HostToWireFormat16( (WORD)(cbSendConfig - lSendLength + cbOptions),
pSendConfig->Length );
}
}
//
// If we are rejecting this packet then we restore the LastAPTried value
//
if ( pSendConfig->Code == CONFIG_REJ )
{
pLcpCb->Remote.fLastAPTried = pLcpCb->Remote.fOldLastAPTried;
}
else
{
pLcpCb->Remote.fOldLastAPTried = pLcpCb->Remote.fLastAPTried;
}
//
// If we have more than 3 conflicts with the magic number then we assume
// that we are talking with ourself.
//
if ((ResultType == CONFIG_NAK) && (pLcpCb->dwMagicNumberFailureCount > 3))
{
return( ERROR_PPP_LOOPBACK_DETECTED );
}
return( NO_ERROR );
}
//**
//
// Call: LcpConfigAckReceived
//
// Returns:
//
// Description:
//
DWORD
LcpConfigAckReceived(
IN VOID * pWorkBuffer,
IN PPP_CONFIG * pRecvConfig
)
{
DWORD dwRetCode;
BYTE ConfigReqSent[LCP_DEFAULT_MRU];
LCPCB * pLcpCb = (LCPCB *)pWorkBuffer;
PPP_OPTION * pRecvOption = (PPP_OPTION *)(pRecvConfig->Data);
DWORD cbConfigReqSent = sizeof( ConfigReqSent );
DWORD dwLength = WireToHostFormat16( pRecvConfig->Length )
- PPP_CONFIG_HDR_LEN;
//
// Get a copy of last request we sent
//
dwRetCode = BuildOptionList( ConfigReqSent,
&cbConfigReqSent,
&(pLcpCb->Local.Work),
pLcpCb->Local.Work.Negotiate );
if ( dwRetCode != NO_ERROR )
return( dwRetCode );
//
// Overall buffer length should match
//
if ( dwLength != cbConfigReqSent )
{
//
// Hack to work around WinCE bug on the server side only.
// If we request EAP, WinCE ACKs without auth option.
// Bug#333332
//
LCP_OPTIONS * pOptionValues = &(pLcpCb->Local.Work);
//
// If we are a client then we simply return
//
if ( !pLcpCb->fServer )
return( ERROR_PPP_INVALID_PACKET );
//
// If we requested EAP
//
if ( pOptionValues->AP == PPP_EAP_PROTOCOL )
{
DWORD dwIndex;
//
// Check to see if ACK did not contain the auth option
//
while ( dwLength > 0 )
{
if ( pRecvOption->Length == 0 )
return( ERROR_PPP_INVALID_PACKET );
if ( (long)(dwLength -= pRecvOption->Length) < 0 )
return( ERROR_PPP_INVALID_PACKET );
if ( pRecvOption->Length < SizeOfOption[ pRecvOption->Type ] )
return( ERROR_PPP_INVALID_PACKET );
if ( pRecvOption->Type == LCP_OPTION_AUTHENT )
return( ERROR_PPP_INVALID_PACKET );
pRecvOption = (PPP_OPTION *)((BYTE*)pRecvOption + pRecvOption->Length);
}
//
// If we get here then no authentication option was sent in the ACK
// so we need to treat this as a NAK. Go to the next auth protocol.
//
pLcpCb->Local.fLastAPTried = LCP_AP_EAP;
//
// We look for the next weakest protocol available.
//
for( dwIndex = 1;
!(( pLcpCb->Local.fLastAPTried << dwIndex ) & LCP_AP_MAX);
dwIndex++ )
{
if ( ( pLcpCb->Local.fLastAPTried << dwIndex ) &
pLcpCb->Local.fAPsAvailable )
{
pLcpCb->Local.fLastAPTried = (pLcpCb->Local.fLastAPTried << dwIndex );
break;
}
}
MakeAuthProtocolOption( &(pLcpCb->Local) );
}
return( ERROR_PPP_INVALID_PACKET );
}
//
// Each byte should match
//
if ( memcmp( ConfigReqSent, pRecvConfig->Data, dwLength ) != 0 )
return( ERROR_PPP_INVALID_PACKET );
return( NO_ERROR );
}
//**
//
// Call: LcpConfigNakReceived
//
// Returns:
//
// Description:
//
DWORD
LcpConfigNakReceived(
IN VOID * pWorkBuffer,
IN PPP_CONFIG * pRecvConfig
)
{
DWORD dwResult;
LCPCB * pLcpCb = (LCPCB *)pWorkBuffer;
PPP_OPTION * pOption = (PPP_OPTION*)(pRecvConfig->Data);
DWORD dwLastOption = 0;
LONG lcbRecvConfig = WireToHostFormat16( pRecvConfig->Length )
- PPP_CONFIG_HDR_LEN;
//
// First, process in order. Then, process extra "important" options
//
while ( lcbRecvConfig > 0 )
{
if ( pOption->Length == 0 )
return( ERROR_PPP_INVALID_PACKET );
if ( ( lcbRecvConfig -= pOption->Length ) < 0 )
return( ERROR_PPP_INVALID_PACKET );
//
// If this option was not requested, we mark it as negotiable
//
if ( ( pOption->Type <= LCP_OPTION_LIMIT ) &&
( pLcpCb->Local.WillNegotiate & (1 << pOption->Type) ) &&
!( pLcpCb->Local.Work.Negotiate & (1 << pOption->Type) ) )
{
pLcpCb->Local.Work.Negotiate |= (1 << pOption->Type );
}
dwLastOption = pOption->Type;
dwResult = CheckOption( pLcpCb, &(pLcpCb->Local), pOption, FALSE );
//
// Update the negotiation status. If we cannot accept this option,
// then we will not send it again.
//
if (( dwResult == CONFIG_REJ ) && ( pOption->Type <= LCP_OPTION_LIMIT ))
pLcpCb->Local.Work.Negotiate &= ~(1 << pOption->Type);
pOption = (PPP_OPTION *)( (BYTE *)pOption + pOption->Length );
}
return( NO_ERROR );
}
//**
//
// Call: LcpConfigRejReceived
//
// Returns:
//
// Description:
//
DWORD
LcpConfigRejReceived(
IN VOID * pWorkBuffer,
IN PPP_CONFIG * pRecvConfig
)
{
DWORD dwRetCode;
LCPCB * pLcpCb = (LCPCB *)pWorkBuffer;
PPP_OPTION * pOption = (PPP_OPTION*)(pRecvConfig->Data);
DWORD dwLastOption = 0;
BYTE ReqOption[LCP_DEFAULT_MRU];
LONG lcbRecvConfig = WireToHostFormat16( pRecvConfig->Length )
- PPP_CONFIG_HDR_LEN;
//
// Process in order, checking for errors
//
while ( lcbRecvConfig > 0 )
{
if ( pOption->Length == 0 )
return( ERROR_PPP_INVALID_PACKET );
if ( ( lcbRecvConfig -= pOption->Length ) < 0 )
return( ERROR_PPP_INVALID_PACKET );
//
// Cannot receive an option out of order or an option that was
// not requested.
//
if ( ( pOption->Type <= LCP_OPTION_LIMIT ) &&
(( pOption->Type < dwLastOption ) ||
( !( pLcpCb->Local.Work.Negotiate & (1 << pOption->Type)))) )
return( ERROR_PPP_INVALID_PACKET );
//
// If we are a server and the client rejects the authentication
// protocol then we fail to converge, if we are not set to allow no
// authentication.
//
if ( ( pLcpCb->Local.Want.Negotiate & LCP_N_AUTHENT ) &&
( pOption->Type == LCP_OPTION_AUTHENT ) &&
( !( pLcpCb->PppConfigInfo.dwConfigMask &
PPPCFG_AllowNoAuthentication ) ) )
{
return( ERROR_PEER_REFUSED_AUTH );
}
//
// The option should not have been modified in any way
//
if ( ( dwRetCode = MakeOption( &(pLcpCb->Local.Work),
pOption->Type,
(PPP_OPTION *)ReqOption,
sizeof( ReqOption ) ) ) != NO_ERROR )
return( dwRetCode );
if ( memcmp( ReqOption, pOption, pOption->Length ) != 0 )
return( ERROR_PPP_INVALID_PACKET );
dwLastOption = pOption->Type;
//
// The next configure request should not contain this option
//
if ( pOption->Type <= LCP_OPTION_LIMIT )
pLcpCb->Local.Work.Negotiate &= ~(1 << pOption->Type);
pOption = (PPP_OPTION *)( (BYTE *)pOption + pOption->Length );
}
return( NO_ERROR );
}
//**
//
// Call: LcpThisLayerStarted
//
// Returns:
//
// Description:
//
DWORD
LcpThisLayerStarted(
IN VOID * pWorkBuffer
)
{
return( NO_ERROR );
}
//**
//
// Call: LcpThisLayerFinished
//
// Returns:
//
// Description:
//
DWORD
LcpThisLayerFinished(
IN VOID * pWorkBuffer
)
{
return( NO_ERROR );
}
//**
//
// Call: LcpThisLayerUp
//
// Returns: None
//
// Description: Sets the framing parameters to what was negotiated.
//
DWORD
LcpThisLayerUp(
IN VOID * pWorkBuffer
)
{
DWORD dwRetCode = NO_ERROR;
RAS_FRAMING_INFO RasFramingInfo;
DWORD LocalMagicNumber;
DWORD RemoteMagicNumber;
DWORD LocalAuthProtocol;
DWORD RemoteAuthProtocol;
LCPCB * pLcpCb = (LCPCB *)pWorkBuffer;
PCB * pPcb;
pPcb = GetPCBPointerFromhPort( pLcpCb->hPort );
if ( pPcb == (PCB *)NULL )
{
return( NO_ERROR );
}
ZeroMemory( &RasFramingInfo, sizeof( RasFramingInfo ) );
if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRU )
{
RasFramingInfo.RFI_MaxRecvFrameSize = pLcpCb->Local.Work.MRU;
}
else
{
RasFramingInfo.RFI_MaxRecvFrameSize = LcpDefault.MRU;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_ACCM )
{
RasFramingInfo.RFI_RecvACCM = pLcpCb->Local.Work.ACCM;
}
else
{
RasFramingInfo.RFI_RecvACCM = LcpDefault.ACCM;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_PFC )
{
RasFramingInfo.RFI_RecvFramingBits |= PPP_COMPRESS_PROTOCOL_FIELD;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_ACFC )
{
RasFramingInfo.RFI_RecvFramingBits |= PPP_COMPRESS_ADDRESS_CONTROL;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_SHORT_SEQ )
{
RasFramingInfo.RFI_RecvFramingBits |= PPP_SHORT_SEQUENCE_HDR_FORMAT;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_AUTHENT )
{
LocalAuthProtocol = pLcpCb->Local.Work.AP;
}
else
{
LocalAuthProtocol = LcpDefault.AP;
pLcpCb->Local.Work.AP = LcpDefault.AP;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_MAGIC )
{
LocalMagicNumber = pLcpCb->Local.Work.MagicNumber;
}
else
{
LocalMagicNumber = LcpDefault.MagicNumber;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRRU )
{
RasFramingInfo.RFI_RecvFramingBits |= PPP_MULTILINK_FRAMING;
RasFramingInfo.RFI_MaxRRecvFrameSize = pLcpCb->Local.Work.MRRU;
}
else
{
RasFramingInfo.RFI_MaxRRecvFrameSize = LcpDefault.MRRU;
}
if ( ( pLcpCb->Local.Work.Negotiate & LCP_N_LINK_DISCRIM ) &&
( pLcpCb->Remote.Work.Negotiate & LCP_N_LINK_DISCRIM ) )
{
pPcb->pBcb->fFlags |= BCBFLAG_CAN_DO_BAP;
}
RasFramingInfo.RFI_RecvFramingBits |= PPP_FRAMING;
PppLog( 1, "LCP Local Options-------------");
PppLog( 1,
"\tMRU=%d,ACCM=%d,Auth=%x,MagicNumber=%d,PFC=%s,ACFC=%s",
RasFramingInfo.RFI_MaxRecvFrameSize, RasFramingInfo.RFI_RecvACCM,
LocalAuthProtocol, LocalMagicNumber,
(RasFramingInfo.RFI_RecvFramingBits & PPP_COMPRESS_PROTOCOL_FIELD)
? "ON" : "OFF",
( RasFramingInfo.RFI_RecvFramingBits & PPP_COMPRESS_ADDRESS_CONTROL )
? "ON" : "OFF" );
PppLog( 1, "\tRecv Framing = %s,SSHF=%s,MRRU=%d,LinkDiscrim=%x,BAP=%s",
( RasFramingInfo.RFI_RecvFramingBits & PPP_MULTILINK_FRAMING )
? "PPP Multilink" : "PPP",
( RasFramingInfo.RFI_RecvFramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT)
? "ON" : "OFF",
RasFramingInfo.RFI_MaxRRecvFrameSize,
pLcpCb->Local.Work.dwLinkDiscriminator,
pPcb->pBcb->fFlags & BCBFLAG_CAN_DO_BAP ? "ON" : "OFF");
if ( pLcpCb->Local.Work.Negotiate & LCP_N_ENDPOINT )
{
PppLog( 1, "\tED Class = %d, ED Value = %0*x%0*x%0*x%0*x%0*x",
*(pLcpCb->Local.Work.EndpointDiscr),
8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+1),
8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+5),
8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+9),
8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+13),
8,WireToHostFormat32(pLcpCb->Local.Work.EndpointDiscr+17) );
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MRU )
{
RasFramingInfo.RFI_MaxSendFrameSize = pLcpCb->Remote.Work.MRU;
}
else
{
RasFramingInfo.RFI_MaxSendFrameSize = LcpDefault.MRU;
pLcpCb->Remote.Work.MRU = LcpDefault.MRU;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ACCM )
{
RasFramingInfo.RFI_SendACCM = pLcpCb->Remote.Work.ACCM;
}
else
{
RasFramingInfo.RFI_SendACCM = LcpDefault.ACCM;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_PFC )
{
RasFramingInfo.RFI_SendFramingBits |= PPP_COMPRESS_PROTOCOL_FIELD;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ACFC )
{
RasFramingInfo.RFI_SendFramingBits |= PPP_COMPRESS_ADDRESS_CONTROL;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_SHORT_SEQ )
{
RasFramingInfo.RFI_SendFramingBits |= PPP_SHORT_SEQUENCE_HDR_FORMAT;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_AUTHENT )
{
RemoteAuthProtocol = pLcpCb->Remote.Work.AP;
}
else
{
RemoteAuthProtocol = LcpDefault.AP;
pLcpCb->Remote.Work.AP = LcpDefault.AP;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MAGIC )
{
RemoteMagicNumber = pLcpCb->Remote.Work.MagicNumber;
}
else
{
RemoteMagicNumber = LcpDefault.MagicNumber;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MRRU )
{
RasFramingInfo.RFI_SendFramingBits |= PPP_MULTILINK_FRAMING;
RasFramingInfo.RFI_MaxRSendFrameSize = pLcpCb->Remote.Work.MRRU;
}
else
{
RasFramingInfo.RFI_MaxRSendFrameSize = LcpDefault.MRRU;
}
RasFramingInfo.RFI_SendFramingBits |= PPP_FRAMING;
PppLog( 1, "LCP Remote Options-------------");
PppLog( 1, "\tMRU=%d,ACCM=%d,Auth=%x,MagicNumber=%d,PFC=%s,ACFC=%s",
RasFramingInfo.RFI_MaxSendFrameSize, RasFramingInfo.RFI_SendACCM,
RemoteAuthProtocol, RemoteMagicNumber,
(RasFramingInfo.RFI_SendFramingBits & PPP_COMPRESS_PROTOCOL_FIELD)
? "ON" : "OFF",
(RasFramingInfo.RFI_SendFramingBits & PPP_COMPRESS_ADDRESS_CONTROL)
? "ON" : "OFF" );
PppLog( 1, "\tSend Framing = %s,SSHF=%s,MRRU=%d,LinkDiscrim=%x",
( RasFramingInfo.RFI_SendFramingBits & PPP_MULTILINK_FRAMING )
? "PPP Multilink" : "PPP",
( RasFramingInfo.RFI_SendFramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT)
? "ON" : "OFF",
RasFramingInfo.RFI_MaxRSendFrameSize,
pLcpCb->Remote.Work.dwLinkDiscriminator );
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ENDPOINT )
{
PppLog( 1, "\tED Class = %d, ED Value = %0*x%0*x%0*x%0*x%0*x",
*(pLcpCb->Remote.Work.EndpointDiscr),
8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+1),
8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+5),
8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+9),
8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+13),
8,WireToHostFormat32(pLcpCb->Remote.Work.EndpointDiscr+17));
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRRU )
{
pPcb->fFlags |= PCBFLAG_CAN_BE_BUNDLED;
}
else
{
pPcb->fFlags &= ~PCBFLAG_CAN_BE_BUNDLED;
}
if ( ( pLcpCb->Local.Work.Negotiate & LCP_N_CALLBACK ) ||
( pLcpCb->Remote.Work.Negotiate & LCP_N_CALLBACK ) )
{
pPcb->fFlags |= PCBFLAG_NEGOTIATE_CALLBACK;
}
else
{
pPcb->fFlags &= ~PCBFLAG_NEGOTIATE_CALLBACK;
}
dwRetCode = RasPortSetFramingEx( pLcpCb->hPort, &RasFramingInfo );
//
// This is a benign error and should not be logged.
//
if ( dwRetCode == ERROR_NOT_CONNECTED )
{
return( NO_ERROR );
}
else
{
return( dwRetCode );
}
}
//**
//
// Call: LcpThisLayerDown
//
// Returns: NO_ERROR - Success
// Non-zero return from RasPortSetFraming - Failure
//
// Description: Simply sets the framing parameters to the default values,
// ie. ACCM = 0xFFFFFFFF, everything else is zeros.
//
DWORD
LcpThisLayerDown(
IN VOID * pWorkBuffer
)
{
DWORD dwRetCode;
RAS_FRAMING_INFO RasFramingInfo;
LCPCB * pLcpCb = (LCPCB *)pWorkBuffer;
ZeroMemory( &RasFramingInfo, sizeof( RasFramingInfo ) );
RasFramingInfo.RFI_RecvACCM = LcpDefault.ACCM;
RasFramingInfo.RFI_SendACCM = LcpDefault.ACCM;
RasFramingInfo.RFI_SendFramingBits = PPP_FRAMING;
RasFramingInfo.RFI_RecvFramingBits = PPP_FRAMING;
dwRetCode = RasPortSetFramingEx( pLcpCb->hPort, &RasFramingInfo );
if ( dwRetCode == ERROR_NOT_CONNECTED )
{
return( NO_ERROR );
}
else
{
return( dwRetCode );
}
}
//**
//
// Call: LcpGetNegotiatedInfo
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD
LcpGetNegotiatedInfo(
IN VOID* pWorkBuffer,
OUT PPP_LCP_RESULT * pLcpResult
)
{
LCPCB * pLcpCb = (LCPCB *)pWorkBuffer;
if ( pLcpCb->Local.Work.Negotiate & LCP_N_MRRU )
{
pLcpResult->dwLocalFramingType |= PPP_MULTILINK_FRAMING;
}
else
{
pLcpResult->dwLocalFramingType |= PPP_FRAMING;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_AUTHENT )
{
pLcpResult->dwLocalAuthProtocol = pLcpCb->Local.Work.AP;
}
else
{
pLcpResult->dwLocalAuthProtocol = LcpDefault.AP;
}
pLcpResult->dwLocalOptions = 0;
if ( pLcpCb->Local.Work.Negotiate & LCP_N_PFC )
{
pLcpResult->dwLocalOptions |= PPPLCPO_PFC;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_ACFC )
{
pLcpResult->dwLocalOptions |= PPPLCPO_ACFC;
}
if ( pLcpCb->Local.Work.Negotiate & LCP_N_SHORT_SEQ )
{
pLcpResult->dwLocalOptions |= PPPLCPO_SSHF;
}
if ( ( pLcpCb->Local.Work.APDataSize > 0 ) &&
( pLcpCb->Local.Work.APDataSize < 5 ) )
{
if ( pLcpCb->Local.Work.APDataSize == 1 )
{
pLcpResult->dwLocalAuthProtocolData =
(DWORD)*(pLcpCb->Local.Work.pAPData);
}
else if ( pLcpCb->Local.Work.APDataSize == 2 )
{
pLcpResult->dwLocalAuthProtocolData =
WireToHostFormat16( pLcpCb->Local.Work.pAPData );
}
else
{
pLcpResult->dwLocalAuthProtocolData =
WireToHostFormat32( pLcpCb->Local.Work.pAPData );
}
}
else
{
pLcpResult->dwLocalAuthProtocolData = 0;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_AUTHENT )
{
pLcpResult->dwRemoteAuthProtocol = pLcpCb->Remote.Work.AP;
}
else
{
pLcpResult->dwRemoteAuthProtocol = LcpDefault.AP;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_MRRU )
{
pLcpResult->dwRemoteFramingType |= PPP_MULTILINK_FRAMING;
}
else
{
pLcpResult->dwRemoteFramingType |= PPP_FRAMING;
}
pLcpResult->dwRemoteOptions = 0;
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_PFC )
{
pLcpResult->dwRemoteOptions |= PPPLCPO_PFC;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_ACFC )
{
pLcpResult->dwRemoteOptions |= PPPLCPO_ACFC;
}
if ( pLcpCb->Remote.Work.Negotiate & LCP_N_SHORT_SEQ )
{
pLcpResult->dwRemoteOptions |= PPPLCPO_SSHF;
}
if ( ( pLcpCb->Remote.Work.APDataSize > 0 ) &&
( pLcpCb->Remote.Work.APDataSize < 5 ) )
{
if ( pLcpCb->Remote.Work.APDataSize == 1 )
{
pLcpResult->dwRemoteAuthProtocolData =
(DWORD)*(pLcpCb->Remote.Work.pAPData);
}
else if ( pLcpCb->Remote.Work.APDataSize == 2 )
{
pLcpResult->dwRemoteAuthProtocolData =
WireToHostFormat16( pLcpCb->Remote.Work.pAPData );
}
else
{
pLcpResult->dwRemoteAuthProtocolData =
WireToHostFormat32( pLcpCb->Remote.Work.pAPData );
}
}
else
{
pLcpResult->dwRemoteAuthProtocolData = 0;
}
return( NO_ERROR );
}
//**
//
// Call: LcpGetInfo
//
// Returns: NO_ERROR - Success
// ERROR_INVALID_PARAMETER - Protocol id is unrecogized
//
// Description: This entry point is called for get all information for the
// control protocol in this module.
//
DWORD
LcpGetInfo(
IN DWORD dwProtocolId,
OUT PPPCP_INFO* pCpInfo
)
{
if ( dwProtocolId != PPP_LCP_PROTOCOL )
return( ERROR_INVALID_PARAMETER );
ZeroMemory( pCpInfo, sizeof( PPPCP_INFO ) );
pCpInfo->Protocol = PPP_LCP_PROTOCOL;
pCpInfo->Recognize = TIME_REMAINING + 1;
pCpInfo->RasCpBegin = LcpBegin;
pCpInfo->RasCpEnd = LcpEnd;
pCpInfo->RasCpReset = LcpReset;
pCpInfo->RasCpThisLayerStarted = LcpThisLayerStarted;
pCpInfo->RasCpThisLayerFinished = LcpThisLayerFinished;
pCpInfo->RasCpThisLayerUp = LcpThisLayerUp;
pCpInfo->RasCpThisLayerDown = LcpThisLayerDown;
pCpInfo->RasCpMakeConfigRequest = LcpMakeConfigRequest;
pCpInfo->RasCpMakeConfigResult = LcpMakeConfigResult;
pCpInfo->RasCpConfigAckReceived = LcpConfigAckReceived;
pCpInfo->RasCpConfigNakReceived = LcpConfigNakReceived;
pCpInfo->RasCpConfigRejReceived = LcpConfigRejReceived;
pCpInfo->RasCpGetNegotiatedInfo = LcpGetNegotiatedInfo;
return( NO_ERROR );
}