--- /dev/null
+/*
+ * 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 data at (0x%X).\n", CurrentF->Data));
+
+ /* Free the fragment data buffer */
+ exFreePool(CurrentF->Data);
+
+ TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
+
+ /* And free the fragment descriptor */
+ ExFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
+ CurrentEntry = NextEntry;
+ }
+
+ /* Free resources for the header, if it exists */
+ if (IPDR->IPv4Header) {
+ TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header));
+ exFreePool(IPDR->IPv4Header);
+ }
+
+ 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));
+
+ KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+ RemoveEntryList(&IPDR->ListEntry);
+ KeReleaseSpinLock(&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));
+
+ KeAcquireSpinLock(&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))) {
+ KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+
+ return Current;
+ }
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+
+ return NULL;
+}
+
+
+PIP_PACKET ReassembleDatagram(
+ 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
+ */
+{
+ PIP_PACKET IPPacket;
+ PLIST_ENTRY CurrentEntry;
+ PIP_FRAGMENT Current;
+ PVOID Data;
+
+ 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));
+
+ TI_DbgPrint(DEBUG_IP, ("Fragment header:\n"));
+ //OskitDumpBuffer((PCHAR)IPDR->IPv4Header, IPDR->HeaderSize);
+
+ /* FIXME: Assume IPv4 */
+ IPPacket = IPCreatePacket(IP_ADDRESS_V4);
+ if (!IPPacket)
+ return NULL;
+
+ IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
+ IPPacket->ContigSize = IPPacket->TotalSize;
+ IPPacket->HeaderSize = IPDR->HeaderSize;
+ /*IPPacket->Position = 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 = exAllocatePool(NonPagedPool, IPPacket->TotalSize);
+ if (!IPPacket->Header) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ (*IPPacket->Free)(IPPacket);
+ return NULL;
+ }
+
+ /* Copy the header into the buffer */
+ RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);
+
+ Data = IPPacket->Header + IPDR->HeaderSize;
+ IPPacket->Data = Data;
+
+ /* Copy data from all fragments into buffer */
+ CurrentEntry = IPDR->FragmentListHead.Flink;
+ while (CurrentEntry != &IPDR->FragmentListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
+
+ TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",
+ Current->Size, Data, Current->Offset));
+ /* Copy fragment data to the destination buffer at the correct offset */
+ RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset),
+ Current->Data,
+ Current->Size);
+ //OskitDumpBuffer( Data, Current->Offset + Current->Size );
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ return IPPacket;
+}
+
+
+__inline VOID Cleanup(
+ PKSPIN_LOCK Lock,
+ KIRQL OldIrql,
+ PIPDATAGRAM_REASSEMBLY IPDR,
+ PVOID Buffer OPTIONAL)
+/*
+ * 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"));
+
+ KeReleaseSpinLock(Lock, OldIrql);
+ RemoveIPDR(IPDR);
+ FreeIPDR(IPDR);
+ if (Buffer)
+ exFreePool(Buffer);
+}
+
+
+VOID ProcessFragment(
+ PIP_INTERFACE IF,
+ PIP_PACKET IPPacket,
+ PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Processes an IP datagram or fragment
+ * ARGUMENTS:
+ * IF = Pointer to IP interface packet was receive on
+ * IPPacket = Pointer to IP packet
+ * NTE = Pointer to NTE packet was received on
+ * 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;
+ PIP_PACKET Datagram;
+ PIP_FRAGMENT Fragment;
+
+ /* 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 */
+ KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
+ CurrentEntry = IPDR->HoleListHead.Flink;
+ Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+ } 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->IPv4Header = NULL;
+ InitializeListHead(&IPDR->FragmentListHead);
+ InitializeListHead(&IPDR->HoleListHead);
+ InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
+ CurrentEntry = IPDR->HoleListHead.Flink;
+
+ KeInitializeSpinLock(&IPDR->Lock);
+
+ KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
+
+ /* Update the reassembly list */
+ ExInterlockedInsertTailList(
+ &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
+ ExFreeToNPagedLookasideList(&IPHoleList, Hole);
+
+ /* If this is the first fragment, save the IP header */
+ if (FragFirst == 0) {
+ IPDR->IPv4Header = exAllocatePool(NonPagedPool, IPPacket->HeaderSize);
+ if (!IPDR->IPv4Header) {
+ /* We don't have the resources to process this packet, discard it */
+ Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
+ return;
+ }
+
+ 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 = ExAllocateFromNPagedLookasideList(&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);
+
+ KeReleaseSpinLock(&IPDR->Lock, OldIrql);
+
+ RemoveIPDR(IPDR);
+ FreeIPDR(IPDR);
+
+ if (!Datagram)
+ /* Not enough free resources, discard the packet */
+ return;
+
+ DISPLAY_IP_PACKET(Datagram);
+
+ /* Give the packet to the protocol dispatcher */
+ IPDispatchProtocol(NTE, 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
+ KeReleaseSpinLock(&IPDR->Lock, OldIrql);
+}
+
+
+VOID IPFreeReassemblyList(
+ VOID)
+/*
+ * FUNCTION: Frees all IP datagram reassembly structures in the list
+ */
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY CurrentEntry;
+ PIPDATAGRAM_REASSEMBLY Current;
+
+ KeAcquireSpinLock(&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;
+ }
+
+ KeReleaseSpinLock(&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
+ */
+{
+ PNEIGHBOR_CACHE_ENTRY NCE;
+ PNET_TABLE_ENTRY NTE;
+ UINT AddressType;
+
+ 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? */
+ NTE = IPLocateNTEOnInterface(IF, &IPPacket->DstAddr, &AddressType);
+
+ if (NTE) {
+ /* This packet is destined for us */
+ ProcessFragment(IF, IPPacket, NTE);
+
+ /* Done with this NTE */
+ DereferenceObject(NTE);
+ } 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) {
+ /* FIXME: Possibly fragment datagram */
+ /* Forward the packet */
+ IPSendFragment(IPPacket->NdisPacket, NCE);
+ } else {
+ TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
+ IPPacket->DstAddr.Address.IPv4Address));
+
+ /* FIXME: Send ICMP error code */
+ }
+ }
+}
+
+
+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 */