Windows2000/private/ntos/io/flunkirp.c

1321 lines
51 KiB
C

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
flunkirp.c
Abstract:
Note to people hitting bugs in these code paths due to core changes:
- "This file is NOT vital to operation of the OS, and could easily be
disabled while a redesign to compensate for the core change is implemented." - the author
This module asserts Irps are handled correctly by drivers.
To Do:
**. Fail non-OS initiators of certain IRPs
Author:
Adrian J. Oney (adriao) 20-Apr-1998
Environment:
Kernel mode
Revision History:
Known BUGBUGs:
>ADRIAO BUGBUG #07 05/11/98 - Add a pass-through filter at every attach.
ADRIAO BUGBUG #03 06/05/98 - Need more chaff. Very much more.
ADRIAO BUGBUG #06 06/11/98 - Figure out when (Internal_)Device_Control
IRPs must be sent at IRQL<DISPATCH_LEVEL...
Known HACKHACKs:
ADRIAO HACKHACK 08/16/1999 - Fix ACPI to enable more chaff.
(HACKHACK_FOR_ACPI)
*/
#include "iop.h"
#include "ob.h"
#if (( defined(_X86_) ) && ( FPO ))
#pragma optimize( "y", off ) // disable FPO for consistent stack traces
#endif
// This entire file is only present if NO_SPECIAL_IRP isn't defined
#ifndef NO_SPECIAL_IRP
// When enabled, everything is locked down on demand...
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGEVRFY, IovpAssertIsNewRequest)
#pragma alloc_text(PAGEVRFY, IovpAssertNewIrps)
#pragma alloc_text(PAGEVRFY, IovpAssertFinalIrpStack)
#pragma alloc_text(PAGEVRFY, IovpAssertNewRequest)
#pragma alloc_text(PAGEVRFY, IovpAssertIrpStackDownward)
#pragma alloc_text(PAGEVRFY, IovpAssertIrpStackUpward)
#pragma alloc_text(PAGEVRFY, IovpThrowChaffAtStartedPdoStack)
#pragma alloc_text(PAGEVRFY, IovpThrowBogusSynchronousIrp)
#pragma alloc_text(PAGEVRFY, IovpStartObRefMonitoring)
#pragma alloc_text(PAGEVRFY, IovpStopObRefMonitoring)
#pragma alloc_text(PAGEVRFY, IovpIsSystemRestrictedIrp)
#endif
extern PUCHAR PnPIrpNames[];
#include <initguid.h>
DEFINE_GUID( GUID_BOGUS_INTERFACE, 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
PCHAR KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING UnicodeString, OUT PCHAR AnsiBuffer, IN ULONG MaxAnsiLength);
BOOLEAN
IovpAssertIsNewRequest(
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp
)
/*++
Description:
Determines whether the two Irp stacks refer to the same "request",
ie starting the same device, etc. This is used to detect whether an IRP
has been simply forwarded or rather the IRP has been reused to initiate a new request.
Arguments:
The two IRP stacks to compare.
N.B. - the device object is not currently part of those IRP stacks.
Return Value:
TRUE if the stacks represent the same request, FALSE otherwise.
*/
{
return ((IrpLastSp==NULL)||
(IrpSp->MajorFunction != IrpLastSp->MajorFunction) ||
(IrpSp->MinorFunction != IrpLastSp->MinorFunction));
}
BOOLEAN
IovpAssertDoAdvanceStatus(
IN PIO_STACK_LOCATION IrpSp,
IN NTSTATUS OriginalStatus,
IN OUT NTSTATUS *StatusToAdvance
)
/*++
Description:
Given an IRP stack pointer, is it legal to change the status for
debug-ability? If so, this function determines what the new status
should be. Note that for each stack location, this function is iterated
over n times where n is equal to the number of drivers who IoSkip'd this location.
Arguments:
IrpSp - Current stack right after complete for the given stack
location, but before the completion routine for the stack location above has been called.
OriginalStatus - The status of the IRP at the time listed above. Does not change over iteration per skipping driver.
StatusToAdvance - Pointer to the current status that should be updated.
Return Value:
TRUE if the status has been adjusted, FALSE otherwise.
*/
{
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
case IRP_MJ_POWER:
if (((ULONG) OriginalStatus) < 256) {
(*StatusToAdvance)++;
if ((*StatusToAdvance) == STATUS_PENDING) {
(*StatusToAdvance)++;
}
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
VOID IovpAssertNewIrps(IN PIOV_REQUEST_PACKET IrpTrackingData, IN PIO_STACK_LOCATION IrpSp, IN PIOV_STACK_LOCATION StackLocationData)
{
}
VOID IovpAssertFinalIrpStack(IN PIOV_REQUEST_PACKET IrpTrackingData, IN PIO_STACK_LOCATION IrpSp)
{
ASSERT(!IrpTrackingData->RefTrackingCount);
}
VOID
IovpAssertNewRequest(
IN PIOV_REQUEST_PACKET IrpTrackingData,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData
)
{
PIRP irp = IrpTrackingData->TrackedIrp;
NTSTATUS currentStatus, lastStatus;
BOOLEAN newRequest, statusChanged, infoChanged, firstRequest;
PDEVICE_OBJECT possiblePdo;
ULONG doeFlags;
PDRIVER_OBJECT driverObject;
PDEVICE_NODE deviceNode;
UCHAR ansiBuffer[ 256 ];
PDEVICE_CAPABILITIES deviceCapabilities;
currentStatus = irp->IoStatus.Status;
lastStatus = StackLocationData->RequestsFirstStackLocation->LastStatusBlock.Status;
statusChanged = (currentStatus != lastStatus);
infoChanged = (irp->IoStatus.Information != StackLocationData->RequestsFirstStackLocation->LastStatusBlock.Information);
firstRequest = ((StackLocationData->RequestsFirstStackLocation->Flags&STACKFLAG_FIRST_REQUEST) != 0);
if ((IrpTrackingData->Flags&TRACKFLAG_IO_ALLOCATED)&& (!(IrpTrackingData->Flags&TRACKFLAG_WATERMARKED))) {
if (IovpIsSystemRestrictedIrp(IrpSp)) {
// We've caught somebody initiating an IRP they shouldn't be sending!
// ADRIAO BUGBUG 01/02/1999 -
// This can't be enabled until all the restricted system IRP's
// in the kernel have been watermarked!
#if 0
WDM_FAIL_CALLER4((DCERROR_RESTRICTED_IRP, DCPARAM_IRP, irp));
#endif
}
}
// Verify new IRPs start out life accordingly
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
if (currentStatus!=STATUS_NOT_SUPPORTED) {
// This is a special WDM (9x) compatibility hack.
if (IrpSp->MinorFunction != IRP_MN_FILTER_RESOURCE_REQUIREMENTS) {
WDM_FAIL_CALLER4((DCERROR_PNP_IRP_BAD_INITIAL_STATUS, DCPARAM_IRP, irp));
}
// Don't blame anyone else for this guy's mistake.
if (!NT_SUCCESS(currentStatus)) {
IrpTrackingData->Flags |= TRACKFLAG_PASSED_FAILURE;
}
}
if (IrpSp->MinorFunction == IRP_MN_QUERY_CAPABILITIES) {
deviceCapabilities = IrpSp->Parameters.DeviceCapabilities.Capabilities;
if (IopIsMemoryRangeReadable(deviceCapabilities, sizeof(DEVICE_CAPABILITIES))) {
// Verify fields are initialized correctly
if (deviceCapabilities->Version < 1) {
// Whoops, it didn't initialize the version correctly!
WDM_FAIL_CALLER4((DCERROR_PNP_QUERY_CAP_BAD_VERSION, DCPARAM_IRP, irp));
}
if (deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES)) {
// Whoops, it didn't initialize the size field correctly!
WDM_FAIL_CALLER4((DCERROR_PNP_QUERY_CAP_BAD_SIZE, DCPARAM_IRP, irp));
}
if (deviceCapabilities->Address != (ULONG) -1) {
// Whoops, it didn't initialize the address field correctly!
WDM_FAIL_CALLER4((DCERROR_PNP_QUERY_CAP_BAD_ADDRESS, DCPARAM_IRP, irp));
}
if (deviceCapabilities->UINumber != (ULONG) -1) {
// Whoops, it didn't initialize the UI number field correctly!
WDM_FAIL_CALLER4((DCERROR_PNP_QUERY_CAP_BAD_UI_NUM, DCPARAM_IRP, irp));
}
}
}
break;
case IRP_MJ_POWER:
if (currentStatus!=STATUS_NOT_SUPPORTED) {
WDM_FAIL_CALLER6((DCERROR_POWER_IRP_BAD_INITIAL_STATUS, DCPARAM_IRP, irp));
// Don't blame anyone else for this guy's mistake.
if (!NT_SUCCESS(currentStatus)) {
IrpTrackingData->Flags |= TRACKFLAG_PASSED_FAILURE;
}
}
break;
case IRP_MJ_SYSTEM_CONTROL:
if (currentStatus!=STATUS_NOT_SUPPORTED) {
WDM_FAIL_CALLER4((DCERROR_WMI_IRP_BAD_INITIAL_STATUS, DCPARAM_IRP, irp));
// Don't blame anyone else for this guy's mistake.
if (!NT_SUCCESS(currentStatus)) {
IrpTrackingData->Flags |= TRACKFLAG_PASSED_FAILURE;
}
}
break;
default:
break;
}
// If this is a target device relation IRP, verify the appropriate
// object will be referenced.
if ((IrpSp->MajorFunction == IRP_MJ_PNP)&&
(IrpSp->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)&&
(IrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation)) {
possiblePdo = IovpGetLowestDevice(DeviceObject);
if (possiblePdo) {
if ((possiblePdo->DeviceObjectExtension->DeviceNode)&&(StackLocationData->ReferencingObject == NULL)) {
// Got'm!
StackLocationData->Flags |= STACKFLAG_CHECK_FOR_REFERENCE;
StackLocationData->ReferencingObject = possiblePdo;
StackLocationData->ReferencingCount = IovpStartObRefMonitoring(possiblePdo);
IrpTrackingData->RefTrackingCount++;
}
// Free our reference (we will have one if we are snapshotting anyway)
ObDereferenceObject(possiblePdo);
}
}
/*
// Print out some stuff...
if (IrpSp->MajorFunction == IRP_MJ_PNP) {
switch(IrpSp->MinorFunction) {
case IRP_MN_QUERY_DEVICE_RELATIONS:
if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations) {
break;
}
// Fall through...
case IRP_MN_START_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
possiblePdo = IovpGetLowestDevice(DeviceObject) ;
deviceNode = (PDEVICE_NODE) possiblePdo->DeviceObjectExtension->DeviceNode ;
if (deviceNode) {
strcpy(ansiBuffer, "<not set>") ;
if (deviceNode->InstancePath.Buffer) {
KeBugCheckUnicodeToAnsi( &deviceNode->InstancePath, ansiBuffer, sizeof( ansiBuffer ));
}
DbgPrint("PNP: %s ( %08lx) initiating IRP_MJ_PNP.%s\n", ansiBuffer, possiblePdo, PnPIrpNames[IrpSp->MinorFunction]);
}
ObDereferenceObject(possiblePdo) ;
break;
default:
break;
}
}
*/
}
VOID
IovpAssertIrpStackDownward(
IN PIOV_REQUEST_PACKET IrpTrackingData,
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION IrpLastSp OPTIONAL,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData
)
{
PIRP irp = IrpTrackingData->TrackedIrp;
NTSTATUS currentStatus, lastStatus;
BOOLEAN newRequest, statusChanged, infoChanged, firstRequest;
PDEVICE_OBJECT possiblePdo;
ULONG doeFlags;
PDRIVER_OBJECT driverObject;
PDEVICE_NODE deviceNode;
UCHAR ansiBuffer[ 256 ];
PDEVICE_CAPABILITIES deviceCapabilities;
PIOV_SESSION_DATA iovSessionData;
currentStatus = irp->IoStatus.Status;
lastStatus = StackLocationData->RequestsFirstStackLocation->LastStatusBlock.Status;
statusChanged = (currentStatus != lastStatus);
infoChanged = (irp->IoStatus.Information != StackLocationData->RequestsFirstStackLocation->LastStatusBlock.Information);
firstRequest = ((StackLocationData->RequestsFirstStackLocation->Flags&STACKFLAG_FIRST_REQUEST) != 0);
iovSessionData = IovpTrackingDataGetCurrentSessionData(IrpTrackingData);
// Do we have a "new" function to process?
newRequest = IovpAssertIsNewRequest(IrpLastSp, IrpSp);
// Verify the IRP was forwarded properly
switch(iovSessionData->ForwardMethod) {
case SKIPPED_A_DO:
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
case IRP_MJ_SYSTEM_CONTROL:
WDM_FAIL_CALLER4((DCERROR_SKIPPED_DEVICE_OBJECT, DCPARAM_IRP, irp));
break;
case IRP_MJ_POWER:
// Unwind back through PoCallDriver...
WDM_FAIL_CALLER6((DCERROR_SKIPPED_DEVICE_OBJECT, DCPARAM_IRP, irp));
break;
default:
break;
}
break;
case STARTED_TOP_OF_STACK:
case FORWARDED_TO_NEXT_DO:
// Perfectly normal
break;
case STARTED_INSIDE_STACK:
// Probably an Internal irp (query cap's, etc)
break;
case CHANGED_STACKS_MID_STACK:
//ASSERT(0);
break ;
case CHANGED_STACKS_AT_BOTTOM:
// This is scary as we are very likely to run out of
// stack locations. In theory, it is safe to do this if one
// is careful though...
// ADRIAO BUGBUG ?? - I should check to see if there are
// enough theoritical stack locations:
// If there are we may be OK. Also
// verify the "jump" in stack loc's from
// the lower dude (5 to 8 instead of 5 to 6)
// account for the stack size of the
// "outbound" forward (ie, 2)
#if 0
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
ASSERT(0);
}
#endif
break ;
}
// For some IRP major's going down a stack, there *must* be a handler
driverObject = DeviceObject->DriverObject;
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
// Umm, this would be waaay too bizarre to fail. Actually, video
// miniports do this. Yick.
#if 0
ASSERT((driverObject->MajorFunction[IrpSp->MajorFunction] != IopInvalidDeviceRequest) ||
((DeviceObject->DeviceObjectExtension->DeviceNode == NULL) &&
(DeviceObject->DeviceObjectExtension->AttachedTo == NULL)));
#endif
break;
case IRP_MJ_POWER:
case IRP_MJ_SYSTEM_CONTROL:
if (driverObject->MajorFunction[IrpSp->MajorFunction] == IopInvalidDeviceRequest) {
WDM_FAIL_ROUTINE((
DCERROR_MISSING_DISPATCH_FUNCTION,
DCPARAM_IRP + DCPARAM_ROUTINE,
irp,
driverObject->MajorFunction[IRP_MJ_PNP]
));
StackLocationData->Flags |= STACKFLAG_NO_HANDLER;
}
break;
default:
break;
}
// Verify IRQL's are legal
switch(IrpSp->MajorFunction) {
case IRP_MJ_POWER:
case IRP_MJ_READ:
case IRP_MJ_WRITE:
// Fall through
// ADRIAO BUGBUG #06 06/11/98 - Figure out when the next two are
// restricted to IRQL<DISPATCH_LEVEL...
case IRP_MJ_DEVICE_CONTROL:
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
break;
default:
if (iovSessionData->ForwardMethod != FORWARDED_TO_NEXT_DO) {
break;
}
if ((IrpTrackingData->CallerIrql >= DISPATCH_LEVEL) && (!(IrpTrackingData->Flags & TRACKFLAG_PASSED_AT_BAD_IRQL))) {
WDM_FAIL_CALLER4((DCERROR_DISPATCH_CALLED_AT_BAD_IRQL, DCPARAM_IRP, irp));
IrpTrackingData->Flags |= TRACKFLAG_PASSED_AT_BAD_IRQL;
}
}
// The following is only executed if we are not a new IRP...
if (IrpLastSp == NULL) {
return;
}
// Let's verify bogus IRPs haven't been touched...
// BUGBUG ADRIAO ?? - Invent better Info/Status/Func memory...
if (IrpTrackingData->Flags&TRACKFLAG_BOGUS) {
if (newRequest && (!firstRequest)) {
WDM_FAIL_CALLER4((DCERROR_BOGUS_FUNC_TRASHED, DCPARAM_IRP, irp));
}
if (statusChanged) {
if (IrpSp->MinorFunction == 0xFF) {
WDM_FAIL_CALLER4((DCERROR_BOGUS_MINOR_STATUS_TRASHED, DCPARAM_IRP, irp));
} else {
WDM_FAIL_CALLER4((DCERROR_BOGUS_STATUS_TRASHED, DCPARAM_IRP, irp));
}
}
if (infoChanged) {
WDM_FAIL_CALLER4((DCERROR_BOGUS_INFO_TRASHED, DCPARAM_IRP, irp));
}
}
// Verify PnP IRPs
// ADRIAO BUGBUG 01/02/1999 -
// This doesn't quite work right for RAW PDO's, as they in truth have
// no one to IoCallDriver so we never see those IRPs. This needs to be
// *request* based in the upward code...
if (IrpSp->MajorFunction == IRP_MJ_PNP) {
// The only legit failure code to pass down is STATUS_NOT_SUPPORTED
if ((!NT_SUCCESS(currentStatus)) && (currentStatus != STATUS_NOT_SUPPORTED) &&
(!(IrpTrackingData->Flags&TRACKFLAG_PASSED_FAILURE))) {
WDM_FAIL_CALLER4((DCERROR_PNP_FAILURE_FORWARDED, DCPARAM_IRP, irp));
// Don't blame anyone else for this dude's mistakes...
IrpTrackingData->Flags |= TRACKFLAG_PASSED_FAILURE;
}
// Status of a PnP IRP may not be converted to STATUS_NOT_SUPPORTED on the way down
if ((currentStatus == STATUS_NOT_SUPPORTED)&&statusChanged) {
WDM_FAIL_CALLER4((DCERROR_PNP_IRP_STATUS_RESET, DCPARAM_IRP, irp));
}
// Some IRPs FDO's are required to handle before passing down. And
// some IRPs should not be touched by the FDO. Assert it is so...
if (iovSessionData->DeviceLastCalled) {
doeFlags = iovSessionData->DeviceLastCalled->DeviceObjectExtension->ExtensionFlags;
} else {
doeFlags = 0;
}
// How could a Raw FDO (aka a PDO) get here? Well, a PDO could forward
// to another stack if he's purposely reserved enough stack locations
// for that eventuality...
//ASSERT(!(doeFlags&DOE_RAW_FDO));
if (doeFlags&DOE_DESIGNATED_FDO) {
switch(IrpSp->MinorFunction) {
case IRP_MN_SURPRISE_REMOVAL:
// ADRIAO BUGBUG 01/22/1999 -
// We are exempting this IRP from support
// (ie, voting success or failure) because it is
// late in the product. This is in my opinion quite
// braindead, but so be it.
break;
case IRP_MN_START_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
// The FDO must set the status as appropriate. If he set a
// completion routine, he can do it there (and thus we cannot
// check). If he has not though, we can indeed verify he has
// responded to the IRP!
if ((currentStatus == STATUS_NOT_SUPPORTED)&&(!IrpSp->CompletionRoutine)) {
WDM_FAIL_CALLER4((DCERROR_PNP_IRP_NEEDS_FDO_HANDLING, DCPARAM_IRP, irp));
}
break ;
case IRP_MN_QUERY_DEVICE_RELATIONS:
switch(IrpSp->Parameters.QueryDeviceRelations.Type) {
case TargetDeviceRelation:
if ((currentStatus != STATUS_NOT_SUPPORTED)&&(!(doeFlags&DOE_RAW_FDO))) {
WDM_FAIL_CALLER4((DCERROR_PNP_IRP_FDO_HANDS_OFF, DCPARAM_IRP, irp));
}
break;
case BusRelations:
case PowerRelations:
case RemovalRelations:
case EjectionRelations:
// Ejection relations are usually a bad idea for
// FDO's - As stopping a device implies powerdown,
// RemovalRelations are usually the proper response
// for an FDO. One exception is ISAPNP, as PCI-to-ISA
// bridges can never be powered down.
default:
break;
}
break;
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
break;
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_QUERY_BUS_INFORMATION:
if ((currentStatus != STATUS_NOT_SUPPORTED)&&(!(doeFlags&DOE_RAW_FDO))) {
WDM_FAIL_CALLER4((DCERROR_PNP_IRP_FDO_HANDS_OFF, DCPARAM_IRP, irp));
}
break;
case IRP_MN_QUERY_ID:
switch(IrpSp->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
case BusQueryHardwareIDs:
case BusQueryCompatibleIDs:
case BusQueryInstanceID:
if ((currentStatus != STATUS_NOT_SUPPORTED)&&(!(doeFlags&DOE_RAW_FDO))) {
WDM_FAIL_CALLER4((DCERROR_PNP_IRP_FDO_HANDS_OFF, DCPARAM_IRP, irp));
}
break;
default:
break;
}
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
break;
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
// ADRIAO BUGBUG 09/25/98 - Is this really optional for an FDO?
break;
default:
break;
}
}
}
// Verify Power IRPs
if (IrpSp->MajorFunction == IRP_MJ_POWER) {
// The only legit failure code to pass down is STATUS_NOT_SUPPORTED
if ((!NT_SUCCESS(currentStatus)) && (currentStatus != STATUS_NOT_SUPPORTED) &&
(!(IrpTrackingData->Flags&TRACKFLAG_PASSED_FAILURE))) {
WDM_FAIL_CALLER6((DCERROR_POWER_FAILURE_FORWARDED, DCPARAM_IRP, irp));
// Don't blame anyone else for this dude's mistakes...
IrpTrackingData->Flags |= TRACKFLAG_PASSED_FAILURE;
}
// Status of a Power IRP may not be converted to STATUS_NOT_SUPPORTED on the way down
if ((currentStatus == STATUS_NOT_SUPPORTED)&&statusChanged) {
WDM_FAIL_CALLER6((DCERROR_POWER_IRP_STATUS_RESET, DCPARAM_IRP, irp));
}
}
if (!IovpAssertIsValidIrpStatus(IrpSp, currentStatus)) {
switch(IrpSp->MajorFunction) {
case IRP_MJ_POWER:
WDM_FAIL_CALLER6((DCERROR_INVALID_STATUS, DCPARAM_IRP, irp));
break;
default:
WDM_FAIL_CALLER4((DCERROR_INVALID_STATUS, DCPARAM_IRP, irp));
break;
}
}
}
VOID
IovpAssertIrpStackUpward(
IN PIOV_REQUEST_PACKET IrpTrackingData,
IN PIO_STACK_LOCATION IrpSp,
IN PIOV_STACK_LOCATION StackLocationData,
IN BOOLEAN IsNewlyCompleted,
IN BOOLEAN RequestFinalized
)
{
PIRP irp = IrpTrackingData->TrackedIrp;
NTSTATUS currentStatus, lastStatus;
BOOLEAN mustPassDown, isBogusIrp, isPdo, statusChanged, infoChanged;
PIOV_STACK_LOCATION originalRequestSLD;
PVOID routine;
LONG referencesTaken;
PDEVICE_OBJECT possiblePdo;
PDEVICE_NODE deviceNode;
UCHAR ansiBuffer[ 256 ];
currentStatus = irp->IoStatus.Status;
lastStatus = StackLocationData->RequestsFirstStackLocation->LastStatusBlock.Status;
statusChanged = (currentStatus != lastStatus);
infoChanged = (irp->IoStatus.Information != StackLocationData->RequestsFirstStackLocation->LastStatusBlock.Information);
// Who'd we call for this one?
routine = StackLocationData->LastDispatch;
ASSERT(routine) ;
// If this "Request" has been "Completed", perform some checks
if (IsNewlyCompleted) {
// Remember bogosity...
isBogusIrp = ((IrpTrackingData->Flags&TRACKFLAG_BOGUS)!=0);
// Is this a PDO?
isPdo = ((StackLocationData->Flags&STACKFLAG_REACHED_PDO)!=0);
// Was anything completed too early?
// A driver may outright fail almost anything but a bogus IRP
mustPassDown = (!(StackLocationData->Flags&STACKFLAG_NO_HANDLER));
mustPassDown &= (!isPdo);
switch(IrpSp->MajorFunction) {
case IRP_MJ_SYSTEM_CONTROL:
mustPassDown &= ((PDEVICE_OBJECT) IrpSp->Parameters.WMI.ProviderId != IrpSp->DeviceObject);
if (mustPassDown) {
WDM_FAIL_ROUTINE((
DCERROR_WMI_IRP_NOT_FORWARDED,
DCPARAM_IRP + DCPARAM_ROUTINE + DCPARAM_DEVOBJ,
irp,
routine,
IrpSp->Parameters.WMI.ProviderId
));
}
break;
case IRP_MJ_PNP:
mustPassDown &= (isBogusIrp || NT_SUCCESS(currentStatus) || (currentStatus == STATUS_NOT_SUPPORTED));
if (mustPassDown) {
// Print appropriate error message
if (IrpTrackingData->Flags&TRACKFLAG_BOGUS) {
WDM_FAIL_ROUTINE((DCERROR_BOGUS_PNP_IRP_COMPLETED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
} else if (NT_SUCCESS(currentStatus)) {
WDM_FAIL_ROUTINE((DCERROR_SUCCESSFUL_PNP_IRP_NOT_FORWARDED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
} else if (currentStatus == STATUS_NOT_SUPPORTED) {
WDM_FAIL_ROUTINE((DCERROR_UNTOUCHED_PNP_IRP_NOT_FORWARDED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
}
break;
case IRP_MJ_POWER:
mustPassDown &= (isBogusIrp || NT_SUCCESS(currentStatus) || (currentStatus == STATUS_NOT_SUPPORTED));
if (mustPassDown) {
// Print appropriate error message
if (IrpTrackingData->Flags&TRACKFLAG_BOGUS) {
WDM_FAIL_ROUTINE((DCERROR_BOGUS_POWER_IRP_COMPLETED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
} else if (NT_SUCCESS(currentStatus)) {
WDM_FAIL_ROUTINE((DCERROR_SUCCESSFUL_POWER_IRP_NOT_FORWARDED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
} else if (currentStatus == STATUS_NOT_SUPPORTED) {
WDM_FAIL_ROUTINE((DCERROR_UNTOUCHED_POWER_IRP_NOT_FORWARDED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
}
break;
}
// Did the PDO respond to it's required set of IRPs?
if (isPdo) {
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
switch(IrpSp->MinorFunction) {
case IRP_MN_SURPRISE_REMOVAL:
// ADRIAO BUGBUG 01/22/1999 -
// We are exempting this IRP from support
// (ie, voting success or failure) because it is
// late in the product. This is in my opinion quite
// braindead, but so be it.
break;
case IRP_MN_START_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
if (currentStatus == STATUS_NOT_SUPPORTED) {
WDM_FAIL_ROUTINE((DCERROR_PNP_IRP_NEEDS_PDO_HANDLING, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
switch(IrpSp->Parameters.QueryDeviceRelations.Type) {
case BusRelations:
case PowerRelations:
case RemovalRelations:
case EjectionRelations:
// Optionals or FDO's
break;
case TargetDeviceRelation:
if (currentStatus == STATUS_NOT_SUPPORTED) {
WDM_FAIL_ROUTINE((DCERROR_PNP_IRP_NEEDS_PDO_HANDLING, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
} else if (NT_SUCCESS(currentStatus)) {
if (irp->IoStatus.Information == (ULONG_PTR) NULL) {
WDM_FAIL_ROUTINE((DCERROR_TARGET_RELATION_LIST_EMPTY, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
// ADRIAO BUGBUG ?? - I could also assert the Information
// matches DeviceObject.
}
break;
default:
break;
}
break;
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_CAPABILITIES:
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
case IRP_MN_QUERY_DEVICE_TEXT:
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
break;
case IRP_MN_QUERY_ID:
switch(IrpSp->Parameters.QueryId.IdType) {
case BusQueryDeviceID:
case BusQueryHardwareIDs:
case BusQueryCompatibleIDs:
case BusQueryInstanceID:
default:
break;
}
break ;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
case IRP_MN_QUERY_BUS_INFORMATION:
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
default:
break ;
}
default:
break;
}
}
// Was TargetDeviceRelation implemented correctly?
originalRequestSLD = StackLocationData->RequestsFirstStackLocation;
if (originalRequestSLD->Flags&STACKFLAG_CHECK_FOR_REFERENCE) {
ASSERT ((IrpSp->MajorFunction == IRP_MJ_PNP)&&
(IrpSp->MinorFunction == IRP_MN_QUERY_DEVICE_RELATIONS)&&
(IrpSp->Parameters.QueryDeviceRelations.Type == TargetDeviceRelation));
ASSERT(originalRequestSLD->ReferencingObject);
ASSERT(IrpTrackingData->RefTrackingCount);
referencesTaken = IovpStopObRefMonitoring(originalRequestSLD->ReferencingObject, originalRequestSLD->ReferencingCount);
IrpTrackingData->RefTrackingCount--;
originalRequestSLD->ReferencingObject = NULL;
originalRequestSLD->Flags&=~STACKFLAG_CHECK_FOR_REFERENCE;
if (NT_SUCCESS(currentStatus)&&(!referencesTaken)) {
WDM_FAIL_ROUTINE((DCERROR_TARGET_RELATION_NEEDS_REF, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
}
}
// Did anyone stomp the status erroneously?
if ((currentStatus == STATUS_NOT_SUPPORTED)&&statusChanged) {
// Status of a PnP or Power IRP may not be converted from success to
// STATUS_NOT_SUPPORTED on the way down.
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
WDM_FAIL_ROUTINE((DCERROR_PNP_IRP_STATUS_RESET, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
break;
case IRP_MJ_POWER:
WDM_FAIL_ROUTINE((DCERROR_POWER_IRP_STATUS_RESET, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
break;
}
}
// Did they touch something stupid?
if (IrpTrackingData->Flags&TRACKFLAG_BOGUS) {
if (statusChanged) {
if (IrpSp->MinorFunction == 0xFF) {
WDM_FAIL_ROUTINE((DCERROR_BOGUS_MINOR_STATUS_TRASHED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
} else {
WDM_FAIL_ROUTINE((DCERROR_BOGUS_STATUS_TRASHED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
}
if (infoChanged) {
WDM_FAIL_ROUTINE((DCERROR_BOGUS_INFO_TRASHED, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
}
if (!IovpAssertIsValidIrpStatus(IrpSp, currentStatus)) {
WDM_FAIL_ROUTINE((DCERROR_INVALID_STATUS, DCPARAM_IRP + DCPARAM_ROUTINE, irp, routine));
}
/*
// Print out some stuff...
if (RequestFinalized&&(IrpSp->MajorFunction == IRP_MJ_PNP)) {
switch(IrpSp->MinorFunction) {
case IRP_MN_QUERY_DEVICE_RELATIONS:
if (IrpSp->Parameters.QueryDeviceRelations.Type != BusRelations) {
break;
}
// Fall through...
case IRP_MN_START_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
possiblePdo = IovpGetLowestDevice(IrpSp->DeviceObject) ;
deviceNode = (PDEVICE_NODE) possiblePdo->DeviceObjectExtension->DeviceNode ;
if (deviceNode) {
strcpy(ansiBuffer, "<not set>") ;
if (deviceNode->InstancePath.Buffer) {
KeBugCheckUnicodeToAnsi( &deviceNode->InstancePath, ansiBuffer, sizeof( ansiBuffer ));
}
DbgPrint("PNP: %s ( %08lx) completing IRP_MJ_PNP.%s with %08lx\n", ansiBuffer, possiblePdo, PnPIrpNames[IrpSp->MinorFunction], currentStatus);
}
ObDereferenceObject(possiblePdo) ;
break;
default:
break;
}
}
*/
}
BOOLEAN IovpAssertIsValidIrpStatus(IN PIO_STACK_LOCATION IrpSp, IN NTSTATUS Status)
/*++
Description:
As per the title, this function determines whether an IRP status is
valid or probably random trash. See NTStatus.h for info on how status
codes break down...
Returns:
TRUE iff IRP status looks to be valid. FALSE otherwise.
*/
{
ULONG severity;
ULONG customer;
ULONG reserved;
ULONG facility;
ULONG code;
ULONG lanManClass;
severity = (((ULONG)Status) >> 30)&3;
customer = (((ULONG)Status) >> 29)&1;
reserved = (((ULONG)Status) >> 28)&1;
facility = (((ULONG)Status) >> 16)&0xFFF;
code = (((ULONG)Status) & 0xFFFF);
// If reserved set, definitely bogus...
if (reserved) {
return FALSE;
}
// Is this a microsoft defined return code? If not, do no checking.
if (customer) {
return TRUE;
}
// ADRIAO N.B. 10/04/1999 -
// The current methodology for doling out error codes appears to be
// fairly chaotic. The primary kernel mode status codes are defined in
// ntstatus.h. However, rtl\generr.c should also be consulted to see which
// error codes can bubble up to user mode. Many OLE error codes from
// winerror.h are now being used within the kernel itself.
if (facility < 0x20) {
// Facilities under 20 are currently legal.
switch(severity) {
case STATUS_SEVERITY_SUCCESS: return (code < 0x200);
case STATUS_SEVERITY_INFORMATIONAL:
// ADRIAO BUGBUG 10/09/1999 -
// This should really be 0x50, but we've been testing with
// 0x400 for a while (and we don't want to change it just before
// Win2k ships).
return (code < 0x400);
case STATUS_SEVERITY_WARNING: return (code < 0x400);
case STATUS_SEVERITY_ERROR: break;
}
// Why the heck does WOW use such an odd error code?
return (code < 0x400)||(code == 0x9898);
} else if (facility == 0x98) {
// This is the lan manager service. In the case on Lan Man, the code
// field is further subdivided into a class field.
lanManClass = code >> 12;
code &= 0xFFF;
// Do no testing here.
return TRUE;
} else {
// Not known, probably bogus.
return FALSE;
}
}
VOID IovpThrowChaffAtStartedPdoStack(IN PDEVICE_OBJECT DeviceObject)
/*++
Description:
As per the title, we are going to throw some IRPs at the stack to see if they are handled correctly.
Returns:
Nothing
*/
{
IO_STACK_LOCATION irpSp;
PDEVICE_OBJECT lowestDeviceObject;
PDEVICE_RELATIONS targetDeviceRelationList;
INTERFACE interface;
NTSTATUS status;
PAGED_CODE();
// Initialize the stack location to pass to IopSynchronousCall()
RtlZeroMemory(&irpSp, sizeof(IO_STACK_LOCATION));
// send lots of bogus PNP IRPs
irpSp.MajorFunction = IRP_MJ_PNP;
irpSp.MinorFunction = 0xff;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS ;
irpSp.Parameters.QueryDeviceRelations.Type = (DEVICE_RELATION_TYPE) -1 ;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
#ifdef HACKHACKS_ENABLED
if (!(IovpHackFlags&HACKFLAG_FOR_ACPI)) {
#endif
// ADRIAO HACKHACK 08/16/1999 - Fix ACPI to enable more chaff
irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS ;
irpSp.Parameters.QueryDeviceRelations.Type = (DEVICE_RELATION_TYPE) -1 ;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) -1, NULL, TRUE) ;
#ifdef HACKHACKS_ENABLED
}
#endif
irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_TEXT ;
irpSp.Parameters.QueryDeviceText.DeviceTextType = (DEVICE_TEXT_TYPE) -1 ;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
irpSp.MinorFunction = IRP_MN_QUERY_ID ;
irpSp.Parameters.QueryId.IdType = (BUS_QUERY_ID_TYPE) -1 ;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
#ifdef HACKHACKS_ENABLED
if (!(IovpHackFlags&HACKFLAG_FOR_BOGUSIRPS)) {
#endif
// Send a bogus WMI IRP
// Note that we aren't sending this IRP to any stack that doesn't terminate
// with a devnode. The WmiSystemControl export from WmiLib says
// "NotWmiIrp if it sees these. The callers should still pass down the IRP.
lowestDeviceObject = IovpGetLowestDevice(DeviceObject) ;
ASSERT(lowestDeviceObject) ;
ASSERT(lowestDeviceObject->DeviceObjectExtension->DeviceNode) ;
irpSp.MajorFunction = IRP_MJ_SYSTEM_CONTROL ;
irpSp.MinorFunction = 0xff;
irpSp.Parameters.WMI.ProviderId = (ULONG_PTR) lowestDeviceObject ;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
ObDereferenceObject(lowestDeviceObject) ;
// And a bogus Power IRP
irpSp.MajorFunction = IRP_MJ_POWER ;
irpSp.MinorFunction = 0xff;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
#ifdef HACKHACKS_ENABLED
}
#endif
// Target device relation test...
irpSp.MajorFunction = IRP_MJ_PNP ;
irpSp.MinorFunction = IRP_MN_QUERY_DEVICE_RELATIONS ;
irpSp.Parameters.QueryDeviceRelations.Type = TargetDeviceRelation ;
targetDeviceRelationList = NULL ;
status = IovpThrowBogusSynchronousIrp(
DeviceObject,
&irpSp,
(ULONG_PTR) 0,
(ULONG_PTR *) &targetDeviceRelationList,
FALSE);
if (NT_SUCCESS(status)) {
ASSERT(targetDeviceRelationList) ;
ASSERT(targetDeviceRelationList->Count == 1) ;
ASSERT(targetDeviceRelationList->Objects[0]) ;
ObDereferenceObject(targetDeviceRelationList->Objects[0]) ;
ExFreePool(targetDeviceRelationList) ;
} else {
// IRP was asserted in other code. We need to do nothing here...
}
RtlZeroMemory(&interface, sizeof(INTERFACE));
irpSp.MinorFunction = IRP_MN_QUERY_INTERFACE;
irpSp.Parameters.QueryInterface.Size = -1;
irpSp.Parameters.QueryInterface.Version = 1;
irpSp.Parameters.QueryInterface.InterfaceType = &GUID_BOGUS_INTERFACE;
irpSp.Parameters.QueryInterface.Interface = &interface;
irpSp.Parameters.QueryInterface.InterfaceSpecificData = (PVOID) -1;
IovpThrowBogusSynchronousIrp(DeviceObject, &irpSp, (ULONG_PTR) 0, NULL, TRUE);
// ADRIAO BUGBUG #03 06/05/98 - Need more chaff. Very much more.
// For example, bogus device usage notifications, etc...
}
NTSTATUS
IovpThrowBogusSynchronousIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIO_STACK_LOCATION TopStackLocation,
IN OUT OPTIONAL ULONG_PTR Information,
IN OUT ULONG_PTR *InformationOut OPTIONAL,
IN BOOLEAN IsBogus
)
/*++
Routine Description:
This function sends a synchronous irp to the top level device
object which roots on DeviceObject. It differs from IopSynchronousIrp
in that it sets the IRP_DIAG_IS_BOGUS flag, and passes in possibly nonzero information.
Parameters:
DeviceObject - Supplies the device object of the device being removed.
TopStackLocation - Supplies a pointer to the parameter block for the irp.
Return Value:
NTSTATUS code.
*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
IO_STATUS_BLOCK statusBlock;
KEVENT event;
NTSTATUS status;
PDEVICE_OBJECT topDeviceObject;
PAGED_CODE();
// Get a pointer to the topmost device object in the stack of devices,
// beginning with the deviceObject.
topDeviceObject = IoGetAttachedDeviceReference(DeviceObject);
// Begin by allocating the IRP for this request. Do not charge quota to
// the current process for this IRP.
irp = IoAllocateIrp(topDeviceObject->StackSize, FALSE);
if (irp == NULL){
ObDereferenceObject(topDeviceObject) ;
return STATUS_INSUFFICIENT_RESOURCES;
}
if (IsBogus) {
SPECIALIRP_WATERMARK_IRP(irp, IRP_BOGUS);
}
// Initialize it to failure.
irp->IoStatus.Status = statusBlock.Status = STATUS_NOT_SUPPORTED;
irp->IoStatus.Information = statusBlock.Information = Information;
// Set the pointer to the status block and initialized event.
KeInitializeEvent( &event, SynchronizationEvent, FALSE );
irp->UserIosb = &statusBlock;
irp->UserEvent = &event;
// Set the address of the current thread (for debugging)
irp->Tail.Overlay.Thread = PsGetCurrentThread();
// Queue this irp onto the current thread. We do this because we are not
// collecting this IRP with a STATUS_MORE_PROCESSING_REQUIRED completion
// routine - an APC will be scheduled and we *must* give it a thread.
IopQueueThreadIrp(irp);
// Get a pointer to the stack location of the first driver which will be
// invoked. This is where the function codes and parameters are set.
irpSp = IoGetNextIrpStackLocation(irp);
// Copy in the caller-supplied stack location contents
*irpSp = *TopStackLocation;
// Call the driver
status = IoCallDriver(topDeviceObject, irp);
ObDereferenceObject(topDeviceObject) ;
// If a driver returns STATUS_PENDING, we will wait for it to complete
if (status == STATUS_PENDING) {
(VOID) KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, (PLARGE_INTEGER) NULL );
status = statusBlock.Status;
}
if (InformationOut) {
*InformationOut = statusBlock.Information ;
}
return status;
}
LONG IovpStartObRefMonitoring(IN PDEVICE_OBJECT DeviceObject)
/*++
Description:
Determines if ObRef has not been called between a call to this function and a subsequent call to IovpStopObRefMonitoring.
Arguments:
Device object to monitor.
Return Value:
A start skew time to pass into IovpStopObRefMonitoring.
N.B. - A reference count is taken by this API and released
by IovpStopObRefMonitoring. That reference is not
counted among the noticed calls to ObRef.
*/
{
// ADRIAO BUGBUG 10/05/1999 -
// Parclass reroutes target-device-relation IRPs around the tree. That
// design will be fixed for NT5.1, but in the meantime this means we will
// not be able to test this driver functionality.
#if 0
POBJECT_HEADER ObjectHeader;
POBJECT_HEADER_NAME_INFO NameInfo;
LONG startSkew, pointerCount ;
ObReferenceObject(DeviceObject) ;
ObjectHeader = OBJECT_TO_OBJECT_HEADER(DeviceObject);
NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
ASSERT(NameInfo) ;
// We will always decrement DbgDereferenceCount prior to PointerCount,
// so any race conditions will look like an increment occured, which
// is an allowable misread...
do {
pointerCount = ObjectHeader->PointerCount ;
startSkew = pointerCount - NameInfo->DbgDereferenceCount ;
} while(pointerCount != ObjectHeader->PointerCount) ;
return startSkew ;
#else
return 1;
#endif
}
LONG IovpStopObRefMonitoring(IN PDEVICE_OBJECT DeviceObject, IN LONG StartSkew)
/*++
Description:
Determines if ObRef has not been called between a call to IovpStartObRefMonitoring and a call to this API.
In a race condition (say ObDereferenceObject is ran in-simo
with this function), the return is gaurenteed to err on the side of a reference occuring.
Arguments:
Device Object and the skew returned by IovpStartObRefMonitoring
Return Value:
Number of calls to ObRef that occured throughout the monitored timeframe.
Note that the return could be positive even though the reference count
actually dropped (ie, one ObRef and two ObDeref's).
*/
{
// ADRIAO BUGBUG 10/05/1999 -
// Parclass reroutes target-device-relation IRPs around the tree. That
// design will be fixed for NT5.1, but in the meantime this means we will
// not be able to test this driver functionality.
#if 0
POBJECT_HEADER ObjectHeader;
POBJECT_HEADER_NAME_INFO NameInfo;
LONG currentSkew, refDelta, pointerCount ;
ObjectHeader = OBJECT_TO_OBJECT_HEADER(DeviceObject);
NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
ASSERT(NameInfo) ;
// We will always decrement DbgDereferenceCount prior to PointerCount,
// so any race conditions will look like an increment occured, which
// is an allowable misread...
do {
pointerCount = ObjectHeader->PointerCount ;
currentSkew = pointerCount - NameInfo->DbgDereferenceCount ;
} while(pointerCount != ObjectHeader->PointerCount) ;
refDelta = currentSkew - StartSkew ;
ASSERT(refDelta>=0) ;
ObDereferenceObject(DeviceObject) ;
return refDelta ;
#else
return 1;
#endif
}
BOOLEAN IovpIsSystemRestrictedIrp(PIO_STACK_LOCATION IrpSp)
{
switch(IrpSp->MajorFunction) {
case IRP_MJ_PNP:
switch(IrpSp->MinorFunction) {
case IRP_MN_START_DEVICE:
case IRP_MN_QUERY_REMOVE_DEVICE:
case IRP_MN_REMOVE_DEVICE:
case IRP_MN_CANCEL_REMOVE_DEVICE:
case IRP_MN_STOP_DEVICE:
case IRP_MN_QUERY_STOP_DEVICE:
case IRP_MN_CANCEL_STOP_DEVICE:
case IRP_MN_SURPRISE_REMOVAL:
return TRUE;
case IRP_MN_QUERY_DEVICE_RELATIONS:
switch(IrpSp->Parameters.QueryDeviceRelations.Type) {
case BusRelations:
case PowerRelations:
return TRUE;
case RemovalRelations:
case EjectionRelations:
case TargetDeviceRelation:
return FALSE;
default:
break;
}
break;
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_CAPABILITIES:
return FALSE;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
case IRP_MN_QUERY_DEVICE_TEXT:
return TRUE;
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
return FALSE;
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
return TRUE;
case IRP_MN_QUERY_ID:
switch(IrpSp->Parameters.QueryId.IdType) {
case BusQueryHardwareIDs:
case BusQueryCompatibleIDs:
return TRUE;
case BusQueryDeviceID:
case BusQueryInstanceID:
return FALSE;
default:
break;
}
break ;
case IRP_MN_QUERY_PNP_DEVICE_STATE:
case IRP_MN_QUERY_BUS_INFORMATION:
return TRUE;
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return FALSE;
default:
break ;
}
case IRP_MJ_POWER:
switch(IrpSp->MinorFunction) {
case IRP_MN_POWER_SEQUENCE:
return FALSE;
case IRP_MN_QUERY_POWER:
case IRP_MN_SET_POWER:
case IRP_MN_WAIT_WAKE:
return TRUE;
default:
break;
}
default:
return FALSE;
}
return TRUE;
}
#endif // NO_SPECIAL_IRP