📄 receive.c
字号:
TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
/* We don't have a reassembly structure, create one */
IPDR = TcpipAllocateFromNPagedLookasideList(&IPDRList);
if (!IPDR)
/* We don't have the resources to process this packet, discard it */
return;
/* Create a descriptor spanning from zero to infinity.
Actually, we use a value slightly greater than the
maximum number of octets an IP datagram can contain */
Hole = CreateHoleDescriptor(0, 65536);
if (!Hole) {
/* We don't have the resources to process this packet, discard it */
TcpipFreeToNPagedLookasideList(&IPDRList, IPDR);
return;
}
AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
IPDR->Id = IPv4Header->Id;
IPDR->Protocol = IPv4Header->Protocol;
InitializeListHead(&IPDR->FragmentListHead);
InitializeListHead(&IPDR->HoleListHead);
InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
CurrentEntry = IPDR->HoleListHead.Flink;
TcpipInitializeSpinLock(&IPDR->Lock);
TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
/* Update the reassembly list */
TcpipInterlockedInsertTailList(
&ReassemblyListHead,
&IPDR->ListEntry,
&ReassemblyListLock);
}
FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
FragLast = FragFirst + WN2H(IPv4Header->TotalLength);
MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
for (;;) {
if (CurrentEntry == &IPDR->HoleListHead)
/* No more entries */
break;
TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
FragFirst, FragLast, Hole->First, Hole->Last));
if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
/* The fragment does not overlap with the hole, try next
descriptor in the list */
CurrentEntry = CurrentEntry->Flink;
if (CurrentEntry != &IPDR->HoleListHead)
Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
continue;
}
/* The fragment overlap with the hole, unlink the descriptor */
RemoveEntryList(CurrentEntry);
if (FragFirst > Hole->First) {
NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
if (!NewHole) {
/* We don't have the resources to process this packet, discard it */
Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);
return;
}
/* Put the new descriptor in the list */
InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
}
if ((FragLast < Hole->Last) && (MoreFragments)) {
/* We can reuse the descriptor for the new hole */
Hole->First = FragLast + 1;
/* Put the new hole descriptor in the list */
InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
} else
TcpipFreeToNPagedLookasideList(&IPHoleList, Hole);
/* If this is the first fragment, save the IP header */
if (FragFirst == 0) {
TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
"Header size is (%d).\n", &IPDR->IPv4Header, IPPacket->HeaderSize));
RtlCopyMemory(&IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
IPDR->HeaderSize = IPPacket->HeaderSize;
}
/* Create a buffer, copy the data into it and put it
in the fragment list */
Fragment = TcpipAllocateFromNPagedLookasideList(&IPFragmentList);
if (!Fragment) {
/* We don't have the resources to process this packet, discard it */
Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
return;
}
TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
Fragment->Data = exAllocatePool(NonPagedPool, Fragment->Size);
if (!Fragment->Data) {
/* We don't have the resources to process this packet, discard it */
Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);
return;
}
/* Position here is an offset from the NdisPacket start, not the header */
TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X) Size (%d) Pos (%d).\n",
Fragment->Data, Fragment->Size, IPPacket->Position));
/* Copy datagram data into fragment buffer */
CopyPacketToBuffer(Fragment->Data,
IPPacket->NdisPacket,
IPPacket->Position,
Fragment->Size);
Fragment->Offset = FragFirst;
/* If this is the last fragment, compute and save the datagram data size */
if (!MoreFragments)
IPDR->DataSize = FragFirst + Fragment->Size;
/* Put the fragment in the list */
InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
break;
}
TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
if (IsListEmpty(&IPDR->HoleListHead)) {
/* Hole list is empty which means a complete datagram can be assembled.
Assemble the datagram and pass it to an upper layer protocol */
TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
Datagram = ReassembleDatagram(IPDR);
RemoveIPDR(IPDR);
TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
FreeIPDR(IPDR);
if (!Datagram)
/* Not enough free resources, discard the packet */
return;
DISPLAY_IP_PACKET(Datagram);
/* Give the packet to the protocol dispatcher */
IPDispatchProtocol(IF, Datagram);
/* We're done with this datagram */
exFreePool(Datagram->Header);
TI_DbgPrint(MAX_TRACE, ("Freeing datagram at (0x%X).\n", Datagram));
(*Datagram->Free)(Datagram);
} else
TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
}
VOID IPFreeReassemblyList(
VOID)
/*
* FUNCTION: Frees all IP datagram reassembly structures in the list
*/
{
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
PIPDATAGRAM_REASSEMBLY Current;
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
CurrentEntry = ReassemblyListHead.Flink;
while (CurrentEntry != &ReassemblyListHead) {
Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
/* Unlink it from the list */
RemoveEntryList(CurrentEntry);
/* And free the descriptor */
FreeIPDR(Current);
CurrentEntry = CurrentEntry->Flink;
}
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
}
VOID IPDatagramReassemblyTimeout(
VOID)
/*
* FUNCTION: IP datagram reassembly timeout handler
* NOTES:
* This routine is called by IPTimeout to free any resources used
* to hold IP fragments that have taken too long to reassemble
*/
{
}
VOID IPv4Receive(PIP_INTERFACE IF, PIP_PACKET IPPacket)
/*
* FUNCTION: Receives an IPv4 datagram (or fragment)
* ARGUMENTS:
* Context = Pointer to context information (IP_INTERFACE)
* IPPacket = Pointer to IP packet
*/
{
TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2;
TI_DbgPrint(DEBUG_IP, ("IPPacket->HeaderSize = %d\n", IPPacket->HeaderSize));
if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {
TI_DbgPrint
(MIN_TRACE,
("Datagram received with incorrect header size (%d).\n",
IPPacket->HeaderSize));
/* Discard packet */
return;
}
/* Checksum IPv4 header */
if (!IPv4CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {
TI_DbgPrint
(MIN_TRACE,
("Datagram received with bad checksum. Checksum field (0x%X)\n",
WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));
/* Discard packet */
return;
}
IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);
AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);
IPPacket->Position += IPPacket->HeaderSize;
IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize);
TI_DbgPrint(MID_TRACE,("IPPacket->Position = %d\n",
IPPacket->Position));
//OskitDumpBuffer(IPPacket->Header, IPPacket->TotalSize);
/* FIXME: Possibly forward packets with multicast addresses */
/* FIXME: Should we allow packets to be received on the wrong interface? */
/* XXX Find out if this packet is destined for us */
ProcessFragment(IF, IPPacket);
#if 0
} else {
/* This packet is not destined for us. If we are a router,
try to find a route and forward the packet */
/* FIXME: Check if acting as a router */
NCE = NULL;
if (NCE) {
PROUTE_CACHE_NODE RCN;
/* FIXME: Possibly fragment datagram */
/* Forward the packet */
if(!RouteGetRouteToDestination( &IPPacket->DstAddr, NULL, &RCN ))
IPSendDatagram(IPPacket, RCN, ReflectPacketComplete, IPPacket);
} else {
TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
IPPacket->DstAddr.Address.IPv4Address));
/* FIXME: Send ICMP error code */
}
}
#endif
}
VOID IPReceive( PIP_INTERFACE IF, PIP_PACKET IPPacket )
/*
* FUNCTION: Receives an IP datagram (or fragment)
* ARGUMENTS:
* IF = Interface
* IPPacket = Pointer to IP packet
*/
{
UINT Version;
/* Check that IP header has a supported version */
Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);
switch (Version) {
case 4:
IPPacket->Type = IP_ADDRESS_V4;
IPv4Receive(IF, IPPacket);
break;
case 6:
IPPacket->Type = IP_ADDRESS_V6;
TI_DbgPrint(MAX_TRACE, ("Datagram of type IPv6 discarded.\n"));
return;
default:
TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
return;
}
}
/* EOF */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -