mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 12:26:09 +00:00
Added double complete protection so that we never call an upper-level
completion routine more than once for the same packet. This alleviates a bug i observe with the realtek 8139, as reported by gge. Define BREAK_ON_DOUBLE_COMPLETE to get a bugcheck if a send completion handler would be called more than once. This define is intended to help us determine if the actual bug is in our ndis. svn path=/trunk/; revision=12031
This commit is contained in:
parent
aeee5da01c
commit
2dc5f4df19
1 changed files with 115 additions and 10 deletions
|
@ -10,6 +10,31 @@
|
||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
|
/* Define this to bugcheck on double complete */
|
||||||
|
/* #define BREAK_ON_DOUBLE_COMPLETE */
|
||||||
|
|
||||||
|
UINT TransferDataCalled = 0;
|
||||||
|
UINT TransferDataCompleteCalled = 0;
|
||||||
|
UINT LanReceiveWorkerCalled = 0;
|
||||||
|
|
||||||
|
#define NGFP(_Packet) \
|
||||||
|
{ \
|
||||||
|
PVOID _Header; \
|
||||||
|
ULONG _ContigSize, _TotalSize; \
|
||||||
|
PNDIS_BUFFER _NdisBuffer; \
|
||||||
|
\
|
||||||
|
TI_DbgPrint(MID_TRACE,("Checking Packet %x\n", _Packet)); \
|
||||||
|
NdisGetFirstBufferFromPacket(_Packet, \
|
||||||
|
&_NdisBuffer, \
|
||||||
|
&_Header, \
|
||||||
|
&_ContigSize, \
|
||||||
|
&_TotalSize); \
|
||||||
|
TI_DbgPrint(MID_TRACE,("NdisBuffer: %x\n", _NdisBuffer)); \
|
||||||
|
TI_DbgPrint(MID_TRACE,("Header : %x\n", _Header)); \
|
||||||
|
TI_DbgPrint(MID_TRACE,("ContigSize: %x\n", _ContigSize)); \
|
||||||
|
TI_DbgPrint(MID_TRACE,("TotalSize : %x\n", _TotalSize)); \
|
||||||
|
}
|
||||||
|
|
||||||
typedef struct _LAN_WQ_ITEM {
|
typedef struct _LAN_WQ_ITEM {
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
PNDIS_PACKET Packet;
|
PNDIS_PACKET Packet;
|
||||||
|
@ -27,6 +52,54 @@ KSPIN_LOCK LanWorkLock;
|
||||||
LIST_ENTRY LanWorkList;
|
LIST_ENTRY LanWorkList;
|
||||||
WORK_QUEUE_ITEM LanWorkItem;
|
WORK_QUEUE_ITEM LanWorkItem;
|
||||||
|
|
||||||
|
/* Double complete protection */
|
||||||
|
KSPIN_LOCK LanSendCompleteLock;
|
||||||
|
LIST_ENTRY LanSendCompleteList;
|
||||||
|
|
||||||
|
VOID LanChainCompletion( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
|
||||||
|
PLAN_WQ_ITEM PendingCompletion =
|
||||||
|
ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
|
||||||
|
|
||||||
|
if( !PendingCompletion ) return;
|
||||||
|
|
||||||
|
PendingCompletion->Packet = NdisPacket;
|
||||||
|
PendingCompletion->Adapter = Adapter;
|
||||||
|
|
||||||
|
ExInterlockedInsertTailList( &LanSendCompleteList,
|
||||||
|
&PendingCompletion->ListEntry,
|
||||||
|
&LanSendCompleteLock );
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOLEAN LanShouldComplete( PLAN_ADAPTER Adapter, PNDIS_PACKET NdisPacket ) {
|
||||||
|
PLIST_ENTRY ListEntry;
|
||||||
|
PLAN_WQ_ITEM CompleteEntry;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
|
||||||
|
for( ListEntry = LanSendCompleteList.Flink;
|
||||||
|
ListEntry != &LanSendCompleteList;
|
||||||
|
ListEntry = ListEntry->Flink ) {
|
||||||
|
CompleteEntry = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
|
||||||
|
|
||||||
|
if( CompleteEntry->Adapter == Adapter &&
|
||||||
|
CompleteEntry->Packet == NdisPacket ) {
|
||||||
|
RemoveEntryList( ListEntry );
|
||||||
|
KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
|
||||||
|
ExFreePool( CompleteEntry );
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
|
||||||
|
|
||||||
|
TI_DbgPrint(MID_TRACE,("NDIS completed the same send packet twice "
|
||||||
|
"(Adapter %x Packet %x)!!\n", Adapter, NdisPacket));
|
||||||
|
#ifdef BREAK_ON_DOUBLE_COMPLETE
|
||||||
|
KeBugCheck(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
NDIS_STATUS NDISCall(
|
NDIS_STATUS NDISCall(
|
||||||
PLAN_ADAPTER Adapter,
|
PLAN_ADAPTER Adapter,
|
||||||
NDIS_REQUEST_TYPE Type,
|
NDIS_REQUEST_TYPE Type,
|
||||||
|
@ -181,11 +254,13 @@ VOID STDCALL ProtocolSendComplete(
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
|
TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
|
||||||
ASSERT_KM_POINTER(Packet);
|
if( LanShouldComplete( (PLAN_ADAPTER)BindingContext, Packet ) ) {
|
||||||
ASSERT_KM_POINTER(PC(Packet));
|
ASSERT_KM_POINTER(Packet);
|
||||||
ASSERT_KM_POINTER(PC(Packet)->DLComplete);
|
ASSERT_KM_POINTER(PC(Packet));
|
||||||
(*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
|
ASSERT_KM_POINTER(PC(Packet)->DLComplete);
|
||||||
TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
|
(*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
|
||||||
|
TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID STDCALL LanReceiveWorker( PVOID Context ) {
|
VOID STDCALL LanReceiveWorker( PVOID Context ) {
|
||||||
|
@ -198,12 +273,14 @@ VOID STDCALL LanReceiveWorker( PVOID Context ) {
|
||||||
PNDIS_BUFFER NdisBuffer;
|
PNDIS_BUFFER NdisBuffer;
|
||||||
IP_PACKET IPPacket;
|
IP_PACKET IPPacket;
|
||||||
|
|
||||||
|
|
||||||
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
|
TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
|
||||||
|
|
||||||
while( (ListEntry =
|
while( (ListEntry =
|
||||||
ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
|
ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
|
||||||
WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
|
WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
|
||||||
|
|
||||||
|
LanReceiveWorkerCalled++;
|
||||||
|
ASSERT(LanReceiveWorkerCalled <= TransferDataCompleteCalled);
|
||||||
|
|
||||||
Packet = WorkItem->Packet;
|
Packet = WorkItem->Packet;
|
||||||
Adapter = WorkItem->Adapter;
|
Adapter = WorkItem->Adapter;
|
||||||
|
@ -273,14 +350,23 @@ VOID STDCALL ProtocolTransferDataComplete(
|
||||||
BOOLEAN WorkStart;
|
BOOLEAN WorkStart;
|
||||||
PLAN_WQ_ITEM WQItem;
|
PLAN_WQ_ITEM WQItem;
|
||||||
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
|
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
|
||||||
|
|
||||||
if( Status != NDIS_STATUS_SUCCESS ) return;
|
if( Status != NDIS_STATUS_SUCCESS ) return;
|
||||||
WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
|
TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
|
||||||
if( !WQItem ) return;
|
|
||||||
|
TransferDataCompleteCalled++;
|
||||||
|
|
||||||
|
ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
|
||||||
|
|
||||||
|
WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
|
||||||
|
if( !WQItem ) {
|
||||||
|
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock );
|
|
||||||
WorkStart = IsListEmpty( &LanWorkList );
|
WorkStart = IsListEmpty( &LanWorkList );
|
||||||
WQItem->Packet = Packet;
|
WQItem->Packet = Packet;
|
||||||
WQItem->Adapter = Adapter;
|
WQItem->Adapter = Adapter;
|
||||||
|
@ -288,7 +374,7 @@ VOID STDCALL ProtocolTransferDataComplete(
|
||||||
InsertTailList( &LanWorkList, &WQItem->ListEntry );
|
InsertTailList( &LanWorkList, &WQItem->ListEntry );
|
||||||
if( WorkStart )
|
if( WorkStart )
|
||||||
ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
|
ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
|
||||||
TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock );
|
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
|
||||||
}
|
}
|
||||||
|
|
||||||
NDIS_STATUS STDCALL ProtocolReceive(
|
NDIS_STATUS STDCALL ProtocolReceive(
|
||||||
|
@ -322,6 +408,7 @@ NDIS_STATUS STDCALL ProtocolReceive(
|
||||||
PNDIS_PACKET NdisPacket;
|
PNDIS_PACKET NdisPacket;
|
||||||
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
|
PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
|
||||||
PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
|
PETH_HEADER EHeader = (PETH_HEADER)HeaderBuffer;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
|
TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
|
||||||
|
|
||||||
|
@ -359,9 +446,12 @@ NDIS_STATUS STDCALL ProtocolReceive(
|
||||||
TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
|
TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n",
|
||||||
Adapter, Adapter->MTU));
|
Adapter, Adapter->MTU));
|
||||||
|
|
||||||
|
TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
|
||||||
|
|
||||||
NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
|
NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
|
||||||
PacketSize + HeaderBufferSize );
|
PacketSize + HeaderBufferSize );
|
||||||
if( NdisStatus != NDIS_STATUS_SUCCESS ) {
|
if( NdisStatus != NDIS_STATUS_SUCCESS ) {
|
||||||
|
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
|
||||||
return NDIS_STATUS_NOT_ACCEPTED;
|
return NDIS_STATUS_NOT_ACCEPTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,6 +464,8 @@ NDIS_STATUS STDCALL ProtocolReceive(
|
||||||
IPPacket.NdisPacket = NdisPacket;
|
IPPacket.NdisPacket = NdisPacket;
|
||||||
IPPacket.Position = 0;
|
IPPacket.Position = 0;
|
||||||
|
|
||||||
|
TransferDataCalled++;
|
||||||
|
|
||||||
if (LookaheadBufferSize == PacketSize)
|
if (LookaheadBufferSize == PacketSize)
|
||||||
{
|
{
|
||||||
/* Optimized code path for packets that are fully contained in
|
/* Optimized code path for packets that are fully contained in
|
||||||
|
@ -398,6 +490,7 @@ NDIS_STATUS STDCALL ProtocolReceive(
|
||||||
BytesTransferred = 0;
|
BytesTransferred = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
|
||||||
TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
|
TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
|
||||||
|
|
||||||
if (NdisStatus != NDIS_STATUS_PENDING)
|
if (NdisStatus != NDIS_STATUS_PENDING)
|
||||||
|
@ -576,6 +669,7 @@ VOID LANTransmit(
|
||||||
TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
|
TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
|
||||||
TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
|
TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
|
||||||
NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
|
NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
|
||||||
|
LanChainCompletion( Adapter, NdisPacket );
|
||||||
TI_DbgPrint(MID_TRACE, ("NdisSend Done\n"));
|
TI_DbgPrint(MID_TRACE, ("NdisSend Done\n"));
|
||||||
TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
|
TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
|
||||||
|
|
||||||
|
@ -1181,6 +1275,8 @@ VOID LANUnregisterProtocol(
|
||||||
|
|
||||||
VOID LANStartup() {
|
VOID LANStartup() {
|
||||||
InitializeListHead( &LanWorkList );
|
InitializeListHead( &LanWorkList );
|
||||||
|
InitializeListHead( &LanSendCompleteList );
|
||||||
|
KeInitializeSpinLock( &LanSendCompleteLock );
|
||||||
ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
|
ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1197,6 +1293,15 @@ VOID LANShutdown() {
|
||||||
ExFreePool( WorkItem );
|
ExFreePool( WorkItem );
|
||||||
}
|
}
|
||||||
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
|
TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
|
||||||
|
|
||||||
|
KeAcquireSpinLock( &LanSendCompleteLock, &OldIrql );
|
||||||
|
while( !IsListEmpty( &LanSendCompleteList ) ) {
|
||||||
|
ListEntry = RemoveHeadList( &LanSendCompleteList );
|
||||||
|
WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
|
||||||
|
FreeNdisPacket( WorkItem->Packet );
|
||||||
|
ExFreePool( WorkItem );
|
||||||
|
}
|
||||||
|
KeReleaseSpinLock( &LanSendCompleteLock, OldIrql );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue