TDI Driver and BSOD on Windows 2008 Server

hi,

i am working on a TDI driver code which just snoop into the stack by calling
IoAttachDeviceToDeviceStackSafe().
the drive works fine on Windows 2000,xp and 2k3.
but when i run it on 2k8 server. it shows BSOD with
“MULTIPLE_IRP_COMPLETE_REQUEST”

here is the code snippet that is causing the problem

//completion routine for open address
static NTSTATUS crOpenAddress(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
{
NTSTATUS status;
snoop_dev_ext_t *dx;
PIO_STACK_LOCATION irps;
k_event_t *evt = (ksnoop_event_t *)ctx;
PMDL mdl = NULL;

if (irp->IoStatus.Status != STATUS_SUCCESS)
goto done;

dx = (dev_ext_t*)dev->DeviceExtension;
InterlockedIncrement(&dx->open_addresses);
irps = IoGetCurrentIrpStackLocation(irp);

mdl = IoAllocateMdl(evt->tai, sizeof(evt->tai), FALSE, FALSE, NULL);
if (!mdl)
goto done;

MmBuildMdlForNonPagedPool(mdl);
TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,
crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);

status = IoCallDriver(dx->dev_lower, evt->qirp);
if (status != STATUS_SUCCESS)
goto done;

mdl = NULL;
evt = NULL;

done:
if (mdl)
IoFreeMdl(mdl);

if (evt)
{
/// the Windbg shows this code fragment problamatic.
IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
snoop_event_free(evt);
///
}

return DoCompletion(dev, irp, NULL);
}

could you show some lights on it?

In absence of any other replies, TdiBuildQueryInformation requires a
completion routine so it is (or at least could be) an async request. In any
case, if the lower level driver returns STATUS_PENDING you are completing
the IRP twice: evt does not become NULL so you call IoCompleteRequests as
well as the lower level driver to which you sent your IRP.

//Daniel

wrote in message news:xxxxx@ntdev…
> hi,
>
> i am working on a TDI driver code which just snoop into the stack by
> calling
> IoAttachDeviceToDeviceStackSafe().
> the drive works fine on Windows 2000,xp and 2k3.
> but when i run it on 2k8 server. it shows BSOD with
> “MULTIPLE_IRP_COMPLETE_REQUEST”
>
> here is the code snippet that is causing the problem
>
> //completion routine for open address
> static NTSTATUS crOpenAddress(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
> {
> NTSTATUS status;
> snoop_dev_ext_t *dx;
> PIO_STACK_LOCATION irps;
> k_event_t *evt = (ksnoop_event_t )ctx;
> PMDL mdl = NULL;
>
> if (irp->IoStatus.Status != STATUS_SUCCESS)
> goto done;
>
> dx = (dev_ext_t
)dev->DeviceExtension;
> InterlockedIncrement(&dx->open_addresses);
> irps = IoGetCurrentIrpStackLocation(irp);
>
> mdl = IoAllocateMdl(evt->tai, sizeof(evt->tai), FALSE, FALSE, NULL);
> if (!mdl)
> goto done;
>
> MmBuildMdlForNonPagedPool(mdl);
> TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,
> crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);
>
> status = IoCallDriver(dx->dev_lower, evt->qirp);
> if (status != STATUS_SUCCESS)
> goto done;
>
> mdl = NULL;
> evt = NULL;
>
> done:
> if (mdl)
> IoFreeMdl(mdl);
>
> if (evt)
> {
> /// the Windbg shows this code fragment problamatic.
> IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
> snoop_event_free(evt);
> ///
> }
>
> return DoCompletion(dev, irp, NULL);
> }
>
> could you show some lights on it?
>
>
>

Where is your check for handling SL_PENDING_RETURNED?

if (Irp->PendingReturned) {
IoMarkIrpPending( Irp );
}

Is that in DoCompletion () somewhere?

Go back and re-read (or read for the first time) the NT Insider articles and
WHDC white papers on IRP handling and pay special attention to how filter
drivers participate in IRP completion by consuming an IO_STACK_LOCATION.
Make sure you have it all just right.

Now the answer to why you are getting that bugcheck:

Just because your driver happened to skate by not playing by the rules in
NT5 where TCPIP.SYS completes this (and many other) requests synchronously
does not mean it was ‘working’ correctly.

In NT6 when TDI became an ‘emulation’ layer (TDX) many of these IRPs now get
completed asynchronously and so TDI filter authors whom did not deal with
that correctly (the possibility that IoCallDriver() will return
STATUS_PENDING) got a big wake-up call.

“Works” is not the same as “follows the rules”.

So the clue is that your error is exactly what the system is telling you.
Your driver is causing the IRP to be completed twice. This is because (if
you had checked) IoCallDriver() is returning STATUS_PENDING when you call to
TDI_QUERY_ADDRESS_INFO. STATUS_PENDING is not a failure. Sure, it is not
STATUS_SUCCESS but it is *not* a failure. You then go on to complete
TDI_QUERY_ADDRESS_INFO Irp either before TDX.SYS does or after (probably
after) and kaboom. The system complains.

STATUS_PENDING - it is important.

Good Luck,
Dave Cattley
Consulting Engineer
Systems Software Development

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.co.in
Sent: Tuesday, March 03, 2009 5:22 AM
To: Windows System Software Devs Interest List
Subject: [ntdev] TDI Driver and BSOD on Windows 2008 Server

hi,

i am working on a TDI driver code which just snoop into the stack by calling

IoAttachDeviceToDeviceStackSafe().
the drive works fine on Windows 2000,xp and 2k3.
but when i run it on 2k8 server. it shows BSOD with
“MULTIPLE_IRP_COMPLETE_REQUEST”

here is the code snippet that is causing the problem

//completion routine for open address
static NTSTATUS crOpenAddress(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
{
NTSTATUS status;
snoop_dev_ext_t *dx;
PIO_STACK_LOCATION irps;
k_event_t *evt = (ksnoop_event_t *)ctx;
PMDL mdl = NULL;

if (irp->IoStatus.Status != STATUS_SUCCESS)
goto done;

dx = (dev_ext_t*)dev->DeviceExtension;
InterlockedIncrement(&dx->open_addresses);
irps = IoGetCurrentIrpStackLocation(irp);

mdl = IoAllocateMdl(evt->tai, sizeof(evt->tai), FALSE, FALSE, NULL);
if (!mdl)
goto done;

MmBuildMdlForNonPagedPool(mdl);
TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,

crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);

status = IoCallDriver(dx->dev_lower, evt->qirp);
if (status != STATUS_SUCCESS)
goto done;

mdl = NULL;
evt = NULL;

done:
if (mdl)
IoFreeMdl(mdl);

if (evt)
{
/// the Windbg shows this code fragment problamatic.
IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
snoop_event_free(evt);
///
}

return DoCompletion(dev, irp, NULL);
}

could you show some lights on it?


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

Just my five cents to comments posted here. I see you are trying to get
address information of address and connection objects. Be ready that it
might fail, i.e., the IoCallDriver returns STATUS_SUCCESS but the data in
address structure is zeroes.

From what I saw, usually the IP is 0 for address objects (UDP) because stack
pick ups local address at lower level, not in TDI.


Volodymyr M. Shcherbyna, blog: http://www.shcherbyna.com/
(This posting is provided “AS IS” with no warranties, and confers no
rights)

wrote in message news:xxxxx@ntdev…
> hi,
>
> i am working on a TDI driver code which just snoop into the stack by
> calling
> IoAttachDeviceToDeviceStackSafe().
> the drive works fine on Windows 2000,xp and 2k3.
> but when i run it on 2k8 server. it shows BSOD with
> “MULTIPLE_IRP_COMPLETE_REQUEST”
>
> here is the code snippet that is causing the problem
>
> //completion routine for open address
> static NTSTATUS crOpenAddress(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
> {
> NTSTATUS status;
> snoop_dev_ext_t *dx;
> PIO_STACK_LOCATION irps;
> k_event_t *evt = (ksnoop_event_t )ctx;
> PMDL mdl = NULL;
>
> if (irp->IoStatus.Status != STATUS_SUCCESS)
> goto done;
>
> dx = (dev_ext_t
)dev->DeviceExtension;
> InterlockedIncrement(&dx->open_addresses);
> irps = IoGetCurrentIrpStackLocation(irp);
>
> mdl = IoAllocateMdl(evt->tai, sizeof(evt->tai), FALSE, FALSE, NULL);
> if (!mdl)
> goto done;
>
> MmBuildMdlForNonPagedPool(mdl);
> TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,
> crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);
>
> status = IoCallDriver(dx->dev_lower, evt->qirp);
> if (status != STATUS_SUCCESS)
> goto done;
>
> mdl = NULL;
> evt = NULL;
>
> done:
> if (mdl)
> IoFreeMdl(mdl);
>
> if (evt)
> {
> /// the Windbg shows this code fragment problamatic.
> IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
> snoop_event_free(evt);
> ///
> }
>
> return DoCompletion(dev, irp, NULL);
> }
>
> could you show some lights on it?
>
>
>

hello,

thanks David R. Cattley.

i took time to understand it and tried to come up with some solution.

here is the code that was in the DoCompletion() it does take care of Making IRP pending if pending returned flag is true.

NTSTATUS DoCompletion(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
{
LONG detaching, pending_io;
snoop_dev_ext_t *dx = (snoop_dev_ext_t *)dev->DeviceExtension;

if (irp->PendingReturned)
IoMarkIrpPending(irp);
return STATUS_SUCCESS;
}
so SL_PENDING_RETURNED issue is not present.

to resolve this. i created a KEVENT object and after passing the driver for next lower level driver i wait upon that event if i get the STATUS_PENDING.

NTSTATUS status;
snoop_dev_ext_t *dx;
PIO_STACK_LOCATION irps;
KEVENT kEvent;
IO_STATUS_BLOCK io_status_block;
BOOLEAN bWait = FALSE;
ksnoop_event_t *evt = (ksnoop_event_t *)ctx;
PMDL mdl = NULL;

if (irp->IoStatus.Status != STATUS_SUCCESS)
goto done;

dx = (snoop_dev_ext_t*)dev->DeviceExtension;
InterlockedIncrement(&dx->open_addresses);
irps = IoGetCurrentIrpStackLocation(irp);

mdl = IoAllocateMdl(evt->tai, sizeof(evt->tai), FALSE, FALSE, NULL);
if (!mdl)
goto done;

if ( KeGetCurrentIrql() <= DISPATCH_LEVEL )
{
KeInitializeEvent ( &kEvent, NotificationEvent, FALSE );
evt->qirp->UserEvent = &kEvent;
evt->qirp->UserIosb = &io_status_block;
bWait = TRUE;
}

MmBuildMdlForNonPagedPool(mdl);
TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,
crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);

status = IoCallDriver(dx->dev_lower, evt->qirp);

if(( bWait == TRUE) && status == STATUS_PENDING )
{
KeWaitForSingleObject( (PVOID)&kEvent, Executive, KernelMode, TRUE, NULL );
status = io_status_block.Status;

return DoCompletion(dev, irp, NULL);
}
else if (status != STATUS_SUCCESS )
goto done;

mdl = NULL;
evt = NULL;

done:
if (mdl)
IoFreeMdl(mdl);

if (evt)
{
IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
snoop_event_free(evt);
}

return DoCompletion(dev, irp, NULL);

}

after adding this i did not get any blue screen. but as you told working does’t mean correct. :slight_smile:

is there any thing wrong with respect to the guide-line?

sorry if i am wrong :0. i am trying my best.

regards
deep

AFAIK, waiting in a IRP Completion Routine is illegal. The call contract is
that the routine runs at IRQL <= DISPATCH_LEVEL.

You should not assume that under all conditions (and other possible TDI
filters) that the completion process can ‘wait’ like this.

