NDIS Immediate driver crashed!

lpsimd is a NDIS immediate filter driver that we have developed. My computer would crashed occasionally, I have dragged the minidump file into Windbg for analyzing and the result is as follow. I still can’t figure out what’s wrong with my driver and how to fix the blue screen problem.

I have searched the problem for several days, there is only one article that has described a similar problem. But it doesn’t mention the solving method.
http://blogs.msdn.com/b/ntdebugging/archive/2008/09/30/ndis-case-study-1-ndis-packet-double-completion.aspx

kd> !analyze -v
*******************************************************************************
* *
* Bugcheck Analysis *
* *
*******************************************************************************

DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
An attempt was made to access a pageable (or completely invalid) address at an
interrupt request level (IRQL) that is too high. This is usually
caused by drivers using improper addresses.
If kernel debugger is available get stack backtrace.
Arguments:
Arg1: 00000008, memory referenced
Arg2: 00000002, IRQL
Arg3: 00000000, value 0 = read operation, 1 = write operation
Arg4: 89ef1d00, address which referenced memory

Debugging Details:

READ_ADDRESS: GetPointerFromAddress: unable to read from 83f88718
Unable to read MiSystemVaType memory at 83f681a0
00000008

CURRENT_IRQL: 2

FAULTING_IP:
ndis!ndisMSendCompleteX+a2
89ef1d00 8b4808 mov ecx,dword ptr [eax+8]

CUSTOMER_CRASH_COUNT: 1

DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

BUGCHECK_STR: 0xD1

PROCESS_NAME: System

TRAP_FRAME: 8d33884c – (.trap 0xffffffff8d33884c)
ErrCode = 00000000
eax=00000000 ebx=00000000 ecx=00000002 edx=00000011 esi=876550e0 edi=86dfcd84
eip=89ef1d00 esp=8d3388c0 ebp=8d3388d4 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010246
ndis!ndisMSendCompleteX+0xa2:
89ef1d00 8b4808 mov ecx,dword ptr [eax+8] ds:0023:00000008=???
Resetting default scope

LAST_CONTROL_TRANSFER: from 89ef1d00 to 83e5f5cb

STACK_TEXT:
8d33884c 89ef1d00 badb0d00 00000011 880c81e8 nt!KiTrap0E+0x2cf
8d3388d4 917ddc90 026550e0 86dfcd84 00000000 ndis!ndisMSendCompleteX+0xa2
8d3388f4 89ef1fd6 87852008 87853ebc 00000000 lpsimd!PtSendComplete+0x4c [d:\build\src\lps\imd\protocol.c @ 1139]
8d338914 89ef1e9e 87851008 87853ebc 00000000 ndis!ndisMSendPacketCompleteToOpen+0xeb
8d338938 916e02c9 004090e0 87853ebc 00000000 ndis!ndisMSendCompleteX+0x240
WARNING: Stack unwind information not available. Following frames may be wrong.
8d338958 89ef3505 00000000 8d3389d8 00000001 Epfwndis+0x12c9
8d338980 89ef16f2 8d3389dc 8d3389d8 00000001 ndis!ndisMSendPacketsXToMiniport+0x142
8d3389b8 89ef33b5 87851008 8d3389d8 00000001 ndis!ndisMSendPackets+0x1b4
8d3389cc 89ef444c 87851008 87853ebc 8d338a0c ndis!ndisMSend+0x13
8d3389dc 917dc1d4 8d338a00 87851008 87853ebc ndis!NdisSend+0xf
8d338a0c 89ef3505 87852008 8d338a54 00000001 lpsimd!MPSendPackets+0x1d4 [d:\build\src\lps\imd\miniport.c @ 672]
8d338a34 89ef332a 8d338a58 8d338a54 00000001 ndis!ndisMSendPacketsXToMiniport+0x142
8d338a9c 89e8b4d8 876550e0 8669d328 00000000 ndis!ndisMSendNetBufferListsToPackets+0x84
8d338abc 89e8b448 8669d328 8669d328 00000000 ndis!ndisFilterSendNetBufferLists+0x87
8d338ad4 9180ac20 878dd498 8669d328 00000000 ndis!NdisFSendNetBufferLists+0x38
8d338b50 89e8b618 878eb468 8669d328 00000000 pacer!PcFilterSendNetBufferLists+0x256
8d338b7c 89eefbad 876550e0 8669d328 00000000 ndis!ndisSendNBLToFilter+0xf2
8d338bac 8a0ac218 8790a008 8669d328 00000000 ndis!NdisSendNetBufferLists+0x162
8d338bf4 8a0b1f1b 8790b578 00000000 00000806 tcpip!FlpSendPacketsHelper+0x3f6
8d338c30 8a0a9be2 8669d328 878c20ac 879140b0 tcpip!Fl48pSendArpPacket+0x116
8d338c50 8a0b4082 8d338c64 879140b0 878d6578 tcpip!Fl48SendNeighborSolicitation+0x1d
8d338c78 8a08de18 00000000 8790c7a8 878d6578 tcpip!Ipv4pSendNeighborSolicitation+0x67
8d338cb0 8a095fb7 00000000 8a112da0 878c70a4 tcpip!IppSendNeighborSolicitation+0x98
8d338cec 84033460 86dfbc78 00000000 860d8a70 tcpip!IppNeighborSolicitationWorker+0xd9
8d338d00 83e9baab 86e271b8 00000000 860d8a70 nt!IopProcessWorkItem+0x23
8d338d50 84027f5e 00000001 91040f3f 00000000 nt!ExpWorkerThread+0x10d
8d338d90 83ecf219 83e9b99e 00000001 00000000 nt!PspSystemThreadStartup+0x9e
00000000 00000000 00000000 00000000 00000000 nt!KiThreadStartup+0x19

