- 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>
/* 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;

View 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)