Would it not be better to:

  1. Issue the IRP with the query address.
  2. Return STATUS_MORE_PROCESSING_REQUIRED from the “connect” CRTN to stop
    completion processing.
  3. In the CRTN for the “query address” call IoCompleteRequest() on the
    “connect” IRP to continue the completion processing.

Or something like that?

Or if you don’t actually *need* the local address to decide how to complete
the connect IRP then just let the query IRP complete asynchronously and
cleanup the query IRP in its CRTN.

Since I don’t actually know that your driver needs to do, I am just
guessing. But it seems you wish to know the full IP address and port on
both ends of a TCP connection, perhaps to make some policy decision.

Good Luck,
Dave Cattley
Consulting Engineer
Systems Software Developement

-----Original Message-----
From: xxxxx@lists.osr.com
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@yahoo.co.in
Sent: Monday, March 09, 2009 8:09 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] TDI Driver and BSOD on Windows 2008 Server

hello,

thanks David R. Cattley.

i took time to understand it and tried to come up with some solution.

here is the code that was in the DoCompletion() it does take care of Making
IRP pending if pending returned flag is true.

NTSTATUS DoCompletion(PDEVICE_OBJECT dev, PIRP irp, PVOID ctx)
{
LONG detaching, pending_io;
snoop_dev_ext_t *dx = (snoop_dev_ext_t *)dev->DeviceExtension;

if (irp->PendingReturned)
IoMarkIrpPending(irp);
return STATUS_SUCCESS;
}
so SL_PENDING_RETURNED issue is not present.

to resolve this. i created a KEVENT object and after passing the driver for
next lower level driver i wait upon that event if i get the STATUS_PENDING.

NTSTATUS status;
snoop_dev_ext_t *dx;
PIO_STACK_LOCATION irps;
KEVENT kEvent;
IO_STATUS_BLOCK io_status_block;
BOOLEAN bWait = FALSE;
ksnoop_event_t *evt = (ksnoop_event_t *)ctx;
PMDL mdl = NULL;

if (irp->IoStatus.Status != STATUS_SUCCESS)
goto done;

dx = (snoop_dev_ext_t*)dev->DeviceExtension;
InterlockedIncrement(&dx->open_addresses);
irps = IoGetCurrentIrpStackLocation(irp);

mdl = IoAllocateMdl(evt->tai, sizeof(evt->tai), FALSE, FALSE, NULL);
if (!mdl)
goto done;

if ( KeGetCurrentIrql() <= DISPATCH_LEVEL )
{
KeInitializeEvent ( &kEvent, NotificationEvent, FALSE );
evt->qirp->UserEvent = &kEvent;
evt->qirp->UserIosb = &io_status_block;
bWait = TRUE;
}

MmBuildMdlForNonPagedPool(mdl);
TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,

crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);

status = IoCallDriver(dx->dev_lower, evt->qirp);

if(( bWait == TRUE) && status == STATUS_PENDING )
{
KeWaitForSingleObject( (PVOID)&kEvent, Executive,
KernelMode, TRUE, NULL );
status = io_status_block.Status;

return DoCompletion(dev, irp, NULL);
}
else if (status != STATUS_SUCCESS )
goto done;

mdl = NULL;
evt = NULL;

done:
if (mdl)
IoFreeMdl(mdl);

if (evt)
{
IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
snoop_event_free(evt);
}

return DoCompletion(dev, irp, NULL);

}

after adding this i did not get any blue screen. but as you told working
does’t mean correct. :slight_smile:

is there any thing wrong with respect to the guide-line?

sorry if i am wrong :0. i am trying my best.

regards
deep


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer

here is the flow of my program

(1) I get a Open address Request in my dispatch routine of my driver.

a. i setup a intenal IRP with this function call since caller should be at PASSIVE_LEVEL
TdiBuildInternalDeviceControlIrp()
b. i setup a completion routine in the address_Request IRP with context having “My newly Created IRP”
*cr = crOpenAddress;
*ctx = evt; //evt-> contains the IRP
c in the completion routine of “crOpenAddress”. i make call to this function.
TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,
crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);

