|
|
/*******************************************************************/ /* Copyright(c) 1995 Microsoft Corporation */ /*******************************************************************/
//***
//
// Filename: rmhand.c
//
// Description: This module contains the procedures for the
// DDM's procedure-driven state machine
// that handles RasMan events.
//
// NOTE:Rasman should be modified to set a flag when a frame is
// received or and state change has occurred. This will save
// DDM from getting info for all the ports.
//
// Author: Stefan Solomon (stefans) May 26, 1992.
//
//***
#include "ddm.h"
#include "timer.h"
#include "handlers.h"
#include "objects.h"
#include "util.h"
#include "routerif.h"
#include <raserror.h>
#include <rasppp.h>
#include <ddmif.h>
#include <serial.h>
#include "rasmanif.h"
#include <ras.h>
#include <string.h>
#include <stdlib.h>
#include <memory.h>
//***
//
// Function: SvDevConnected
//
// Description: Handles the device transition to connected state
//
//***
VOID SvDevConnected( IN PDEVICE_OBJECT pDeviceObj ) { PCONNECTION_OBJECT pConnObj; HCONN hConnection; DWORD dwRetCode; LPWSTR auditstrp[3];
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "SvDevConnected: Entered, hPort=%d", pDeviceObj->hPort);
//
// Get handle to the connection or bundle for this link
//
if ( RasPortGetBundle( NULL, pDeviceObj->hPort, &hConnection ) != NO_ERROR ) { DevStartClosing(pDeviceObj);
return; }
switch (pDeviceObj->DeviceState) { case DEV_OBJ_LISTEN_COMPLETE:
pDeviceObj->hConnection = hConnection;
//
// reset the H/W Error signal state
//
pDeviceObj->dwHwErrorSignalCount = HW_FAILURE_CNT;
//
// get the system time for this connection
//
GetLocalTime( &pDeviceObj->ConnectionTime );
//
// get the frame broadcasted by the client
//
if ( ( dwRetCode = RmReceiveFrame( pDeviceObj ) ) != NO_ERROR ) { //
// can't get the broadcast frame. This is a fatal error
// Log the error
//
auditstrp[0] = pDeviceObj->wchPortName;
DDMLogErrorString( ROUTERLOG_CANT_RECEIVE_FRAME, 1, auditstrp, dwRetCode, 1);
DevStartClosing( pDeviceObj ); } else { //
// switch to frame receiving state
//
pDeviceObj->DeviceState = DEV_OBJ_RECEIVING_FRAME;
if ( RAS_DEVICE_TYPE( pDeviceObj->dwDeviceType ) != RDT_Atm ) { //
// start authentication timer
//
TimerQRemove( (HANDLE)pDeviceObj->hPort, SvAuthTimeout );
TimerQInsert( (HANDLE)pDeviceObj->hPort, gblDDMConfigInfo.dwAuthenticateTime, SvAuthTimeout ); } }
break;
case DEV_OBJ_CALLBACK_CONNECTING:
{
//
// log on the client disconnection
//
WCHAR wchFullUserName[UNLEN+DNLEN+2];
if ( pDeviceObj->wchDomainName[0] != TEXT('\0') ) { wcscpy( wchFullUserName, pDeviceObj->wchDomainName ); wcscat( wchFullUserName, TEXT("\\") ); wcscat( wchFullUserName, pDeviceObj->wchUserName ); } else { wcscpy( wchFullUserName, pDeviceObj->wchUserName ); }
auditstrp[0] = wchFullUserName; auditstrp[1] = pDeviceObj->wchPortName; auditstrp[2] = pDeviceObj->wchCallbackNumber;
DDMLogInformation( ROUTERLOG_CLIENT_CALLED_BACK, 3, auditstrp);
}
//
// set up the new state
//
pDeviceObj->DeviceState = DEV_OBJ_AUTH_IS_ACTIVE;
//
// start authentication timer
//
TimerQRemove( (HANDLE)pDeviceObj->hPort, SvAuthTimeout );
TimerQInsert( (HANDLE)pDeviceObj->hPort, gblDDMConfigInfo.dwAuthenticateTime, SvAuthTimeout );
//
// and tell auth to restart conversation
//
if ( pDeviceObj->fFlags & DEV_OBJ_IS_PPP ) { //
// Need to set framing to PPP to make callback over ISDN
// work.
//
RAS_FRAMING_INFO RasFramingInfo;
ZeroMemory( &RasFramingInfo, sizeof( RasFramingInfo ) );
//
// Default ACCM for PPP is 0xFFFFFFFF
//
RasFramingInfo.RFI_RecvACCM = 0xFFFFFFFF; RasFramingInfo.RFI_SendACCM = 0xFFFFFFFF; RasFramingInfo.RFI_MaxSendFrameSize = 1500; RasFramingInfo.RFI_MaxRecvFrameSize = 1500; RasFramingInfo.RFI_SendFramingBits = PPP_FRAMING; RasFramingInfo.RFI_RecvFramingBits = PPP_FRAMING;
RasPortSetFramingEx( pDeviceObj->hPort, &RasFramingInfo );
pDeviceObj->hConnection = hConnection;
PppDdmCallbackDone(pDeviceObj->hPort, pDeviceObj->wchCallbackNumber); } else { // We only suport PPP framing in the server
//
RTASSERT(FALSE); }
break;
default:
break; } }
//***
//
// Function: SvDevDisconnected
//
// Descr: Handles the device transition to disconnected state
//
//***
VOID SvDevDisconnected( IN PDEVICE_OBJECT pDeviceObj ) { DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "SvDevDisconnected:Entered, hPort=%d",pDeviceObj->hPort);
switch (pDeviceObj->DeviceState) { case DEV_OBJ_LISTENING:
//
// h/w error; start h/w error timer
//
pDeviceObj->DeviceState = DEV_OBJ_HW_FAILURE;
TimerQRemove( (HANDLE)pDeviceObj->hPort, SvHwErrDelayCompleted );
TimerQInsert( (HANDLE)pDeviceObj->hPort, HW_FAILURE_WAIT_TIME, SvHwErrDelayCompleted );
//
// if hw error has not been signaled for this port,
// decrement the counter and signal when 0
//
if(pDeviceObj->dwHwErrorSignalCount) { pDeviceObj->dwHwErrorSignalCount--;
if(pDeviceObj->dwHwErrorSignalCount == 0) { SignalHwError(pDeviceObj); } }
break;
case DEV_OBJ_CALLBACK_DISCONNECTING:
//
// disconnection done; can start waiting the callback delay
//
pDeviceObj->DeviceState = DEV_OBJ_CALLBACK_DISCONNECTED;
TimerQRemove( (HANDLE)pDeviceObj->hPort, SvCbDelayCompleted );
TimerQInsert( (HANDLE)pDeviceObj->hPort, pDeviceObj->dwCallbackDelay, SvCbDelayCompleted);
break;
case DEV_OBJ_CALLBACK_CONNECTING:
if (gblDDMConfigInfo.dwCallbackRetries > pDeviceObj->dwCallbackRetries) { DDMTRACE( "Callback failed, retrying" );
pDeviceObj->dwCallbackRetries++;
pDeviceObj->DeviceState = DEV_OBJ_CALLBACK_DISCONNECTED;
TimerQRemove( (HANDLE)pDeviceObj->hPort, SvCbDelayCompleted );
TimerQInsert( (HANDLE)pDeviceObj->hPort, pDeviceObj->dwCallbackDelay, SvCbDelayCompleted ); break; }
case DEV_OBJ_LISTEN_COMPLETE: case DEV_OBJ_RECEIVING_FRAME: case DEV_OBJ_AUTH_IS_ACTIVE:
//
// accidental disconnection; clean-up and restart on this device
//
DevStartClosing( pDeviceObj );
break;
case DEV_OBJ_ACTIVE:
DevStartClosing(pDeviceObj);
break;
case DEV_OBJ_CLOSING:
DevCloseComplete(pDeviceObj); break;
default:
break; } }
VOID SvDevListenComplete( IN PDEVICE_OBJECT pDeviceObj ) { LPWSTR auditstrp[1]; DWORD dwLength; DWORD dwRetCode; DWORD dwBucketIndex = DeviceObjHashPortToBucket( pDeviceObj->hPort );
//
// We reset these values here is case they were set for dialout and the
// dialout failed, we may have not been able to clean up in
// the RasConnectCallback routine in rasapiif.c since the
// RasGetSubEntryHandle may have failed and we hence do not get a
// pointer to the port so we could not cleanup.
//
pDeviceObj->DeviceState = DEV_OBJ_LISTEN_COMPLETE; pDeviceObj->fFlags &= ~DEV_OBJ_OPENED_FOR_DIALOUT; pDeviceObj->fFlags &= ~DEV_OBJ_SECURITY_DLL_USED; pDeviceObj->hConnection = (HCONN)INVALID_HANDLE_VALUE; pDeviceObj->wchUserName[0] = (WCHAR)NULL; pDeviceObj->wchDomainName[0] = (WCHAR)NULL; pDeviceObj->wchCallbackNumber[0] = (WCHAR)NULL; pDeviceObj->hRasConn = (HRASCONN)NULL; pDeviceObj->pRasmanSendBuffer = NULL; pDeviceObj->pRasmanRecvBuffer = NULL; pDeviceObj->dwCallbackRetries = 0;
pDeviceObj->dwRecvBufferLen = 1500;
dwRetCode = RasGetBuffer((CHAR**)&pDeviceObj->pRasmanRecvBuffer, &((pDeviceObj->dwRecvBufferLen)) );
if ( dwRetCode != NO_ERROR ) { auditstrp[0] = pDeviceObj->wchPortName;
DDMLogErrorString( ROUTERLOG_CANT_RECEIVE_BYTES, 1, auditstrp, dwRetCode, 1);
DevStartClosing(pDeviceObj);
return; }
//
// If the security DLL is not loaded or we are not serial, simply
// change the state
//
if ( ( gblDDMConfigInfo.lpfnRasBeginSecurityDialog == NULL ) || ( gblDDMConfigInfo.lpfnRasEndSecurityDialog == NULL ) || (RAS_DEVICE_TYPE(pDeviceObj->dwDeviceType) != RDT_Modem) ) { //
// Change RASMAN state to CONNECTED from LISTENCOMPLETE and signal
// RmEventHandler
//
if ( RasPortConnectComplete(pDeviceObj->hPort) != NO_ERROR ) { DevStartClosing(pDeviceObj); return; }
SetEvent( gblSupervisorEvents[NUM_DDM_EVENTS+dwBucketIndex] ); } else { // Otherwise call the security dll ordinal to begin the 3rd party
// security dialog with the client
dwLength = 1500;
dwRetCode = RasGetBuffer((CHAR**)&pDeviceObj->pRasmanSendBuffer, &dwLength );
if ( dwRetCode != NO_ERROR ) { auditstrp[0] = pDeviceObj->wchPortName;
DDMLogErrorString( ROUTERLOG_CANT_RECEIVE_BYTES, 1, auditstrp, dwRetCode, 1);
DevStartClosing(pDeviceObj);
return; }
//
// Make sure that this device type supports raw mode.
//
if ( RasPortSend( pDeviceObj->hPort, (CHAR*)pDeviceObj->pRasmanSendBuffer, 0 ) != NO_ERROR ) { RasFreeBuffer( pDeviceObj->pRasmanSendBuffer );
pDeviceObj->pRasmanSendBuffer = NULL;
//
// Change RASMAN state to CONNECTED from LISTENCOMPLETE and signal
// RmEventHandler
//
if ( RasPortConnectComplete( pDeviceObj->hPort ) != NO_ERROR ) { DevStartClosing(pDeviceObj); return; }
SetEvent( gblSupervisorEvents[NUM_DDM_EVENTS+dwBucketIndex] );
return; }
dwRetCode = (*gblDDMConfigInfo.lpfnRasBeginSecurityDialog)( pDeviceObj->hPort, pDeviceObj->pRasmanSendBuffer , dwLength, pDeviceObj->pRasmanRecvBuffer, pDeviceObj->dwRecvBufferLen, RasSecurityDialogComplete );
if ( dwRetCode != NO_ERROR ) { //
// Audit failure due to error and hangup the line
//
auditstrp[0] = pDeviceObj->wchPortName;
DDMLogErrorString( ROUTERLOG_SEC_AUTH_INTERNAL_ERROR,1,auditstrp, dwRetCode, 1);
DevStartClosing(pDeviceObj);
return; } else { pDeviceObj->SecurityState = DEV_OBJ_SECURITY_DIALOG_ACTIVE;
pDeviceObj->fFlags |= DEV_OBJ_SECURITY_DLL_USED;
//
// Start timer for 3rd party security
//
TimerQRemove( (HANDLE)pDeviceObj->hPort, SvSecurityTimeout );
TimerQInsert( (HANDLE)pDeviceObj->hPort, gblDDMConfigInfo.dwSecurityTime, SvSecurityTimeout); } }
return; }
//
//*** Array of previous connection state/ current connection state
// used to select the Ras Manager signaled event handler
//
typedef VOID (* RMEVHDLR)(PDEVICE_OBJECT);
typedef struct _RMEHNODE { RASMAN_STATE previous_state; RASMAN_STATE current_state; RMEVHDLR rmevhandler;
} RMEHNODE, *PRMEHNODE;
RMEHNODE rmehtab[] = { // Transition
// Previous --> Current
{ CONNECTING, CONNECTED, SvDevConnected }, { LISTENING, LISTENCOMPLETED, SvDevListenComplete }, { LISTENCOMPLETED, CONNECTED, SvDevConnected }, { LISTENCOMPLETED, DISCONNECTED, SvDevDisconnected }, { LISTENING, DISCONNECTED, SvDevDisconnected }, { CONNECTED, DISCONNECTED, SvDevDisconnected }, { DISCONNECTING, DISCONNECTED, SvDevDisconnected }, { CONNECTED, CONNECTING, SvDevDisconnected }, { 0xffff, 0xffff, NULL }// Table Guard
};
VOID RmEventHandler( DWORD dwEventIndex ) { RASMAN_INFO RasPortInfo; PDEVICE_OBJECT pDevObj; PRMEHNODE ehnp; DWORD dwRetCode; DWORD dwBucketIndex = dwEventIndex - NUM_DDM_EVENTS;
EnterCriticalSection( &(gblDeviceTable.CriticalSection) );
//
// for each port in this bucket
//
for ( pDevObj = gblDeviceTable.DeviceBucket[dwBucketIndex]; pDevObj != (DEVICE_OBJECT *)NULL; pDevObj = pDevObj->pNext ) { //
// get the port state
//
dwRetCode = RasGetInfo( NULL, pDevObj->hPort, &RasPortInfo );
if ( dwRetCode != NO_ERROR ) { SetLastError( dwRetCode );
DDMTRACE3( "RasGetInfo( 0x%x, 0x%x ) = %d", pDevObj->hPort, &RasPortInfo, dwRetCode );
//
// Assume the the port is disconnected
//
pDevObj->ConnectionState = DISCONNECTED;
SvDevDisconnected( pDevObj );
continue; }
//
// check if we own the port now
//
if (!RasPortInfo.RI_OwnershipFlag) { //
// skip biplexed ports used by other processes
//
continue; }
//
// switch on our private connection state
//
switch (pDevObj->ConnectionState) { case CONNECTING:
if (RasPortInfo.RI_ConnState == CONNECTING) { switch (RasPortInfo.RI_LastError) { case SUCCESS:
RasPortConnectComplete(pDevObj->hPort);
//
// force current state to connected.
//
RasPortInfo.RI_ConnState = CONNECTED;
break;
case PENDING:
//
// no action
//
break;
default:
//
// error occured -> force state to disconnecting
//
pDevObj->ConnectionState = DISCONNECTING;
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "RmEventHandler: RI_LastError indicates error when"); DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, " CONNECTING on port %d !!!\n", pDevObj->hPort ); DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "RmEventHandler:RasPortDisconnect posted on port%d\n", pDevObj->hPort);
if ( pDevObj->DeviceState == DEV_OBJ_CALLBACK_CONNECTING ) { LPWSTR Parms[3]; WCHAR wchFullUserName[UNLEN+DNLEN+2];
if ( pDevObj->wchDomainName[0] != TEXT('\0') ) { wcscpy( wchFullUserName, pDevObj->wchDomainName); wcscat( wchFullUserName, TEXT("\\") ); wcscat( wchFullUserName, pDevObj->wchUserName ); } else { wcscpy( wchFullUserName, pDevObj->wchUserName ); }
Parms[0] = wchFullUserName; Parms[1] = pDevObj->wchPortName; Parms[2] = pDevObj->wchCallbackNumber;
DDMLogErrorString(ROUTERLOG_CALLBACK_FAILURE, 3, Parms, RasPortInfo.RI_LastError, 3 ); }
dwRetCode = RasPortDisconnect( pDevObj->hPort, gblSupervisorEvents[NUM_DDM_EVENTS + dwBucketIndex ] );
RTASSERT((dwRetCode == PENDING) || (dwRetCode == SUCCESS));
break; } }
break;
case LISTENING:
if (RasPortInfo.RI_ConnState != LISTENING) { break; }
switch (RasPortInfo.RI_LastError) { case PENDING:
//
// no action
//
break;
default:
//
// error occured -> force state to disconnecting
//
pDevObj->ConnectionState = DISCONNECTING;
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "RmEventHandler: RI_LastError indicates error %d when", RasPortInfo.RI_LastError ); DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, " LISTENING on port %d !!!\n", pDevObj->hPort ); DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "RmEventHandler:RasPortDisconnect posted on port%d\n", pDevObj->hPort);
dwRetCode = RasPortDisconnect( pDevObj->hPort, gblSupervisorEvents[NUM_DDM_EVENTS + dwBucketIndex ] );
RTASSERT((dwRetCode == PENDING) || (dwRetCode == SUCCESS));
break; }
break;
default:
break;
}
//
// try to find the table element with the matching previous and
// current connection states
//
for (ehnp=rmehtab; ehnp->rmevhandler != NULL; ehnp++) { if ((ehnp->previous_state == pDevObj->ConnectionState) && (ehnp->current_state == RasPortInfo.RI_ConnState)) { //
//*** Match ***
//
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "Rasman state change received from port %d, %d->%d", pDevObj->hPort, ehnp->previous_state, ehnp->current_state );
//
// change the dcb conn state (previous state) with the
// current state
//
pDevObj->ConnectionState = RasPortInfo.RI_ConnState;
//
// invoke the handler
//
(*ehnp->rmevhandler)(pDevObj);
break; } } }
LeaveCriticalSection( &(gblDeviceTable.CriticalSection) ); }
//***
//
// Function: SvFrameReceived
//
// Descr: starts authentication
//
//***
VOID SvFrameReceived( IN PDEVICE_OBJECT pDeviceObj, IN CHAR *framep, // pointer to the received frame
IN DWORD framelen, IN DWORD dwBucketIndex ) { DWORD dwRetCode; DWORD FrameType; LPWSTR portnamep; PCONNECTION_OBJECT pConnObj; BYTE RecvBuffer[1500];
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "SvFrameReceived: Entered, hPort: %d", pDeviceObj->hPort);
if ( framelen > sizeof( RecvBuffer ) ) { DDMTRACE2( "Illegal frame length of %d received for port %d", framelen, pDeviceObj->hPort );
RTASSERT( FALSE );
//
// Frame length is illegal so truncate it
//
framelen = sizeof( RecvBuffer ); }
memcpy( RecvBuffer, framep, framelen);
switch (pDeviceObj->DeviceState) { case DEV_OBJ_RECEIVING_FRAME:
if ( !DDMRecognizeFrame( RecvBuffer, (WORD)framelen, &FrameType) ) { portnamep = pDeviceObj->wchPortName;
DDMLogError(ROUTERLOG_UNRECOGNIZABLE_FRAME_RECVD, 1, &portnamep, 0);
DevStartClosing(pDeviceObj);
return; }
//
// check first with our authentication module
//
switch( FrameType ) {
case PPP_LCP_PROTOCOL:
pDeviceObj->fFlags |= DEV_OBJ_IS_PPP;
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "SvFrameReceived: PPP frame on port %d", pDeviceObj->hPort);
dwRetCode = PppDdmStart( pDeviceObj->hPort, pDeviceObj->wchPortName, RecvBuffer, framelen, gblDDMConfigInfo.dwAuthenticateRetries );
if ( dwRetCode != NO_ERROR ) { portnamep = pDeviceObj->wchPortName;
DDMLogErrorString( ROUTERLOG_CANT_START_PPP, 1, &portnamep, dwRetCode,1);
DevStartClosing(pDeviceObj);
return; }
break;
case APPLETALK:
DDM_PRINT( gblDDMConfigInfo.dwTraceId, TRACE_FSM, "SvFrameReceived: protocol not supported! %d", pDeviceObj->hPort);
RTASSERT( FALSE );
break;
default:
break; }
//
// auth has started OK. Update state
// start auth timer
//
pDeviceObj->DeviceState = DEV_OBJ_AUTH_IS_ACTIVE; pDeviceObj->fFlags |= DEV_OBJ_AUTH_ACTIVE;
break;
case DEV_OBJ_CLOSING:
DevCloseComplete(pDeviceObj);
break;
default:
break; } }
//***
//
// Function: RmRecvFrameEventHandler
//
// Description: Scans the set of opened ports and detects the ports where
// RasPortReceive has completed. Invokes the FSM handling
// procedure for each detected port and frees the receive
// buffer.
//
//***
VOID RmRecvFrameEventHandler( DWORD dwEventIndex ) { PDEVICE_OBJECT pDevObj; RASMAN_INFO RasPortInfo; DWORD dwRetCode; DWORD dwBucketIndex = dwEventIndex - NUM_DDM_EVENTS - gblDeviceTable.NumDeviceBuckets;
EnterCriticalSection( &(gblDeviceTable.CriticalSection) );
//
// for each port in this bucket
//
for ( pDevObj = gblDeviceTable.DeviceBucket[dwBucketIndex]; pDevObj != (DEVICE_OBJECT *)NULL; pDevObj = pDevObj->pNext ) { //
// get the port state
//
dwRetCode = RasGetInfo( NULL, pDevObj->hPort, &RasPortInfo );
if ( dwRetCode != NO_ERROR ) { //
// Assume port is disconncted, so clean up
//
DevStartClosing(pDevObj);
continue; }
//
// check if we own the port now
//
if (!RasPortInfo.RI_OwnershipFlag) { //
// skip biplexed ports used by other processes
//
continue; }
if ( ( pDevObj->fFlags & DEV_OBJ_RECEIVE_ACTIVE ) && ( RasPortInfo.RI_LastError != PENDING ) ) { //
// recv frame API has completed
//
pDevObj->fFlags &= (~DEV_OBJ_RECEIVE_ACTIVE );
if ( RasPortInfo.RI_LastError != ERROR_PORT_DISCONNECTED ) { LPBYTE lpBuffer = LocalAlloc(LPTR,RasPortInfo.RI_BytesReceived);
if ( lpBuffer == NULL ) { DevStartClosing(pDevObj);
continue; }
memcpy( lpBuffer, pDevObj->pRasmanRecvBuffer, RasPortInfo.RI_BytesReceived );
RasFreeBuffer(pDevObj->pRasmanRecvBuffer);
pDevObj->pRasmanRecvBuffer = NULL;
//
// call the FSM handler
//
SvFrameReceived( pDevObj, lpBuffer, RasPortInfo.RI_BytesReceived, dwBucketIndex);
LocalFree( lpBuffer ); }
if ( pDevObj->pRasmanRecvBuffer != NULL ) { RasFreeBuffer(pDevObj->pRasmanRecvBuffer);
pDevObj->pRasmanRecvBuffer = NULL; } } }
LeaveCriticalSection( &(gblDeviceTable.CriticalSection) ); }
|