|
|
/********************************************************************/ /** 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;
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; }
for (dwIndex = 0; pAttributes[dwIndex].raaType != raatMinimum; 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()); return; } }
//
// Convert the ppp message into a string
//
pbTempBuf = LocalAlloc(LPTR, dwLength ); if ( NULL == pbTempBuf ) { PppLog( 1, "ReceiveIdentification: Failed to alloc memory %d", GetLastError() ); } memcpy ( pbTempBuf, pRecvConfig->Data+4, dwLength - PPP_CONFIG_HDR_LEN - 4 );
//
// And add the attribs to the list of User Attributes
//
if ( strstr ( pbTempBuf, MS_RAS_WITHOUT_MESSENGER ) || strstr ( pbTempBuf, MS_RAS_WITH_MESSENGER ) ) { //
// 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] = 34;
//
// 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); } 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] = 35;
//
// 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 ); }
pAttributes[dwIndex].raaType = raatMinimum; pAttributes[dwIndex].dwLength = 0; pAttributes[dwIndex].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; } 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; }
|