windows-nt/Source/XPSP1/NT/net/rras/ras/ddm/rmhand.c

1020 lines
26 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*******************************************************************/
/* 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 ) )
{
//
// 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) );
}