presnetly i am not doing any thing with the Connection.
i am just using the OpenAddress and CleanupAddress to keep track of request.
as you said that CL should not wait as they may be called at IRQL <= DISPATCH. so KeWaitforsingleObject() will not work.
how i understood your suggestion is as follows.

//in the completion routine for TdiBuildQueryInformation. I will do some things like this
{
if (irp->MdlAddress)
{
IoFreeMdl(irp->MdlAddress);
irp->MdlAddress = NULL;
}
//Save My Events
return STATUS_MORE_PROCESSING_REQUIRED; // this will cause IO manager to stop the completion process and the control will return to the caller.
}

things i have understood so far is
a CLR should not mark IRP pending if it returns the STATUS_MORE_PROCESSING_REQUIRED. as that call will be modifing randon chuncks and the IoConpleteRequest() will not propagate to upper driver. it will just return to the caller.

//in the completion routine of “crOpenAddress”


status = IoCallDriver(dx->dev_lower, evt->qirp);
if ( status != STATUS_PENDING && (status != STATUS_SUCCESS) )
goto done;
else
{
IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
return DoCompletion(dev, irp, NULL);
}
mdl = NULL;
evt = NULL;
done:
if (mdl)
IoFreeMdl(mdl);
if (evt)
{
IoCompleteRequest(evt->qirp, IO_NO_INCREMENT);
snoop_event_free(evt);
}
return DoCompletion(dev, irp, NULL);
}

this code does not use wait. It should be fine at any IRQL.
or there are any other things that i must take care of :frowning:
is it what you want to say?

regards
Deep

Volodymyr

you are right. i am getting the 0.0.0.0 in the address in the above code.
could you please tell me how should i get the address information.

regards
Deep

hello,

i found this link
http://www.eggheadcafe.com/software/aspnet/31189440/how-to-get-correct-source.aspx

which says that

“Solution would to query TDI_QUERY_ADDRESS_INFO AFTER the connection was
initiated. …”

here is my efforts for it.

in the driver entry :
name=>L"\Device\Tcp"
name=>L"\Device\udp"

RtlInitUnicodeString(&s, name);
status = IoGetDeviceObjectPointer(&s, FILE_ALL_ACCESS, &fo_target, &dev_target);


IoAttachDeviceToDeviceStackSafe(*dev, dx->dev_target, &dx->dev_lower);

now if i get “IRP_MJ_CREATE” then i do like this

if (irps->MajorFunction == IRP_MJ_CREATE)
{
PFILE_FULL_EA_INFORMATION ea = (PFILE_FULL_EA_INFORMATION)irp->AssociatedIrp.SystemBuffer;

if (eaIsAddress(ea))
*cr = crOpenAddress;
if (eaIsConnection(ea))
return onOpenConnection(irp, irps, cr, ctx);

if (eaIsControlChannel(ea))
*cr = crOpenControlChannel;
}

in the “onOpenConnection”

i created the IRP and set the completion routine for “OpenConnection”

evt->qirp = TdiBuildInternalDeviceControlIrp(TDI_QUERY_INFORMATION,
dx->dev_lower, irps->FileObject, NULL, NULL);
*cr = crOpenConnection;
*ctx = evt;

now in the completion routine, i query like this…

TdiBuildQueryInformation(evt->qirp, dx->dev_lower, irps->FileObject,
crQueryAddressInfo, evt, TDI_QUERY_ADDRESS_INFO, mdl);
status = IoCallDriver(dx->dev_lower, evt->qirp);

but the IoCallDriver(). fails. and status is

“STATUS_ADDRESS_NOT_ASSOCIATED” which means that no address is associated with it.
i searched for it and found that i need to associate address with this end point.

i found a article in codeproject.com
http://www.codeproject.com/KB/system/driverdev4asp.aspx
which explains how to associate the connection end point to the address by calling

TdiBuildAssociateAddress()

it requires a handle as a last parameter, retrieved by ZwCreateFile(). how do i get this handle since i am not using ZwCreateFile?

any help!! i am clueless, and do not know how to proceed.

regards