Commit in reactos/drivers/net/tcpip/datalink on MAIN
lan.c+114-91.31 -> 1.32
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.

reactos/drivers/net/tcpip/datalink
lan.c 1.31 -> 1.32
diff -u -r1.31 -r1.32
--- lan.c	4 Dec 2004 23:29:55 -0000	1.31
+++ lan.c	11 Dec 2004 20:48:33 -0000	1.32
@@ -10,6 +10,31 @@
 
 #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 {
     LIST_ENTRY ListEntry;
     PNDIS_PACKET Packet;
@@ -27,6 +52,54 @@
 LIST_ENTRY LanWorkList;
 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(
     PLAN_ADAPTER Adapter,
     NDIS_REQUEST_TYPE Type,
@@ -181,11 +254,13 @@
  */
 {
     TI_DbgPrint(DEBUG_DATALINK, ("Calling completion routine\n"));
-    ASSERT_KM_POINTER(Packet);
-    ASSERT_KM_POINTER(PC(Packet));
-    ASSERT_KM_POINTER(PC(Packet)->DLComplete);
-    (*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
-    TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
+    if( LanShouldComplete( (PLAN_ADAPTER)BindingContext, Packet ) ) {
+	ASSERT_KM_POINTER(Packet);
+	ASSERT_KM_POINTER(PC(Packet));
+	ASSERT_KM_POINTER(PC(Packet)->DLComplete);
+	(*PC(Packet)->DLComplete)( PC(Packet)->Context, Packet, Status);
+	TI_DbgPrint(DEBUG_DATALINK, ("Finished\n"));
+    }
 }
 
 VOID STDCALL LanReceiveWorker( PVOID Context ) {
@@ -198,12 +273,14 @@
     PNDIS_BUFFER NdisBuffer;
     IP_PACKET IPPacket;
 
-
     TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
     
     while( (ListEntry = 
 	    ExInterlockedRemoveHeadList( &LanWorkList, &LanWorkLock )) ) {
 	WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
+
+	LanReceiveWorkerCalled++;
+	ASSERT(LanReceiveWorkerCalled <= TransferDataCompleteCalled);
 	
 	Packet = WorkItem->Packet;
 	Adapter = WorkItem->Adapter;
@@ -273,14 +350,23 @@
     BOOLEAN WorkStart;
     PLAN_WQ_ITEM WQItem;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+    KIRQL OldIrql;
 
     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
 
     if( Status != NDIS_STATUS_SUCCESS ) return;
+    TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
+    
+    TransferDataCompleteCalled++;
+
+    ASSERT(TransferDataCompleteCalled <= TransferDataCalled);
+
     WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
-    if( !WQItem ) return;
+    if( !WQItem ) {
+	TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
+	return;
+    }
 
-    TcpipAcquireSpinLockAtDpcLevel( &LanWorkLock );
     WorkStart = IsListEmpty( &LanWorkList );
     WQItem->Packet = Packet;
     WQItem->Adapter = Adapter;
@@ -288,7 +374,7 @@
     InsertTailList( &LanWorkList, &WQItem->ListEntry );
     if( WorkStart )
 	ExQueueWorkItem( &LanWorkItem, CriticalWorkQueue );
-    TcpipReleaseSpinLockFromDpcLevel( &LanWorkLock );
+    TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
 }
 
 NDIS_STATUS STDCALL ProtocolReceive(
@@ -322,6 +408,7 @@
     PNDIS_PACKET NdisPacket;
     PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
     PETH_HEADER EHeader  = (PETH_HEADER)HeaderBuffer;
+    KIRQL OldIrql;
 
     TI_DbgPrint(DEBUG_DATALINK, ("Called. (packetsize %d)\n",PacketSize));
 
@@ -359,9 +446,12 @@
     TI_DbgPrint(DEBUG_DATALINK, ("Adapter: %x (MTU %d)\n", 
 				 Adapter, Adapter->MTU));
 
+    TcpipAcquireSpinLock( &LanWorkLock, &OldIrql );
+
     NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL,
                                            PacketSize + HeaderBufferSize );
     if( NdisStatus != NDIS_STATUS_SUCCESS ) {
+	TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
 	return NDIS_STATUS_NOT_ACCEPTED;
     }
 
@@ -374,6 +464,8 @@
     IPPacket.NdisPacket = NdisPacket;
     IPPacket.Position = 0;
 
+    TransferDataCalled++;
+
     if (LookaheadBufferSize == PacketSize)
     {
         /* Optimized code path for packets that are fully contained in
@@ -398,6 +490,7 @@
             BytesTransferred = 0;
         }
     }
+    TcpipReleaseSpinLock( &LanWorkLock, OldIrql );
     TI_DbgPrint(DEBUG_DATALINK, ("Calling complete\n"));
 
     if (NdisStatus != NDIS_STATUS_PENDING)
@@ -576,6 +669,7 @@
 	TcpipAcquireSpinLock( &Adapter->Lock, &OldIrql );
 	TI_DbgPrint(MID_TRACE, ("NdisSend\n"));
         NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
+	LanChainCompletion( Adapter, NdisPacket );
 	TI_DbgPrint(MID_TRACE, ("NdisSend Done\n"));
 	TcpipReleaseSpinLock( &Adapter->Lock, OldIrql );
 
@@ -1181,6 +1275,8 @@
 
 VOID LANStartup() {
     InitializeListHead( &LanWorkList );
+    InitializeListHead( &LanSendCompleteList );
+    KeInitializeSpinLock( &LanSendCompleteLock );
     ExInitializeWorkItem( &LanWorkItem, LanReceiveWorker, NULL );
 }
 
@@ -1197,6 +1293,15 @@
 	ExFreePool( WorkItem );
     }
     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 */
CVSspam 0.2.8