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
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;
|
|
}
|