reactos/sdk/lib/drivers/ip/network/receive.c
Joachim Henze e7cfa907e9 [0.4.14][KERNEL32][TCPIP] A big squashed fix for CORE-16757 CORE-17596 CORE-17647 CORE-6473 (#3170)
The interesting kernel32 part is a port of
0.4.15-dev-2069-g fd8080b094
CORE-16757 'Task Manager failed to show process's priority'
which I actually wanted to improve for 0.4.14.

But if we took that on its own, then it would unhide
CORE-17596 'Google Earth 7.1.8 regressed AGAIN by the same work'
That's why we take with us:
0.4.15-dev-2766-g 27fcfe66a2 (is also part of CORE-6473, I left the 2nd commit out that added an assert in NTOSKRNL)

Small hack: this backport required me to define _Unreferenced_parameter_ myself in tcp.c
stolen from newer sdk/include/psdk/specstrings.h. I didn't want to port back that entire file as well.

In combination those two fixes allow both 'Google Earth and to change process priority' to be fixed within the same build.

But I felt a bit more safe then by taking
0.4.15-dev-2793-g 979b7d4d8e
with me as well, because I was too afraid, that I might otherwise introduce
CORE-17647 'BSOD 0xc2 BAD_POOL_CALLER induced by networking, triggered by using KeePass 2.23'
although I could not trigger that in practice when leaving that third commit out as an experiment.

And since it was a safe no-brainer-fix, I couldn't resist to also pick
0.4.15-dev-764-g 4aeb45ce0c (#3170)
2021-11-20 05:09:54 +01:00

682 lines
20 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: network/receive.c
* PURPOSE: Internet Protocol receive routines
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
* NOTES: The IP datagram reassembly algorithm is taken from
* from RFC 815
* REVISIONS:
* CSH 01/08-2000 Created
*/
#include "precomp.h"
LIST_ENTRY ReassemblyListHead;
KSPIN_LOCK ReassemblyListLock;
NPAGED_LOOKASIDE_LIST IPDRList;
NPAGED_LOOKASIDE_LIST IPFragmentList;
NPAGED_LOOKASIDE_LIST IPHoleList;
PIPDATAGRAM_HOLE CreateHoleDescriptor(
ULONG First,
ULONG Last)
/*
* FUNCTION: Returns a pointer to a IP datagram hole descriptor
* ARGUMENTS:
* First = Offset of first octet of the hole
* Last = Offset of last octet of the hole
* RETURNS:
* Pointer to descriptor, NULL if there was not enough free
* resources
*/
{
PIPDATAGRAM_HOLE Hole;
TI_DbgPrint(DEBUG_IP, ("Called. First (%d) Last (%d).\n", First, Last));
Hole = ExAllocateFromNPagedLookasideList(&IPHoleList);
if (!Hole) {
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
return NULL;
}
Hole->First = First;
Hole->Last = Last;
TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));
return Hole;
}
VOID FreeIPDR(
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Frees an IP datagram reassembly structure
* ARGUMENTS:
* IPDR = Pointer to IP datagram reassembly structure
*/
{
PLIST_ENTRY CurrentEntry;
PLIST_ENTRY NextEntry;
PIPDATAGRAM_HOLE CurrentH;
PIP_FRAGMENT CurrentF;
TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));
/* Free all descriptors */
CurrentEntry = IPDR->HoleListHead.Flink;
while (CurrentEntry != &IPDR->HoleListHead) {
NextEntry = CurrentEntry->Flink;
CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
/* Unlink it from the list */
RemoveEntryList(CurrentEntry);
TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));
/* And free the hole descriptor */
ExFreeToNPagedLookasideList(&IPHoleList, CurrentH);
CurrentEntry = NextEntry;
}
/* Free all fragments */
CurrentEntry = IPDR->FragmentListHead.Flink;
while (CurrentEntry != &IPDR->FragmentListHead) {
NextEntry = CurrentEntry->Flink;
CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
/* Unlink it from the list */
RemoveEntryList(CurrentEntry);
TI_DbgPrint(DEBUG_IP, ("Freeing fragment packet at (0x%X).\n", CurrentF->Packet));
/* Free the fragment data buffer */
if (CurrentF->ReturnPacket)
{
NdisReturnPackets(&CurrentF->Packet, 1);
}
else
{
FreeNdisPacket(CurrentF->Packet);
}
TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
/* And free the fragment descriptor */
ExFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
CurrentEntry = NextEntry;
}
if (IPDR->IPv4Header)
{
TI_DbgPrint(DEBUG_IP, ("Freeing IPDR header at (0x%X).\n", IPDR->IPv4Header));
ExFreePoolWithTag(IPDR->IPv4Header, PACKET_BUFFER_TAG);
}
TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
ExFreeToNPagedLookasideList(&IPDRList, IPDR);
}
VOID RemoveIPDR(
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Removes an IP datagram reassembly structure from the global list
* ARGUMENTS:
* IPDR = Pointer to IP datagram reassembly structure
*/
{
KIRQL OldIrql;
TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
RemoveEntryList(&IPDR->ListEntry);
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
}
PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
PIP_PACKET IPPacket)
/*
* FUNCTION: Returns a pointer to an IP datagram reassembly structure
* ARGUMENTS:
* IPPacket = Pointer to IP packet
* NOTES:
* A datagram is identified by four paramters, which are
* Source and destination address, protocol number and
* identification number
*/
{
KIRQL OldIrql;
PLIST_ENTRY CurrentEntry;
PIPDATAGRAM_REASSEMBLY Current;
PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
/* FIXME: Assume IPv4 */
CurrentEntry = ReassemblyListHead.Flink;
while (CurrentEntry != &ReassemblyListHead) {
Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
(Header->Id == Current->Id) &&
(Header->Protocol == Current->Protocol) &&
(AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
return Current;
}
CurrentEntry = CurrentEntry->Flink;
}
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
return NULL;
}
BOOLEAN
ReassembleDatagram(
PIP_PACKET IPPacket,
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Reassembles an IP datagram
* ARGUMENTS:
* IPDR = Pointer to IP datagram reassembly structure
* NOTES:
* This routine concatenates fragments into a complete IP datagram.
* The lock is held when this routine is called
* RETURNS:
* Pointer to IP packet, NULL if there was not enough free resources
* NOTES:
* At this point, header is expected to point to the IP header
*/
{
PLIST_ENTRY CurrentEntry;
PIP_FRAGMENT Fragment;
PCHAR Data;
PAGED_CODE();
TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
TI_DbgPrint(DEBUG_IP, ("IPDR->HeaderSize = %d\n", IPDR->HeaderSize));
TI_DbgPrint(DEBUG_IP, ("IPDR->DataSize = %d\n", IPDR->DataSize));
IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
IPPacket->HeaderSize = IPDR->HeaderSize;
RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
/* Allocate space for full IP datagram */
IPPacket->Header = ExAllocatePoolWithTag(NonPagedPool, IPPacket->TotalSize, PACKET_BUFFER_TAG);
if (!IPPacket->Header) {
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
(*IPPacket->Free)(IPPacket);
return FALSE;
}
IPPacket->MappedHeader = FALSE;
/* Copy the header into the buffer */
RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);
Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
IPPacket->Data = Data;
/* Copy data from all fragments into buffer */
CurrentEntry = IPDR->FragmentListHead.Flink;
while (CurrentEntry != &IPDR->FragmentListHead) {
Fragment = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
/* Copy fragment data into datagram buffer */
CopyPacketToBuffer(Data + Fragment->Offset,
Fragment->Packet,
Fragment->PacketOffset,
Fragment->Size);
CurrentEntry = CurrentEntry->Flink;
}
return TRUE;
}
static inline VOID Cleanup(
PKSPIN_LOCK Lock,
KIRQL OldIrql,
PIPDATAGRAM_REASSEMBLY IPDR)
/*
* FUNCTION: Performs cleaning operations on errors
* ARGUMENTS:
* Lock = Pointer to spin lock to be released
* OldIrql = Value of IRQL when spin lock was acquired
* IPDR = Pointer to IP datagram reassembly structure to free
* Buffer = Optional pointer to a buffer to free
*/
{
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
TcpipReleaseSpinLock(Lock, OldIrql);
RemoveIPDR(IPDR);
FreeIPDR(IPDR);
}
VOID ProcessFragment(
PIP_INTERFACE IF,
PIP_PACKET IPPacket)
/*
* FUNCTION: Processes an IP datagram or fragment
* ARGUMENTS:
* IF = Pointer to IP interface packet was receive on
* IPPacket = Pointer to IP packet
* NOTES:
* This routine reassembles fragments and, if a whole datagram can
* be assembled, passes the datagram on to the IP protocol dispatcher
*/
{
KIRQL OldIrql;
PIPDATAGRAM_REASSEMBLY IPDR;
PLIST_ENTRY CurrentEntry;
PIPDATAGRAM_HOLE Hole, NewHole;
USHORT FragFirst;
USHORT FragLast;
BOOLEAN MoreFragments;
PIPv4_HEADER IPv4Header;
IP_PACKET Datagram;
PIP_FRAGMENT Fragment;
BOOLEAN Success;
/* FIXME: Assume IPv4 */
IPv4Header = (PIPv4_HEADER)IPPacket->Header;
/* Check if we already have an reassembly structure for this datagram */
IPDR = GetReassemblyInfo(IPPacket);
if (IPDR) {
TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
/* We have a reassembly structure */
TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
/* Reset the timeout since we received a fragment */
IPDR->TimeoutCount = 0;
} else {
TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
/* We don't have a reassembly structure, create one */
IPDR = ExAllocateFromNPagedLookasideList(&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 */
ExFreeToNPagedLookasideList(&IPDRList, IPDR);
return;
}
AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
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);
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;
CurrentEntry = IPDR->HoleListHead.Flink;
for (;;) {
if (CurrentEntry == &IPDR->HoleListHead)
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));
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;
continue;
}
/* The fragment overlap with the hole, unlink the descriptor */
RemoveEntryList(CurrentEntry);
if (FragFirst > Hole->First) {
NewHole = CreateHoleDescriptor(Hole->First, FragFirst - 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 descriptor in the list */
InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
}
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, &NewHole->ListEntry);
}
ExFreeToNPagedLookasideList(&IPHoleList, Hole);
/* If this is the first fragment, save the IP header */
if (FragFirst == 0) {
IPDR->IPv4Header = ExAllocatePoolWithTag(NonPagedPool,
IPPacket->HeaderSize,
PACKET_BUFFER_TAG);
if (!IPDR->IPv4Header)
{
Cleanup(&IPDR->Lock, OldIrql, IPDR);
return;
}
RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
IPDR->HeaderSize = IPPacket->HeaderSize;
TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
"Header size is (%d).\n", &IPDR->IPv4Header, IPPacket->HeaderSize));
}
/* Create a buffer, copy the data into it and put it
in the fragment list */
Fragment = ExAllocateFromNPagedLookasideList(&IPFragmentList);
if (!Fragment) {
/* We don't have the resources to process this packet, discard it */
Cleanup(&IPDR->Lock, OldIrql, IPDR);
return;
}
TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
Fragment->Packet = IPPacket->NdisPacket;
Fragment->ReturnPacket = IPPacket->ReturnPacket;
Fragment->PacketOffset = IPPacket->Position + IPPacket->HeaderSize;
Fragment->Offset = FragFirst;
/* Disassociate the NDIS packet so it isn't freed upon return from IPReceive() */
IPPacket->NdisPacket = NULL;
/* 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"));
RemoveIPDR(IPDR);
TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
/* FIXME: Assumes IPv4 */
IPInitializePacket(&Datagram, IP_ADDRESS_V4);
Success = ReassembleDatagram(&Datagram, IPDR);
FreeIPDR(IPDR);
if (!Success)
/* 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 */
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, NextEntry;
PIPDATAGRAM_REASSEMBLY Current;
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
CurrentEntry = ReassemblyListHead.Flink;
while (CurrentEntry != &ReassemblyListHead) {
NextEntry = CurrentEntry->Flink;
Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
/* Unlink it from the list */
RemoveEntryList(CurrentEntry);
/* And free the descriptor */
FreeIPDR(Current);
CurrentEntry = NextEntry;
}
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
*/
{
PLIST_ENTRY CurrentEntry, NextEntry;
PIPDATAGRAM_REASSEMBLY CurrentIPDR;
TcpipAcquireSpinLockAtDpcLevel(&ReassemblyListLock);
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;
}
TcpipReleaseSpinLockFromDpcLevel(&ReassemblyListLock);
}
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
*/
{
UCHAR FirstByte;
ULONG BytesCopied;
TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
/* Read in the first IP header byte for size information */
BytesCopied = CopyPacketToBuffer((PCHAR)&FirstByte,
IPPacket->NdisPacket,
IPPacket->Position,
sizeof(UCHAR));
if (BytesCopied != sizeof(UCHAR))
{
TI_DbgPrint(MIN_TRACE, ("Failed to copy in first byte\n"));
/* Discard packet */
return;
}
IPPacket->HeaderSize = (FirstByte & 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;
}
/* This is freed by IPPacket->Free() */
IPPacket->Header = ExAllocatePoolWithTag(NonPagedPool,
IPPacket->HeaderSize,
PACKET_BUFFER_TAG);
if (!IPPacket->Header)
{
TI_DbgPrint(MIN_TRACE, ("No resources to allocate header\n"));
/* Discard packet */
return;
}
IPPacket->MappedHeader = FALSE;
BytesCopied = CopyPacketToBuffer((PCHAR)IPPacket->Header,
IPPacket->NdisPacket,
IPPacket->Position,
IPPacket->HeaderSize);
if (BytesCopied != IPPacket->HeaderSize)
{
TI_DbgPrint(MIN_TRACE, ("Failed to copy in header\n"));
/* 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);
TI_DbgPrint(MID_TRACE,("IPPacket->Position = %d\n",
IPPacket->Position));
/* 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);
}
VOID IPReceive( PIP_INTERFACE IF, PIP_PACKET IPPacket )
/*
* FUNCTION: Receives an IP datagram (or fragment)
* ARGUMENTS:
* IF = Interface
* IPPacket = Pointer to IP packet
*/
{
UCHAR FirstByte;
UINT Version, BytesCopied;
/* Read in the first IP header byte for version information */
BytesCopied = CopyPacketToBuffer((PCHAR)&FirstByte,
IPPacket->NdisPacket,
IPPacket->Position,
sizeof(UCHAR));
if (BytesCopied != sizeof(UCHAR))
{
TI_DbgPrint(MIN_TRACE, ("Failed to copy in first byte\n"));
IPPacket->Free(IPPacket);
return;
}
/* Check that IP header has a supported version */
Version = (FirstByte >> 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"));
break;
default:
TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
break;
}
IPPacket->Free(IPPacket);
}
/* EOF */