Added a work item to prevent stack overflow.
Modified: trunk/reactos/drivers/lib/ip/network/loopback.c

Modified: trunk/reactos/drivers/lib/ip/network/loopback.c
--- trunk/reactos/drivers/lib/ip/network/loopback.c	2005-01-10 03:03:24 UTC (rev 12914)
+++ trunk/reactos/drivers/lib/ip/network/loopback.c	2005-01-10 04:43:05 UTC (rev 12915)
@@ -11,7 +11,108 @@
 #include "precomp.h"
 
 PIP_INTERFACE Loopback = NULL;
+typedef struct _LAN_WQ_ITEM {
+    LIST_ENTRY ListEntry;
+    PNDIS_PACKET Packet;
+    PLAN_ADAPTER Adapter;
+    UINT BytesTransferred;
+} LAN_WQ_ITEM, *PLAN_WQ_ITEM;
 
+/* Work around being called back into afd at Dpc level */
+KSPIN_LOCK LoopWorkLock;
+LIST_ENTRY LoopWorkList;
+WORK_QUEUE_ITEM LoopWorkItem;
+BOOLEAN LoopReceiveWorkerBusy = FALSE;
+
+VOID STDCALL LoopReceiveWorker( PVOID Context ) {
+    PLIST_ENTRY ListEntry;
+    PLAN_WQ_ITEM WorkItem;
+    PNDIS_PACKET Packet;
+    PLAN_ADAPTER Adapter;
+    UINT BytesTransferred;
+    PNDIS_BUFFER NdisBuffer;
+    IP_PACKET IPPacket;
+
+    TI_DbgPrint(DEBUG_DATALINK, ("Called.\n"));
+    
+    while( (ListEntry = 
+	    ExInterlockedRemoveHeadList( &LoopWorkList, &LoopWorkLock )) ) {
+	WorkItem = CONTAINING_RECORD(ListEntry, LAN_WQ_ITEM, ListEntry);
+
+	TI_DbgPrint(DEBUG_DATALINK, ("WorkItem: %x\n", WorkItem));
+
+	Packet = WorkItem->Packet;
+	Adapter = WorkItem->Adapter;
+	BytesTransferred = WorkItem->BytesTransferred;
+
+	ExFreePool( WorkItem );
+
+        IPPacket.NdisPacket = Packet;
+
+        TI_DbgPrint(DEBUG_DATALINK, ("Packet %x Adapter %x Trans %x\n",
+                                     Packet, Adapter, BytesTransferred));
+
+        NdisGetFirstBufferFromPacket(Packet,
+                                     &NdisBuffer,
+                                     &IPPacket.Header,
+                                     &IPPacket.ContigSize,
+                                     &IPPacket.TotalSize);
+
+	IPPacket.ContigSize = IPPacket.TotalSize = BytesTransferred;
+        /* Determine which upper layer protocol that should receive
+           this packet and pass it to the correct receive handler */
+
+	TI_DbgPrint(MID_TRACE,
+		    ("ContigSize: %d, TotalSize: %d, BytesTransferred: %d\n",
+		     IPPacket.ContigSize, IPPacket.TotalSize,
+		     BytesTransferred));
+
+	IPPacket.Position = 0;
+
+        IPReceive(Loopback, &IPPacket);
+
+	FreeNdisPacket( Packet );
+    }
+    TI_DbgPrint(DEBUG_DATALINK, ("Leaving\n"));
+    LoopReceiveWorkerBusy = FALSE;
+}
+
+VOID LoopSubmitReceiveWork( 
+    NDIS_HANDLE BindingContext,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS Status,
+    UINT BytesTransferred) {
+    PLAN_WQ_ITEM WQItem;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+    KIRQL OldIrql;
+
+    TcpipAcquireSpinLock( &LoopWorkLock, &OldIrql );
+    
+    WQItem = ExAllocatePool( NonPagedPool, sizeof(LAN_WQ_ITEM) );
+    if( !WQItem ) {
+	TcpipReleaseSpinLock( &LoopWorkLock, OldIrql );
+	return;
+    }
+
+    WQItem->Packet = Packet;
+    WQItem->Adapter = Adapter;
+    WQItem->BytesTransferred = BytesTransferred;
+    InsertTailList( &LoopWorkList, &WQItem->ListEntry );
+
+    TI_DbgPrint(DEBUG_DATALINK, ("Packet %x Adapter %x BytesTrans %x\n",
+                                 Packet, Adapter, BytesTransferred));
+
+    if( !LoopReceiveWorkerBusy ) {
+	LoopReceiveWorkerBusy = TRUE;
+	ExQueueWorkItem( &LoopWorkItem, CriticalWorkQueue );
+	TI_DbgPrint(DEBUG_DATALINK,
+		    ("Work item inserted %x %x\n", &LoopWorkItem, WQItem));
+    } else {
+        DbgPrint("LOOP WORKER BUSY %x %x\n", &LoopWorkItem, WQItem);
+    }
+    TcpipReleaseSpinLock( &LoopWorkLock, OldIrql );
+}
+
 VOID LoopTransmit(
   PVOID Context,
   PNDIS_PACKET NdisPacket,
@@ -28,30 +129,31 @@
  *   Type        = LAN protocol type (unused)
  */
 {
-  IP_PACKET IPPacket;
+    PCHAR PacketBuffer;
+    UINT PacketLength;
+    PNDIS_PACKET XmitPacket;
+    NDIS_STATUS NdisStatus;
 
-  ASSERT_KM_POINTER(NdisPacket);
-  ASSERT_KM_POINTER(PC(NdisPacket));
-  ASSERT_KM_POINTER(PC(NdisPacket)->DLComplete);
+    ASSERT_KM_POINTER(NdisPacket);
+    ASSERT_KM_POINTER(PC(NdisPacket));
+    ASSERT_KM_POINTER(PC(NdisPacket)->DLComplete);
+    
+    TI_DbgPrint(MAX_TRACE, ("Called (NdisPacket = %x)\n", NdisPacket));
 
-  TI_DbgPrint(MAX_TRACE, ("Called (NdisPacket = %x)\n", NdisPacket));
+    GetDataPtr( NdisPacket, MaxLLHeaderSize, &PacketBuffer, &PacketLength );
 
-  IPPacket.NdisPacket = NdisPacket;
-  IPPacket.HeaderSize = 0;
-  GetDataPtr( NdisPacket, 0, (PCHAR *)&IPPacket.Header, &IPPacket.TotalSize );
-  IPPacket.Header += Offset;
-  IPPacket.ContigSize = IPPacket.TotalSize;
-  IPPacket.Position = Offset;
+    NdisStatus = AllocatePacketWithBuffer
+        ( &XmitPacket, PacketBuffer, PacketLength );
 
-  TI_DbgPrint(MAX_TRACE, 
-	      ("Doing receive (complete: %x, context %x, packet %x)\n",
-	       PC(NdisPacket)->DLComplete, Context, NdisPacket));
-  IPReceive(Context, &IPPacket);
-  TI_DbgPrint(MAX_TRACE, 
-	      ("Finished receive (complete: %x, context %x, packet %x)\n",
-	       PC(NdisPacket)->DLComplete, Context, NdisPacket));
-  PC(NdisPacket)->DLComplete(PC(NdisPacket)->Context, NdisPacket, NDIS_STATUS_SUCCESS);
-  TI_DbgPrint(MAX_TRACE, ("Done\n"));
+    if( NT_SUCCESS(NdisStatus) ) {
+        LoopSubmitReceiveWork
+            ( NULL, XmitPacket, STATUS_SUCCESS, PacketLength );
+    }
+
+    (PC(NdisPacket)->DLComplete)
+        ( PC(NdisPacket)->Context, NdisPacket, STATUS_SUCCESS );
+
+    TI_DbgPrint(MAX_TRACE, ("Done\n"));
 }
 
 NDIS_STATUS LoopRegisterAdapter(
@@ -73,6 +175,9 @@
 
   TI_DbgPrint(MID_TRACE, ("Called.\n"));
 
+  InitializeListHead( &LoopWorkList );
+  ExInitializeWorkItem( &LoopWorkItem, LoopReceiveWorker, NULL );
+  
   /* Bind the adapter to network (IP) layer */
   BindInfo.Context = NULL;
   BindInfo.HeaderSize = 0;