IRP_MN_QUERY_INTERFACE questions

Hi guys,

Here is my WDF driver stack:

NDIS
TS_II_NDIS (Miniport Driver)
TS_II_BUS (Bus Driver)
PCI

The TS_II_BUS driver provides an FDO that is used to provide an API to get/put video frames. The TS_II_NDIS mp driver is used to allow apps to receive data coming from the card via a socket connection.

The TS_II_BUS driver also exports an TSII_BUS_NDIS_INTERFACE, shown below, which is what I want to focus on in this post.

typedef struct _TSII_BUS_NDIS_INTERFACE
{
// Generic Interface Header:
USHORT Size;
USHORT Version;
PVOID Context;
PINTERFACE_REFERENCE InterfaceReference;
PINTERFACE_DEREFERENCE InterfaceDereference;

// Additional Input Params:

// Output params:
PTSII_BUS_NDIS_READ_PACKET GetPacket;

} TSII_BUS_NDIS_INTERFACE, *PTSII_BUS_NDIS_INTERFACE;

The TS_II_NDIS driver sends an IRP_MN_QUERY_INTERFACE pnp irp down to the TS_II_BUS driver to wire up the interface. Right now, the interface doesn’t support the input/output params that Doron mentions here (http://blogs.msdn.com/doronh/archive/2007/03/06/interfaces-can-contain-both-input-and-output-parameters-and-not-just-function-pointers.aspx), but it will. This will *eventually* allow my bus driver (which will be receiving network data), to send the packets up to the TS_II_NDIS driver, and then up through NDIS.

The TS_II_BUS driver (in DeviceAdd) staticly enumerates a child PDO, which serves as the PDO for the TS_II_NDIS driver. Additionally, it sets up the TSII_BUS_NDIS_INTERFACE above once it enumerates the child PDO.

Once I install both drivers. I am able to see that the drivers/devices *seem* to look like they’re wired up in the stack okay (although the TS_II_NDIS driver doesn’t finish installing because of a bug I mention below)…

===============
Debugger Output Start

2: kd> !devobj ts_ii_bus
Device object (8ab182b8) is for: TS_II_BUS \Driver\TS_II_BUS DriverObject 8abcc088
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00002050
Dacl e168c02c DevExt 8ab59c38 DevObjExt 8ab18388
ExtensionFlags (0000000000)
AttachedTo (Lower) 8acc3358 \Driver\PCI
Device queue is not busy.

2: kd> !drvobj ts_ii_bus
Driver object (8abcc088) is for:
\Driver\TS_II_BUS
Driver Extension List: (id , addr)
(b759ce7e 8acb6c00)
Device Object list:
8ab30570 8ab182b8

2: kd> !devobj 8ab30570
Device object (8ab30570) is for: 00000084 \Driver\TS_II_BUS DriverObject 8abcc088
Current Irp 00000000 RefCount 0 Type 00000012 Flags 00003044
Dacl e167353c DevExt 8ac47b90 DevObjExt 8ab30640 DevNode 8ab08768
ExtensionFlags (0x00000010) DOE_START_PENDING
AttachedDevice (Upper) 859b2030 \Driver\TS_II_NDIS
Device queue is not busy.

2: kd> !devstack 8ab30570
!DevObj !DrvObj !DevExt ObjectName
859b2030 \Driver\TS_II_NDIS 859b20e8 {CE0D0129-2523-4FC6-90A5-C0C653540427}

8ab30570 \Driver\TS_II_BUS 8ac47b90 00000084
!DevNode 8ab08768 : DeviceInst is “{9cf7c715-2e6b-48b6-8495-4f1418782ab4}\TsiiNdis\5&22e2d7ff&11”
ServiceName is “TS_II_NDIS”

2: kd> !devobj 8ab182b8
Device object (8ab182b8) is for: TS_II_BUS \Driver\TS_II_BUS DriverObject 8abcc088
Current Irp 00000000 RefCount 0 Type 00000022 Flags 00002050
Dacl e168c02c DevExt 8ab59c38 DevObjExt 8ab18388
ExtensionFlags (0000000000)
AttachedTo (Lower) 8acc3358 \Driver\PCI
Device queue is not busy.

2: kd> !devstack 8ab182b8
!DevObj !DrvObj !DevExt ObjectName

8ab182b8 \Driver\TS_II_BUS 8ab59c38 TS_II_BUS
8acc3358 \Driver\PCI 8acc3410 NTPNP_PCI0028
!DevNode 8acf17e8 : DeviceInst is “PCI\VEN_CAAD&DEV_FEED&SUBSYS_FEEDCAAD&REV_01\4&31e3abfc&0&0048”
ServiceName is “TS_II_BUS”

==============
Debugger Output End

In the TS_II_NDIS miniport driver, in MPInitialize(), I attempt to query the interface, however, here’s where I’m running into problems (and thus the driver crashes and doesn’t finish installing).

From within the MPInitialize() method, I create the Miniport WdfDevice as follows…

NDIS_STATUS
MpIntialize(
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE WrapperConfigurationContext)
{

ntStatus = WdfDeviceMiniportCreate(WdfGetDriver(),
&attribs,
adapter->Fdo,
adapter->NextDeviceObject,
adapter->Pdo,
&adapter->WdfDevice);
if (!NT_SUCCESS (ntStatus))
{
DbgPrint(“WdfDeviceMiniportCreate failed (0x%x)\n”, ntStatus);
ndisStatus = NDIS_STATUS_FAILURE;
break;
}

GetWdfDeviceInfo(adapter->WdfDevice)->Adapter = adapter;

// Get the Adapter Resources & Initialize the hardware.
ndisStatus = NICInitializeAdapter(adapter, WrapperConfigurationContext);
if (ndisStatus != NDIS_STATUS_SUCCESS)
{
ndisStatus = NDIS_STATUS_FAILURE;
break;
}

That part works, and I eventually get to calling GetPCIBusInterfaceStandard() as follows, using adapter->NextDeviceObject, which I assume should represent the TS_II_BUS FDO device:

ntStatus = GetPCIBusInterfaceStandard(adapter->NextDeviceObject,
adapter->tsiiBusNdisInterface);
if (!NT_SUCCESS(ntStatus))
{
DbgPrint(“GetPCIBusInterfaceStandard failed (0x%x)\n”, ntStatus);
ndisStatus = NDIS_STATUS_FAILURE;
break;
}

NTSTATUS
GetPCIBusInterfaceStandard(
IN PDEVICE_OBJECT DeviceObject,
OUT PTSII_BUS_NDIS_INTERFACE tsiiBusNdisInterface)
{
KEVENT pnpEvent;
NTSTATUS status;
PIRP irp;
IO_STATUS_BLOCK ioStatusBlock;
PIO_STACK_LOCATION irpStack;
PDEVICE_OBJECT targetObject;

DbgPrint(“TS_II_NDIS GetPCIBusInterfaceStandard()\n”);

KeInitializeEvent(&pnpEvent, NotificationEvent, FALSE);

// We will want to get the IO target stored in the device object,
// which points to the PDO parent!
targetObject = IoGetAttachedDeviceReference(DeviceObject);

irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
targetObject,
NULL,
0,
NULL,
&pnpEvent,
&ioStatusBlock);

if (irp == NULL)
{
status = STATUS_INSUFFICIENT_RESOURCES;
goto End;
}

irpStack = IoGetNextIrpStackLocation( irp );
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_NDIS_INTERFACE_TSII;
irpStack->Parameters.QueryInterface.Size = sizeof(TSII_BUS_NDIS_INTERFACE);
irpStack->Parameters.QueryInterface.Version = 1;
irpStack->Parameters.QueryInterface.Interface = (PINTERFACE)tsiiBusNdisInterface;
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;

// Initialize the status to error in case the bus driver does not set it correctly.
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;

status = IoCallDriver(targetObject, irp);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject( &pnpEvent, Executive, KernelMode, FALSE, NULL );
status = ioStatusBlock.Status;
}

End:
// Done with reference
ObDereferenceObject( targetObject );
return status;
}

