Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

532 lines
15 KiB

////////////////////////////////////////////////////////////////////////////
//
// 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
////////////////////////////////////////////////////////////////////////////