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