When this method is called, I get an exception (see below) when it reaches the call to IoCallDriver().

TS_II_NDIS DriverEntry()
ts_ii_ndis sample is built with NDIS Version 5.1
TS_II_NDIS DriverEntry built on Dec 3 2009 at 17:27:28
Calling NdisMRegisterMiniport…x
TS_II_NDIS MPInitialize()
NICAllocAdapter()–>
<– NICAllocAdapter
–> NICReadRegParameters()
NdisReadConfiguration for promiscuous key failed
Permanent Address = 02-50-f2-00-01-81
Current Address = 02-50-f2-00-01-81
<– NICReadRegParameters()
–> InitializeAdapter
–> NICInitAdapterWorker 89B84B60
Waiting on the InitEvent…
–> NICAllocRecvResources
–> NICAllocRecvResources 0
Current Address = 00-00-00-00-00-00
<– NICInitAdapterWorker 0
TS_II_NDIS NICPostReadsWorkItemCallBack()
<– InitializeAdapter, Status=0
TS_II_NDIS GetPCIBusInterfaceStandard()

*** Fatal System Error: 0x0000007e
(0xC0000005,0x8053A670,0xB8527500,0xB85271FC)

Break instruction exception - code 80000003 (first chance)

A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.

A fatal system error has occurred.

