|
|
/********************************************************************/ /** 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 ); }
|