Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1877 lines
44 KiB

/********************************************************************/
/** Copyright(c) 1989 Microsoft Corporation. **/
/********************************************************************/
//***
//
// Filename: receive.c
//
// Description: This module contains code to handle all packets received.
//
// 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 <lmcons.h>
#include <raserror.h>
#include <mprerror.h>
#include <mprlog.h>
#include <rasman.h>
#include <rtutils.h>
#include <rasppp.h>
#include <pppcp.h>
#include <ppp.h>
#include <smaction.h>
#include <smevents.h>
#include <receive.h>
#include <auth.h>
#include <lcp.h>
#include <timer.h>
#include <util.h>
#include <worker.h>
#define INCL_RASAUTHATTRIBUTES
#include <ppputil.h>
//**
//
// Call: ReceiveConfigReq
//
// Returns: None.
//
// Description: Handles an incomming CONFIG_REQ packet and related state
// transitions.
//
VOID
ReceiveConfigReq(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pRecvConfig
)
{
PPP_CONFIG * pSendConfig = (PPP_CONFIG*)(pPcb->pSendBuf->Information);
BOOL fAcked;
switch( pCpCb->State )
{
case FSM_OPENED:
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
if ( !FsmSendConfigReq( pPcb, CpIndex, FALSE ) )
return;
if( !FsmSendConfigResult( pPcb, CpIndex, pRecvConfig, &fAcked ) )
return;
pCpCb->State = ( fAcked ) ? FSM_ACK_SENT : FSM_REQ_SENT;
break;
case FSM_STOPPED:
InitRestartCounters( pPcb, pCpCb );
if ( !FsmSendConfigReq( pPcb, CpIndex, FALSE ) )
return;
//
// Fallthru
//
case FSM_REQ_SENT:
case FSM_ACK_SENT:
if ( !FsmSendConfigResult( pPcb, CpIndex, pRecvConfig, &fAcked ) )
return;
pCpCb->State = ( fAcked ) ? FSM_ACK_SENT : FSM_REQ_SENT;
break;
case FSM_ACK_RCVD:
if ( !FsmSendConfigResult( pPcb, CpIndex, pRecvConfig, &fAcked ) )
return;
if( fAcked )
{
pCpCb->State = FSM_OPENED;
FsmThisLayerUp( pPcb, CpIndex );
}
break;
case FSM_CLOSED:
FsmSendTermAck( pPcb, CpIndex, pRecvConfig );
break;
case FSM_CLOSING:
case FSM_STOPPING:
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog(2,"Illegal transition->ConfigReq received while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveConfigAck
//
// Returns: none.
//
// Description: Handles an incomming CONFIG_ACK packet and related state
// transitions.
//
VOID
ReceiveConfigAck(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pRecvConfig
)
{
//
// The Id of the Ack HAS to match the Id of the last request sent
// If it is different, then we should silently discard it.
//
if ( pRecvConfig->Id != pCpCb->LastId )
{
PppLog(1,
"Config Ack rcvd. on port %d silently discarded. Invalid Id",
pPcb->hPort );
return;
}
switch( pCpCb->State )
{
case FSM_REQ_SENT:
if ( !FsmConfigResultReceived( pPcb, CpIndex, pRecvConfig ) )
return;
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
InitRestartCounters( pPcb, pCpCb );
pCpCb->State = FSM_ACK_RCVD;
break;
case FSM_ACK_SENT:
if ( !FsmConfigResultReceived( pPcb, CpIndex, pRecvConfig ) )
return;
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
InitRestartCounters( pPcb, pCpCb );
pCpCb->State = FSM_OPENED;
FsmThisLayerUp( pPcb, CpIndex );
break;
case FSM_OPENED:
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
//
// Fallthru
//
case FSM_ACK_RCVD:
if ( !FsmSendConfigReq( pPcb, CpIndex, FALSE ) )
return;
pCpCb->State = FSM_REQ_SENT;
break;
case FSM_CLOSED:
case FSM_STOPPED:
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
//
// Out of Sync; kill the remote
//
FsmSendTermAck( pPcb, CpIndex, pRecvConfig );
break;
case FSM_CLOSING:
case FSM_STOPPING:
//
// We are attempting to close connection
// wait for timeout to resend a Terminate Request
//
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
PPP_ASSERT( pCpCb->State < 10 );
PppLog(2,"Illegal transition->ConfigAck received while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveConfigNakRej
//
// Returns: none.
//
// Description: Handles an incomming CONFIG_NAK or CONFIF_REJ packet and
// related state transitions.
//
VOID
ReceiveConfigNakRej(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pRecvConfig
)
{
//
// The Id of the Nak/Rej HAS to match the Id of the last request sent
// If it is different, then we should silently discard it.
//
if ( pRecvConfig->Id != pCpCb->LastId )
{
PppLog(1,"Config Nak/Rej on port %d silently discarded. Invalid Id",
pPcb->hPort );
return;
}
switch( pCpCb->State )
{
case FSM_REQ_SENT:
case FSM_ACK_SENT:
if ( !FsmConfigResultReceived( pPcb, CpIndex, pRecvConfig ) )
return;
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
InitRestartCounters( pPcb, pCpCb );
if ( !FsmSendConfigReq( pPcb, CpIndex, FALSE ) )
return;
break;
case FSM_OPENED:
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
//
// Fallthru
//
case FSM_ACK_RCVD:
if ( !FsmSendConfigReq( pPcb, CpIndex, FALSE ) )
return;
pCpCb->State = FSM_REQ_SENT;
break;
case FSM_CLOSED:
case FSM_STOPPED:
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
//
// Out of Sync; kill the remote
//
FsmSendTermAck( pPcb, CpIndex, pRecvConfig );
break;
case FSM_CLOSING:
case FSM_STOPPING:
//
// We are attempting to close connection
// wait for timeout to resend a Terminate Request
//
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
PPP_ASSERT( pCpCb->State < 10 );
PppLog(2,"Illegal transition->CfgNakRej received while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveTermReq
//
// Returns: none
//
// Description: Handles an incomming TERM_REQ packet and
// related state transitions.
//
VOID
ReceiveTermReq(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pConfig
)
{
//
// We are shutting down so do not resend any outstanding request.
//
RemoveFromTimerQ( pPcb->dwPortId,
pCpCb->LastId,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
if ( CpIndex == LCP_INDEX )
{
//
// If we are receiving a terminate request, remove any hangup event
// that we may have put into the timer queue if there was a previous
// LCP TermReq sent.
RemoveFromTimerQ( pPcb->dwPortId,
0,
0,
FALSE,
TIMER_EVENT_HANGUP );
}
switch( pCpCb->State )
{
case FSM_OPENED:
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
//
// Zero restart counters
//
pCpCb->ConfigRetryCount = 0;
pCpCb->TermRetryCount = 0;
pCpCb->NakRetryCount = 0;
pCpCb->RejRetryCount = 0;
FsmSendTermAck( pPcb, CpIndex, pConfig );
pCpCb->State = FSM_STOPPING;
break;
case FSM_ACK_RCVD:
case FSM_ACK_SENT:
case FSM_REQ_SENT:
FsmSendTermAck( pPcb, CpIndex, pConfig );
pCpCb->State = FSM_REQ_SENT;
break;
case FSM_CLOSED:
case FSM_CLOSING:
case FSM_STOPPED:
case FSM_STOPPING:
FsmSendTermAck( pPcb, CpIndex, pConfig );
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog(2,"Illegal transition->CfgNakRej received while in %s state",
FsmStates[pCpCb->State] );
break;
}
if ( CpIndex == LCP_INDEX )
{
pPcb->fFlags |= PCBFLAG_RECVD_TERM_REQ;
//
// If we got a terminate request from the remote peer.
//
if ( pPcb->fFlags & PCBFLAG_DOING_CALLBACK ) {
//
// If we are the server side we need to tell the server
// to callback.
//
if ( pPcb->fFlags & PCBFLAG_IS_SERVER ) {
PPPDDM_CALLBACK_REQUEST PppDdmCallbackRequest;
PppDdmCallbackRequest.fUseCallbackDelay = TRUE;
PppDdmCallbackRequest.dwCallbackDelay =
pPcb->ConfigInfo.dwCallbackDelay;
strcpy( PppDdmCallbackRequest.szCallbackNumber,
pPcb->szCallbackNumber );
PppLog( 2, "Notifying server to callback at %s, delay = %d",
PppDdmCallbackRequest.szCallbackNumber,
PppDdmCallbackRequest.dwCallbackDelay );
NotifyCaller( pPcb,
PPPDDMMSG_CallbackRequest,
&PppDdmCallbackRequest );
}
//
// If we are the client?
//
}
else
{
//
// Check to see if the remote peer sent a Terminate Request reason
//
DWORD dwLength = WireToHostFormat16( pConfig->Length );
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
DWORD dwRetCode = ERROR_PPP_LCP_TERMINATED;
if ( dwLength == PPP_CONFIG_HDR_LEN + 12 )
{
//
// Check to see if this is our signature
//
if ( ( WireToHostFormat32( pConfig->Data ) ==
pLcpCb->Remote.Work.MagicNumber )
&&
( WireToHostFormat32( pConfig->Data + 4 ) == 3984756 ) )
{
dwRetCode = WireToHostFormat32( pConfig->Data + 8 );
//
// Should not be larger than the highest winerror.h
//
if ( dwRetCode > ERROR_DHCP_ADDRESS_CONFLICT )
{
//
// Ignore this error
//
dwRetCode = ERROR_PPP_LCP_TERMINATED;
}
if ( dwRetCode == ERROR_NO_LOCAL_ENCRYPTION )
{
dwRetCode = ERROR_NO_REMOTE_ENCRYPTION;
}
else if ( dwRetCode == ERROR_NO_REMOTE_ENCRYPTION )
{
dwRetCode = ERROR_NO_LOCAL_ENCRYPTION;
}
}
}
if ( pCpCb->dwError == NO_ERROR )
{
pCpCb->dwError = dwRetCode;
}
if ( !( pPcb->fFlags & PCBFLAG_IS_SERVER ) )
{
NotifyCallerOfFailure( pPcb, pCpCb->dwError );
//
// If we are a client check to see if the server disconnected us
// because of autodisconnect.
//
if ( ( dwRetCode == ERROR_IDLE_DISCONNECTED ) ||
( dwRetCode == ERROR_PPP_SESSION_TIMEOUT ) )
{
CHAR * pszPortName = pPcb->szPortName;
PppLogInformation(
( dwRetCode == ERROR_IDLE_DISCONNECTED )
? ROUTERLOG_CLIENT_AUTODISCONNECT
: ROUTERLOG_PPP_SESSION_TIMEOUT,
1,
&pszPortName );
}
}
//
// If the remote LCP is terminating we MUST wait at least one
// restart timer time period before we hangup.
//
InsertInTimerQ( pPcb->dwPortId,
pPcb->hPort,
0,
0,
FALSE,
TIMER_EVENT_HANGUP,
pPcb->RestartTimer );
}
}
else
{
if ( pCpCb->dwError == NO_ERROR )
{
pCpCb->dwError = ERROR_PPP_NCP_TERMINATED;
}
FsmThisLayerFinished( pPcb, CpIndex, FALSE );
}
}
//**
//
// Call: ReceiveTermAck
//
// Returns: none
//
// Description: Handles an incomming TERM_ACK packet and
// related state transitions.
//
VOID
ReceiveTermAck(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pRecvConfig
)
{
//
// The Id of the Term Ack HAS to match the Id of the last request sent
// If it is different, then we should silently discard it.
//
if ( pRecvConfig->Id != pCpCb->LastId )
{
PppLog(1,"Term Ack with on port %d silently discarded. Invalid Id",
pPcb->hPort );
return;
}
switch( pCpCb->State )
{
case FSM_OPENED:
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
if ( !FsmSendConfigReq( pPcb, CpIndex, FALSE ) )
return;
pCpCb->State = FSM_REQ_SENT;
break;
case FSM_ACK_RCVD:
pCpCb->State = FSM_REQ_SENT;
break;
case FSM_CLOSING:
case FSM_STOPPING:
//
// Remove the timeout for this Id from the timer Q
//
RemoveFromTimerQ( pPcb->dwPortId,
pRecvConfig->Id,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
if ( !FsmThisLayerFinished( pPcb, CpIndex, TRUE ) )
return;
pCpCb->State = ( pCpCb->State == FSM_CLOSING ) ? FSM_CLOSED
: FSM_STOPPED;
break;
case FSM_REQ_SENT:
case FSM_ACK_SENT:
case FSM_CLOSED:
case FSM_STOPPED:
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog( 2,"Illegal transition->CfgNakRej received while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveUnknownCode
//
// Returns: none.
//
// Description: Handles a packet with an unknown/unrecognizable code and
// related state transitions.
//
VOID
ReceiveUnknownCode(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pConfig
)
{
PppLog( 2, "Received packet with unknown code %d", pConfig->Code );
switch( pCpCb->State )
{
case FSM_STOPPED:
case FSM_STOPPING:
case FSM_OPENED:
case FSM_ACK_SENT:
case FSM_ACK_RCVD:
case FSM_REQ_SENT:
case FSM_CLOSING:
case FSM_CLOSED:
FsmSendCodeReject( pPcb, CpIndex, pConfig );
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog( 2, "Illegal transition->UnknownCode rcvd while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveDiscardReq
//
// Returns: none
//
// Description: Handles an incomming DISCARD_REQ packet and
// related state transitions.
//
VOID
ReceiveDiscardReq(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pConfig
)
{
//
// Simply discard the packet.
//
PppLog( 2, "Illegal transition->Discard rqst rcvd while in %s state",
FsmStates[pCpCb->State] );
}
//**
//
// Call: ReceiveEchoReq
//
// Returns: none
//
// Description: Handles an incomming ECHO_REQ packet and
// related state transitions.
//
VOID
ReceiveEchoReq(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pConfig
)
{
//
// Silently discard this packet if LCP is not in an opened state
//
if ( !IsLcpOpened( pPcb ) )
return;
switch( pCpCb->State )
{
case FSM_STOPPED:
case FSM_STOPPING:
case FSM_ACK_SENT:
case FSM_ACK_RCVD:
case FSM_REQ_SENT:
case FSM_CLOSING:
case FSM_CLOSED:
case FSM_STARTING:
case FSM_INITIAL:
break;
case FSM_OPENED:
FsmSendEchoReply( pPcb, CpIndex, pConfig );
break;
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog( 2, "Illegal transition->UnknownCode rcvd while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveEchoReply
//
// Returns: none
//
// Description: Handles an incomming ECHO_REPLY packet and
// related state transitions. The only Echo request we send
// is to calculate the link speed, so we assume that we get called
// only when we receive the reply.
//
VOID
ReceiveEchoReply(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pConfig
)
{
LCPCB * pLcpCb = (LCPCB*)(pPcb->LcpCb.pWorkBuf);
DWORD dwLength = PPP_PACKET_HDR_LEN +
WireToHostFormat16( pConfig->Length );
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 echo response packet on port=%d",
pPcb->hPort );
return;
}
//
// Pass on the echo reply to whoever send the echo request.
//
if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) && ( RAS_DEVICE_TYPE(pPcb->dwDeviceType) == RDT_PPPoE) && pPcb->dwIdleBeforeEcho )
{
if ( pPcb->fEchoRequestSend )
{
//check to see if we are getting the same text back on the echo
if ( !memcmp( pConfig->Data+ 4, PPP_DEF_ECHO_TEXT, strlen(PPP_DEF_ECHO_TEXT)) )
{
//got the echo response for our echo request
//so reset the flag.
pPcb->fEchoRequestSend = 0;
pPcb->dwNumEchoResponseMissed = 0;
}
}
}
}
//**
//
// Call: ReceiveCodeRej
//
// Returns: none
//
// Description: Handles an incomming CODE_REJ packet and
// related state transitions.
//
VOID
ReceiveCodeRej(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pConfig
)
{
pConfig = (PPP_CONFIG*)(pConfig->Data);
PppLog( 2, "PPP Code Reject rcvd, rejected Code = %d", pConfig->Code );
//
// First check to see if these codes may be rejected without
// affecting implementation. Permitted code rejects
//
if ( CpIndex == LCP_INDEX )
{
switch( pConfig->Code )
{
case CONFIG_REQ:
case CONFIG_ACK:
case CONFIG_NAK:
case CONFIG_REJ:
case TERM_REQ:
case TERM_ACK:
case CODE_REJ:
case PROT_REJ:
case ECHO_REQ:
case ECHO_REPLY:
case DISCARD_REQ:
//
// Unpermitted code rejects.
//
break;
case IDENTIFICATION:
case TIME_REMAINING:
//
// Turn these off.
//
pPcb->ConfigInfo.dwConfigMask &= (~PPPCFG_UseLcpExtensions);
//
// no break here no purpose.
//
default:
//
// Permitted code rejects, we can still work.
//
switch ( pCpCb->State )
{
case FSM_ACK_RCVD:
pCpCb->State = FSM_REQ_SENT;
break;
default:
break;
}
return;
}
}
//
// Log this error
//
//PPPLogEvent( PPP_EVENT_RECV_UNKNOWN_CODE, pConfig->Code );
PppLog( 1, "Unpermitted code reject rcvd. on port %d", pPcb->hPort );
//
// Actually the remote side did not reject the protocol, it rejected
// the code. But for all practical purposes we cannot talk with
// the corresponding CP on the remote side. This is actually an
// implementation error in the remote side.
//
pCpCb->dwError = ERROR_PPP_NOT_CONVERGING;
RemoveFromTimerQ( pPcb->dwPortId,
pCpCb->LastId,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
switch ( pCpCb->State )
{
case FSM_CLOSING:
if ( !FsmThisLayerFinished( pPcb, CpIndex, TRUE ) )
return;
pCpCb->State = FSM_CLOSED;
break;
case FSM_REQ_SENT:
case FSM_ACK_RCVD:
case FSM_ACK_SENT:
case FSM_STOPPING:
if ( !FsmThisLayerFinished( pPcb, CpIndex, TRUE ) )
return;
pCpCb->State = FSM_STOPPED;
break;
case FSM_OPENED:
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
InitRestartCounters( pPcb, pCpCb );
FsmSendTermReq( pPcb, CpIndex );
pCpCb->State = FSM_STOPPING;
break;
case FSM_CLOSED:
case FSM_STOPPED:
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog( 2, "Illegal transition->UnknownCode rcvd while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: ReceiveProtocolRej
//
// Returns: none
//
// Description: Handles an incomming PROT_REJ packet and
// related state transitions.
//
VOID
ReceiveProtocolRej(
IN PCB * pPcb,
IN PPP_PACKET * pPacket
)
{
PPP_CONFIG * pRecvConfig = (PPP_CONFIG *)(pPacket->Information);
DWORD dwProtocol = WireToHostFormat16( pRecvConfig->Data );
CPCB * pCpCb;
DWORD CpIndex;
PppLog( 2, "PPP Protocol Reject, Protocol = %x", dwProtocol );
CpIndex = GetCpIndexFromProtocol( dwProtocol );
if ( CpIndex == (DWORD)-1 )
{
return;
}
//
// "Protocol Reject" in the middle of LCP (RXJ- in state 2-9) should cause
// immediate termination.
//
if ( LCP_INDEX == CpIndex )
{
pPcb->LcpCb.dwError = ERROR_PPP_NOT_CONVERGING;
NotifyCallerOfFailure( pPcb, pPcb->LcpCb.dwError );
return;
}
//
// If LCP is not in the opened state we silently discard this packet
//
if ( !IsLcpOpened( pPcb ) )
{
PppLog(1,"Protocol Rej silently discarded on port %d. Lcp not open",
pPcb->hPort );
return;
}
//
// If remote peer rejected an Authentication protocol, then bring down
// the link (LCP) since this should never happen.
//
if ( IsCpIndexOfAp( CpIndex ) )
{
CpIndex = LCP_INDEX;
pCpCb = GetPointerToCPCB( pPcb, LCP_INDEX );
pCpCb->dwError = ERROR_AUTH_PROTOCOL_REJECTED;
}
else
{
pCpCb = GetPointerToCPCB( pPcb, CpIndex );
pCpCb->dwError = ERROR_PPP_CP_REJECTED;
}
RemoveFromTimerQ( pPcb->dwPortId,
pCpCb->LastId,
CpTable[CpIndex].CpInfo.Protocol,
FALSE,
TIMER_EVENT_TIMEOUT );
switch ( pCpCb->State )
{
case FSM_CLOSING:
if ( !FsmThisLayerFinished( pPcb, CpIndex, TRUE ) )
return;
pCpCb->State = FSM_CLOSED;
break;
case FSM_REQ_SENT:
case FSM_ACK_RCVD:
case FSM_ACK_SENT:
case FSM_STOPPING:
if ( !FsmThisLayerFinished( pPcb, CpIndex, TRUE ) )
return;
pCpCb->State = FSM_STOPPED;
break;
case FSM_OPENED:
if ( !FsmThisLayerDown( pPcb, CpIndex ) )
return;
InitRestartCounters( pPcb, pCpCb );
FsmSendTermReq( pPcb, CpIndex );
pCpCb->State = FSM_STOPPING;
break;
case FSM_CLOSED:
case FSM_STOPPED:
break;
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog( 2, "Illegal transition->UnknownCode rcvd while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: NbfCpCompletionRoutine
//
// Returns: none
//
// Description: Called by a NBFCP when it has finished preparing a respose to
// the client's add name request.
//
VOID
NbfCpCompletionRoutine(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pSendConfig
)
{
BOOL fAcked = FALSE;
DWORD dwLength;
DWORD dwRetCode;
switch( pSendConfig->Code )
{
case CONFIG_ACK:
fAcked = TRUE;
break;
case CONFIG_NAK:
if ( pCpCb->NakRetryCount > 0 )
{
(pCpCb->NakRetryCount)--;
}
else
{
pCpCb->dwError = ERROR_PPP_NOT_CONVERGING;
NotifyCallerOfFailure( pPcb, pCpCb->dwError );
return;
}
break;
case CONFIG_REJ:
if ( pCpCb->RejRetryCount > 0 )
{
(pCpCb->RejRetryCount)--;
}
else
{
pCpCb->dwError = ERROR_PPP_NOT_CONVERGING;
FsmClose( pPcb, CpIndex );
return;
}
break;
default:
break;
}
HostToWireFormat16( (WORD)CpTable[CpIndex].CpInfo.Protocol,
(PBYTE)(pPcb->pSendBuf->Protocol) );
dwLength = WireToHostFormat16( pSendConfig->Length );
if ( ( dwLength + PPP_PACKET_HDR_LEN ) > LCP_DEFAULT_MRU )
{
pCpCb->dwError = ERROR_PPP_INVALID_PACKET;
FsmClose( pPcb, CpIndex );
return;
}
else
{
CopyMemory( pPcb->pSendBuf->Information, pSendConfig, dwLength );
}
LogPPPPacket(FALSE,pPcb,pPcb->pSendBuf,dwLength+PPP_PACKET_HDR_LEN);
if ( ( dwRetCode = PortSendOrDisconnect( pPcb,
(dwLength + PPP_PACKET_HDR_LEN)))
!= NO_ERROR )
{
return;
}
switch ( pCpCb->State )
{
case FSM_ACK_RCVD:
if ( fAcked )
{
pCpCb->State = FSM_OPENED;
FsmThisLayerUp( pPcb, CpIndex );
}
break;
case FSM_OPENED:
case FSM_ACK_SENT:
case FSM_REQ_SENT:
case FSM_STOPPED:
pCpCb->State = fAcked ? FSM_ACK_SENT : FSM_REQ_SENT;
break;
case FSM_CLOSING:
case FSM_STOPPING:
//
// no transition
//
break;
case FSM_CLOSED:
case FSM_STARTING:
case FSM_INITIAL:
default:
PPP_ASSERT( pCpCb->State < 10 );
PppLog( 2, "Illegal transition->ConfigReq rcvd while in %s state",
FsmStates[pCpCb->State] );
break;
}
}
//**
//
// Call: CompletionRoutine
//
// Returns: none
//
// Description: Called by a CP when it has completed an asynchronous operation.
//
VOID
CompletionRoutine(
IN HCONN hPortOrConnection,
IN DWORD Protocol,
IN PPP_CONFIG * pSendConfig,
IN DWORD dwError
)
{
DWORD dwRetCode;
CPCB * pCpCb;
PCB * pPcb;
HPORT hPort;
DWORD CpIndex = GetCpIndexFromProtocol( Protocol );
if ( CpIndex == (DWORD)-1 )
{
return;
}
PppLog( 2, "CompletionRoutine called for protocol %x",
CpTable[CpIndex].CpInfo.Protocol );
dwRetCode = RasBundleGetPort( NULL, (HCONN)hPortOrConnection, &hPort );
if ( dwRetCode != NO_ERROR )
{
return;
}
pPcb = GetPCBPointerFromhPort( hPort );
if ( pPcb == (PCB *)NULL )
{
return;
}
pCpCb = GetPointerToCPCB( pPcb, CpIndex );
if ( pCpCb == NULL )
{
return;
}
if ( dwError != NO_ERROR )
{
pCpCb->dwError = dwError;
PppLog( 1,
"The control protocol for %x on port %d, returned error %d",
CpTable[CpIndex].CpInfo.Protocol, hPort, dwError );
FsmClose( pPcb, CpIndex );
return;
}
switch( Protocol )
{
case PPP_NBFCP_PROTOCOL:
NbfCpCompletionRoutine( pPcb, CpIndex, pCpCb, pSendConfig );
break;
case PPP_IPXCP_PROTOCOL:
//
// If IPXCP is still in the OPENED state then call ThisLayerUp
// otherwise ignore this call.
//
if ( pCpCb->State == FSM_OPENED )
{
FsmThisLayerUp( pPcb, CpIndex );
}
break;
default:
RTASSERT( FALSE );
break;
}
return;
}
//**
//
// Call: FsmConfigResultReceived
//
// Returns: TRUE - Success
// FALSE - Otherwise
//
// Description: This call will process a Config result ie Ack/Nak/Rej.
//
BOOL
FsmConfigResultReceived(
IN PCB * pPcb,
IN DWORD CpIndex,
IN PPP_CONFIG * pRecvConfig
)
{
DWORD dwRetCode;
CPCB * pCpCb = GetPointerToCPCB( pPcb, CpIndex );
if ( pCpCb == NULL )
{
return( FALSE );
}
switch( pRecvConfig->Code )
{
case CONFIG_NAK:
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpConfigNakReceived)(
pCpCb->pWorkBuf, pRecvConfig );
break;
case CONFIG_ACK:
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpConfigAckReceived)(
pCpCb->pWorkBuf, pRecvConfig );
break;
case CONFIG_REJ:
dwRetCode = (CpTable[CpIndex].CpInfo.RasCpConfigRejReceived)(
pCpCb->pWorkBuf, pRecvConfig );
break;
default:
return( FALSE );
}
if ( dwRetCode != NO_ERROR )
{
if ( dwRetCode == ERROR_PPP_INVALID_PACKET )
{
PppLog( 1,
"Invalid packet received on port %d silently discarded",
pPcb->hPort );
}
else
{
PppLog(1,
"The control protocol for %x on port %d returned error %d",
CpTable[CpIndex].CpInfo.Protocol, pPcb->hPort, dwRetCode );
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" );
switch( dwRetCode )
{
case ERROR_NO_LOCAL_ENCRYPTION:
case ERROR_NO_REMOTE_ENCRYPTION:
pPcb->LcpCb.dwError = dwRetCode;
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;
//
// If we do FsmClose for CCP instead, the other side may
// conclude that PPP was negotiated successfully before we
// send an LCP Terminate Request.
//
FsmClose( pPcb, LCP_INDEX );
return( FALSE );
}
}
pCpCb->dwError = dwRetCode;
FsmClose( pPcb, CpIndex );
}
return( FALSE );
}
return( TRUE );
}
//**
//
// Call: ReceiveIdentification
//
// Returns: none
//
// Description: Handles an incomming IDENTIFICATION packet.
//
VOID
ReceiveIdentification(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pRecvConfig
)
{
DWORD dwLength = WireToHostFormat16( pRecvConfig->Length );
RAS_AUTH_ATTRIBUTE * pAttributes = pPcb->pUserAttributes;
BYTE MSRASClient[MAX_COMPUTERNAME_LENGTH
+ sizeof(MS_RAS_WITH_MESSENGER) + 10];
PBYTE pbTempBuf = NULL;
BYTE MSRASClientVersion[30];
DWORD dwIndex = 0;
DWORD dwRetCode = NO_ERROR;
BOOL fClientName = FALSE;
DWORD dwNumAttribs = 0;
PppLog( 2, "Identification packet received" );
//
// If we are a client we just discard this packet.
//
if ( !(pPcb->fFlags & PCBFLAG_IS_SERVER) )
{
return;
}
//
// check to see if the identification is version.
// if version store it in version field
// or else store it in computer name field
//
// If this is not our identification message
//
if ( (dwLength < PPP_CONFIG_HDR_LEN+4+strlen(MS_RAS_WITH_MESSENGER)) ||
(dwLength > PPP_CONFIG_HDR_LEN+4+
strlen(MS_RAS_WITH_MESSENGER)+MAX_COMPUTERNAME_LENGTH))
{
*(pPcb->pBcb->szComputerName) = (CHAR)NULL;
*(pPcb->pBcb->szClientVersion) = (CHAR)NULL;
return;
}
//
// Convert the ppp message into a string
//
pbTempBuf = LocalAlloc(LPTR, dwLength );
if ( NULL == pbTempBuf )
{
PppLog( 1,
"ReceiveIdentification: Failed to alloc memory %d",
GetLastError()
);
return;
}
memcpy ( pbTempBuf,
pRecvConfig->Data+4,
dwLength - PPP_CONFIG_HDR_LEN - 4
);
if ( strstr ( pbTempBuf, MS_RAS_WITHOUT_MESSENGER ) ||
strstr ( pbTempBuf, MS_RAS_WITH_MESSENGER )
)
{
fClientName = TRUE;
}
//
// First Check to see if the attribute is already present in the
// user attribute list. This can happen if LCP is reset for any
// reason.
//
if( (fClientName &&
(NULL != RasAuthAttributeGetVendorSpecific(
311, MS_VSA_RAS_Client_Name,
pAttributes)))
|| (!fClientName &&
(NULL != RasAuthAttributeGetVendorSpecific(
311, MS_VSA_RAS_Client_Version,
pAttributes))))
{
PppLog(2, "ReceiveIndication: Client%s already present for port %d",
(fClientName) ? "Name":"Version", pPcb->hPort);
goto done;
}
for (dwIndex = 0;
pAttributes[dwIndex].raaType != raatMinimum;
dwIndex ++);
dwNumAttribs = dwIndex;
//
// If theres no space in the user attributes list
// expand the list for the one new attribute being
// added.
//
if(dwIndex >= PPP_NUM_USER_ATTRIBUTES)
{
pAttributes = RasAuthAttributeCopyWithAlloc(
pPcb->pUserAttributes, 1);
PppLog(1, "ReceiveIdentification: allocated new user list %p",
pAttributes);
if(NULL == pAttributes)
{
PppLog(1, "ReceiveIdentification: Failed to allocate attributes. %d",
GetLastError());
goto done;
}
//
// RasAuthAttributeCopyWithAlloc creates space at the beginning.
//
dwIndex = 0;
}
//
// And add the attribs to the list of User Attributes
//
if (fClientName)
{
//
// computer name
//
ZeroMemory( pPcb->pBcb->szComputerName,
sizeof(pPcb->pBcb->szComputerName));
CopyMemory( pPcb->pBcb->szComputerName,
pbTempBuf,
dwLength - PPP_CONFIG_HDR_LEN - 4 );
//
// Vendor-Id
//
HostToWireFormat32( 311, MSRASClient );
//
// Vendor-Type: MS-RAS-Client - New
//
MSRASClient[4] = MS_VSA_RAS_Client_Name;
//
// Length
//
MSRASClient[5] = 2 + (BYTE) (dwLength - PPP_CONFIG_HDR_LEN - 4);
//
// Vendor-Id
//
CopyMemory ( MSRASClient + 6,
pPcb->pBcb->szComputerName,
dwLength - PPP_CONFIG_HDR_LEN - 4) ;
pAttributes[dwIndex].raaType = raatReserved;
dwRetCode = RasAuthAttributeInsert( dwIndex,
pAttributes,
raatVendorSpecific,
FALSE,
6 + dwLength - PPP_CONFIG_HDR_LEN - 4,
MSRASClient );
if ( NO_ERROR != dwRetCode )
{
PppLog( 2, "Error inserting user attribute = %s, %d",
pPcb->pBcb->szComputerName, dwRetCode );
}
PppLog(2, "Remote identification = %s", pPcb->pBcb->szComputerName);
dwNumAttribs++;
}
else
{
//
// version
//
ZeroMemory( pPcb->pBcb->szClientVersion,
sizeof( pPcb->pBcb->szClientVersion ) );
CopyMemory( pPcb->pBcb->szClientVersion,
pRecvConfig->Data+4,
dwLength - PPP_CONFIG_HDR_LEN - 4 );
//
// Vendor-Id
//
HostToWireFormat32( 311, MSRASClientVersion );
//
// Vendor-Type: MS-RAS-Client-Version
//
MSRASClientVersion[4] = MS_VSA_RAS_Client_Version;
//
// Vendor-Length
//
MSRASClientVersion[5] = (BYTE)(2 + dwLength - PPP_CONFIG_HDR_LEN - 4);
CopyMemory( MSRASClientVersion + 6,
pPcb->pBcb->szClientVersion,
dwLength - PPP_CONFIG_HDR_LEN - 4 );
pAttributes[dwIndex].raaType = raatReserved;
dwRetCode = RasAuthAttributeInsert( dwIndex,
pAttributes,
raatVendorSpecific,
FALSE,
6 + dwLength - PPP_CONFIG_HDR_LEN - 4,
MSRASClientVersion );
if ( dwRetCode != NO_ERROR )
{
PppLog( 2, "Error inserting user attribute = %s, %d", pPcb->pBcb->szClientVersion, dwRetCode );
}
PppLog( 2, "Remote identification = %s", pPcb->pBcb->szClientVersion );
dwNumAttribs ++;
}
pAttributes[dwNumAttribs].raaType = raatMinimum;
pAttributes[dwNumAttribs].dwLength = 0;
pAttributes[dwNumAttribs].Value = NULL;
//
// If we allocated a new attribute list, free the old list and save
// the new one.
//
if(pPcb->pUserAttributes != pAttributes)
{
PppLog(2, "ReceiveIdentification: Replaced userlist %p with %p",
pPcb->pUserAttributes,
pAttributes);
RasAuthAttributeDestroy(pPcb->pUserAttributes);
pPcb->pUserAttributes = pAttributes;
}
done:
if ( pbTempBuf )
LocalFree(pbTempBuf);
return;
}
//**
//
// Call: ReceiveTimeRemaining
//
// Returns: none
//
// Description: Handles an incomming TIME_REMAINING packet.
//
VOID
ReceiveTimeRemaining(
IN PCB * pPcb,
IN DWORD CpIndex,
IN CPCB * pCpCb,
IN PPP_CONFIG * pRecvConfig
)
{
DWORD dwLength = WireToHostFormat16( pRecvConfig->Length );
PppLog( 2, "Time Remaining packet received");
//
// If we are a server we just discard this packet.
//
if ( pPcb->fFlags & PCBFLAG_IS_SERVER )
{
return;
}
//
// If this is not our time remaining message
//
if ( dwLength != PPP_CONFIG_HDR_LEN + 8 + strlen( MS_RAS ) )
{
return;
}
return;
}