Connected to Windows XP 2600 x86 compatible target at (Thu Dec 3 17:29:55.794 2009 (GMT-5)), ptr64 FALSE
Loading Kernel Symbols


Loading User Symbols

Loading unloaded module list

*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 7E, {c0000005, 8053a670, b8527500, b85271fc}

*** No owner thread found for resource 8055b4e0
*** No owner thread found for resource 8055b4e0
*** No owner thread found for resource 8055b4e0
*** No owner thread found for resource 8055b4e0
Probably caused by : TSII_NDIS.SYS ( TSII_NDIS!GetPCIBusInterfaceStandard+bd )

Followup: MachineOwner

nt!RtlpBreakWithStatusInstruction:
8052b5ec cc int 3
6: kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

SYSTEM_THREAD_EXCEPTION_NOT_HANDLED (7e)
This is a very common bugcheck. Usually the exception address pinpoints
the driver/function that caused the problem. Always note this address
as well as the link date of the driver/image that contains this address.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 8053a670, The address that the exception occurred at
Arg3: b8527500, Exception Record Address
Arg4: b85271fc, Context Record Address

Debugging Details:

*** No owner thread found for resource 8055b4e0
*** No owner thread found for resource 8055b4e0
*** No owner thread found for resource 8055b4e0
*** No owner thread found for resource 8055b4e0

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

FAULTING_IP:
nt!memcpy+110
8053a670 89448fec mov dword ptr [edi+ecx*4-14h],eax

EXCEPTION_RECORD: b8527500 – (.exr 0xffffffffb8527500)
ExceptionAddress: 8053a670 (nt!memcpy+0x00000110)
ExceptionCode: c0000005 (Access violation)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000001
Parameter[1]: 00000000
Attempt to write to address 00000000

CONTEXT: b85271fc – (.cxr 0xffffffffb85271fc)
eax=00010014 ebx=b8527658 ecx=00000005 edx=00000000 esi=e10eb378 edi=00000000
eip=8053a670 esp=b85275c8 ebp=b85275d0 iopl=0 nv up ei ng nz ac po cy
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010293
nt!memcpy+0x110:
8053a670 89448fec mov dword ptr [edi+ecx*4-14h],eax ds:0023:00000000=???
Resetting default scope

PROCESS_NAME: System

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

EXCEPTION_PARAMETER1: 00000001

EXCEPTION_PARAMETER2: 00000000

WRITE_ADDRESS: 00000000

FOLLOWUP_IP:
TSII_NDIS!GetPCIBusInterfaceStandard+bd [c:\twc\he\thunderstorm\v1.1.0\src\driver\tsii_ndis_driver_project\tsii_ndis_driver_project\sys\tsii_bus_to_ndis_interface.c @ 58]
b84a207d 8945e8 mov dword ptr [ebp-18h],eax

