- Simplify and fix a few bugs in datagram reassembly
authorCameron Gutman <aicommander@gmail.com>
Sun, 20 Sep 2009 21:07:45 +0000 (21:07 +0000)
committerCameron Gutman <aicommander@gmail.com>
Sun, 20 Sep 2009 21:07:45 +0000 (21:07 +0000)
 - Implement reassembly timeout

svn path=/trunk/; revision=43099

reactos/drivers/network/tcpip/include/receive.h
reactos/lib/drivers/ip/network/receive.c

index 52e520f..2681732 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <ip.h>
 
+/* Number of timeout ticks before destroying the IPDR */
+#define MAX_TIMEOUT_COUNT 10
 
 /* IP datagram fragment descriptor. Used to store IP datagram fragments */
 typedef struct IP_FRAGMENT {
@@ -38,6 +40,7 @@ typedef struct IPDATAGRAM_REASSEMBLY {
     UINT HeaderSize;             /* Length of IP header */
     LIST_ENTRY FragmentListHead; /* IP fragment list */
     LIST_ENTRY HoleListHead;     /* IP datagram hole list */
+    UINT TimeoutCount;           /* Timeout counter */
 } IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY;
 
 
index aff556b..174b647 100644 (file)
@@ -18,12 +18,6 @@ NPAGED_LOOKASIDE_LIST IPDRList;
 NPAGED_LOOKASIDE_LIST IPFragmentList;
 NPAGED_LOOKASIDE_LIST IPHoleList;
 
-VOID ReflectPacketComplete(
-    PVOID Context,
-    PNDIS_PACKET Packet,
-    NDIS_STATUS Status ) {
-}
-
 PIPDATAGRAM_HOLE CreateHoleDescriptor(
   ULONG First,
   ULONG Last)
@@ -299,8 +293,6 @@ VOID ProcessFragment(
     TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
     /* We have a reassembly structure */
     TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
-    CurrentEntry = IPDR->HoleListHead.Flink;
-    Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
   } else {
     TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
 
@@ -323,10 +315,10 @@ VOID ProcessFragment(
     AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
     IPDR->Id         = IPv4Header->Id;
     IPDR->Protocol   = IPv4Header->Protocol;
+    IPDR->TimeoutCount = 0;
     InitializeListHead(&IPDR->FragmentListHead);
     InitializeListHead(&IPDR->HoleListHead);
     InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
-    CurrentEntry = IPDR->HoleListHead.Flink;
 
     TcpipInitializeSpinLock(&IPDR->Lock);
 
@@ -343,10 +335,12 @@ VOID ProcessFragment(
   FragLast      = FragFirst + WN2H(IPv4Header->TotalLength);
   MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
 
+  CurrentEntry = IPDR->HoleListHead.Flink;
   for (;;) {
     if (CurrentEntry == &IPDR->HoleListHead)
-      /* No more entries */
-      break;
+        break;
+
+    Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
 
     TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
       FragFirst, FragLast, Hole->First, Hole->Last));
@@ -357,8 +351,6 @@ VOID ProcessFragment(
          descriptor in the list */
 
       CurrentEntry = CurrentEntry->Flink;
-      if (CurrentEntry != &IPDR->HoleListHead)
-          Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
       continue;
     }
 
@@ -366,7 +358,7 @@ VOID ProcessFragment(
     RemoveEntryList(CurrentEntry);
 
     if (FragFirst > Hole->First) {
-      NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
+      NewHole = CreateHoleDescriptor(Hole->First, FragFirst - 1);
       if (!NewHole) {
         /* We don't have the resources to process this packet, discard it */
         exFreeToNPagedLookasideList(&IPHoleList, Hole);
@@ -378,14 +370,20 @@ VOID ProcessFragment(
       InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
     }
 
-    if ((FragLast < Hole->Last) && (MoreFragments)) {
-      /* We can reuse the descriptor for the new hole */
-      Hole->First = FragLast + 1;
+    if ((FragLast < Hole->Last) && MoreFragments) {
+      NewHole = CreateHoleDescriptor(FragLast + 1, Hole->Last);
+      if (!NewHole) {
+        /* We don't have the resources to process this packet, discard it */
+        exFreeToNPagedLookasideList(&IPHoleList, Hole);
+        Cleanup(&IPDR->Lock, OldIrql, IPDR);
+        return;
+      }
 
       /* Put the new hole descriptor in the list */
-      InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
-    } else
-      exFreeToNPagedLookasideList(&IPHoleList, Hole);
+      InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
+    }
+
+    exFreeToNPagedLookasideList(&IPHoleList, Hole);
 
     /* If this is the first fragment, save the IP header */
     if (FragFirst == 0) {
@@ -424,7 +422,7 @@ VOID ProcessFragment(
     /* Copy datagram data into fragment buffer */
     CopyPacketToBuffer(Fragment->Data,
                       IPPacket->NdisPacket,
-                      IPPacket->Position,
+                      IPPacket->HeaderSize,
                       Fragment->Size);
     Fragment->Offset = FragFirst;
 
@@ -434,7 +432,7 @@ VOID ProcessFragment(
 
     /* Put the fragment in the list */
     InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
-         break;
+    break;
   }
 
   TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
@@ -512,6 +510,36 @@ VOID IPDatagramReassemblyTimeout(
  *     to hold IP fragments that have taken too long to reassemble
  */
 {
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry, NextEntry;
+    PIPDATAGRAM_REASSEMBLY CurrentIPDR;
+
+    TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+
+    CurrentEntry = ReassemblyListHead.Flink;
+    while (CurrentEntry != &ReassemblyListHead)
+    {
+       NextEntry = CurrentEntry->Flink;
+       CurrentIPDR = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
+
+       TcpipAcquireSpinLockAtDpcLevel(&CurrentIPDR->Lock);
+
+       if (++CurrentIPDR->TimeoutCount == MAX_TIMEOUT_COUNT)
+       {
+           TcpipReleaseSpinLockFromDpcLevel(&CurrentIPDR->Lock);
+           RemoveEntryList(CurrentEntry);
+           FreeIPDR(CurrentIPDR);
+       } 
+       else
+       {
+           ASSERT(CurrentIPDR->TimeoutCount < MAX_TIMEOUT_COUNT);
+           TcpipReleaseSpinLockFromDpcLevel(&CurrentIPDR->Lock);
+       }
+
+       CurrentEntry = NextEntry;
+    }
+
+    TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
 }
 
 VOID IPv4Receive(PIP_INTERFACE IF, PIP_PACKET IPPacket)