mirror of https://github.com/tongzx/nt5src
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.
1252 lines
32 KiB
1252 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 2000-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Driver.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the DRIVER_INITIALIZATION routine for
|
|
the PGM Transport and other routines that are specific to the
|
|
NT implementation of a driver.
|
|
|
|
Author:
|
|
|
|
Mohammad Shabbir Alam (MAlam) 3-30-2000
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
#include "precomp.h"
|
|
|
|
// ULONG PgmDebugFlags = DBG_ENABLE_DBGPRINT;
|
|
// ULONG PgmDebugFlags = 0xffffffff;
|
|
|
|
#if DBG
|
|
enum eSEVERITY_LEVEL PgmDebuggerSeverity = PGM_LOG_INFORM_STATUS;
|
|
#else
|
|
enum eSEVERITY_LEVEL PgmDebuggerSeverity = PGM_LOG_DISABLED;
|
|
#endif // DBG
|
|
ULONG PgmDebuggerPath = 0xffffffff;
|
|
|
|
enum eSEVERITY_LEVEL PgmLogFileSeverity = PGM_LOG_DISABLED;
|
|
ULONG PgmLogFilePath = 0x0;
|
|
|
|
tPGM_STATIC_CONFIG PgmStaticConfig;
|
|
tPGM_DYNAMIC_CONFIG PgmDynamicConfig;
|
|
tPGM_REGISTRY_CONFIG *pPgmRegistryConfig = NULL;
|
|
|
|
tPGM_DEVICE *pgPgmDevice = NULL;
|
|
DEVICE_OBJECT *pPgmDeviceObject = NULL;
|
|
|
|
//******************* Pageable Routine Declarations ****************
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, DriverEntry)
|
|
#pragma alloc_text(PAGE, PgmUnload)
|
|
#endif
|
|
//******************* Pageable Routine Declarations ****************
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Internal routines
|
|
//
|
|
|
|
FILE_FULL_EA_INFORMATION *
|
|
FindEA(
|
|
IN PFILE_FULL_EA_INFORMATION StartEA,
|
|
IN CHAR *pTargetName,
|
|
IN USHORT TargetNameLength
|
|
);
|
|
|
|
VOID
|
|
CompleteDispatchIrp(
|
|
IN PIRP pIrp,
|
|
IN NTSTATUS status
|
|
);
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DriverEntry(
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialization routine for the PGM device driver.
|
|
This routine creates the device object for the PGM
|
|
device and does other driver initialization.
|
|
|
|
Arguments:
|
|
|
|
IN DriverObject - Pointer to driver object created by the system.
|
|
IN RegistryPath - Pgm driver's registry location
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The function value is the final status from the initialization
|
|
operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
status = InitPgm (DriverObject, RegistryPath);
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "DriverEntry",
|
|
"InitPgm returned <%x>\n", status);
|
|
return (status);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
//
|
|
// Initialize the driver object with this driver's entry points.
|
|
//
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)PgmDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PgmDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = (PDRIVER_DISPATCH)PgmDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)PgmDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)PgmDispatch;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)PgmDispatch;
|
|
DriverObject->DriverUnload = PgmUnload;
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
status = SetTdiHandlers ();
|
|
if (!NT_SUCCESS (status))
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "DriverEntry",
|
|
"SetTdiHandlers returned <%x>\n", status);
|
|
CleanupInit (E_CLEANUP_DEVICE);
|
|
return (status);
|
|
}
|
|
|
|
//---------------------------------------------------------------------------------------
|
|
|
|
//
|
|
// Return to the caller.
|
|
//
|
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_DRIVER_ENTRY, "DriverEntry",
|
|
"Succeeded! ...\n");
|
|
|
|
return (status);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
NTSTATUS
|
|
PgmDispatch(
|
|
IN PDEVICE_OBJECT pDeviceObject,
|
|
IN PIRP pIrp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the PGM driver's primary dispatch function for all Irp requests.
|
|
|
|
Arguments:
|
|
|
|
IN pDeviceObject - ptr to device object for target device
|
|
IN pIrp - ptr to I/O request packet
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
tPGM_DEVICE *pPgmDevice = pDeviceObject->DeviceExtension;
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
UCHAR IrpFlags;
|
|
UCHAR IrpMajorFunction;
|
|
UCHAR IrpMinorFunction;
|
|
|
|
pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
|
|
|
|
IrpFlags = pIrpSp->Control;
|
|
IrpMajorFunction = pIrpSp->MajorFunction;
|
|
IrpMinorFunction = pIrpSp->MinorFunction;
|
|
|
|
pIrp->IoStatus.Information = 0;
|
|
pIrp->IoStatus.Status = STATUS_PENDING;
|
|
IoMarkIrpPending(pIrp);
|
|
|
|
ASSERT (pDeviceObject == pPgmDeviceObject);
|
|
|
|
switch (IrpMajorFunction)
|
|
{
|
|
case IRP_MJ_CREATE:
|
|
{
|
|
status = PgmCreate (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MJ_CLEANUP:
|
|
{
|
|
status = PgmCleanup (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
case IRP_MJ_CLOSE:
|
|
{
|
|
status = PgmClose (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
case IRP_MJ_DEVICE_CONTROL:
|
|
{
|
|
if (STATUS_SUCCESS != TdiMapUserRequest (pDeviceObject, pIrp, pIrpSp))
|
|
{
|
|
//
|
|
// This is not a Tdi request!
|
|
//
|
|
status = PgmDispatchIoctls (pPgmDevice, pIrp, pIrpSp); // To handle Ioctls
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Fall through for Internal Device Control!
|
|
//
|
|
}
|
|
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
{
|
|
status = PgmDispatchInternalDeviceControl (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IRP_MJ_PNP:
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "PgmDispatch",
|
|
"[IRP_MJ_PNP:%x]: pIrp=<%x> Unsupported!\n", pIrpSp->MinorFunction, pIrp);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "PgmDispatch",
|
|
"pIrp=<%x>, Unsupported! [%x:%x]\n", pIrp, pIrpSp->MajorFunction, pIrpSp->MinorFunction);
|
|
break;
|
|
}
|
|
}
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "PgmDispatch",
|
|
"pIrp=<%x>, status=<%x>, [%d-->%d]\n", pIrp, status, IrpMajorFunction, IrpMinorFunction);
|
|
|
|
if (status != STATUS_PENDING)
|
|
{
|
|
// reset the pending returned bit, since we are NOT returning pending
|
|
pIrpSp->Control = IrpFlags;
|
|
CompleteDispatchIrp (pIrp, status);
|
|
}
|
|
|
|
return (status);
|
|
} // PgmDispatch
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
CleanupInit(
|
|
enum eCLEANUP_STAGE CleanupStage
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called either at DriverEntry or DriverUnload
|
|
to cleanup (or do partial cleanup) of items initialized at Init-time
|
|
|
|
Arguments:
|
|
|
|
IN CleanupStage -- determines the stage to which we had initialized
|
|
settings
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
LIST_ENTRY *pEntry;
|
|
PGMLockHandle OldIrq;
|
|
PGM_WORKER_CONTEXT *pWorkerContext;
|
|
PPGM_WORKER_ROUTINE pDelayedWorkerRoutine;
|
|
tLOCAL_INTERFACE *pLocalInterface = NULL;
|
|
tADDRESS_ON_INTERFACE *pLocalAddress = NULL;
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "CleanupInit",
|
|
"CleanupStage=<%d>\n", CleanupStage);
|
|
|
|
switch (CleanupStage)
|
|
{
|
|
case (E_CLEANUP_UNLOAD):
|
|
{
|
|
//
|
|
// Ensure that there are no more worker threads to be cleaned up
|
|
//
|
|
//
|
|
// See if there are any worker threads currently executing, and if so, wait for
|
|
// them to complete
|
|
//
|
|
KeClearEvent (&PgmDynamicConfig.LastWorkerItemEvent);
|
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|
if (PgmDynamicConfig.NumWorkerThreadsQueued)
|
|
{
|
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|
|
|
status = KeWaitForSingleObject(&PgmDynamicConfig.LastWorkerItemEvent, // Object to wait on.
|
|
Executive, // Reason for waiting
|
|
KernelMode, // Processor mode
|
|
FALSE, // Alertable
|
|
NULL); // Timeout
|
|
ASSERT (status == STATUS_SUCCESS);
|
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|
}
|
|
|
|
ASSERT (!PgmDynamicConfig.NumWorkerThreadsQueued);
|
|
|
|
//
|
|
// Dequeue each of the requests in the Worker Queue and complete them
|
|
//
|
|
while (!IsListEmpty (&PgmDynamicConfig.WorkerQList))
|
|
{
|
|
pWorkerContext = CONTAINING_RECORD(PgmDynamicConfig.WorkerQList.Flink, PGM_WORKER_CONTEXT, PgmConfigLinkage);
|
|
RemoveEntryList (&pWorkerContext->PgmConfigLinkage);
|
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|
|
|
pDelayedWorkerRoutine = pWorkerContext->WorkerRoutine;
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "CleanupInit",
|
|
"Completing Worker request <%x>\n", pDelayedWorkerRoutine);
|
|
|
|
(*pDelayedWorkerRoutine) (pWorkerContext->Context1,
|
|
pWorkerContext->Context2,
|
|
pWorkerContext->Context3);
|
|
PgmFreeMem ((PVOID) pWorkerContext);
|
|
|
|
//
|
|
// Acquire Lock again to check if we have completed all the requests
|
|
//
|
|
PgmLock (&PgmDynamicConfig, OldIrq);
|
|
}
|
|
|
|
PgmUnlock (&PgmDynamicConfig, OldIrq);
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
case (E_CLEANUP_PNP):
|
|
{
|
|
status = TdiDeregisterPnPHandlers (TdiClientHandle);
|
|
|
|
while (!IsListEmpty (&PgmDynamicConfig.LocalInterfacesList))
|
|
{
|
|
pEntry = RemoveHeadList (&PgmDynamicConfig.LocalInterfacesList);
|
|
pLocalInterface = CONTAINING_RECORD (pEntry, tLOCAL_INTERFACE, Linkage);
|
|
while (!IsListEmpty (&pLocalInterface->Addresses))
|
|
{
|
|
pEntry = RemoveHeadList (&pLocalInterface->Addresses);
|
|
pLocalAddress = CONTAINING_RECORD (pEntry, tADDRESS_ON_INTERFACE, Linkage);
|
|
PgmFreeMem (pLocalAddress);
|
|
}
|
|
PgmFreeMem (pLocalInterface);
|
|
}
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
|
|
case (E_CLEANUP_DEVICE):
|
|
{
|
|
PGM_DEREFERENCE_DEVICE (&pgPgmDevice, REF_DEV_CREATE);
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
|
|
case (E_CLEANUP_STRUCTURES):
|
|
{
|
|
// Nothing specific to cleanup
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
|
|
case (E_CLEANUP_REGISTRY_PARAMETERS):
|
|
{
|
|
if (pPgmRegistryConfig)
|
|
{
|
|
if (pPgmRegistryConfig->ucSenderFileLocation.Buffer)
|
|
{
|
|
PgmFreeMem (pPgmRegistryConfig->ucSenderFileLocation.Buffer);
|
|
pPgmRegistryConfig->ucSenderFileLocation.Buffer = NULL;
|
|
}
|
|
|
|
PgmFreeMem (pPgmRegistryConfig);
|
|
pPgmRegistryConfig = NULL;
|
|
}
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
|
|
case (E_CLEANUP_DYNAMIC_CONFIG):
|
|
{
|
|
// Nothing specific to cleanup
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
|
|
case (E_CLEANUP_STATIC_CONFIG):
|
|
{
|
|
ExDeleteNPagedLookasideList(&PgmStaticConfig.DebugMessagesLookasideList);
|
|
ExDeleteNPagedLookasideList(&PgmStaticConfig.TdiLookasideList);
|
|
|
|
PgmFreeMem (PgmStaticConfig.RegistryPath.Buffer);
|
|
}
|
|
|
|
// no break -- Fall through!
|
|
|
|
default:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
VOID
|
|
PgmUnload(
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the Pgm driver's function for Unload requests
|
|
|
|
Arguments:
|
|
|
|
IN DriverObject - Pointer to driver object created by the system.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
PgmDynamicConfig.GlobalFlags |= PGM_CONFIG_FLAG_UNLOADING;
|
|
|
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_DRIVER_ENTRY, "PgmUnload",
|
|
"Unloading ...\n");
|
|
|
|
CleanupInit (E_CLEANUP_UNLOAD);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmCreate(
|
|
IN tPGM_DEVICE *pPgmDevice,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch function for creating Pgm objects
|
|
|
|
Arguments:
|
|
|
|
IN pPgmDevice - Pointer to the Pgm device extension for this request.
|
|
IN Irp - Pointer to I/O request packet
|
|
IN IrpSp - Pointer to the current stack location in the Irp.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of the create request
|
|
|
|
--*/
|
|
|
|
{
|
|
tCONTROL_CONTEXT *pControlContext = NULL;
|
|
FILE_FULL_EA_INFORMATION *ea = (PFILE_FULL_EA_INFORMATION) pIrp->AssociatedIrp.SystemBuffer;
|
|
FILE_FULL_EA_INFORMATION *TargetEA;
|
|
TRANSPORT_ADDRESS UNALIGNED *pTransportAddr;
|
|
TA_ADDRESS *pAddress;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// See if this is a Control Channel open.
|
|
//
|
|
if (!ea)
|
|
{
|
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_DRIVER_ENTRY, "PGMCreate",
|
|
"Opening control channel for file object %lx\n", pIrpSp->FileObject);
|
|
|
|
if (pControlContext = PgmAllocMem (sizeof(tCONTROL_CONTEXT), PGM_TAG('0')))
|
|
{
|
|
PgmZeroMemory (pControlContext, sizeof (tCONTROL_CONTEXT));
|
|
InitializeListHead (&pControlContext->Linkage);
|
|
PgmInitLock (pControlContext, CONTROL_LOCK);
|
|
pControlContext->Verify = PGM_VERIFY_CONTROL;
|
|
PGM_REFERENCE_CONTROL (pControlContext, REF_CONTROL_CREATE, TRUE);
|
|
|
|
pIrpSp->FileObject->FsContext = pControlContext;
|
|
pIrpSp->FileObject->FsContext2 = (PVOID) TDI_CONTROL_CHANNEL_FILE;
|
|
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
//
|
|
// See if this is a Connection Object open.
|
|
//
|
|
if (TargetEA = FindEA (ea, TdiConnectionContext, TDI_CONNECTION_CONTEXT_LENGTH))
|
|
{
|
|
status = PgmCreateConnection (pPgmDevice, pIrp, pIrpSp, TargetEA);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_DRIVER_ENTRY | DBG_CONNECT), "PGMCreate",
|
|
"Open Connection, pIrp=<%x>, status=<%x>\n", pIrp, status);
|
|
}
|
|
//
|
|
// See if this is an Address Object open.
|
|
//
|
|
else if (TargetEA = FindEA (ea, TdiTransportAddress, TDI_TRANSPORT_ADDRESS_LENGTH))
|
|
{
|
|
status = PgmCreateAddress (pPgmDevice, pIrp, pIrpSp, TargetEA);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_DRIVER_ENTRY | DBG_ADDRESS), "PGMCreate",
|
|
"Open Address, pIrp=<%x>, status=<%x>\n", pIrp, status);
|
|
}
|
|
else
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "PGMCreate",
|
|
"Unsupported EA!\n");
|
|
|
|
status = STATUS_INVALID_EA_NAME;
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmCleanup(
|
|
IN tPGM_DEVICE *pPgmDevice,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dispatch function for cleaning-up Pgm objects
|
|
|
|
Arguments:
|
|
|
|
IN pPgmDevice - Pointer to the Pgm device extension for this request.
|
|
IN Irp - Pointer to I/O request packet
|
|
IN IrpSp - Pointer to the current stack location in the Irp.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of the cleanup request
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PVOID *pContext = pIrpSp->FileObject->FsContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (PtrToUlong (pIrpSp->FileObject->FsContext2))
|
|
{
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
{
|
|
status = PgmCleanupAddress ((tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext, pIrp);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_DRIVER_ENTRY | DBG_ADDRESS), "PGMCleanup",
|
|
"pConnect=<%x>, pIrp=<%x>, status=<%x>\n", pContext, pIrp, status);
|
|
break;
|
|
}
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
{
|
|
status = PgmCleanupConnection ((tCOMMON_SESSION_CONTEXT *) pIrpSp->FileObject->FsContext, pIrp);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_DRIVER_ENTRY | DBG_CONNECT), "PGMCleanup",
|
|
"pConnect=<%x>, pIrp=<%x>, status=<%x>\n", pContext, pIrp, status);
|
|
break;
|
|
}
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
{
|
|
//
|
|
// Nothing to Cleanup here!
|
|
//
|
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_DRIVER_ENTRY, "PGMCleanup",
|
|
"pControl=<%x>, pIrp=<%x>, status=<%x>\n", pContext, pIrp, status);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "PGMCleanup",
|
|
"pIrp=<%x>, Context=[%x:%d] ...\n",
|
|
pIrp, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmClose(
|
|
IN tPGM_DEVICE *pPgmDevice,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine completes the cleanup, closing handles, free'ing all
|
|
memory associated with the object
|
|
|
|
Arguments:
|
|
|
|
IN pPgmDevice - Pointer to the Pgm device extension for this request.
|
|
IN Irp - Pointer to I/O request packet
|
|
IN IrpSp - Pointer to the current stack location in the Irp.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of the close request
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
tCONTROL_CONTEXT *pControlContext = pIrpSp->FileObject->FsContext;
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (PtrToUlong (pIrpSp->FileObject->FsContext2))
|
|
{
|
|
case TDI_TRANSPORT_ADDRESS_FILE:
|
|
{
|
|
status = PgmCloseAddress (pIrp, pIrpSp);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_DRIVER_ENTRY | DBG_ADDRESS), "PgmClose",
|
|
"pAddress=<%x>, pIrp=<%x>, status=<%x>\n", pControlContext, pIrp, status);
|
|
break;
|
|
}
|
|
|
|
case TDI_CONNECTION_FILE:
|
|
{
|
|
status = PgmCloseConnection (pIrp, pIrpSp);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, (DBG_DRIVER_ENTRY | DBG_CONNECT), "PgmClose",
|
|
"pConnect=<%x>, pIrp=<%x>, status=<%x>\n", pControlContext, pIrp, status);
|
|
break;
|
|
}
|
|
|
|
case TDI_CONTROL_CHANNEL_FILE:
|
|
{
|
|
//
|
|
// There is nothing special to do here so just dereference!
|
|
//
|
|
PgmLog (PGM_LOG_INFORM_STATUS, DBG_DRIVER_ENTRY, "PgmClose",
|
|
"pControl=<%x>, pIrp=<%x>, status=<%x>\n", pIrpSp->FileObject->FsContext, pIrp, status);
|
|
|
|
PGM_DEREFERENCE_CONTROL (pControlContext, REF_CONTROL_CREATE);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "PgmClose",
|
|
"pIrp=<%x>, Context=[%x:%d] ...\n",
|
|
pIrp, pIrpSp->FileObject->FsContext, pIrpSp->FileObject->FsContext2);
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmDispatchInternalDeviceControl(
|
|
IN tPGM_DEVICE *pPgmDevice,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine primarily handles Tdi requests since we are a Tdi component
|
|
|
|
Arguments:
|
|
|
|
IN pPgmDevice - Pointer to the Pgm device extension for this request.
|
|
IN Irp - Pointer to I/O request packet
|
|
IN IrpSp - Pointer to the current stack location in the Irp.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of the request
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "PgmDispatchInternalDeviceControl",
|
|
"[%d] Context=<%x> ...\n", pIrpSp->MinorFunction, pIrpSp->FileObject->FsContext);
|
|
|
|
switch (pIrpSp->MinorFunction)
|
|
{
|
|
case TDI_QUERY_INFORMATION:
|
|
{
|
|
Status = PgmQueryInformation (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_SET_EVENT_HANDLER:
|
|
{
|
|
Status = PgmSetEventHandler (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_ASSOCIATE_ADDRESS:
|
|
{
|
|
Status = PgmAssociateAddress (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_DISASSOCIATE_ADDRESS:
|
|
{
|
|
Status = PgmDisassociateAddress (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_CONNECT:
|
|
{
|
|
Status = PgmConnect (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_DISCONNECT:
|
|
{
|
|
Status = PgmDisconnect (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_SEND:
|
|
{
|
|
Status = PgmSendRequestFromClient (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case TDI_RECEIVE:
|
|
{
|
|
Status = PgmReceive (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
/*
|
|
case TDI_SEND_DATAGRAM:
|
|
{
|
|
Status = PgmSendDatagram (pPgmDevice, pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
*/
|
|
|
|
default:
|
|
{
|
|
PgmLog (PGM_LOG_ERROR, DBG_DRIVER_ENTRY, "PgmDispatchInternalDeviceControl",
|
|
"[%x]: Context=<%x> ...\n", pIrpSp->MinorFunction, pIrpSp->FileObject->FsContext);
|
|
|
|
return (STATUS_UNSUCCESSFUL);
|
|
}
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmDispatchIoctls(
|
|
IN tPGM_DEVICE *pPgmDevice,
|
|
IN PIRP pIrp,
|
|
IN PIO_STACK_LOCATION pIrpSp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles private Ioctls into Pgm. These Ioctls are
|
|
to be called only by the Pgm Winsock helper (WshPgm.dll)
|
|
|
|
Arguments:
|
|
|
|
IN pPgmDevice - Pointer to the Pgm device extension for this request.
|
|
IN Irp - Pointer to I/O request packet
|
|
IN IrpSp - Pointer to the current stack location in the Irp.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Final status of the request
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
|
|
switch (pIrpSp->Parameters.DeviceIoControl.IoControlCode)
|
|
{
|
|
case IOCTL_PGM_WSH_SET_WINDOW_SIZE_RATE:
|
|
{
|
|
status = PgmSetWindowSizeAndSendRate (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_WINDOW_SIZE_RATE:
|
|
{
|
|
status = PgmQueryWindowSizeAndSendRate (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_ADVANCE_WINDOW_RATE:
|
|
{
|
|
status = PgmSetWindowAdvanceRate (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_ADVANCE_WINDOW_RATE:
|
|
{
|
|
status = PgmQueryWindowAdvanceRate (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_LATE_JOINER_PERCENTAGE:
|
|
{
|
|
status = PgmSetLateJoinerPercentage (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_LATE_JOINER_PERCENTAGE:
|
|
{
|
|
status = PgmQueryLateJoinerPercentage (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_WINDOW_ADVANCE_METHOD:
|
|
{
|
|
status = PgmSetWindowAdvanceMethod (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_WINDOW_ADVANCE_METHOD:
|
|
{
|
|
status = PgmQueryWindowAdvanceMethod (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_NEXT_MESSAGE_BOUNDARY:
|
|
{
|
|
status = PgmSetNextMessageBoundary (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_SEND_IF:
|
|
{
|
|
status = PgmSetMCastOutIf (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_ADD_RECEIVE_IF:
|
|
case IOCTL_PGM_WSH_JOIN_MCAST_LEAF:
|
|
{
|
|
status = PgmAddMCastReceiveIf (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_DEL_RECEIVE_IF:
|
|
{
|
|
status = PgmDelMCastReceiveIf (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_RCV_BUFF_LEN:
|
|
{
|
|
status = PgmSetRcvBufferLength (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_SENDER_STATS:
|
|
{
|
|
status = PgmQuerySenderStats (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_RECEIVER_STATS:
|
|
{
|
|
status = PgmQueryReceiverStats (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_USE_FEC:
|
|
{
|
|
status = PgmSetFECInfo (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_QUERY_FEC_INFO:
|
|
{
|
|
status = PgmQueryFecInfo (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
case IOCTL_PGM_WSH_SET_MCAST_TTL:
|
|
{
|
|
status = PgmSetMCastTtl (pIrp, pIrpSp);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "PgmDispatchIoctls",
|
|
"WARNING: Invalid Ioctl=[%x]: Context=<%x> ...\n",
|
|
pIrpSp->Parameters.DeviceIoControl.IoControlCode,
|
|
pIrpSp->FileObject->FsContext);
|
|
|
|
return (STATUS_NOT_IMPLEMENTED);
|
|
}
|
|
}
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "PgmDispatchIoctls",
|
|
"[%d]: Context=<%x>, status=<%x>\n",
|
|
pIrpSp->Parameters.DeviceIoControl.IoControlCode,
|
|
pIrpSp->FileObject->FsContext, status);
|
|
|
|
return (status);
|
|
}
|
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Utility functions
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
FILE_FULL_EA_INFORMATION *
|
|
FindEA(
|
|
IN PFILE_FULL_EA_INFORMATION StartEA,
|
|
IN CHAR *pTargetName,
|
|
IN USHORT TargetNameLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Parses and extended attribute list for a given target attribute.
|
|
|
|
Arguments:
|
|
|
|
IN StartEA - the first extended attribute in the list.
|
|
IN pTargetName - the name of the target attribute.
|
|
IN TargetNameLength - the length of the name of the target attribute.
|
|
|
|
Return Value:
|
|
|
|
A pointer to the requested attribute or NULL if the target wasn't found.
|
|
|
|
--*/
|
|
|
|
{
|
|
USHORT i;
|
|
BOOLEAN found;
|
|
FILE_FULL_EA_INFORMATION *CurrentEA;
|
|
|
|
for (CurrentEA = StartEA;
|
|
CurrentEA;
|
|
CurrentEA = (PFILE_FULL_EA_INFORMATION) ((PUCHAR)CurrentEA + CurrentEA->NextEntryOffset))
|
|
{
|
|
if (strncmp (CurrentEA->EaName, pTargetName, CurrentEA->EaNameLength) == 0)
|
|
{
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "FindEA",
|
|
"Found EA, Target=<%s>\n", pTargetName);
|
|
|
|
return (CurrentEA);
|
|
}
|
|
|
|
if (CurrentEA->NextEntryOffset == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "FindEA",
|
|
"FAILed to find EA, Target=<%s>\n", pTargetName);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
VOID
|
|
PgmIoComplete(
|
|
IN PIRP pIrp,
|
|
IN NTSTATUS Status,
|
|
IN ULONG SentLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine
|
|
|
|
Arguments:
|
|
|
|
IN pIrp -- Pointer to I/O request packet
|
|
IN Status -- the final status of the request
|
|
IN SentLength -- the value to be set in the Information field
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
pIrp->IoStatus.Status = Status;
|
|
|
|
// use -1 as a flag to mean do not adjust the sent length since it is
|
|
// already set
|
|
if (SentLength != -1)
|
|
{
|
|
pIrp->IoStatus.Information = SentLength;
|
|
}
|
|
|
|
// set the Irps cancel routine to null or the system may bugcheck
|
|
// with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
|
|
//
|
|
// refer to IoCancelIrp() ..\ntos\io\iosubs.c
|
|
//
|
|
PgmCancelCancelRoutine (pIrp);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "PgmIoComplete",
|
|
"pIrp=<%x>, Status=<%x>, SentLength=<%d>\n", pIrp, Status, SentLength);
|
|
|
|
IoCompleteRequest (pIrp, IO_NETWORK_INCREMENT);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
CompleteDispatchIrp(
|
|
IN PIRP pIrp,
|
|
IN NTSTATUS status
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function completes an IRP, and arranges for return parameters,
|
|
if any, to be copied.
|
|
|
|
Although somewhat a misnomer, this function is named after a similar
|
|
function in the SpiderSTREAMS emulator.
|
|
|
|
Arguments:
|
|
|
|
IN pIrp - pointer to the IRP to complete
|
|
IN status - completion status of the IRP
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
|
|
{
|
|
CCHAR priboost;
|
|
|
|
//
|
|
// pIrp->IoStatus.Information is meaningful only for STATUS_SUCCESS
|
|
//
|
|
|
|
// set the Irps cancel routine to null or the system may bugcheck
|
|
// with a bug code of CANCEL_STATE_IN_COMPLETED_IRP
|
|
//
|
|
// refer to IoCancelIrp() ..\ntos\io\iosubs.c
|
|
//
|
|
PgmCancelCancelRoutine (pIrp);
|
|
|
|
pIrp->IoStatus.Status = status;
|
|
|
|
priboost = (CCHAR) ((status == STATUS_SUCCESS) ? IO_NETWORK_INCREMENT : IO_NO_INCREMENT);
|
|
|
|
PgmLog (PGM_LOG_INFORM_ALL_FUNCS, DBG_DRIVER_ENTRY, "CompleteDispatchIrp",
|
|
"Completing pIrp=<%x>, status=<%x>\n", pIrp, status);
|
|
|
|
IoCompleteRequest (pIrp, priboost);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmCheckSetCancelRoutine(
|
|
IN PIRP pIrp,
|
|
IN PVOID CancelRoutine,
|
|
IN BOOLEAN fLocked
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This Routine sets the cancel routine for an Irp.
|
|
|
|
Arguments:
|
|
|
|
status - a completion status for the Irp
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of the request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PGMLockHandle CancelIrql;
|
|
|
|
//
|
|
// Check if the irp was cancelled yet and if not, then set the
|
|
// irp cancel routine.
|
|
//
|
|
if (!fLocked)
|
|
{
|
|
IoAcquireCancelSpinLock (&CancelIrql);
|
|
}
|
|
|
|
if (pIrp->Cancel)
|
|
{
|
|
pIrp->IoStatus.Status = STATUS_CANCELLED;
|
|
status = STATUS_CANCELLED;
|
|
}
|
|
else
|
|
{
|
|
// setup the cancel routine
|
|
IoMarkIrpPending (pIrp);
|
|
IoSetCancelRoutine (pIrp, CancelRoutine);
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!fLocked)
|
|
{
|
|
IoReleaseCancelSpinLock (CancelIrql);
|
|
}
|
|
|
|
return(status);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
PgmCancelCancelRoutine(
|
|
IN PIRP pIrp
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
|
|
This Routine sets the cancel routine for an Irp to NULL
|
|
|
|
Arguments:
|
|
|
|
status - a completion status for the Irp
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - status of the request
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PGMLockHandle CancelIrql;
|
|
|
|
//
|
|
// Check if the irp was cancelled yet and if not, then set the
|
|
// irp cancel routine.
|
|
//
|
|
IoAcquireCancelSpinLock (&CancelIrql);
|
|
if (pIrp->Cancel)
|
|
{
|
|
status = STATUS_CANCELLED;
|
|
}
|
|
|
|
IoSetCancelRoutine (pIrp, NULL);
|
|
IoReleaseCancelSpinLock (CancelIrql);
|
|
|
|
return(status);
|
|
}
|
|
|