BUGCHECK_STR: 0x7E

DEFAULT_BUCKET_ID: NULL_DEREFERENCE

LOCK_ADDRESS: 8055b560 – (!locks 8055b560)

Resource @ nt!IopDeviceTreeLock (0x8055b560) Shared 1 owning threads
Threads: 8ad143c8-01<*>
1 total locks, 1 locks currently held

PNP_TRIAGE:
Lock address : 0x8055b560
Thread Count : 1
Thread address: 0x8ad143c8
Thread wait : 0xe2d78

LAST_CONTROL_TRANSFER: from 804f8e09 to 8052b5ec

STACK_TEXT:
b85275d0 b38cd23b 00000000 e10eb378 00000014 nt!memcpy+0x110
b852761c b38d0d06 c00000bb b852762f 00000008 wdf01000!FxPkgPnp::HandleQueryInterface+0x114
b8527630 b38cce02 89499048 b8527658 89469c88 wdf01000!FxPkgPdo::_PnpQueryInterface+0x15
b8527650 b38a9a3f 89469c88 b8527678 b38a9c63 wdf01000!FxPkgPnp::Dispatch+0x207
b852765c b38a9c63 895f4f00 89469c88 00000000 wdf01000!FxDevice::Dispatch+0x7f
b8527678 804ef19f 895f4f00 89469c88 89469c88 wdf01000!FxDevice::DispatchWithLock+0x7b
b8527688 b7e11b3e 00000000 8aa399d0 89466ad0 nt!IopfCallDriver+0x31
b85276b8 804ef19f 894669d0 89469c88 b852791c NDIS!ndisPnPDispatch+0x47e
b85276c8 b84a207d b8047600 00000000 b85276d8 nt!IopfCallDriver+0x31
b85276f8 b84a42ca 895f4f00 00000000 89b84b60 TSII_NDIS!GetPCIBusInterfaceStandard+0xbd [c:\twc\he\thunderstorm\v1.1.0\src\driver\tsii_ndis_driver_project\tsii_ndis_driver_project\sys\tsii_bus_to_ndis_interface.c @ 58]
b8527740 b7e12dea b852777c b8527784 b7e0e200 TSII_NDIS!MPInitialize+0x23a [c:\twc\he\thunderstorm\v1.1.0\src\driver\tsii_ndis_driver_project\tsii_ndis_driver_project\sys\tsii_ndis.c @ 292]
b85278f8 b7e129cc 8ab54d40 b852791c b85279c4 NDIS!ndisMInitializeAdapter+0x3b7
b85279cc b7e128ba 8ab54d40 00000000 89b9f410 NDIS!ndisInitializeAdapter+0xb9
b8527a00 b7e13daf 89575108 8aa399d0 89575008 NDIS!ndisPnPStartDevice+0xd6
b8527a30 804ef19f 894669d0 89575008 b8527aac NDIS!ndisPnPDispatch+0x306
b8527a40 80592b63 b8527aac 895f4f00 00000000 nt!IopfCallDriver+0x31
b8527a6c 80592be1 894669d0 b8527a88 00000000 nt!IopSynchronousCall+0xb7
b8527ab0 804f61fa 895f4f00 894610a0 00000001 nt!IopStartDevice+0x4d
b8527acc 8059229b 895f4f00 895f4f01 894610a0 nt!PipProcessStartPhase1+0x4e
b8527d24 805927fa 8aa52478 00000001 00000000 nt!PipProcessDevNodeTree+0x1db
b8527d54 804f699e 00000003 8055b5c0 8056485c nt!PiRestartDevice+0x80
b8527d7c 8053877d 00000000 00000000 8ad143c8 nt!PipDeviceActionWorker+0x168
b8527dac 805cffa0 00000000 00000000 00000000 nt!ExpWorkerThread+0xef
b8527ddc 805460ee 8053868e 00000001 00000000 nt!PspSystemThreadStartup+0x34
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x16

