533 lines
15 KiB
C++
533 lines
15 KiB
C++
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Copyright (c) 2001 Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
// tdisample.cpp
|
||
|
//
|
||
|
// Abstract:
|
||
|
// This module contains functions called directly from the system,
|
||
|
// at startup(DriverEntry), at shutdown(TdiUnloadDriver), and to service
|
||
|
// requests (TdiDispatch). It also contains functions called only by
|
||
|
// DriverEntry.
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
#define _IN_MAIN_
|
||
|
#include "sysvars.h"
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// local constants, prototypes, and variables
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
const PWCHAR wstrDD_TDI_DEVICE_NAME = L"\\Device\\TdiSample";
|
||
|
const PWCHAR wstrDOS_DEVICE_NAME = L"\\DosDevices\\TdiSample";
|
||
|
|
||
|
|
||
|
const PCHAR strFunc1 = "TSDriverEntry";
|
||
|
const PCHAR strFunc2 = "TSDispatch";
|
||
|
const PCHAR strFunc3 = "TSUnloadDriver";
|
||
|
//const PCHAR strFuncP1 = "TSCreateDeviceContext";
|
||
|
//const PCHAR strFuncP2 = "TSCreateSymbolicLinkObject";
|
||
|
|
||
|
|
||
|
HANDLE hTdiSamplePnp;
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
// Local Prototypes
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
TSCreateSymbolicLinkObject(
|
||
|
VOID
|
||
|
);
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
TSDispatch(
|
||
|
IN PDEVICE_OBJECT pDeviceObject,
|
||
|
IN PIRP pIrp
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
TSUnloadDriver(
|
||
|
IN PDRIVER_OBJECT pDriverObject
|
||
|
);
|
||
|
|
||
|
NTSTATUS
|
||
|
TSCreateDeviceContext(
|
||
|
IN PDRIVER_OBJECT DriverObject,
|
||
|
IN OUT PDEVICE_CONTEXT *ppDeviceContext
|
||
|
);
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
// Functions called from system
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
// -----------------------------------------------------------------
|
||
|
//
|
||
|
// Function: DriverEntry
|
||
|
//
|
||
|
// Arguments: DriverObject -- ptr to driver object created by the system
|
||
|
// RegistryPath -- unreferenced parameter
|
||
|
//
|
||
|
// Returns: Final status of the initialization operation
|
||
|
// (STATUS_SUCCESS if no error, else error code)
|
||
|
//
|
||
|
// Descript: This routine performs initialization of the tdi sample
|
||
|
// driver. It creates the device objects for the driver and
|
||
|
// performs other driver initialization.
|
||
|
//
|
||
|
// -----------------------------------------------------------------
|
||
|
|
||
|
|
||
|
#pragma warning(disable: UNREFERENCED_PARAM)
|
||
|
|
||
|
|
||
|
|
||
|
extern "C"
|
||
|
NTSTATUS
|
||
|
DriverEntry(PDRIVER_OBJECT pDriverObject,
|
||
|
PUNICODE_STRING pRegistryPath)
|
||
|
|
||
|
{
|
||
|
PDEVICE_CONTEXT pDeviceContext; // device context (to create)
|
||
|
NTSTATUS lStatus; // status of operations
|
||
|
|
||
|
//
|
||
|
// General Version Information
|
||
|
//
|
||
|
TSAllocateSpinLock(&MemTdiSpinLock);
|
||
|
|
||
|
DebugPrint1("\nTdiSample Driver for Windows2000/WindowsXP -- Built %s \n\n",
|
||
|
__DATE__);
|
||
|
|
||
|
//
|
||
|
// show the version id...
|
||
|
//
|
||
|
DebugPrint1("TdiSample version %s\n\n", VER_FILEVERSION_STR);
|
||
|
|
||
|
//
|
||
|
// First initialize the DeviceContext struct,
|
||
|
//
|
||
|
lStatus = TSCreateDeviceContext(pDriverObject,
|
||
|
&pDeviceContext);
|
||
|
|
||
|
if (!NT_SUCCESS (lStatus))
|
||
|
{
|
||
|
DebugPrint2("%s: failed to create device context: Status = 0x%08x\n",
|
||
|
strFunc1,
|
||
|
lStatus);
|
||
|
return lStatus;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create symbolic link between the Dos Device name and Nt
|
||
|
// Device name for the test protocol driver.
|
||
|
//
|
||
|
lStatus = TSCreateSymbolicLinkObject();
|
||
|
if (!NT_SUCCESS(lStatus))
|
||
|
{
|
||
|
DebugPrint2("%s: failed to create symbolic link. Status = 0x%08x\n",
|
||
|
strFunc1,
|
||
|
lStatus);
|
||
|
return lStatus;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// put on debug for handlers during pnp callbacks
|
||
|
//
|
||
|
ulDebugLevel = ulDebugShowHandlers;
|
||
|
|
||
|
//
|
||
|
// allocate all necessary memory blocks
|
||
|
//
|
||
|
|
||
|
if ((TSAllocateMemory((PVOID *)&pTdiDevnodeList,
|
||
|
sizeof(TDI_DEVNODE_LIST),
|
||
|
strFunc1,
|
||
|
"DevnodeList")) == STATUS_SUCCESS)
|
||
|
{
|
||
|
if ((TSAllocateMemory((PVOID *)&pObjectList,
|
||
|
sizeof(OBJECT_LIST),
|
||
|
strFunc1,
|
||
|
"ObjectList")) != STATUS_SUCCESS)
|
||
|
{
|
||
|
TSFreeMemory(pTdiDevnodeList);
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
TSAllocateSpinLock(&pTdiDevnodeList->TdiSpinLock);
|
||
|
|
||
|
|
||
|
//
|
||
|
// register pnp handlers
|
||
|
//
|
||
|
UNICODE_STRING Name;
|
||
|
TDI_CLIENT_INTERFACE_INFO ClientInfo;
|
||
|
|
||
|
RtlInitUnicodeString(&Name, L"TDISAMPLE");
|
||
|
ClientInfo.MajorTdiVersion = 2;
|
||
|
ClientInfo.MinorTdiVersion = 0;
|
||
|
ClientInfo.ClientName = &Name;
|
||
|
|
||
|
ClientInfo.BindingHandler = TSPnpBindCallback;
|
||
|
ClientInfo.AddAddressHandlerV2 = TSPnpAddAddressCallback;
|
||
|
ClientInfo.DelAddressHandlerV2 = TSPnpDelAddressCallback;
|
||
|
ClientInfo.PnPPowerHandler = TSPnpPowerHandler;
|
||
|
|
||
|
lStatus = TdiRegisterPnPHandlers(&ClientInfo,
|
||
|
sizeof(TDI_CLIENT_INTERFACE_INFO),
|
||
|
&hTdiSamplePnp);
|
||
|
|
||
|
if (!NT_SUCCESS( lStatus ) )
|
||
|
{
|
||
|
DebugPrint1("TdiRegisterPnPHandlers: status 0x%08x\n", lStatus );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// default -- debug on for commands only
|
||
|
//
|
||
|
ulDebugLevel = ulDebugShowCommand;
|
||
|
|
||
|
TSAllocateSpinLock(&pObjectList->TdiSpinLock);
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
#pragma warning(default: UNREFERENCED_PARAM)
|
||
|
|
||
|
|
||
|
// -------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TSDispatch
|
||
|
//
|
||
|
// Arguments: pDeviceObject -- ptr to the device object for this driver
|
||
|
// pIrp -- ptr to the request packet representing
|
||
|
// the i/o request
|
||
|
//
|
||
|
// Returns: Status of the operation
|
||
|
// (usually, STATUS_SUCCESS or STATUS_PENDING)
|
||
|
//
|
||
|
// Descript: This is the main dispatch routine for the tdisample driver.
|
||
|
// It deals with requests that the dll sends via
|
||
|
// DeviceIoControl. It accepts an I/O request packet,
|
||
|
// performs the request, and then returns the appropriate
|
||
|
// status. If there is an error, the exact error code will
|
||
|
// be returned as part of the "return buffer"
|
||
|
//
|
||
|
// --------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
TSDispatch(PDEVICE_OBJECT pDeviceObject,
|
||
|
PIRP pIrp)
|
||
|
{
|
||
|
PDEVICE_CONTEXT pDeviceContext // get global data struct for driver
|
||
|
= (PDEVICE_CONTEXT)pDeviceObject;
|
||
|
PIO_STACK_LOCATION pIrpSp; // ptr to DeviceIoControl args
|
||
|
NTSTATUS lStatus; // status of operations
|
||
|
|
||
|
//
|
||
|
// Sanity check. Driver better be initialized.
|
||
|
//
|
||
|
|
||
|
if (!pDeviceContext->fInitialized)
|
||
|
{
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// initialize status information
|
||
|
//
|
||
|
pIrp->IoStatus.Information = 0;
|
||
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get a pointer to the current stack location in the IRP. This is where
|
||
|
// the function codes and parameters are stored.
|
||
|
//
|
||
|
|
||
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
||
|
|
||
|
//
|
||
|
// switch 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 (pIrpSp->MajorFunction)
|
||
|
{
|
||
|
//
|
||
|
// The Create function is called when the DLL tries to open the driver
|
||
|
//
|
||
|
case IRP_MJ_CREATE:
|
||
|
lStatus = STATUS_SUCCESS;
|
||
|
pDeviceContext->ulOpenCount++;
|
||
|
DebugPrint2("\n%s: IRP_MJ_CREATE. OpenCount = %d\n",
|
||
|
strFunc2,
|
||
|
pDeviceContext->ulOpenCount);
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// The Close function is the second function called when the DLL tries
|
||
|
// to close the driver. It does nothing (all the work is done by the
|
||
|
// first part -- IRP_MJ_CLEANUP
|
||
|
//
|
||
|
case IRP_MJ_CLOSE:
|
||
|
DebugPrint1("\n%s: IRP_MJ_CLOSE.\n", strFunc2);
|
||
|
lStatus = STATUS_SUCCESS;
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// The DeviceControl function is the main interface to the tdi sample
|
||
|
// driver. Every request is has an Io Control
|
||
|
// code that is used by this function to determine the routine to
|
||
|
// call. Returns either STATUS_PENDING or STATUS_SUCCESS
|
||
|
//
|
||
|
case IRP_MJ_DEVICE_CONTROL:
|
||
|
IoMarkIrpPending(pIrp);
|
||
|
lStatus = TSIssueRequest(pDeviceContext, pIrp, pIrpSp);
|
||
|
break;
|
||
|
|
||
|
//
|
||
|
// Handle the two stage IRP for a file close operation. We really only
|
||
|
// need to do this work when the last dll closes us.
|
||
|
//
|
||
|
case IRP_MJ_CLEANUP:
|
||
|
if (!pDeviceContext->ulOpenCount) // sanity check
|
||
|
{
|
||
|
DebugPrint1("\n%s: IRP_MJ_CLEANUP -- no active opens!\n", strFunc2);
|
||
|
lStatus = STATUS_SUCCESS; // what should happen here?
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDeviceContext->ulOpenCount--;
|
||
|
DebugPrint2("\n%s: IRP_MJ_CLEANUP, OpenCount = %d\n",
|
||
|
strFunc2,
|
||
|
pDeviceContext->ulOpenCount);
|
||
|
lStatus = STATUS_SUCCESS;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DebugPrint1("\n%s: OTHER (DEFAULT).\n", strFunc2);
|
||
|
lStatus = STATUS_INVALID_DEVICE_REQUEST;
|
||
|
|
||
|
} // major function switch
|
||
|
|
||
|
//
|
||
|
// If the request did not pend, then complete it now, otherwise it
|
||
|
// will be completed when the pending routine finishes.
|
||
|
//
|
||
|
|
||
|
if (lStatus != STATUS_PENDING)
|
||
|
{
|
||
|
pIrp->IoStatus.Status = STATUS_SUCCESS;
|
||
|
IoCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the immediate status code to the caller.
|
||
|
//
|
||
|
return lStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TSUnloadDriver
|
||
|
//
|
||
|
// Arguments: DriverObject -- ptr to the object for this driver
|
||
|
//
|
||
|
// Returns: none
|
||
|
//
|
||
|
// Descript: This function deals with cleanup if this driver is ever
|
||
|
// unloaded by the system.
|
||
|
//
|
||
|
// ---------------------------------------------------------------
|
||
|
|
||
|
BOOLEAN fInUnload = FALSE;
|
||
|
|
||
|
VOID
|
||
|
TSUnloadDriver(PDRIVER_OBJECT pDriverObject)
|
||
|
{
|
||
|
if (fInUnload)
|
||
|
{
|
||
|
DebugPrint0("TSUnloadDriver: re-entry!\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
fInUnload = TRUE;
|
||
|
|
||
|
PDEVICE_CONTEXT pDeviceContext // global data for driver
|
||
|
= (PDEVICE_CONTEXT)pDriverObject->DeviceObject;
|
||
|
|
||
|
//
|
||
|
// unload pnp handlers
|
||
|
//
|
||
|
NTSTATUS lStatus = TdiDeregisterPnPHandlers(hTdiSamplePnp);
|
||
|
|
||
|
hTdiSamplePnp = NULL;
|
||
|
|
||
|
if (lStatus != STATUS_SUCCESS)
|
||
|
{
|
||
|
DebugPrint1("TdiDeregisterPnPHandlers: 0x%08x\n", lStatus);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// free any device nodes that may still remain
|
||
|
//
|
||
|
for (ULONG ulCount = 0; ulCount < ulMAX_DEVICE_NODES; ulCount++)
|
||
|
{
|
||
|
PTDI_DEVICE_NODE pTdiDeviceNode = &(pTdiDevnodeList->TdiDeviceNode[ulCount]);
|
||
|
|
||
|
if (pTdiDeviceNode->ulState > ulDEVSTATE_UNUSED)
|
||
|
{
|
||
|
TSFreeMemory(pTdiDeviceNode->ustrDeviceName.Buffer);
|
||
|
TSFreeMemory(pTdiDeviceNode->pTaAddress);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
TSFreeSpinLock(&pTdiDevnodeList->TdiSpinLock);
|
||
|
TSFreeSpinLock(&pObjectList->TdiSpinLock);
|
||
|
TSFreeMemory(pTdiDevnodeList);
|
||
|
TSFreeMemory(pObjectList);
|
||
|
TSScanMemoryPool();
|
||
|
TSFreeSpinLock(&MemTdiSpinLock);
|
||
|
|
||
|
//
|
||
|
// Close the Dos Symbolic link to remove traces of the device
|
||
|
//
|
||
|
UNICODE_STRING wstrDosUnicodeString; // dosdevices string
|
||
|
|
||
|
RtlInitUnicodeString(&wstrDosUnicodeString, wstrDOS_DEVICE_NAME);
|
||
|
IoDeleteSymbolicLink(&wstrDosUnicodeString);
|
||
|
|
||
|
//
|
||
|
// Then delete the device object from the system.
|
||
|
//
|
||
|
IoDeleteDevice((PDEVICE_OBJECT)pDeviceContext);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
// Local functions
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
// --------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TSCreateDeviceContext
|
||
|
//
|
||
|
// Arguments: DriverObject -- ptr to the IO subsystem supplied
|
||
|
// driver object
|
||
|
// DeviceContext -- ptr to a ptr to a transport device
|
||
|
// context object
|
||
|
//
|
||
|
// Returns: STATUS_SUCCESS if ok, else error code
|
||
|
// (probably STATUS_INSUFFICIENT_RESOURCES)
|
||
|
//
|
||
|
// Descript: Create and initialize the driver object for this driver
|
||
|
//
|
||
|
// --------------------------------------------------------------
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
TSCreateDeviceContext(PDRIVER_OBJECT pDriverObject,
|
||
|
PDEVICE_CONTEXT *ppDeviceContext)
|
||
|
{
|
||
|
PDEVICE_OBJECT pDeviceObject; // local work copy of device object
|
||
|
PDEVICE_CONTEXT pLocDeviceContext; // portion of device object
|
||
|
NTSTATUS lStatus; // operation status
|
||
|
UNICODE_STRING wstrDeviceName; // name of device
|
||
|
|
||
|
//
|
||
|
// set up the name of the device
|
||
|
//
|
||
|
RtlInitUnicodeString(&wstrDeviceName, wstrDD_TDI_DEVICE_NAME);
|
||
|
|
||
|
//
|
||
|
// Create the device object for tditest.sys
|
||
|
//
|
||
|
lStatus = IoCreateDevice(pDriverObject,
|
||
|
sizeof(DEVICE_CONTEXT) - sizeof(DEVICE_OBJECT),
|
||
|
&wstrDeviceName,
|
||
|
FILE_DEVICE_TRANSPORT,
|
||
|
0,
|
||
|
FALSE,
|
||
|
&pDeviceObject );
|
||
|
|
||
|
if (!NT_SUCCESS(lStatus))
|
||
|
{
|
||
|
return lStatus;
|
||
|
}
|
||
|
|
||
|
pDeviceObject->Flags |= DO_DIRECT_IO;
|
||
|
|
||
|
//
|
||
|
// Initialize the driver object with this driver's entry points.
|
||
|
//
|
||
|
pDriverObject->MajorFunction [IRP_MJ_CREATE] = TSDispatch;
|
||
|
pDriverObject->MajorFunction [IRP_MJ_CLOSE] = TSDispatch;
|
||
|
pDriverObject->MajorFunction [IRP_MJ_CLEANUP] = TSDispatch;
|
||
|
pDriverObject->MajorFunction [IRP_MJ_DEVICE_CONTROL] = TSDispatch;
|
||
|
pDriverObject->DriverUnload = TSUnloadDriver;
|
||
|
|
||
|
pLocDeviceContext = (PDEVICE_CONTEXT)pDeviceObject;
|
||
|
|
||
|
//
|
||
|
// Now initialize the Device Context structure Signatures.
|
||
|
//
|
||
|
pLocDeviceContext->fInitialized = TRUE;
|
||
|
|
||
|
*ppDeviceContext = pLocDeviceContext;
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
// -------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: TSCreateSymbolicLinkObject
|
||
|
//
|
||
|
// Arguments: none
|
||
|
//
|
||
|
// Returns: status of the operation (STATUS_SUCCESS or error status)
|
||
|
//
|
||
|
// Descript: Set up a name for us so our dll can grab hold of us..
|
||
|
//
|
||
|
// -------------------------------------------------------------------
|
||
|
|
||
|
NTSTATUS
|
||
|
TSCreateSymbolicLinkObject(VOID)
|
||
|
{
|
||
|
UNICODE_STRING wstrDosUnicodeString; // dosdevices string
|
||
|
UNICODE_STRING wstrNtUnicodeString; // nt device name
|
||
|
|
||
|
RtlInitUnicodeString(&wstrDosUnicodeString, wstrDOS_DEVICE_NAME);
|
||
|
RtlInitUnicodeString(&wstrNtUnicodeString, wstrDD_TDI_DEVICE_NAME);
|
||
|
|
||
|
|
||
|
return IoCreateSymbolicLink(&wstrDosUnicodeString, &wstrNtUnicodeString);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
// end of file tditest.cpp
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|