- Simplify and fix a few bugs in datagram reassembly

- Implement reassembly timeout

svn path=/trunk/; revision=43099
This commit is contained in:
Cameron Gutman 2009-09-20 21:07:45 +00:00
parent 5ec7ec1632
commit 4d2e0e023f
2 changed files with 53 additions and 22 deletions

View file

@ -9,6 +9,8 @@
#include <ip.h> #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 */ /* IP datagram fragment descriptor. Used to store IP datagram fragments */
typedef struct IP_FRAGMENT { typedef struct IP_FRAGMENT {
@ -38,6 +40,7 @@ typedef struct IPDATAGRAM_REASSEMBLY {
UINT HeaderSize; /* Length of IP header */ UINT HeaderSize; /* Length of IP header */
LIST_ENTRY FragmentListHead; /* IP fragment list */ LIST_ENTRY FragmentListHead; /* IP fragment list */
LIST_ENTRY HoleListHead; /* IP datagram hole list */ LIST_ENTRY HoleListHead; /* IP datagram hole list */
UINT TimeoutCount; /* Timeout counter */
} IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY; } IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY;

View file

@ -18,12 +18,6 @@ NPAGED_LOOKASIDE_LIST IPDRList;
NPAGED_LOOKASIDE_LIST IPFragmentList; NPAGED_LOOKASIDE_LIST IPFragmentList;
NPAGED_LOOKASIDE_LIST IPHoleList; NPAGED_LOOKASIDE_LIST IPHoleList;
VOID ReflectPacketComplete(
PVOID Context,
PNDIS_PACKET Packet,
NDIS_STATUS Status ) {
}
PIPDATAGRAM_HOLE CreateHoleDescriptor( PIPDATAGRAM_HOLE CreateHoleDescriptor(
ULONG First, ULONG First,
ULONG Last) ULONG Last)
@ -299,8 +293,6 @@ VOID ProcessFragment(
TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n")); TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
/* We have a reassembly structure */ /* We have a reassembly structure */
TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql); TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
CurrentEntry = IPDR->HoleListHead.Flink;
Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
} else { } else {
TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n")); TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
@ -323,10 +315,10 @@ VOID ProcessFragment(
AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr); AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
IPDR->Id = IPv4Header->Id; IPDR->Id = IPv4Header->Id;
IPDR->Protocol = IPv4Header->Protocol; IPDR->Protocol = IPv4Header->Protocol;
IPDR->TimeoutCount = 0;
InitializeListHead(&IPDR->FragmentListHead); InitializeListHead(&IPDR->FragmentListHead);
InitializeListHead(&IPDR->HoleListHead); InitializeListHead(&IPDR->HoleListHead);
InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry); InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
CurrentEntry = IPDR->HoleListHead.Flink;
TcpipInitializeSpinLock(&IPDR->Lock); TcpipInitializeSpinLock(&IPDR->Lock);
@ -343,10 +335,12 @@ VOID ProcessFragment(
FragLast = FragFirst + WN2H(IPv4Header->TotalLength); FragLast = FragFirst + WN2H(IPv4Header->TotalLength);
MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0; MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
CurrentEntry = IPDR->HoleListHead.Flink;
for (;;) { for (;;) {
if (CurrentEntry == &IPDR->HoleListHead) 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", TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
FragFirst, FragLast, Hole->First, Hole->Last)); FragFirst, FragLast, Hole->First, Hole->Last));
@ -357,8 +351,6 @@ VOID ProcessFragment(
descriptor in the list */ descriptor in the list */
CurrentEntry = CurrentEntry->Flink; CurrentEntry = CurrentEntry->Flink;
if (CurrentEntry != &IPDR->HoleListHead)
Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
continue; continue;
} }
@ -366,7 +358,7 @@ VOID ProcessFragment(
RemoveEntryList(CurrentEntry); RemoveEntryList(CurrentEntry);
if (FragFirst > Hole->First) { if (FragFirst > Hole->First) {
NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1); NewHole = CreateHoleDescriptor(Hole->First, FragFirst - 1);
if (!NewHole) { if (!NewHole) {
/* We don't have the resources to process this packet, discard it */ /* We don't have the resources to process this packet, discard it */
exFreeToNPagedLookasideList(&IPHoleList, Hole); exFreeToNPagedLookasideList(&IPHoleList, Hole);
@ -378,14 +370,20 @@ VOID ProcessFragment(
InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry); InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
} }
if ((FragLast < Hole->Last) && (MoreFragments)) { if ((FragLast < Hole->Last) && MoreFragments) {
/* We can reuse the descriptor for the new hole */ NewHole = CreateHoleDescriptor(FragLast + 1, Hole->Last);
Hole->First = FragLast + 1; 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 */ /* Put the new hole descriptor in the list */
InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry); InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
} else }
exFreeToNPagedLookasideList(&IPHoleList, Hole);
exFreeToNPagedLookasideList(&IPHoleList, Hole);
/* If this is the first fragment, save the IP header */ /* If this is the first fragment, save the IP header */
if (FragFirst == 0) { if (FragFirst == 0) {
@ -424,7 +422,7 @@ VOID ProcessFragment(
/* Copy datagram data into fragment buffer */ /* Copy datagram data into fragment buffer */
CopyPacketToBuffer(Fragment->Data, CopyPacketToBuffer(Fragment->Data,
IPPacket->NdisPacket, IPPacket->NdisPacket,
IPPacket->Position, IPPacket->HeaderSize,
Fragment->Size); Fragment->Size);
Fragment->Offset = FragFirst; Fragment->Offset = FragFirst;
@ -434,7 +432,7 @@ VOID ProcessFragment(
/* Put the fragment in the list */ /* Put the fragment in the list */
InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry); InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
break; break;
} }
TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n")); 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 * 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) VOID IPv4Receive(PIP_INTERFACE IF, PIP_PACKET IPPacket)