FAULTING_SOURCE_CODE:
54: // Initialize the status to error in case the bus driver does not
55: // set it correctly.
56: irp->IoStatus.Status = STATUS_NOT_SUPPORTED ;
57:

58: status = IoCallDriver(targetObject, irp);
59:
60: if (status == STATUS_PENDING)
61: {
62: KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
63: status = ioStatusBlock.Status;

SYMBOL_STACK_INDEX: 9

SYMBOL_NAME: TSII_NDIS!GetPCIBusInterfaceStandard+bd

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: TSII_NDIS

IMAGE_NAME: TSII_NDIS.SYS

DEBUG_FLR_IMAGE_TIMESTAMP: 4b183b52

STACK_COMMAND: .cxr 0xffffffffb85271fc ; kb

FAILURE_BUCKET_ID: 0x7E_TSII_NDIS!GetPCIBusInterfaceStandard+bd

BUCKET_ID: 0x7E_TSII_NDIS!GetPCIBusInterfaceStandard+bd

Followup: MachineOwner

So, I have a few questions:

1.) Based on this exception, I think that I don’t have something structured right in the stack maybe? It’s like it tried to send the irp to a non existent ioTarget? Could it be that the TSII_BUS_NDIS_INTERFACE wasn’t set up correctly to begin with?

2.) Since the TS_II_BUS driver creates a static child PDO, which I use to install the TS_II_NIDS driver on top of, I assume that the next lower device will be the Default IoTarget, and that I shouldn’t have to create/use a remote IoTarget. Right? Do I maybe need to call WdfDeviceGetIoTarget() in the mp driver, passing in the adapter->WdfDevice?

I have read so many articles on structuring this, that I think I’m confusing myself. :slight_smile: Could someone please offer some clarity, and validate/invalidate my process for wiring up the interface?

Thank you as always! I apologize for the long thread, but I thougt it’d be easier to include all pertinent information from the get-go! :slight_smile:

Jason

> It’s like it tried to send the irp to a non existent ioTarget?
You should check a return value in IoGetAttachedDeviceReference function.

Igor Sharovar

Good point Igor! :slight_smile: Let me see what I find…

xxxxx@gmail.com wrote:

That part works, and I eventually get to calling GetPCIBusInterfaceStandard() as follows, using adapter->NextDeviceObject, which I assume should represent the TS_II_BUS FDO device:

ntStatus = GetPCIBusInterfaceStandard(adapter->NextDeviceObject,
adapter->tsiiBusNdisInterface);

I have a pretty good guess. Because this didn’t generate a compiler
warning, I assume that adapter->tsiiBusNdisInterface is declared as a
PTSII_BUS_NDIS_INTERFACE (that is, a pointer to the interface). I
further assume that you never initialized that pointer. This pointer
then gets copied into the IRP:

irpStack = IoGetNextIrpStackLocation( irp );
irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_NDIS_INTERFACE_TSII;
irpStack->Parameters.QueryInterface.Size = sizeof(TSII_BUS_NDIS_INTERFACE);
irpStack->Parameters.QueryInterface.Version = 1;
irpStack->Parameters.QueryInterface.Interface = (PINTERFACE)tsiiBusNdisInterface;
irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;

So, I’m guessing that Parameters.QueryInterface.Interface is NULL.
Unfortunately, that’s supposed to contain the address of a structure
that the IRP will fill in. I believe that’s where the crash happened,
when it was memcpy’ing the interface information to your structure.

If I’m right, just change your adapter structure so that you have a real
struct, not a pointer:
TSII_BUS_NDIS_INTERFACE tsiiBusNdisInterface;

Then change the top-level call to pass the address of that space:

ntStatus = GetPCIBusInterfaceStandard(adapter->NextDeviceObject,
&adapter->tsiiBusNdisInterface);


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

I think you’re right Tim…That makes a lot of sense.

Thanks buddy!

Jason

Woohoo! LoL That was it Tim! You’re the man…yet again! Thanks again!

Jason