You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2093 lines
59 KiB
2093 lines
59 KiB
/********************************************************************/
|
|
/** Copyright(c) 1989 Microsoft Corporation. **/
|
|
/********************************************************************/
|
|
|
|
//***
|
|
//
|
|
// Filename: smaction.c
|
|
//
|
|
// Description: This module contains actions that occure during state
|
|
// transitions withing the Finite State Machine for PPP.
|
|
//
|
|
// History:
|
|
// Oct 25,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 <ntlsapi.h>
|
|
#include <lmcons.h>
|
|
#include <raserror.h>
|
|
#include <rasman.h>
|
|
#include <rtutils.h>
|
|
#include <mprlog.h>
|
|
#include <mprerror.h>
|
|
#include <rasppp.h>
|
|
#include <pppcp.h>
|
|
#include <ppp.h>
|
|
#include <smaction.h>
|
|
#include <smevents.h>
|
|
#include <receive.h>
|
|
#include <auth.h>
|
|
#include <callback.h>
|
|
#include <receive.h>
|
|
#include <lcp.h>
|
|
#include <timer.h>
|
|
#include <util.h>
|
|
#include <worker.h>
|
|
#include <bap.h>
|
|
|
|
#define INCL_RASAUTHATTRIBUTES
|
|
#include <ppputil.h>
|
|
|
|
extern WORD WLinkDiscriminator; // Next Link Discriminator to use
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendConfigReq
|
|
//
|
|
// Returns: TRUE - Config Req. sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send a configuration request
|
|
//
|
|
BOOL
|
|
FsmSendConfigReq(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex,
|
|
IN BOOL fTimeout
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
DWORD dwLength;
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpMakeConfigRequest)(
|
|
pCpCb->pWorkBuf,
|
|
pSendConfig,
|
|
LCP_DEFAULT_MRU
|
|
- PPP_PACKET_HDR_LEN );
|
|
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
pCpCb->dwError = dwRetCode;
|
|
|
|
PppLog( 1,"The control protocol for %x, returned error %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, dwRetCode );
|
|
PppLog(1,"while making a configure request on port %d",pPcb->hPort);
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = CONFIG_REQ;
|
|
|
|
//
|
|
// If we are resending a configure request because of a timeout, we do not
|
|
// use the id of the previous configure request, instead we get a new Id.
|
|
// Id we do not, then the wrong Config-Req's and Config-Acks may be matched
|
|
// up and we start getting crossed connections.
|
|
//
|
|
|
|
pSendConfig->Id = GetUId( pPcb, CpIndex );
|
|
|
|
dwLength = WireToHostFormat16( pSendConfig->Length );
|
|
|
|
LogPPPPacket(FALSE,pPcb,pPcb->pSendBuf,dwLength+PPP_PACKET_HDR_LEN);
|
|
|
|
if ( (dwRetCode = PortSendOrDisconnect( pPcb,
|
|
(dwLength + PPP_PACKET_HDR_LEN)))
|
|
!= NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pCpCb->LastId = pSendConfig->Id;
|
|
|
|
InsertInTimerQ( pPcb->dwPortId,
|
|
pPcb->hPort,
|
|
pCpCb->LastId,
|
|
CpTable[CpIndex].CpInfo.Protocol,
|
|
FALSE,
|
|
TIMER_EVENT_TIMEOUT,
|
|
pPcb->RestartTimer );
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendTermReq
|
|
//
|
|
// Returns: TRUE - Termination Req. sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send a termination request.
|
|
//
|
|
BOOL
|
|
FsmSendTermReq(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
HostToWireFormat16( (WORD)(CpTable[CpIndex].CpInfo.Protocol),
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = TERM_REQ;
|
|
pSendConfig->Id = GetUId( pPcb, CpIndex );
|
|
|
|
HostToWireFormat16( (WORD)((PPP_CONFIG_HDR_LEN)+(sizeof(DWORD)*3)),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
HostToWireFormat32( pLcpCb->Local.Work.MagicNumber,
|
|
(PBYTE)(pSendConfig->Data) );
|
|
|
|
//
|
|
// Signature
|
|
//
|
|
|
|
HostToWireFormat32( 3984756, (PBYTE)(pSendConfig->Data+4) );
|
|
|
|
HostToWireFormat32( pCpCb->dwError, (PBYTE)(pSendConfig->Data+8) );
|
|
|
|
LogPPPPacket( FALSE,pPcb,pPcb->pSendBuf,
|
|
PPP_PACKET_HDR_LEN+PPP_CONFIG_HDR_LEN+(sizeof(DWORD)*3) );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb,
|
|
PPP_PACKET_HDR_LEN +
|
|
PPP_CONFIG_HDR_LEN +
|
|
(sizeof(DWORD)*3)))
|
|
!= NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pCpCb->LastId = pSendConfig->Id;
|
|
|
|
dwRetCode = InsertInTimerQ( pPcb->dwPortId,
|
|
pPcb->hPort,
|
|
pCpCb->LastId,
|
|
CpTable[CpIndex].CpInfo.Protocol,
|
|
FALSE,
|
|
TIMER_EVENT_TIMEOUT,
|
|
pPcb->RestartTimer );
|
|
|
|
if ( dwRetCode == NO_ERROR)
|
|
{
|
|
return( TRUE );
|
|
}
|
|
else
|
|
{
|
|
PppLog( 1, "InsertInTimerQ on port %d failed: %d",
|
|
pPcb->hPort, dwRetCode );
|
|
|
|
pPcb->LcpCb.dwError = dwRetCode;
|
|
|
|
pPcb->fFlags |= PCBFLAG_STOPPED_MSG_SENT;
|
|
|
|
NotifyCaller( pPcb,
|
|
( pPcb->fFlags & PCBFLAG_IS_SERVER )
|
|
? PPPDDMMSG_Stopped
|
|
: PPPMSG_Stopped,
|
|
&(pPcb->LcpCb.dwError) );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendTermAck
|
|
//
|
|
// Returns: TRUE - Termination Ack. sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Caller to send a Termination Ack packet.
|
|
//
|
|
BOOL
|
|
FsmSendTermAck(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex,
|
|
IN PPP_CONFIG * pRecvConfig
|
|
)
|
|
{
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
DWORD dwLength = PPP_PACKET_HDR_LEN +
|
|
WireToHostFormat16( pRecvConfig->Length );
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
DWORD dwRetCode;
|
|
|
|
if ( dwLength > LCP_DEFAULT_MRU )
|
|
{
|
|
dwLength = LCP_DEFAULT_MRU;
|
|
}
|
|
|
|
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = TERM_ACK;
|
|
pSendConfig->Id = pRecvConfig->Id;
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
CopyMemory( pSendConfig->Data,
|
|
pRecvConfig->Data,
|
|
dwLength - PPP_CONFIG_HDR_LEN - PPP_PACKET_HDR_LEN );
|
|
|
|
LogPPPPacket( FALSE, pPcb, pPcb->pSendBuf, dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendConfigResult
|
|
//
|
|
// Returns: TRUE - Config Result sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send a Ack/Nak/Rej packet.
|
|
//
|
|
BOOL
|
|
FsmSendConfigResult(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex,
|
|
IN PPP_CONFIG * pRecvConfig,
|
|
IN BOOL * pfAcked
|
|
)
|
|
{
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
DWORD dwLength;
|
|
DWORD dwRetCode;
|
|
|
|
*pfAcked = FALSE;
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
ZeroMemory( pSendConfig, 30 );
|
|
|
|
pSendConfig->Id = pRecvConfig->Id;
|
|
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpMakeConfigResult)(
|
|
pCpCb->pWorkBuf,
|
|
pRecvConfig,
|
|
pSendConfig,
|
|
LCP_DEFAULT_MRU - PPP_PACKET_HDR_LEN,
|
|
( pCpCb->NakRetryCount == 0 ));
|
|
|
|
if ( dwRetCode == PENDING )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( dwRetCode == ERROR_PPP_INVALID_PACKET )
|
|
{
|
|
PppLog( 1, "Silently discarding invalid packet on port=%d",
|
|
pPcb->hPort );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
pCpCb->dwError = dwRetCode;
|
|
|
|
PppLog( 1, "The control protocol for %x, returned error %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, dwRetCode );
|
|
PppLog( 1, "while making a configure result on port %d", pPcb->hPort );
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
switch( pSendConfig->Code )
|
|
{
|
|
|
|
case CONFIG_ACK:
|
|
|
|
*pfAcked = TRUE;
|
|
|
|
break;
|
|
|
|
case CONFIG_NAK:
|
|
|
|
if ( pCpCb->NakRetryCount > 0 )
|
|
{
|
|
(pCpCb->NakRetryCount)--;
|
|
}
|
|
else
|
|
{
|
|
if ( CpTable[CpIndex].CpInfo.Protocol == PPP_CCP_PROTOCOL )
|
|
{
|
|
//
|
|
// If we need to force encryption but encryption negotiation
|
|
// failed then we drop the link
|
|
//
|
|
|
|
if ( pPcb->ConfigInfo.dwConfigMask &
|
|
(PPPCFG_RequireEncryption |
|
|
PPPCFG_RequireStrongEncryption ) )
|
|
{
|
|
PppLog( 1, "Encryption is required" );
|
|
|
|
//
|
|
// We need to send an Accounting Stop if RADIUS sends
|
|
// an Access Accept but we still drop the line.
|
|
//
|
|
|
|
pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE;
|
|
|
|
//
|
|
// If we do FsmClose for CCP instead, the other side may
|
|
// conclude that PPP was negotiated successfully before we
|
|
// send an LCP Terminate Request.
|
|
//
|
|
|
|
pPcb->LcpCb.dwError = ERROR_NO_REMOTE_ENCRYPTION;
|
|
|
|
FsmClose( pPcb, LCP_INDEX );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
pCpCb->dwError = ERROR_PPP_NOT_CONVERGING;
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
break;
|
|
|
|
case CONFIG_REJ:
|
|
|
|
if ( pCpCb->RejRetryCount > 0 )
|
|
{
|
|
(pCpCb->RejRetryCount)--;
|
|
}
|
|
else
|
|
{
|
|
pCpCb->dwError = ERROR_PPP_NOT_CONVERGING;
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Id = pRecvConfig->Id;
|
|
dwLength = WireToHostFormat16( pSendConfig->Length );
|
|
|
|
|
|
LogPPPPacket(FALSE,pPcb,pPcb->pSendBuf,dwLength+PPP_PACKET_HDR_LEN);
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb,
|
|
(dwLength + PPP_PACKET_HDR_LEN)))
|
|
!= NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendEchoRequest
|
|
//
|
|
// Returns: TRUE - Echo reply sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send an Echo Rely packet
|
|
//
|
|
BOOL
|
|
FsmSendEchoRequest(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwRetCode = NO_ERROR;
|
|
|
|
char szEchoText[] = PPP_DEF_ECHO_TEXT;
|
|
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
DWORD dwLength = (DWORD)(PPP_PACKET_HDR_LEN + PPP_CONFIG_HDR_LEN + strlen( szEchoText)+ sizeof(pLcpCb->Local.Work.MagicNumber));
|
|
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
|
|
|
|
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
|
|
pSendConfig->Code = ECHO_REQ;
|
|
//Get a unique Id for this request
|
|
pSendConfig->Id = GetUId( pPcb, CpIndex );
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
HostToWireFormat32( pLcpCb->Local.Work.MagicNumber,
|
|
(PBYTE)(pSendConfig->Data) );
|
|
|
|
CopyMemory( pSendConfig->Data + 4,
|
|
szEchoText,
|
|
strlen(szEchoText));
|
|
|
|
LogPPPPacket( FALSE, pPcb, pPcb->pSendBuf, dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendEchoReply
|
|
//
|
|
// Returns: TRUE - Echo reply sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send an Echo Rely packet
|
|
//
|
|
BOOL
|
|
FsmSendEchoReply(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex,
|
|
IN PPP_CONFIG * pRecvConfig
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
DWORD dwLength = PPP_PACKET_HDR_LEN +
|
|
WireToHostFormat16( pRecvConfig->Length );
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( dwLength > LCP_DEFAULT_MRU )
|
|
{
|
|
dwLength = LCP_DEFAULT_MRU;
|
|
}
|
|
|
|
if ( dwLength < PPP_PACKET_HDR_LEN + PPP_CONFIG_HDR_LEN + 4 )
|
|
{
|
|
PppLog( 1, "Silently discarding invalid packet on port=%d",
|
|
pPcb->hPort );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = ECHO_REPLY;
|
|
pSendConfig->Id = pRecvConfig->Id;
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
HostToWireFormat32( pLcpCb->Local.Work.MagicNumber,
|
|
(PBYTE)(pSendConfig->Data) );
|
|
|
|
CopyMemory( pSendConfig->Data + 4,
|
|
pRecvConfig->Data + 4,
|
|
dwLength - PPP_CONFIG_HDR_LEN - PPP_PACKET_HDR_LEN - 4 );
|
|
|
|
LogPPPPacket( FALSE, pPcb, pPcb->pSendBuf, dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendCodeReject
|
|
//
|
|
// Returns: TRUE - Code Reject sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send a Code Reject packet.
|
|
//
|
|
BOOL
|
|
FsmSendCodeReject(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex,
|
|
IN PPP_CONFIG * pRecvConfig
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
DWORD dwLength = PPP_PACKET_HDR_LEN +
|
|
PPP_CONFIG_HDR_LEN +
|
|
WireToHostFormat16( pRecvConfig->Length );
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( dwLength > LCP_DEFAULT_MRU )
|
|
dwLength = LCP_DEFAULT_MRU;
|
|
|
|
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = CODE_REJ;
|
|
pSendConfig->Id = GetUId( pPcb, CpIndex );
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
CopyMemory( pSendConfig->Data,
|
|
pRecvConfig,
|
|
dwLength - PPP_CONFIG_HDR_LEN - PPP_PACKET_HDR_LEN );
|
|
|
|
LogPPPPacket( FALSE, pPcb, pPcb->pSendBuf, dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
//**
|
|
//
|
|
// Call: FsmSendProtocolRej
|
|
//
|
|
// Returns: TRUE - Protocol Reject sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send a protocol reject packet.
|
|
//
|
|
BOOL
|
|
FsmSendProtocolRej(
|
|
IN PCB * pPcb,
|
|
IN PPP_PACKET * pPacket,
|
|
IN DWORD dwPacketLength
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pRecvConfig = (PPP_CONFIG*)(pPacket->Information);
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
DWORD dwLength = PPP_PACKET_HDR_LEN +
|
|
PPP_CONFIG_HDR_LEN +
|
|
dwPacketLength;
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
//
|
|
// If LCP is not in the opened state we cannot send a protocol reject
|
|
// packet
|
|
//
|
|
|
|
if ( !IsLcpOpened( pPcb ) )
|
|
return( FALSE );
|
|
|
|
if ( dwLength > LCP_DEFAULT_MRU )
|
|
dwLength = LCP_DEFAULT_MRU;
|
|
|
|
HostToWireFormat16( (WORD)CpTable[LCP_INDEX].CpInfo.Protocol,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = PROT_REJ;
|
|
pSendConfig->Id = GetUId( pPcb, LCP_INDEX );
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
CopyMemory( pSendConfig->Data,
|
|
pPacket,
|
|
dwLength - PPP_CONFIG_HDR_LEN - PPP_PACKET_HDR_LEN );
|
|
|
|
LogPPPPacket( FALSE, pPcb, pPcb->pSendBuf, dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendIndentification
|
|
//
|
|
// Returns: TRUE - Identification sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send an LCP Identification message to the peer
|
|
//
|
|
BOOL
|
|
FsmSendIdentification(
|
|
IN PCB * pPcb,
|
|
IN BOOL fSendVersion
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
DWORD dwLength = PPP_PACKET_HDR_LEN + PPP_CONFIG_HDR_LEN + 4;
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( !(pPcb->ConfigInfo.dwConfigMask & PPPCFG_UseLcpExtensions) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( fSendVersion )
|
|
{
|
|
CopyMemory( pSendConfig->Data + 4,
|
|
MS_RAS_VERSION,
|
|
strlen( MS_RAS_VERSION ) );
|
|
|
|
dwLength += strlen( MS_RAS_VERSION );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If we couldn't get the computername for any reason
|
|
//
|
|
|
|
if ( *(pPcb->pBcb->szComputerName) == (CHAR)NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
CopyMemory( pSendConfig->Data + 4,
|
|
pPcb->pBcb->szComputerName,
|
|
strlen( pPcb->pBcb->szComputerName ) );
|
|
|
|
dwLength += strlen( pPcb->pBcb->szComputerName );
|
|
}
|
|
|
|
HostToWireFormat16( (WORD)PPP_LCP_PROTOCOL,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = IDENTIFICATION;
|
|
pSendConfig->Id = GetUId( pPcb, LCP_INDEX );
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
HostToWireFormat32( pLcpCb->Local.Work.MagicNumber,
|
|
(PBYTE)(pSendConfig->Data) );
|
|
|
|
LogPPPPacket( FALSE,pPcb,pPcb->pSendBuf,dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmSendTimeRemaining
|
|
//
|
|
// Returns: TRUE - TimeRemaining sent successfully.
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called to send an LCP Time Remaining packet from the server
|
|
// to the client
|
|
//
|
|
BOOL
|
|
FsmSendTimeRemaining(
|
|
IN PCB * pPcb
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
|
|
DWORD dwLength = PPP_PACKET_HDR_LEN + PPP_CONFIG_HDR_LEN + 8;
|
|
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( !(pPcb->ConfigInfo.dwConfigMask & PPPCFG_UseLcpExtensions) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
dwLength += strlen( MS_RAS );
|
|
|
|
HostToWireFormat16( (WORD)PPP_LCP_PROTOCOL,
|
|
(PBYTE)(pPcb->pSendBuf->Protocol) );
|
|
|
|
pSendConfig->Code = TIME_REMAINING;
|
|
pSendConfig->Id = GetUId( pPcb, LCP_INDEX );
|
|
|
|
HostToWireFormat16( (WORD)(dwLength - PPP_PACKET_HDR_LEN),
|
|
(PBYTE)(pSendConfig->Length) );
|
|
|
|
HostToWireFormat32( pLcpCb->Local.Work.MagicNumber,
|
|
(PBYTE)(pSendConfig->Data) );
|
|
|
|
HostToWireFormat32( 0, (PBYTE)(pSendConfig->Data+4) );
|
|
|
|
CopyMemory( pSendConfig->Data + 8, MS_RAS, strlen( MS_RAS ) );
|
|
|
|
LogPPPPacket( FALSE, pPcb, pPcb->pSendBuf, dwLength );
|
|
|
|
if ( ( dwRetCode = PortSendOrDisconnect( pPcb, dwLength ) ) != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmInit
|
|
//
|
|
// Returns: TRUE - Control Protocol was successfully initialized
|
|
// FALSE - Otherwise.
|
|
//
|
|
// Description: Called to initialize the state machine
|
|
//
|
|
BOOL
|
|
FsmInit(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPPCP_INIT PppCpInit;
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
PppLog( 1, "FsmInit called for protocol = %x, port = %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort );
|
|
|
|
pCpCb->NcpPhase = NCP_CONFIGURING;
|
|
pCpCb->dwError = NO_ERROR;
|
|
pCpCb->State = FSM_INITIAL;
|
|
|
|
PppCpInit.fServer = (pPcb->fFlags & PCBFLAG_IS_SERVER);
|
|
PppCpInit.hPort = pPcb->hPort;
|
|
PppCpInit.dwDeviceType = pPcb->dwDeviceType;
|
|
PppCpInit.CompletionRoutine = CompletionRoutine;
|
|
PppCpInit.pszzParameters = pPcb->pBcb->InterfaceInfo.szzParameters;
|
|
PppCpInit.fThisIsACallback = pPcb->fFlags & PCBFLAG_THIS_IS_A_CALLBACK;
|
|
PppCpInit.IfType = pPcb->pBcb->InterfaceInfo.IfType;
|
|
PppCpInit.pszUserName = pPcb->pBcb->szRemoteUserName;
|
|
PppCpInit.pszPortName = pPcb->szPortName;
|
|
PppCpInit.hConnection = pPcb->pBcb->hConnection;
|
|
PppCpInit.pAttributes = ( pPcb->pAuthProtocolAttributes )
|
|
? pPcb->pAuthProtocolAttributes
|
|
: pPcb->pAuthenticatorAttributes;
|
|
PppCpInit.fDisableNetbt = (pPcb->fFlags & PCBFLAG_DISABLE_NETBT);
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_IS_SERVER )
|
|
{
|
|
PppCpInit.PppConfigInfo = PppConfigInfo.ServerConfigInfo;
|
|
|
|
if ( PppConfigInfo.ServerConfigInfo.dwConfigMask
|
|
& PPPCFG_AllowNoAuthOnDCPorts )
|
|
{
|
|
if ( RAS_DEVICE_CLASS( pPcb->dwDeviceType ) & RDT_Direct )
|
|
{
|
|
PppCpInit.PppConfigInfo.dwConfigMask |=
|
|
PPPCFG_AllowNoAuthentication;
|
|
}
|
|
else
|
|
{
|
|
PppCpInit.PppConfigInfo.dwConfigMask &=
|
|
~PPPCFG_AllowNoAuthOnDCPorts;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PppCpInit.PppConfigInfo = pPcb->ConfigInfo;
|
|
}
|
|
|
|
switch( CpTable[CpIndex].CpInfo.Protocol )
|
|
{
|
|
case PPP_IPCP_PROTOCOL:
|
|
PppCpInit.hInterface = pPcb->pBcb->InterfaceInfo.hIPInterface;
|
|
break;
|
|
|
|
case PPP_IPXCP_PROTOCOL:
|
|
PppCpInit.hInterface = pPcb->pBcb->InterfaceInfo.hIPXInterface;
|
|
break;
|
|
|
|
default:
|
|
PppCpInit.hInterface = INVALID_HANDLE_VALUE;
|
|
break;
|
|
}
|
|
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpBegin)(
|
|
&(pCpCb->pWorkBuf), &PppCpInit );
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
PppLog( 1, "FsmInit for protocol = %x failed with error %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, dwRetCode );
|
|
|
|
pCpCb->dwError = dwRetCode;
|
|
|
|
pCpCb->fConfigurable = FALSE;
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
pCpCb->fBeginCalled = TRUE;
|
|
|
|
if ( !FsmReset( pPcb, CpIndex ) )
|
|
{
|
|
pCpCb->fConfigurable = FALSE;
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmReset
|
|
//
|
|
// Returns: TRUE - Control Protocol was successfully reset
|
|
// FALSE - Otherwise.
|
|
//
|
|
// Description: Called to reset the state machine
|
|
//
|
|
BOOL
|
|
FsmReset(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
PppLog( 1, "FsmReset called for protocol = %x, port = %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort );
|
|
|
|
pCpCb->LastId = 0;
|
|
|
|
InitRestartCounters( pPcb, pCpCb );
|
|
|
|
pCpCb->NakRetryCount = PppConfigInfo.MaxFailure;
|
|
pCpCb->RejRetryCount = PppConfigInfo.MaxReject;
|
|
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpReset)( pCpCb->pWorkBuf );
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
PppLog( 1, "Reset for protocol = %x failed with error %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, dwRetCode );
|
|
|
|
pCpCb->dwError = dwRetCode;
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
|
|
//**
|
|
//
|
|
// Call: FsmThisLayerUp
|
|
//
|
|
// Returns: TRUE - Success
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called when configuration negotiation is completed.
|
|
//
|
|
BOOL
|
|
FsmThisLayerUp(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwIndex;
|
|
DWORD dwRetCode;
|
|
PPP_PROJECTION_RESULT ProjectionResult;
|
|
RAS_AUTH_ATTRIBUTE * pUserAttributes = NULL;
|
|
NCP_PHASE dwNcpState;
|
|
BOOL fAreCPsDone = FALSE;
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
LCPCB * pLcpCb;
|
|
DWORD dwLinkDiscrim;
|
|
BOOL fCanDoBAP = FALSE;
|
|
|
|
if ( NULL != pCpCb )
|
|
{
|
|
PppLog( 1, "FsmThisLayerUp called for protocol = %x, port = %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort );
|
|
|
|
if ( CpTable[CpIndex].CpInfo.RasCpThisLayerUp != NULL )
|
|
{
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpThisLayerUp)(
|
|
pCpCb->pWorkBuf);
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
PppLog( 1, "FsmThisLayerUp for protocol=%x,port=%d,RetCode=%d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort,
|
|
dwRetCode);
|
|
|
|
if ( dwRetCode != PENDING )
|
|
{
|
|
pCpCb->dwError = dwRetCode;
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
}
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PppLog( 1, "FsmThisLayerUp called in no auth case, port = %d",
|
|
pPcb->hPort );
|
|
}
|
|
|
|
if ( CpIndex == GetCpIndexFromProtocol( PPP_BACP_PROTOCOL ) )
|
|
{
|
|
BapSetPolicy( pPcb->pBcb );
|
|
}
|
|
|
|
switch( pPcb->PppPhase )
|
|
{
|
|
case PPP_LCP:
|
|
|
|
PppLog( 1, "LCP Configured successfully" );
|
|
|
|
if (!( pPcb->fFlags & PCBFLAG_IS_SERVER ) )
|
|
{
|
|
AdjustHTokenImpersonateUser( pPcb );
|
|
}
|
|
|
|
//
|
|
// Send Identification messages if we are a client.
|
|
//
|
|
|
|
if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) )
|
|
{
|
|
FsmSendIdentification( pPcb, TRUE );
|
|
|
|
FsmSendIdentification( pPcb, FALSE );
|
|
}
|
|
|
|
//
|
|
// If an Authentication protocol was negotiated
|
|
//
|
|
|
|
pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( ( pLcpCb->Local.Work.AP != 0 ) || ( pLcpCb->Remote.Work.AP != 0 ) )
|
|
{
|
|
//
|
|
// Start authenticating
|
|
//
|
|
|
|
PppLog( 1, "Authenticating phase started" );
|
|
|
|
pPcb->PppPhase = PPP_AP;
|
|
|
|
//
|
|
// Start server side authentication if one was negotiated
|
|
//
|
|
|
|
if ( pLcpCb->Local.Work.AP != 0 )
|
|
{
|
|
CpIndex = GetCpIndexFromProtocol( pLcpCb->Local.Work.AP );
|
|
|
|
PPP_ASSERT(( CpIndex != (DWORD)-1 ));
|
|
|
|
ApStart( pPcb, CpIndex, TRUE );
|
|
}
|
|
|
|
//
|
|
// Start client side negotiation if one was negotiated
|
|
//
|
|
|
|
if ( pLcpCb->Remote.Work.AP != 0 )
|
|
{
|
|
CpIndex = GetCpIndexFromProtocol( pLcpCb->Remote.Work.AP );
|
|
|
|
PPP_ASSERT(( CpIndex != (DWORD)-1 ));
|
|
|
|
ApStart( pPcb, CpIndex, FALSE );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If we are a server and did not authenticate the user, then see if
|
|
// Guests have dial-in privilege. In the case of DCC, we don't care if
|
|
// Guests have the privilege. We allow the call to succeed.
|
|
//
|
|
|
|
if ( ( pPcb->fFlags & PCBFLAG_IS_SERVER )
|
|
&& ( pLcpCb->Local.Work.AP == 0 )
|
|
&& (0 == (pLcpCb->PppConfigInfo.dwConfigMask & PPPCFG_AllowNoAuthOnDCPorts)))
|
|
// && ( ( RAS_DEVICE_CLASS( pPcb->dwDeviceType ) & RDT_Direct ) == 0 ))
|
|
{
|
|
pPcb->PppPhase = PPP_AP;
|
|
|
|
pUserAttributes = RasAuthAttributeCopy(
|
|
pPcb->pUserAttributes );
|
|
|
|
if ( pUserAttributes == NULL )
|
|
{
|
|
dwRetCode = GetLastError();
|
|
|
|
pPcb->LcpCb.dwError = dwRetCode;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
dwRetCode = RasAuthenticateClient(pPcb->hPort, pUserAttributes);
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
pPcb->LcpCb.dwError = dwRetCode;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If there was no authentication protocol negotiated, fallthru and
|
|
// begin NCP configurations.
|
|
//
|
|
|
|
case PPP_AP:
|
|
|
|
//
|
|
// Make sure authentication phase is completed before moving on.
|
|
//
|
|
|
|
if ( pPcb->AuthenticatorCb.fConfigurable )
|
|
{
|
|
if ( pPcb->AuthenticatorCb.State != FSM_OPENED )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pPcb->AuthenticateeCb.fConfigurable )
|
|
{
|
|
if ( pPcb->AuthenticateeCb.State != FSM_OPENED )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
NotifyCaller( pPcb, PPPDDMMSG_Authenticated, NULL );
|
|
|
|
//
|
|
// If we are to negotiate callback
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_NEGOTIATE_CALLBACK )
|
|
{
|
|
CpIndex = GetCpIndexFromProtocol( PPP_CBCP_PROTOCOL );
|
|
|
|
PPP_ASSERT(( CpIndex != (DWORD)-1 ));
|
|
|
|
//
|
|
// Start callback
|
|
//
|
|
|
|
PppLog( 1, "Callback phase started" );
|
|
|
|
pPcb->PppPhase = PPP_NEGOTIATING_CALLBACK;
|
|
|
|
pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
|
|
if ( NULL == pCpCb )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pCpCb->fConfigurable = TRUE;
|
|
|
|
CbStart( pPcb, CpIndex );
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If the remote peer did not negotiate callback during LCP and
|
|
// the authenticated user HAS to be called back for security
|
|
// reasons, we bring the link down
|
|
//
|
|
|
|
if ( ( pPcb->fFlags & PCBFLAG_IS_SERVER ) &&
|
|
( !(pPcb->fFlags & PCBFLAG_THIS_IS_A_CALLBACK) ) &&
|
|
( pPcb->fCallbackPrivilege & RASPRIV_AdminSetCallback ) )
|
|
{
|
|
pPcb->LcpCb.dwError = ERROR_NO_DIALIN_PERMISSION;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
//
|
|
// We need to send an Accounting Stop if RADIUS sends an Access
|
|
// Accept but we still drop the line.
|
|
//
|
|
|
|
pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Fallthru
|
|
//
|
|
|
|
case PPP_NEGOTIATING_CALLBACK:
|
|
|
|
//
|
|
// Progress to NCP phase only if we are sure that we have passed the
|
|
// callback phase
|
|
//
|
|
|
|
if ( ( pPcb->fFlags & PCBFLAG_NEGOTIATE_CALLBACK ) &&
|
|
( CpTable[CpIndex].CpInfo.Protocol != PPP_CBCP_PROTOCOL ) )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) )
|
|
{
|
|
NotifyCaller( pPcb, PPPMSG_Projecting, NULL );
|
|
}
|
|
|
|
//
|
|
// We may lose pPcb->pBcb when we call TryToBundleWithAnotherLink().
|
|
// Save pPcb->pBcb->fFlags & BCBFLAG_CAN_DO_BAP first.
|
|
//
|
|
|
|
fCanDoBAP = pPcb->pBcb->fFlags & BCBFLAG_CAN_DO_BAP;
|
|
|
|
//
|
|
// If multilink was negotiated on this link check to see if this
|
|
// link can be bundled and is not already bundled with another link
|
|
//
|
|
|
|
if ( ( pPcb->fFlags & PCBFLAG_CAN_BE_BUNDLED ) &&
|
|
( !(pPcb->fFlags & PCBFLAG_IS_BUNDLED ) ) )
|
|
{
|
|
//
|
|
// If we are bundled with another link then skip NCP phase
|
|
//
|
|
|
|
dwRetCode = TryToBundleWithAnotherLink( pPcb );
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
pPcb->LcpCb.dwError = dwRetCode;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are bundled
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_IS_BUNDLED )
|
|
{
|
|
if ( pPcb->pBcb->fFlags & BCBFLAG_CAN_DO_BAP )
|
|
{
|
|
if ( !fCanDoBAP )
|
|
{
|
|
//
|
|
// A new link can join a bundle that does BAP only if the
|
|
// link has negotiated Link Discriminator.
|
|
//
|
|
|
|
PppLog( 1, "Link to be terminated on hPort = %d because "
|
|
"it can't do BAP.",
|
|
pPcb->hPort );
|
|
|
|
pPcb->LcpCb.dwError = ERROR_PPP_NOT_CONVERGING;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Reset the start time for the sample period. Now that the
|
|
// bandwidth has changed, ndiswan shouldn't ask us to bring
|
|
// links up or down based on what happened in the past.
|
|
//
|
|
|
|
BapSetPolicy( pPcb->pBcb );
|
|
}
|
|
|
|
if ( !FLinkDiscriminatorIsUnique( pPcb, &dwLinkDiscrim ) )
|
|
{
|
|
PppLog( 1,
|
|
"New link discriminator %d to be negotiated for "
|
|
"port %d",
|
|
dwLinkDiscrim, pPcb->hPort );
|
|
|
|
WLinkDiscriminator = (WORD) dwLinkDiscrim;
|
|
|
|
FsmDown( pPcb, LCP_INDEX );
|
|
|
|
((LCPCB*)
|
|
(pPcb->LcpCb.pWorkBuf))->Local.Work.dwLinkDiscriminator =
|
|
dwLinkDiscrim;
|
|
|
|
FsmUp( pPcb, LCP_INDEX );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get state of bundle NCPs
|
|
//
|
|
|
|
dwNcpState = QueryBundleNCPState( pPcb );
|
|
|
|
switch ( dwNcpState )
|
|
{
|
|
case NCP_CONFIGURING:
|
|
|
|
pPcb->PppPhase = PPP_NCP;
|
|
|
|
PppLog(2,"Bundle NCPs not done for port %d, wait", pPcb->hPort);
|
|
|
|
NotifyCaller( pPcb, PPPDDMMSG_NewLink, NULL );
|
|
|
|
break;
|
|
|
|
case NCP_DOWN:
|
|
|
|
pPcb->PppPhase = PPP_NCP;
|
|
|
|
pPcb->LcpCb.dwError = ERROR_PPP_NO_PROTOCOLS_CONFIGURED;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
|
|
case NCP_UP:
|
|
|
|
pPcb->PppPhase = PPP_NCP;
|
|
|
|
NotifyCaller( pPcb, PPPDDMMSG_NewLink, NULL );
|
|
|
|
NotifyCallerOfBundledProjection( pPcb );
|
|
|
|
RemoveFromTimerQ( pPcb->dwPortId,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
TIMER_EVENT_NEGOTIATETIME );
|
|
|
|
StartAutoDisconnectForPort( pPcb );
|
|
StartLCPEchoForPort ( pPcb );
|
|
MakeStartAccountingCall( pPcb );
|
|
|
|
break;
|
|
|
|
case NCP_DEAD:
|
|
|
|
//
|
|
// NCPs still have not started so notify DDM that this a
|
|
// new bundle and get interface handles for this new bundle.
|
|
//
|
|
|
|
NotifyCaller( pPcb, PPPDDMMSG_NewBundle, NULL );
|
|
|
|
break;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//
|
|
// We are a client so we have all the interface handles already.
|
|
// We are not part of a bundle, so initialize all NCPs
|
|
//
|
|
|
|
if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) )
|
|
{
|
|
dwRetCode = InitializeNCPs( pPcb, pPcb->ConfigInfo.dwConfigMask );
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
pPcb->LcpCb.dwError = dwRetCode;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Start NCPs
|
|
//
|
|
|
|
StartNegotiatingNCPs( pPcb );
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Take care of the RAS server policy on workstation. If we have
|
|
// already checked the policy for this link, don't check again.
|
|
//
|
|
|
|
if ( ( PppConfigInfo.fFlags & PPPCONFIG_FLAG_WKSTA )
|
|
&& !( pPcb->pBcb->fFlags & BCBFLAG_WKSTA_IN ) )
|
|
{
|
|
//
|
|
// We did not bundle with another link. Allow atmost one
|
|
// dial in client in each class.
|
|
//
|
|
|
|
if ( ( (pPcb->dwDeviceType & RDT_Tunnel)
|
|
&& (PppConfigInfo.fFlags & PPPCONFIG_FLAG_TUNNEL))
|
|
|| ( (pPcb->dwDeviceType & RDT_Direct)
|
|
&& (PppConfigInfo.fFlags & PPPCONFIG_FLAG_DIRECT))
|
|
|| ( !(pPcb->dwDeviceType & RDT_Tunnel)
|
|
&& !(pPcb->dwDeviceType & RDT_Direct)
|
|
&& (PppConfigInfo.fFlags & PPPCONFIG_FLAG_DIALUP)))
|
|
{
|
|
pPcb->LcpCb.dwError = ERROR_USER_LIMIT;
|
|
|
|
PppLog( 2, "User limit reached. Flags: %d",
|
|
PppConfigInfo.fFlags );
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( pPcb->dwDeviceType & RDT_Tunnel )
|
|
{
|
|
PppConfigInfo.fFlags |= PPPCONFIG_FLAG_TUNNEL;
|
|
}
|
|
else if ( pPcb->dwDeviceType & RDT_Direct )
|
|
{
|
|
PppConfigInfo.fFlags |= PPPCONFIG_FLAG_DIRECT;
|
|
}
|
|
else
|
|
{
|
|
PppConfigInfo.fFlags |= PPPCONFIG_FLAG_DIALUP;
|
|
}
|
|
|
|
pPcb->pBcb->fFlags |= BCBFLAG_WKSTA_IN;
|
|
}
|
|
|
|
//
|
|
// Increase client license count if we are on the recieving end
|
|
// of the call.
|
|
//
|
|
|
|
if ( pPcb->pBcb->hLicense == INVALID_HANDLE_VALUE )
|
|
{
|
|
LS_STATUS_CODE LsStatus;
|
|
NT_LS_DATA NtLSData;
|
|
|
|
NtLSData.DataType = NT_LS_USER_NAME;
|
|
NtLSData.Data = pPcb->pBcb->szLocalUserName;
|
|
NtLSData.IsAdmin = FALSE;
|
|
|
|
LsStatus = NtLicenseRequest(
|
|
"REMOTE_ACCESS",
|
|
"",
|
|
(LS_HANDLE*)&(pPcb->pBcb->hLicense),
|
|
&NtLSData );
|
|
|
|
if ( LsStatus != LS_SUCCESS )
|
|
{
|
|
pPcb->LcpCb.dwError =
|
|
( LsStatus == LS_RESOURCES_UNAVAILABLE )
|
|
? ERROR_OUTOFMEMORY
|
|
: ERROR_REQ_NOT_ACCEP;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// We are DDM and this is a new Bundle.
|
|
//
|
|
|
|
NotifyCaller( pPcb, PPPDDMMSG_NewBundle, NULL );
|
|
}
|
|
|
|
break;
|
|
|
|
case PPP_NCP:
|
|
|
|
//
|
|
// If we are a client and got rechallenged and we responded while we
|
|
// were in the NCP state then we are done.
|
|
//
|
|
|
|
pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
if ( pLcpCb->Remote.Work.AP != 0 )
|
|
{
|
|
if ( CpIndex == GetCpIndexFromProtocol( pLcpCb->Remote.Work.AP ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If we are a server and we got another auth request while we were
|
|
// in NCP state, we are done
|
|
//
|
|
|
|
if ( pLcpCb->Local.Work.AP != 0 )
|
|
{
|
|
if ( CpIndex == GetCpIndexFromProtocol( pLcpCb->Local.Work.AP ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( NULL == pCpCb )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
pCpCb->NcpPhase = NCP_UP;
|
|
|
|
if ( ( CpTable[CpIndex].CpInfo.Protocol == PPP_NBFCP_PROTOCOL ) ||
|
|
( CpTable[CpIndex].CpInfo.Protocol == PPP_IPCP_PROTOCOL ) )
|
|
{
|
|
if ( !NotifyIPCPOfNBFCPProjection( pPcb, CpIndex ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
dwRetCode = AreNCPsDone(pPcb, CpIndex, &ProjectionResult, &fAreCPsDone);
|
|
|
|
//
|
|
// We failed to get information from CP with CpIndex.
|
|
//
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( fAreCPsDone == TRUE )
|
|
{
|
|
RemoveFromTimerQ( pPcb->dwPortId,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
TIMER_EVENT_NEGOTIATETIME );
|
|
|
|
//
|
|
// Notify the ras client and the ras server about the projections
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_IS_SERVER )
|
|
{
|
|
NotifyCaller( pPcb, PPPDDMMSG_PppDone, &ProjectionResult );
|
|
}
|
|
else
|
|
{
|
|
RASMAN_INFO rasmanInfo;
|
|
|
|
NotifyCaller(pPcb, PPPMSG_ProjectionResult, &ProjectionResult);
|
|
|
|
NotifyCaller(pPcb, PPPMSG_PppDone, NULL);
|
|
|
|
if ( RasGetInfo(NULL, pPcb->hPort, &rasmanInfo ) == NO_ERROR )
|
|
{
|
|
RasSetConnectionUserData(
|
|
rasmanInfo.RI_ConnectionHandle,
|
|
1,
|
|
(PBYTE)&ProjectionResult,
|
|
sizeof( ProjectionResult ) );
|
|
}
|
|
}
|
|
|
|
StartAutoDisconnectForPort( pPcb );
|
|
StartLCPEchoForPort ( pPcb );
|
|
|
|
if ( !( pPcb->fFlags & PCBFLAG_IS_SERVER ) &&
|
|
!( pPcb->fFlags & PCBFLAG_CONNECTION_LOGGED ) )
|
|
{
|
|
LPSTR lpsSubStringArray[3];
|
|
|
|
lpsSubStringArray[0] = pPcb->pBcb->szLocalUserName;
|
|
lpsSubStringArray[1] = pPcb->pBcb->szEntryName;
|
|
lpsSubStringArray[2] = pPcb->szPortName;
|
|
|
|
PppLogInformation( ROUTERLOG_CONNECTION_ESTABLISHED,
|
|
3,
|
|
lpsSubStringArray );
|
|
|
|
pPcb->fFlags |= PCBFLAG_CONNECTION_LOGGED;
|
|
}
|
|
|
|
//
|
|
// If we are bundled, then we need to notify all other bundled ports
|
|
// that PPP on that port is done too.
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_IS_BUNDLED )
|
|
{
|
|
NotifyCompletionOnBundledPorts( pPcb );
|
|
}
|
|
|
|
MakeStartAccountingCall( pPcb );
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmThisLayerDown
|
|
//
|
|
// Returns: TRUE - Success
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called when leaving the OPENED state.
|
|
//
|
|
BOOL
|
|
FsmThisLayerDown(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
DWORD dwIndex;
|
|
LCPCB * pLcpCb;
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
PppLog( 1, "FsmThisLayerDown called for protocol = %x, port = %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort );
|
|
|
|
if ( CpTable[CpIndex].CpInfo.RasCpThisLayerDown != NULL )
|
|
{
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpThisLayerDown)(
|
|
pCpCb->pWorkBuf );
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
PppLog( 1, "FsmThisLayerDown for protocol=%x,port=%d,RetCode=%d",
|
|
CpTable[CpIndex].CpInfo.Protocol,
|
|
pPcb->hPort,
|
|
dwRetCode );
|
|
|
|
if ( pCpCb->dwError != NO_ERROR )
|
|
{
|
|
pCpCb->dwError = dwRetCode;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( CpIndex == LCP_INDEX )
|
|
{
|
|
//
|
|
// If this port is not part of a bundle, or it is but is the only
|
|
// remaining link in the bundle, then bring all the NCPs down.
|
|
//
|
|
|
|
if ( (!( pPcb->fFlags & PCBFLAG_IS_BUNDLED )) ||
|
|
( ( pPcb->fFlags & PCBFLAG_IS_BUNDLED ) &&
|
|
( pPcb->pBcb->dwLinkCount == 1 ) ) )
|
|
{
|
|
//
|
|
// Bring all the NCPs down
|
|
//
|
|
|
|
for( dwIndex = LCP_INDEX+1;
|
|
dwIndex < PppConfigInfo.NumberOfCPs;
|
|
dwIndex++ )
|
|
{
|
|
pCpCb = GetPointerToCPCB( pPcb, dwIndex );
|
|
|
|
if ( ( NULL != pCpCb )
|
|
&& ( pCpCb->fConfigurable ) )
|
|
{
|
|
FsmDown( pPcb, dwIndex );
|
|
}
|
|
}
|
|
}
|
|
|
|
pPcb->PppPhase = PPP_LCP;
|
|
|
|
pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
|
|
|
|
dwIndex = GetCpIndexFromProtocol( pLcpCb->Local.Work.AP );
|
|
|
|
if ( dwIndex != (DWORD)-1 )
|
|
{
|
|
ApStop( pPcb, dwIndex, TRUE );
|
|
|
|
//
|
|
// Setting this will allow all outstanding request that are
|
|
// completed to be dropped
|
|
//
|
|
|
|
pPcb->dwOutstandingAuthRequestId = 0xFFFFFFFF;
|
|
}
|
|
|
|
dwIndex = GetCpIndexFromProtocol( pLcpCb->Remote.Work.AP );
|
|
|
|
if ( dwIndex != (DWORD)-1 )
|
|
{
|
|
ApStop( pPcb, dwIndex, FALSE );
|
|
}
|
|
|
|
dwIndex = GetCpIndexFromProtocol( PPP_CBCP_PROTOCOL );
|
|
|
|
if ( dwIndex != (DWORD)-1 )
|
|
{
|
|
CbStop( pPcb, dwIndex );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCpCb->NcpPhase = NCP_CONFIGURING;
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmThisLayerStarted
|
|
//
|
|
// Returns: TRUE - Success
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called when leaving the OPENED state.
|
|
//
|
|
BOOL
|
|
FsmThisLayerStarted(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
CPCB* pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
PppLog( 1, "FsmThisLayerStarted called for protocol = %x, port = %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort );
|
|
|
|
if ( CpTable[CpIndex].CpInfo.RasCpThisLayerStarted != NULL )
|
|
{
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpThisLayerStarted)(
|
|
pCpCb->pWorkBuf);
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
pCpCb->dwError = dwRetCode;
|
|
|
|
FsmClose( pPcb, CpIndex );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
pCpCb->NcpPhase = NCP_CONFIGURING;
|
|
|
|
return( TRUE );
|
|
|
|
}
|
|
|
|
//**
|
|
//
|
|
// Call: FsmThisLayerFinished
|
|
//
|
|
// Returns: TRUE - Success
|
|
// FALSE - Otherwise
|
|
//
|
|
// Description: Called when leaving the OPENED state.
|
|
//
|
|
BOOL
|
|
FsmThisLayerFinished(
|
|
IN PCB * pPcb,
|
|
IN DWORD CpIndex,
|
|
IN BOOL fCallCp
|
|
)
|
|
{
|
|
DWORD dwRetCode;
|
|
PPP_PROJECTION_RESULT ProjectionResult;
|
|
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
|
|
BOOL fAreCPsDone = FALSE;
|
|
|
|
if ( pCpCb == NULL )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
PppLog( 1, "FsmThisLayerFinished called for protocol = %x, port = %d",
|
|
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort );
|
|
|
|
if ( ( CpTable[CpIndex].CpInfo.RasCpThisLayerFinished != NULL )
|
|
&& ( fCallCp ) )
|
|
{
|
|
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpThisLayerFinished)(
|
|
pCpCb->pWorkBuf);
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
NotifyCallerOfFailure( pPcb, dwRetCode );
|
|
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Take care of special cases first.
|
|
//
|
|
|
|
switch ( CpTable[CpIndex].CpInfo.Protocol )
|
|
{
|
|
case PPP_LCP_PROTOCOL:
|
|
|
|
//
|
|
// If we are in the callback phase and LCP went down because of an
|
|
// error.
|
|
//
|
|
|
|
//
|
|
// If we LCP layer is finished and we are doing a callback
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_DOING_CALLBACK )
|
|
{
|
|
if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) )
|
|
{
|
|
PppLog( 2, "pPcb->fFlags = %x", pPcb->fFlags ) ;
|
|
|
|
NotifyCaller( pPcb, PPPMSG_Callback, NULL );
|
|
|
|
//
|
|
// We unset this flag now because if we get another
|
|
// FsmClose, it will call FsmThisLayerFinished (this routine)
|
|
// again, and this time we will need to send a failure
|
|
// message back, not Callback, so that the client can
|
|
// clean up.
|
|
//
|
|
|
|
pPcb->fFlags &= ~PCBFLAG_DOING_CALLBACK;
|
|
|
|
return( TRUE );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// If this port is not part of a bundle, or it is but is the only
|
|
// remaining link in the bundle, then call ThisLayerFinished for all
|
|
// NCPs.
|
|
//
|
|
|
|
if ( (!( pPcb->fFlags & PCBFLAG_IS_BUNDLED )) ||
|
|
( ( pPcb->fFlags & PCBFLAG_IS_BUNDLED ) &&
|
|
( pPcb->pBcb->dwLinkCount == 1 ) ) )
|
|
{
|
|
DWORD dwIndex;
|
|
CPCB * pNcpCb;
|
|
|
|
for( dwIndex = LCP_INDEX+1;
|
|
dwIndex < PppConfigInfo.NumberOfCPs;
|
|
dwIndex++ )
|
|
{
|
|
pNcpCb = GetPointerToCPCB( pPcb, dwIndex );
|
|
|
|
if ( pNcpCb->fConfigurable )
|
|
{
|
|
if ( NULL !=
|
|
CpTable[dwIndex].CpInfo.RasCpThisLayerFinished )
|
|
{
|
|
dwRetCode =
|
|
(CpTable[dwIndex].CpInfo.RasCpThisLayerFinished)
|
|
(pNcpCb->pWorkBuf);
|
|
|
|
PppLog( 1, "FsmThisLayerFinished called for "
|
|
"protocol = %x, port = %d: %d",
|
|
CpTable[dwIndex].CpInfo.Protocol, pPcb->hPort,
|
|
dwRetCode );
|
|
|
|
dwRetCode = NO_ERROR;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pPcb->fFlags |= PCBFLAG_STOPPED_MSG_SENT;
|
|
|
|
NotifyCaller( pPcb,
|
|
( pPcb->fFlags & PCBFLAG_IS_SERVER )
|
|
? PPPDDMMSG_Stopped
|
|
: PPPMSG_Stopped,
|
|
&(pPcb->LcpCb.dwError) );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
break;
|
|
|
|
case PPP_CCP_PROTOCOL:
|
|
|
|
//
|
|
// If we need to force encryption but encryption negotiation failed
|
|
// then we drop the link
|
|
//
|
|
|
|
if ( pPcb->ConfigInfo.dwConfigMask & (PPPCFG_RequireEncryption |
|
|
PPPCFG_RequireStrongEncryption ) )
|
|
{
|
|
switch( pCpCb->dwError )
|
|
{
|
|
case ERROR_NO_LOCAL_ENCRYPTION:
|
|
case ERROR_NO_REMOTE_ENCRYPTION:
|
|
pPcb->LcpCb.dwError = pCpCb->dwError;
|
|
break;
|
|
|
|
case ERROR_PROTOCOL_NOT_CONFIGURED:
|
|
pPcb->LcpCb.dwError = ERROR_NO_LOCAL_ENCRYPTION;
|
|
break;
|
|
|
|
default:
|
|
pPcb->LcpCb.dwError = ERROR_NO_REMOTE_ENCRYPTION;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// We need to send an Accounting Stop if RADIUS sends
|
|
// an Access Accept but we still drop the line.
|
|
//
|
|
|
|
pPcb->fFlags |= PCBFLAG_SERVICE_UNAVAILABLE;
|
|
|
|
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
|
|
|
|
return( FALSE );
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch( pPcb->PppPhase )
|
|
{
|
|
|
|
case PPP_NCP:
|
|
|
|
//
|
|
// This NCP failed to be configured. If there are more then
|
|
// try to configure them.
|
|
//
|
|
|
|
pCpCb->NcpPhase = NCP_DOWN;
|
|
|
|
if ( ( CpTable[CpIndex].CpInfo.Protocol == PPP_NBFCP_PROTOCOL ) ||
|
|
( CpTable[CpIndex].CpInfo.Protocol == PPP_IPCP_PROTOCOL ) )
|
|
{
|
|
if ( !NotifyIPCPOfNBFCPProjection( pPcb, CpIndex ) )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check to see if we are all done
|
|
//
|
|
|
|
dwRetCode = AreNCPsDone(pPcb, CpIndex, &ProjectionResult, &fAreCPsDone);
|
|
|
|
//
|
|
// We failed to get information from CP with CpIndex.
|
|
//
|
|
|
|
if ( dwRetCode != NO_ERROR )
|
|
{
|
|
return( FALSE );
|
|
}
|
|
|
|
if ( fAreCPsDone == TRUE )
|
|
{
|
|
RemoveFromTimerQ( pPcb->dwPortId,
|
|
0,
|
|
0,
|
|
FALSE,
|
|
TIMER_EVENT_NEGOTIATETIME );
|
|
|
|
|
|
//
|
|
// Notify the ras client and the ras server about the projections
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_IS_SERVER )
|
|
{
|
|
NotifyCaller( pPcb, PPPDDMMSG_PppDone, &ProjectionResult );
|
|
}
|
|
else
|
|
{
|
|
RASMAN_INFO rasmanInfo;
|
|
|
|
NotifyCaller(pPcb, PPPMSG_ProjectionResult, &ProjectionResult);
|
|
|
|
NotifyCaller(pPcb, PPPMSG_PppDone, NULL);
|
|
|
|
//
|
|
// We call RasSetConnectionUserData in FsmThisLayerUp and
|
|
// FsmThisLayerFinished, in case an NCP is renegotiated. An
|
|
// PPPMSG_ProjectionResult sent after PPPMSG_PppDone is ignored.
|
|
// This is a bad hack. The real fix is to change RasDialMachine
|
|
// such that PPPMSG_ProjectionResult is not ignored.
|
|
//
|
|
|
|
//
|
|
// We are commenting out RasSetConnectionUserData to work
|
|
// around bug 375125. A multilink call was made and the two
|
|
// links connected to two different servers. The second link
|
|
// only should go down in this case. However, IPCP failed
|
|
// for the second link, and RasSetConnectionUserData marked
|
|
// IPCP as failed for the first link also. Both links came down.
|
|
//
|
|
|
|
#if 0
|
|
if ( RasGetInfo(NULL, pPcb->hPort, &rasmanInfo ) == NO_ERROR )
|
|
{
|
|
RasSetConnectionUserData(
|
|
rasmanInfo.RI_ConnectionHandle,
|
|
1,
|
|
(PBYTE)&ProjectionResult,
|
|
sizeof( ProjectionResult ) );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
StartAutoDisconnectForPort( pPcb );
|
|
StartLCPEchoForPort ( pPcb );
|
|
|
|
//
|
|
// If we are bundled, then we need to notify all other bundled ports
|
|
// that PPP on that port is done too.
|
|
//
|
|
|
|
if ( pPcb->fFlags & PCBFLAG_IS_BUNDLED )
|
|
{
|
|
NotifyCompletionOnBundledPorts( pPcb );
|
|
}
|
|
|
|
MakeStartAccountingCall( pPcb );
|
|
}
|
|
|
|
break;
|
|
|
|
case PPP_AP:
|
|
default:
|
|
break;
|
|
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|