STACK_COMMAND: kb

FOLLOWUP_IP:
lpsimd!PtSendComplete+4c [d:\build\src\lps\imd\protocol.c @ 1139]
917ddc90 ?? ???

FAULTING_SOURCE_CODE:
1135: NdisMSendComplete(pAdapt->MiniportHandle,
1136: Pkt,
1137: Status);
1138: }

1139: else
1140: {
1141: PIRP pIrp = SendRsvd->pIrp;
1142: PIO_STACK_LOCATION pIrpSp;
1143: if( pIrp != NULL )
1144: {

SYMBOL_STACK_INDEX: 2

SYMBOL_NAME: lpsimd!PtSendComplete+4c

FOLLOWUP_NAME: MachineOwner

MODULE_NAME: lpsimd

IMAGE_NAME: lpsimd.sys

DEBUG_FLR_IMAGE_TIMESTAMP: 4d9138dc

FAILURE_BUCKET_ID: 0xD1_lpsimd!PtSendComplete+4c

BUCKET_ID: 0xD1_lpsimd!PtSendComplete+4c

Followup: MachineOwner

Obviously the function ndis!ndisMSendCompleteX have intentionally raise a null-point reference.
Here is the position that blue screen takes place:

89ef1cfe 33c0 xor eax,eax
89ef1d00 8b4808 mov ecx,dword ptr [eax+8]

Hah, I did a double-take on reading that bit of assembly. But it’s actually an intentional failure designed to catch a problem with the packet stack. I’m not quite sure what you think is missing from the Ntdebugging blog article on this topic – it looks like it is an uncanny match for your problem. You can follow their procedure to check for the “6COM” tag in NDIS’s reserved area to confirm.

One way this can happen is if your packet pool has already been free’d. That will trash all the packets in it, so SendRsvd->OriginalPacket points to garbage. Check if your adapter is being halted, and if its packet pool is still registered (see if it’s listed in !ndiskd.pktpools).

If that’s the problem, then you should diff your code against the latest WDK. We fixed a PASSTHRU bug in that area back around… let’s see… 2002. The bugfix adds a “ADAPT_DECR_PENDING_SENDS(pAdapt);” to that function.

Hi, Jeffrey! Thanks very much for your quick reply!
I have followed the article to check the packet and don’t find the “6COM” tag at all.
Here is the code snippet of my driver:

VOID
PtSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status
)
/*++

Routine Description:

Called by NDIS when the miniport below had completed a send. We should
complete the corresponding upper-edge send this represents.

Arguments:

ProtocolBindingContext - Points to ADAPT structure
Packet - Low level packet being completed
Status - status of send

Return Value:

None

–*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
PNDIS_PACKET Pkt;
NDIS_HANDLE PoolHandle;

#ifdef NDIS51
//
// Packet stacking:
//
// Determine if the packet we are completing is the one we allocated. If so, then
// get the original packet from the reserved area and completed it and free the
// allocated packet. If this is the packet that was sent down to us, then just
// complete it
//
PoolHandle = NdisGetPoolFromPacket(Packet);
if (PoolHandle != pAdapt->SendPacketPoolHandle)
{
//
// We had passed down a packet belonging to the protocol above us.
//
// DBGPRINT((“PtSendComp: Adapt %p, Stacked Packet %p\n”, pAdapt, Packet));

NdisMSendComplete(pAdapt->MiniportHandle,
Packet,
Status);
}
else
#endif // NDIS51
{
PSEND_RSVD SendRsvd;

SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
Pkt = SendRsvd->OriginalPkt;
if ( NULL != Pkt )
{

#ifndef WIN9X
NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
#endif

NdisDprFreePacket(Packet);

NdisMSendComplete(pAdapt->MiniportHandle,
Pkt,
Status);
}
else
{

}
}
}

Judging from the code, SendRsvd->OriginalPacket is not NULL pointer. What’s more, NdisIMCopySendCompletePerPacketInfo has copied the function parameter: Packet to Pkt. So Pkt should be allocated and is valid memory. Is it right?

I have also checked all occurrences of “ADAPT_DECR_PENDING_SENDS(pAdapt)” and “OutstandingSends” string in DDK sample, the “OutstandingSends” variable is only referenced in the function PtPnPNetEventSetPower, it seems to have nothing with PtSendComplete and MPSend routines.

Pkt can be freed memory, even if it’s still accessible. The memory can be reused, in which case the contents of the memory are written over with something else. In your crash, NDIS is trying to read the location of the packet stack from its private area on the packet, but it has gotten some invalid data back. The case in the Ntdebugging blog was caused by double-completion. Internally, we’ve seen others caused by freeing the packet pool because the datapath isn’t synchronized with the control path.

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@sohu.com
Sent: Thursday, April 14, 2011 7:51 PM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] NDIS Immediate driver crashed!

Hi, Jeffrey! Thanks very much for your quick reply!
I have followed the article to check the packet and don’t find the “6COM” tag at all.
Here is the code snippet of my driver:

VOID
PtSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET Packet,
IN NDIS_STATUS Status
)
/*++

Routine Description:

Called by NDIS when the miniport below had completed a send. We should
complete the corresponding upper-edge send this represents.

Arguments:

ProtocolBindingContext - Points to ADAPT structure
Packet - Low level packet being completed
Status - status of send

Return Value:

None

–*/
{
PADAPT pAdapt =(PADAPT)ProtocolBindingContext;
PNDIS_PACKET Pkt;
NDIS_HANDLE PoolHandle;

#ifdef NDIS51
//
// Packet stacking:
//
// Determine if the packet we are completing is the one we allocated. If so, then
// get the original packet from the reserved area and completed it and free the
// allocated packet. If this is the packet that was sent down to us, then just
// complete it
//
PoolHandle = NdisGetPoolFromPacket(Packet);
if (PoolHandle != pAdapt->SendPacketPoolHandle)
{
//
// We had passed down a packet belonging to the protocol above us.
//
// DBGPRINT((“PtSendComp: Adapt %p, Stacked Packet %p\n”, pAdapt, Packet));

NdisMSendComplete(pAdapt->MiniportHandle,
Packet,
Status);
}
else
#endif // NDIS51
{
PSEND_RSVD SendRsvd;

SendRsvd = (PSEND_RSVD)(Packet->ProtocolReserved);
Pkt = SendRsvd->OriginalPkt;
if ( NULL != Pkt )
{

#ifndef WIN9X
NdisIMCopySendCompletePerPacketInfo (Pkt, Packet);
#endif

NdisDprFreePacket(Packet);

NdisMSendComplete(pAdapt->MiniportHandle,
Pkt,
Status);
}
else
{

}
}
}

Judging from the code, SendRsvd->OriginalPacket is not NULL pointer. What’s more, NdisIMCopySendCompletePerPacketInfo has copied the function parameter: Packet to Pkt. So Pkt should be allocated and is valid memory. Is it right?

I have also checked all occurrences of “ADAPT_DECR_PENDING_SENDS(pAdapt)” and “OutstandingSends” string in DDK sample, the “OutstandingSends” variable is only referenced in the function PtPnPNetEventSetPower, it seems to have nothing with PtSendComplete and MPSend routines.


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