Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

1656 lines
42 KiB

// -------------
//
// Copyright (c) 1990 Microsoft Corporation
//
// Module Name:
//
// tpdrvr.c
//
// Abstract:
//
// This module contains code which defines the Test Protocol
// device object.
//
// Author:
//
// Tom Adams (tomad) 19-Apr-1991
//
// Environment:
//
// Kernel mode, FSD
//
// Revision History:
//
// Sanjeev Katariya Forced unload of driver thru the control panel was not working
// Effected function : TpUnloadDriver()
//
// Tim Wynsma (timothyw) 4-27-94
// Added performance tests
// Tim Wynsma (timothyw) 6-08-94
// Chgd perf tests to use client/server model
//
// --------------
#include <ndis.h>
#include "tpdefs.h"
#include "media.h"
#include "tpprocs.h"
// the following function is prototyped in public\oak\inc\zwapi.h, but including that file
// produces MANY compile errors.
NTSYSAPI
NTSTATUS
NTAPI
ZwCreateSymbolicLinkObject(
OUT PHANDLE LinkHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PUNICODE_STRING LinkTarget
);
POPEN_BLOCK TpOpen = NULL;
HANDLE SymbolicLinkHandle;
//
// The debugging longword, containing a bitmask as defined in common.h
// If a bit is set, then debugging is turned on for that component.
//
#if DBG
ULONG TpDebug = TP_DEBUG_NDIS_CALLS|TP_DEBUG_NDIS_ERROR|TP_DEBUG_STATISTICS|
TP_DEBUG_DATA|TP_DEBUG_DISPATCH|TP_DEBUG_IOCTL_ARGS|
TP_DEBUG_NT_STATUS|TP_DEBUG_DPC|TP_DEBUG_INITIALIZE|
TP_DEBUG_RESOURCES|TP_DEBUG_BREAKPOINT|TP_DEBUG_INFOLEVEL_1;
BOOLEAN TpAssert = TRUE;
#endif // DBG
NDIS_PHYSICAL_ADDRESS HighestAddress = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
//
// Driver Entry function
//
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
// ----------
//
// Routine Description:
//
// This routine performs initialization of the Test Protocol driver.
// It creates the device objects for the driver and performs
// other driver initialization.
//
// Arguments:
//
// DriverObject - Pointer to driver object created by the system.
//
// Return Value:
//
// The function value is the final status from the initialization operation.
//
// ----------
{
STRING nameString;
PDEVICE_CONTEXT DeviceContext;
NTSTATUS Status;
//
// General Version Information
//
IF_TPDBG( TP_DEBUG_ALL )
{
TpPrint0("\nMAC NDIS 3.0 Tester - Test Driver Version 1.5.1\n\n");
}
//
// First initialize the DeviceContext struct,
//
RtlInitString( &nameString, DD_TP_DEVICE_NAME );
Status = TpCreateDeviceContext (DriverObject,
nameString,
&DeviceContext );
if (!NT_SUCCESS (Status))
{
TpPrint1 ("TPDRVR: failed to create device context: Status = %s\n",
TpGetStatus(Status));
return Status;
}
else
{
TpOpen = &DeviceContext->Open[0];
}
//
// Create symbolic link between the Dos Device name and Nt
// Device name for the test protocol driver.
//
Status = TpCreateSymbolicLinkObject( );
if (!NT_SUCCESS (Status))
{
TpPrint1 ("TPDRVR: failed to create symbolic link. Status = %s\n", TpGetStatus(Status));
return Status;
}
//
// then set up the EventQueue for any spurious event, indications,
// or completions. This should be ready at all times, from the
// time the test protocol is registered to the time it is unloaded.
//
Status = TpInitializeEventQueue( DeviceContext );
if (!NT_SUCCESS (Status)) {
TpPrint1 ("TPDRVR: failed to create initialize Event Queue. Status = %s\n",
TpGetStatus(Status));
return Status;
}
//
// make ourselves known to the NDIS wrapper.
//
Status = TpRegisterProtocol ( DeviceContext, &nameString );
if (!NT_SUCCESS(Status))
{
DeviceContext->Initialized = FALSE;
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint1("TPDRVR: TpRegisterProtocol failed. Status= %s\n", TpGetStatus(Status));
}
}
return Status;
}
NTSTATUS
TpCreateDeviceContext(
IN PDRIVER_OBJECT DriverObject,
IN STRING DeviceName,
PDEVICE_CONTEXT *DeviceContext
)
// -----------
//
// Routine Description:
//
// This routine creates and initializes a device context structure.
//
// Arguments:
//
// DriverObject - pointer to the IO subsystem supplied driver object.
//
// DeviceContext - Pointer to a pointer to a transport device context object.
//
// DeviceName - pointer to the name of the device this device object points to.
//
// Return Value:
//
// STATUS_SUCCESS if all is well; STATUS_INSUFFICIENT_RESOURCES otherwise.
//
// ------------
{
NTSTATUS Status;
UNICODE_STRING unicodeString;
PDEVICE_OBJECT deviceObject;
PDEVICE_CONTEXT deviceContext;
//
// Convert the input name string to Unicode until it is actually
// passed as a Unicode string.
//
Status = RtlAnsiStringToUnicodeString( &unicodeString,
&DeviceName,
TRUE );
if ( !NT_SUCCESS( Status ))
{
return Status;
}
//
// Create the device object for Test Protocol.
//
Status = IoCreateDevice(DriverObject,
sizeof (DEVICE_CONTEXT) - sizeof (DEVICE_OBJECT),
&unicodeString,
FILE_DEVICE_TRANSPORT,
0,
FALSE,
&deviceObject );
RtlFreeUnicodeString( &unicodeString );
if ( !NT_SUCCESS( Status ))
{
return Status;
}
deviceObject->Flags |= DO_DIRECT_IO;
//
// Initialize the driver object with this driver's entry points.
//
DriverObject->MajorFunction [IRP_MJ_CREATE] = TpDispatch;
DriverObject->MajorFunction [IRP_MJ_CLOSE] = TpDispatch;
DriverObject->MajorFunction [IRP_MJ_CLEANUP] = TpDispatch;
DriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = TpDispatch;
DriverObject->DriverUnload = TpUnloadDriver;
deviceContext = (PDEVICE_CONTEXT)deviceObject;
//
// Now initialize the Device Context structure Signatures.
//
deviceContext->OpenSignature = OPEN_BLOCK_SIGNATURE;
deviceContext->Initialized = TRUE;
*DeviceContext = deviceContext;
return STATUS_SUCCESS;
}
NTSTATUS
TpCreateSymbolicLinkObject(
VOID
)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttr;
STRING DosString;
STRING NtString;
UNICODE_STRING DosUnicodeString;
UNICODE_STRING NtUnicodeString;
RtlInitAnsiString( &DosString, "\\DosDevices\\Tpdrvr" );
Status = RtlAnsiStringToUnicodeString( &DosUnicodeString,
&DosString,
TRUE );
if ( !NT_SUCCESS( Status ))
{
return Status;
}
RtlInitAnsiString( &NtString, DD_TP_DEVICE_NAME );
Status = RtlAnsiStringToUnicodeString( &NtUnicodeString,
&NtString,
TRUE );
if ( !NT_SUCCESS( Status ))
{
return Status;
}
//
// Removed the OBJ_PERMANENT attribute since we should be able to load and
// unload this driver and create the necessary links at will. Buf Fix# 13183
//
InitializeObjectAttributes( &ObjectAttr,
&DosUnicodeString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = ZwCreateSymbolicLinkObject(&SymbolicLinkHandle,
SYMBOLIC_LINK_ALL_ACCESS,
&ObjectAttr,
&NtUnicodeString );
if ( Status != STATUS_SUCCESS )
{
return Status;
}
RtlFreeUnicodeString( &DosUnicodeString );
RtlFreeUnicodeString( &NtUnicodeString );
return STATUS_SUCCESS;
}
NTSTATUS
TpInitializeEventQueue(
IN PDEVICE_CONTEXT DeviceContext
)
{
NTSTATUS Status;
ULONG i, j;
for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
{
//
// Finally, allocate Event Queue header struct, and its spin lock.
//
Status = NdisAllocateMemory((PVOID *)&DeviceContext->Open[i].EventQueue,
sizeof( EVENT_QUEUE ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpInitializeEventQueue: failed to allocate EVENT_QUEUE struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( (PVOID)DeviceContext->Open[i].EventQueue,
sizeof( EVENT_QUEUE ) );
}
NdisAllocateSpinLock( &DeviceContext->Open[i].EventQueue->SpinLock );
//
// Initialize the Event Queue header, and each of the seperate events
// in the Event Queue array.
//
DeviceContext->Open[i].EventQueue->ReceiveIndicationCount = 0;
DeviceContext->Open[i].EventQueue->StatusIndicationCount = 0;
DeviceContext->Open[i].EventQueue->ExpectReceiveComplete = FALSE;
DeviceContext->Open[i].EventQueue->ExpectStatusComplete = FALSE;
DeviceContext->Open[i].EventQueue->Head = 0;
DeviceContext->Open[i].EventQueue->Tail = 0;
for ( j=0;j<MAX_EVENT;j++ )
{
DeviceContext->Open[i].EventQueue->Events[j].TpEventType = Unknown;
DeviceContext->Open[i].EventQueue->Events[j].Status = NDIS_STATUS_SUCCESS;
DeviceContext->Open[i].EventQueue->Events[j].Overflow = FALSE;
DeviceContext->Open[i].EventQueue->Events[j].EventInfo = NULL;
}
}
return STATUS_SUCCESS;
}
NTSTATUS
TpRegisterProtocol (
IN PDEVICE_CONTEXT DeviceContext,
IN STRING *NameString
)
// -----
//
// Routine Description:
//
// This routine introduces this transport to the NDIS interface.
//
// Arguments:
//
// DeviceObject - Pointer to the device object for this driver.
//
// NameString - The name of the device to be registered.
//
// Return Value:
//
// The function value is the status of the operation.
// STATUS_SUCCESS if all goes well,
// STATUS_UNSUCCESSFUL if we tried to register and couldn't,
// STATUS_INSUFFICIENT_RESOURCES if we couldn't even try to register.
//
// -------------
{
NDIS_STATUS Status;
USHORT i;
//
// Set up the characteristics of this protocol
//
Status = NdisAllocateMemory((PVOID *)&DeviceContext->ProtChars,
sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) + NameString->Length,
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_INITIALIZE)
{
TpPrint0 ("TpRegisterProtocol: insufficient memory to allocate Protocol descriptor.\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( DeviceContext->ProtChars,
sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) );
}
//
// Setup the Characteristics Block and register the protocol with
// the NDIS Wrapper.
//
DeviceContext->ProtChars->MajorNdisVersion = 3;
DeviceContext->ProtChars->MinorNdisVersion = 0;
DeviceContext->ProtChars->Name.Length = NameString->Length;
DeviceContext->ProtChars->Name.Buffer = (PVOID)NameString->Buffer;
DeviceContext->ProtChars->OpenAdapterCompleteHandler =
TestProtocolOpenComplete;
DeviceContext->ProtChars->CloseAdapterCompleteHandler =
TestProtocolCloseComplete;
DeviceContext->ProtChars->SendCompleteHandler = TestProtocolSendComplete;
DeviceContext->ProtChars->TransferDataCompleteHandler =
TestProtocolTransferDataComplete;
DeviceContext->ProtChars->ResetCompleteHandler =
TestProtocolResetComplete;
DeviceContext->ProtChars->RequestCompleteHandler =
TestProtocolRequestComplete;
DeviceContext->ProtChars->ReceiveHandler = TestProtocolReceive;
DeviceContext->ProtChars->ReceiveCompleteHandler =
TestProtocolReceiveComplete;
DeviceContext->ProtChars->StatusHandler = TestProtocolStatus;
DeviceContext->ProtChars->StatusCompleteHandler =
TestProtocolStatusComplete;
NdisRegisterProtocol ( &Status,
&DeviceContext->NdisProtocolHandle,
DeviceContext->ProtChars,
(UINT)sizeof( NDIS_PROTOCOL_CHARACTERISTICS ) + NameString->Length );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_INITIALIZE)
{
TpPrint1("TpRegisterProtocol: NdisRegisterProtocol failed: %s\n",
TpGetStatus( Status ));
}
NdisFreeMemory( DeviceContext->ProtChars,0,0 );
return STATUS_UNSUCCESSFUL;
}
for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
{
DeviceContext->Open[i].NdisProtocolHandle = DeviceContext->NdisProtocolHandle;
}
return STATUS_SUCCESS;
}
NTSTATUS
TpDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
// -------
//
// Routine Description:
//
// This routine is the main dispatch routine for the Test Protocol
// driver. It accepts an I/O Request Packet, performs the request,
// and then returns with the appropriate status.
//
// Arguments:
//
// DeviceObject - Pointer to the device object for this driver.
//
// Irp - Pointer to the request packet representing the I/O request.
//
// Return Value:
//
// The function value is the status of the operation.
//
// -------
{
NTSTATUS Status;
PIO_STACK_LOCATION IrpSp;
PDEVICE_CONTEXT DeviceContext;
//
// Check to see if TP has been initialized; if not, don't allow any use.
//
DeviceContext = (PDEVICE_CONTEXT)DeviceObject;
if ( !DeviceContext->Initialized )
{
return STATUS_UNSUCCESSFUL;
}
//
// Make sure status information is consistent every time.
//
Irp->IoStatus.Status = NDIS_STATUS_PENDING;
Irp->IoStatus.Information = 0;
//
// Get a pointer to the current stack location in the IRP. This is where
// the function codes and parameters are stored.
//
IrpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Case on the function that is being performed by the requestor. If the
// operation is a valid one for this device, then make it look like it was
// successfully completed, where possible.
//
switch ( IrpSp->MajorFunction )
{
//
// The Create function opens the Test Protocol driver and initializes
// the OpenBlock and its various data structures used to control the
// tests. Only one instance of TPCTL.EXE may have the driver open at
// any given time, all other open requests will fail with the error
// STATUS_DEVICE_ALREADY_ATTACHED
//
case IRP_MJ_CREATE:
IF_TPDBG(TP_DEBUG_DISPATCH)
{
TpPrint0("TpDispatch: IRP_MJ_CREATE.\n");
}
Status = TpOpenDriver( DeviceContext );
Irp->IoStatus.Status = Status;
break;
//
// The Close function closes the Test Protocol driver and deallocates
// the various data structures attached to the OpenBlock.
//
case IRP_MJ_CLOSE:
IF_TPDBG(TP_DEBUG_DISPATCH)
{
TpPrint0("TpDispatch: IRP_MJ_CLOSE.\n");
}
TpCloseDriver( DeviceContext );
Status = Irp->IoStatus.Status = STATUS_SUCCESS;
break;
//
// The DeviceControl function is the main path to the test protocol
// driver interface. Every Test Protocol request is has an Io Control
// code that is used by this function to determine the routine to
// call.
//
case IRP_MJ_DEVICE_CONTROL:
IF_TPDBG(TP_DEBUG_DISPATCH)
{
TpPrint0("TpDispatch: IRP_MJ_DEVICE_CONTROL.\n");
}
Status = TpIssueRequest( DeviceContext,Irp,IrpSp );
break;
//
// Handle the two stage IRP for a file close operation. When the first
// stage hits,
//
case IRP_MJ_CLEANUP:
IF_TPDBG( TP_DEBUG_DISPATCH )
{
TpPrint0("TpDispatch: IRP_MJ_CLEANUP.\n");
}
Status = TpCleanUpDriver( DeviceContext,Irp );
Irp->IoStatus.Status = Status;
break;
default:
IF_TPDBG( TP_DEBUG_DISPATCH )
{
TpPrint0("TpDispatch: OTHER (DEFAULT).\n");
}
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
Status = STATUS_INVALID_DEVICE_REQUEST;
} // major function switch
//
// If the request did not pend, the complete it now, otherwise it
// will be completed when the pending routine finishes.
//
if ( Status == STATUS_PENDING )
{
IF_TPDBG( TP_DEBUG_DISPATCH )
{
TpPrint0("TpDispatch: request PENDING in handler.\n");
}
}
else if ( Status == STATUS_CANCELLED )
{
IF_TPDBG( TP_DEBUG_DISPATCH )
{
TpPrint0("TpDispatch: request CANCELLED by handler.\n");
}
}
else
{
IF_TPDBG(TP_DEBUG_DISPATCH)
{
TpPrint0("TpDispatch: request COMPLETED by handler.\n");
}
IoAcquireCancelSpinLock( &Irp->CancelIrql );
IoSetCancelRoutine( Irp,NULL );
IoReleaseCancelSpinLock( Irp->CancelIrql );
IoCompleteRequest( Irp,IO_NETWORK_INCREMENT );
}
//
// Return the immediate status code to the caller.
//
return Status;
}
NTSTATUS
TpOpenDriver(
IN PDEVICE_CONTEXT DeviceContext
)
{
NTSTATUS Status;
USHORT i;
//
// If the Device did not successfully initialize at boot time than
// fail this open.
//
if( DeviceContext->Initialized != TRUE )
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
//
// if the device has already been opened by an instance of TPCTL.EXE
// then fail this open.
//
if ( DeviceContext->Opened == TRUE )
{
return STATUS_DEVICE_ALREADY_ATTACHED;
}
for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
{
//
// Allocate each of the instances of the OpenBlock.
//
Status = TpAllocateOpenArray( &DeviceContext->Open[i] );
if ( Status != STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint1("TpCreateDeviceContext: failed to allocate Open Array. Status = %s\n",
TpGetStatus(Status));
}
//
// If one of the allocation calls fails deallocate any of
// the structs that were just successfully allocated.
//
while ( i >= 0 )
{
TpDeallocateOpenArray( &DeviceContext->Open[i--] );
}
return Status;
}
}
DeviceContext->Opened = TRUE;
return STATUS_SUCCESS;
}
NTSTATUS
TpCleanUpDriver(
IN PDEVICE_CONTEXT DeviceContext,
IN PIRP Irp
)
// ----
//
// Routine Description:
//
//
// Arguments:
//
//
// Return Value:
//
// ----
{
NDIS_STATUS Status;
USHORT i;
//
// Make this Irp Cancellable
//
NdisAcquireSpinLock( &DeviceContext->Open[0].SpinLock );
DeviceContext->Open[0].Irp = Irp;
DeviceContext->Open[0].IrpCancelled = FALSE;
IoAcquireCancelSpinLock( &Irp->CancelIrql );
if ( Irp->Cancel )
{
Irp->IoStatus.Status = STATUS_CANCELLED;
return STATUS_CANCELLED;
}
IoSetCancelRoutine( Irp,(PDRIVER_CANCEL)TpCancelIrp );
IoReleaseCancelSpinLock( Irp->CancelIrql );
NdisReleaseSpinLock( &DeviceContext->Open[0].SpinLock );
for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
{
if ( DeviceContext->Open[i].OpenInstance != (UCHAR)-1 )
{
//
// Set the open instance's closing flag to true, then signal
// all the async test protocol routines to end.
//
DeviceContext->Open[i].Closing = TRUE;
if ( DeviceContext->Open[i].Stress->Stressing == TRUE )
{
DeviceContext->Open[i].Stress->StopStressing = TRUE;
}
if ( DeviceContext->Open[i].Send->Sending == TRUE )
{
DeviceContext->Open[i].Send->StopSending = TRUE;
}
if ( DeviceContext->Open[i].Receive->Receiving == TRUE )
{
DeviceContext->Open[i].Receive->StopReceiving = TRUE;
}
if ( DeviceContext->Open[i].PerformanceTest == TRUE)
{
DeviceContext->Open[i].Perform->Active = FALSE;
}
//
// Wait for all of the four asynchronous routines STRESS,
// SEND, PERFORMANCE, and RECEIVE to finish, then close the adapter.
//
while (( DeviceContext->Open[i].ReferenceCount > 0 ) &&
( DeviceContext->Open[0].IrpCancelled != TRUE ))
{
/* NULL */ ;
}
//
// Now close each of the existing OpenInstances.
//
NdisCloseAdapter( &Status,
DeviceContext->Open[i].NdisBindingHandle );
if (( Status != NDIS_STATUS_SUCCESS ) &&
( Status != NDIS_STATUS_PENDING ))
{
IF_TPDBG ( TP_DEBUG_NDIS_ERROR )
{
TpPrint2(
"TpCleanUpDriver: failed to close adapter for instance #%d. Status = %s\n",
i, TpGetStatus(Status));
}
}
else
{
// XXX: handle the close pending.
DeviceContext->Open[i].NdisBindingHandle = NULL;
DeviceContext->Open[i].OpenInstance = (UCHAR)-1;
DeviceContext->Open[i].Closing = FALSE;
NdisFreeMemory( DeviceContext->Open[i].AdapterName,0,0 );
DeviceContext->Open[i].AdapterName = NULL;
//
// We will also free the media block at this point because
// the info it contains may not hold for the next adapter
// open on this instance.
//
NdisFreeMemory( DeviceContext->Open[i].Media,0,0 );
DeviceContext->Open[i].Media = NULL;
}
}
}
//
// If this Irp has been cancelled return now, otherwise make it
// non cancellable.
//
NdisAcquireSpinLock( &DeviceContext->Open[0].SpinLock );
if ( DeviceContext->Open[0].IrpCancelled == TRUE )
{
return STATUS_CANCELLED;
}
else
{
IoAcquireCancelSpinLock( &Irp->CancelIrql );
IoSetCancelRoutine( Irp,NULL );
IoReleaseCancelSpinLock( Irp->CancelIrql );
}
NdisReleaseSpinLock( &DeviceContext->Open[0].SpinLock );
//
// Deallocate each of the instances of the OpenBlock.
//
for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
{
TpDeallocateOpenArray( &DeviceContext->Open[i] );
}
return STATUS_SUCCESS;
}
VOID
TpCloseDriver(
IN PDEVICE_CONTEXT DeviceContext
)
// ----
//
// Routine Description:
//
//
// Arguments:
//
//
// Return Value:
//
// ----
{
DeviceContext->Opened = FALSE;
}
VOID
TpUnloadDriver(
IN PDRIVER_OBJECT DriverObject
)
{
USHORT i;
PDEVICE_CONTEXT DeviceContext = (PDEVICE_CONTEXT)DriverObject->DeviceObject;
TpPrint0("TpUnloadDriver called.\n");
//
// Fixed error for deallocation of memory contigent to having been opened
// Bug# 13183
//
if ( DeviceContext->Opened == TRUE )
{
//
// for each of the open instances in the open array.
//
for ( i=0;i<NUM_OPEN_INSTANCES;i++ )
{
//
// Deallocate each of the instances of the OpenBlock.
//
TpDeallocateOpenArray( &DeviceContext->Open[i] );
}
}
//
// Close the Dos Symbolic link to remove traces of the device
//
ZwClose( SymbolicLinkHandle );
//
// Then delete the device object from the system. Fixed for Bug#: 13183
//
IoDeleteDevice( (PDEVICE_OBJECT)DeviceContext );
TpPrint0("TpUnloadDriver completed.\n");
}
BOOLEAN
TpAddReference(
IN POPEN_BLOCK OpenP
)
// ---
//
// Routine Description:
//
// Add a reference to an open block, to prevent it being removed
// by TpCloseDriver.
//
// Arguments:
//
// OpenP - The open block holding the adapter information to add the
// reference to.
//
// Return Value:
//
// TRUE if the reference is added.
// FALSE if the open is already closing.
//
// ----
{
NdisAcquireSpinLock( &OpenP->SpinLock );
if ( OpenP->Closing )
{
NdisReleaseSpinLock( &OpenP->SpinLock );
return FALSE;
}
++OpenP->ReferenceCount;
NdisReleaseSpinLock( &OpenP->SpinLock );
return TRUE;
}
VOID
TpRemoveReference(
IN POPEN_BLOCK OpenP
)
// --
//
// Routine Description:
//
// Remove a reference to an adapter. If the count goes to
// zero, then the adapter may be closed if requested.
//
// Arguments:
//
// Argument - The open block holding the adapter information to
// remove the reference from.
//
// Return Value:
//
// None.
//
// --
{
NdisAcquireSpinLock( &OpenP->SpinLock );
--OpenP->ReferenceCount;
NdisReleaseSpinLock( &OpenP->SpinLock );
}
NTSTATUS
TpAllocateOpenArray(
POPEN_BLOCK OpenP
)
// -----
//
// Routine Description:
//
// This routine allocates the various data structures and spinlocks
// in the OpenBlock.
//
// Arguments:
//
// OpenP - a pointer to the OpenBlock containing the data structures which
// will be allocated during this routine.
//
// Return Value:
//
// NTSTATUS - STATUS_SUCCESS if all the memory and spinlocks are allocated
// else STATUS_INSUFFICIENT_RESOURCES if an allocation of memory
// fails.
//
// ----------
{
NDIS_STATUS Status;
ULONG i;
//
// Initialize the Open Block fields,
//
OpenP->NdisBindingHandle = NULL;
OpenP->OpenInstance = (UCHAR)-1;
OpenP->Closing = FALSE;
OpenP->AdapterName = NULL;
OpenP->ReferenceCount = 0;
OpenP->MediumIndex = 0xFFFFFFFF;
OpenP->Media = NULL;
OpenP->GlobalCounters = NULL;
OpenP->Environment = NULL;
OpenP->Stress = NULL;
OpenP->Send = NULL;
OpenP->Receive = NULL;
OpenP->OpenReqHndl = NULL;
OpenP->CloseReqHndl = NULL;
OpenP->ResetReqHndl = NULL;
OpenP->RequestReqHndl = NULL;
OpenP->StressReqHndl = NULL;
OpenP->IrpCancelled = FALSE;
OpenP->Irp = NULL;
OpenP->Signature = OPEN_BLOCK_SIGNATURE;
OpenP->PerformanceTest = FALSE;
//
// and set the station address for this open instance to nulls.
//
for ( i=0;i<ADDRESS_LENGTH;i++ )
{
OpenP->StationAddress[i] = 0x00;
}
//
// Allocate the Environment struct
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Environment,
sizeof( ENVIRONMENT_VARIABLES ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate Environment struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( OpenP->Environment,sizeof( ENVIRONMENT_VARIABLES ));
}
//
// Then initialize the Environment Variables to the default settings.
//
OpenP->Environment->WindowSize = WINDOW_SIZE;
OpenP->Environment->RandomBufferNumber = BUFFER_NUMBER;
OpenP->Environment->StressDelayInterval = DELAY_INTERVAL;
OpenP->Environment->UpForAirDelay = UP_FOR_AIR_DELAY;
OpenP->Environment->StandardDelay = STANDARD_DELAY;
//
// Allocate the Stress struct and the pend counters and stress results
// counters attached to it.
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Stress,
sizeof( STRESS_BLOCK ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate STRESS_BLOCK struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( OpenP->Stress,sizeof( STRESS_BLOCK ));
}
//
// Initialize the Stress Block and set the request pending counters
// and the stress results structs to null.
//
OpenP->Stress->Stressing = FALSE;
OpenP->Stress->StressStarted = FALSE;
OpenP->Stress->StopStressing = TRUE;
OpenP->Stress->StressFinal = FALSE;
OpenP->Stress->StressEnded = TRUE;
OpenP->Stress->Client = NULL;
OpenP->Stress->Server = NULL;
OpenP->Stress->Arguments = NULL;
OpenP->Stress->DataBuffer[0] = NULL;
OpenP->Stress->DataBuffer[1] = NULL;
OpenP->Stress->DataBufferMdl[0] = NULL;
OpenP->Stress->DataBufferMdl[1] = NULL;
OpenP->Stress->PoolInitialized = FALSE;
OpenP->Stress->PacketHandle = NULL;
OpenP->Stress->StressIrp = NULL;
//
// allocate the pend counter, we need to create this here because
// it will be used in starting all instances of the stress test.
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Pend,
sizeof( PENDING ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate PEND_COUNTER struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( OpenP->Stress->Pend,sizeof( PENDING ));
}
NdisAllocateSpinLock( &OpenP->Stress->Pend->SpinLock );
TpInitializePending( OpenP->Stress->Pend );
Status = NdisAllocateMemory((PVOID *)&OpenP->Stress->Results,
sizeof( STRESS_RESULTS ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate Stress Results struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( OpenP->Stress->Results,sizeof( STRESS_RESULTS ));
TpInitializeStressResults( OpenP->Stress->Results );
}
//
// Initialize the timer to regulate when to call each of the routines.
//
KeInitializeTimer( &OpenP->Stress->TpStressTimer );
KeInitializeTimer( &OpenP->Stress->TpStressReg2Timer );
//
// Now allocate the Send and Receive structs.
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Send,
sizeof( SEND_BLOCK ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate SEND_BLOCK struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( OpenP->Send,sizeof( SEND_BLOCK ));
}
//
// Initialize the Send Block fields and set the SEND destination
// address and resend address to nulls.
//
OpenP->Send->Sending = FALSE;
OpenP->Send->StopSending = TRUE;
OpenP->Send->ResendPackets = FALSE;
OpenP->Send->PacketSize = 0;
OpenP->Send->NumberOfPackets = 0;
OpenP->Send->PacketsSent = 0;
OpenP->Send->PacketsPending = 0;
OpenP->Send->PacketHandle = NULL;
OpenP->Send->Counters = NULL;
OpenP->Send->SendIrp = NULL;
KeInitializeTimer( &OpenP->Send->SendTimer );
for ( i=0;i<ADDRESS_LENGTH;i++ )
{
OpenP->Send->DestAddress[i] = 0x00;
OpenP->Send->ResendAddress[i] = 0x00;
}
//
// Allocate the Send PacketPool.
//
NdisAllocatePacketPool( &Status,
&OpenP->Send->PacketHandle,
NUMBER_OF_POOL_PACKETS,
sizeof( PROTOCOL_RESERVED ) );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: could not allocate Packet Pool\n");
}
return Status;
}
//
// Now allocate the SEND Counters and initialize them to zero.
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Send->Counters,
sizeof( INSTANCE_COUNTERS ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate counters.\n");
}
return NDIS_STATUS_RESOURCES;
}
else
{
NdisZeroMemory( (PVOID)OpenP->Send->Counters,
sizeof( INSTANCE_COUNTERS ) );
}
//
// Initialize the DPC used to call SendDpc, and SendEndDpc.
//
KeInitializeDpc(&OpenP->Send->SendDpc,
TpFuncSendDpc,
(PVOID)OpenP );
KeInitializeDpc(&OpenP->Send->SendEndDpc,
TpFuncSendEndDpc,
(PVOID)OpenP );
Status = NdisAllocateMemory((PVOID *)&OpenP->Receive,
sizeof( RECEIVE_BLOCK ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate RECEIVE_BLOCK struct\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory((PVOID)OpenP->Receive,sizeof( RECEIVE_BLOCK ));
}
//
// Initialize the Receive Block fields.
//
OpenP->Receive->Receiving = FALSE;
OpenP->Receive->StopReceiving = TRUE;
OpenP->Receive->PacketsPending = 0;
OpenP->Receive->PacketHandle = NULL;
OpenP->Receive->Counters = NULL;
OpenP->Receive->ReceiveIrp = NULL;
KeInitializeTimer( &OpenP->Receive->ReceiveTimer );
KeInitializeTimer( &OpenP->Receive->ResendTimer);
//
// Create a PacketPool, and initialize it, we will need this in case
// we receive any RESEND packets (FUNC2_PACKET).
//
NdisAllocatePacketPool( &Status,
&OpenP->Receive->PacketHandle,
NUMBER_OF_POOL_PACKETS,
sizeof( PROTOCOL_RESERVED ) );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint1("TpAllocateOpenArray: could not allocate Packet Pool: return %s.\n",
TpGetStatus(Status));
}
return Status;
}
//
// Now allocate the COUNTERS structure and set the counters to zero.
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Receive->Counters,
sizeof( INSTANCE_COUNTERS ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG ( TP_DEBUG_RESOURCES )
{
TpPrint0("TpAllocateOpenArray: failed to allocate counters.\n");
}
return NDIS_STATUS_RESOURCES;
}
else
{
NdisZeroMemory( (PVOID)OpenP->Receive->Counters,
sizeof( INSTANCE_COUNTERS ) );
}
//
// Initialize the DPCs used to call ReceiveDpc and ReceiveEndDpc.
//
KeInitializeDpc(&OpenP->Receive->ReceiveDpc,
TpFuncReceiveDpc,
(PVOID)OpenP );
KeInitializeDpc(&OpenP->Receive->ReceiveEndDpc,
TpFuncReceiveEndDpc,
(PVOID)OpenP );
KeInitializeDpc(&OpenP->Receive->ResendDpc,
TpFuncResendDpc,
(PVOID)OpenP );
//
// the performance structure is not allocated here, but is allocated and freed
// within the performance functions themselves
//
// OpenP->Perform = NULL;
//
// now deal with the PAUSE Block
//
Status = NdisAllocateMemory((PVOID *)&OpenP->Pause,
sizeof( PAUSE_BLOCK ),
0,
HighestAddress );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: failed to allocate PAUSE_BLOCK struct.\n");
}
return STATUS_INSUFFICIENT_RESOURCES;
}
else
{
NdisZeroMemory( (PVOID)OpenP->Pause,
sizeof( PAUSE_BLOCK ) );
}
//
// Initialize the Pause Block fields.
//
OpenP->Pause->GoReceived = FALSE;
for ( i=0;i<ADDRESS_LENGTH;i++ )
{
OpenP->Pause->RemoteAddress[i] = 0x00;
}
OpenP->Pause->TestSignature = 0xFFFFFFFF;
OpenP->Pause->PacketType = (UCHAR)-1;
OpenP->Pause->UniqueSignature = 0xFFFFFFFF;
OpenP->Pause->TimeOut = 0;
NdisAllocateSpinLock( &OpenP->Pause->SpinLock );
OpenP->Pause->PoolAllocated = FALSE;
//
// and Allocate the PacketPool.
//
NdisAllocatePacketPool( &Status,
&OpenP->Pause->PacketHandle,
10,
sizeof( PROTOCOL_RESERVED ) );
if ( Status != NDIS_STATUS_SUCCESS )
{
IF_TPDBG (TP_DEBUG_RESOURCES)
{
TpPrint0("TpAllocateOpenArray: could not allocate Packet Pool.\n");
}
return Status;
}
else
{
OpenP->Pause->PoolAllocated = TRUE;
}
//
// Then allocate the Open Blocks open spin lock.
//
NdisAllocateSpinLock( &OpenP->SpinLock );
return STATUS_SUCCESS;
}
VOID
TpDeallocateOpenArray(
POPEN_BLOCK OpenP
)
// -------
//
// Routine Description:
//
// This routine deallocates the various data structures and spinlocks
// in the OpenBlock that are used to control the tests.
//
// Arguments:
//
// OpenP - a pointer to the OpenBlock containing the data structures which
// will be deallocated during this routine.
//
// Return Value:
//
// None.
//
// -------
{
NdisFreeSpinLock( &OpenP->SpinLock );
if ( OpenP->AdapterName != NULL )
{
NdisFreeMemory( OpenP->AdapterName,0,0 );
}
if ( OpenP->Environment != NULL )
{
NdisFreeMemory( OpenP->Environment,0,0 );
}
if ( OpenP->Stress->Pend != NULL )
{
NdisFreeMemory( OpenP->Stress->Pend,0,0 );
NdisFreeSpinLock( &OpenP->Stress->Pend->SpinLock );
}
if ( OpenP->Stress->Results != NULL )
{
NdisFreeMemory( OpenP->Stress->Results,0,0 );
}
if ( OpenP->Send != NULL )
{
NdisFreePacketPool( OpenP->Send->PacketHandle );
NdisFreeMemory( (PVOID)OpenP->Send->Counters,0,0 );
NdisFreeMemory( OpenP->Send,0,0 );
}
if ( OpenP->Receive != NULL )
{
NdisFreePacketPool( OpenP->Receive->PacketHandle );
NdisFreeMemory( (PVOID)OpenP->Receive->Counters,0,0 );
NdisFreeMemory( OpenP->Receive,0,0 );
}
if ( OpenP->Pause != NULL )
{
if ( OpenP->Pause->PoolAllocated == TRUE )
{
NdisFreePacketPool( OpenP->Pause->PacketHandle );
}
NdisFreeSpinLock( &OpenP->Pause->SpinLock );
NdisFreeMemory( OpenP->Pause,0,0 );
}
}
VOID
TpCancelIrp(
IN PDEVICE_CONTEXT DeviceContext,
IN PIRP Irp
)
// ----------
//
// Routine Description:
//
// Arguments:
//
// DeviceObject - Pointer to device object for this driver.
//
// Irp - Pointer to the request packet representing the I/O request
// to cancel.
//
// Return Value:
//
// None.
//
// ----------
{
POPEN_BLOCK OpenP;
PIO_STACK_LOCATION IrpSp;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
OpenP = (POPEN_BLOCK)Irp->IoStatus.Information;
IoSetCancelRoutine( Irp,NULL );
IoReleaseCancelSpinLock( Irp->CancelIrql );
NdisAcquireSpinLock( &OpenP->SpinLock );
if ((( Irp == OpenP->Stress->StressIrp ) ||
( Irp == OpenP->Send->SendIrp )) ||
( Irp == OpenP->Receive->ReceiveIrp ) ||
( OpenP->PerformanceTest && (Irp == OpenP->Perform->PerformIrp)))
{
//
// These Irps will handle the cancel and clean up themselves
// so just return
//
NdisReleaseSpinLock( &OpenP->SpinLock );
return;
}
else if ( Irp == OpenP->Irp )
{
//
// We have found one of the General Case Irp to be cancelled.
// first set the flag that this Irp has been cancelled, them
// complete it.
//
OpenP->IrpCancelled = TRUE;
OpenP->Irp = NULL;
NdisReleaseSpinLock( &OpenP->SpinLock );
IoCompleteRequest( Irp, IO_NETWORK_INCREMENT );
}
else
{
NdisReleaseSpinLock( &OpenP->SpinLock );
}
}