Added networking code from Casper Hornstrup
authorDavid Welch <welch@cwcom.net>
Wed, 2 Aug 2000 00:02:53 +0000 (00:02 +0000)
committerDavid Welch <welch@cwcom.net>
Wed, 2 Aug 2000 00:02:53 +0000 (00:02 +0000)
svn path=/trunk/; revision=1282

70 files changed:
reactos/drivers/net/tcpip/DIRS [new file with mode: 0644]
reactos/drivers/net/tcpip/datalink/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/datalink/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/datalink/arp.c [new file with mode: 0644]
reactos/drivers/net/tcpip/datalink/lan.c [new file with mode: 0644]
reactos/drivers/net/tcpip/datalink/loopback.c [new file with mode: 0644]
reactos/drivers/net/tcpip/include/address.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/arp.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/checksum.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/datagram.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/debug.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/dispatch.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/fileobjs.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/icmp.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/info.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/ip.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/lan.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/loopback.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/neighbor.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/pool.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/rawip.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/receive.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/route.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/router.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/routines.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/tcp.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/tcpip.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/ticonsts.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/titypes.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/transmit.h [new file with mode: 0644]
reactos/drivers/net/tcpip/include/udp.h [new file with mode: 0644]
reactos/drivers/net/tcpip/makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/network/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/network/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/network/icmp.c [new file with mode: 0644]
reactos/drivers/net/tcpip/network/ip.c [new file with mode: 0644]
reactos/drivers/net/tcpip/network/neighbor.c [new file with mode: 0644]
reactos/drivers/net/tcpip/network/receive.c [new file with mode: 0644]
reactos/drivers/net/tcpip/network/route.c [new file with mode: 0644]
reactos/drivers/net/tcpip/network/router.c [new file with mode: 0644]
reactos/drivers/net/tcpip/network/transmit.c [new file with mode: 0644]
reactos/drivers/net/tcpip/readme.txt [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip.def [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip.edf [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip.rc [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/Copy of info.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/address.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/checksum.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/dispatch.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/fileobjs.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/info.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/main.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/pool.c [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/resource.rc [new file with mode: 0644]
reactos/drivers/net/tcpip/tcpip/routines.c [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/DIRS [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/datagram/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/datagram/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/datagram/datagram.c [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/rawip/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/rawip/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/rawip/rawip.c [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/tcp/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/tcp/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/tcp/tcp.c [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/udp/Makefile [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/udp/SOURCES [new file with mode: 0644]
reactos/drivers/net/tcpip/transport/udp/udp.c [new file with mode: 0644]

diff --git a/reactos/drivers/net/tcpip/DIRS b/reactos/drivers/net/tcpip/DIRS
new file mode 100644 (file)
index 0000000..a49d00e
--- /dev/null
@@ -0,0 +1,5 @@
+DIRS= datalink \\r
+      network \\r
+      transport \\r
+      tcpip\r
+\r
diff --git a/reactos/drivers/net/tcpip/datalink/Makefile b/reactos/drivers/net/tcpip/datalink/Makefile
new file mode 100644 (file)
index 0000000..9c985f5
--- /dev/null
@@ -0,0 +1,7 @@
+#\r
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source\r
+# file to this component.  This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE $(NTMAKEENV)\makefile.def\r
diff --git a/reactos/drivers/net/tcpip/datalink/SOURCES b/reactos/drivers/net/tcpip/datalink/SOURCES
new file mode 100644 (file)
index 0000000..b941923
--- /dev/null
@@ -0,0 +1,13 @@
+TARGETNAME=datalink\r
+TARGETPATH=..\objects\r
+TARGETTYPE=LIBRARY\r
+\r
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \\r
+           $(DDK_LIB_PATH)\ndis.lib\r
+\r
+INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net\r
+SOURCES= arp.c \\r
+                lan.c \\r
+         loopback.c\r
+\r
+MSC_WARNING_LEVEL=/W3 /WX\r
diff --git a/reactos/drivers/net/tcpip/datalink/arp.c b/reactos/drivers/net/tcpip/datalink/arp.c
new file mode 100644 (file)
index 0000000..83d2490
--- /dev/null
@@ -0,0 +1,277 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        datalink/arp.c\r
+ * PURPOSE:     Address Resolution Protocol routines\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <arp.h>\r
+#include <routines.h>\r
+#include <neighbor.h>\r
+#include <address.h>\r
+#include <pool.h>\r
+#include <lan.h>\r
+\r
+\r
+PNDIS_PACKET PrepareARPPacket(\r
+    USHORT HardwareType,\r
+    USHORT ProtocolType,\r
+    UCHAR LinkAddressLength,\r
+    UCHAR ProtoAddressLength,\r
+    PVOID SenderLinkAddress,\r
+    PVOID SenderProtoAddress,\r
+    PVOID TargetLinkAddress,\r
+    PVOID TargetProtoAddress,\r
+    USHORT Opcode)\r
+/*\r
+ * FUNCTION: Prepares an ARP packet\r
+ * ARGUMENTS:\r
+ *     HardwareType       = Hardware type (in network byte order)\r
+ *     ProtocolType       = Protocol type (in network byte order)\r
+ *     LinkAddressLength  = Length of link address fields\r
+ *     ProtoAddressLength = Length of protocol address fields\r
+ *     SenderLinkAddress  = Sender's link address\r
+ *     SenderProtoAddress = Sender's protocol address\r
+ *     TargetLinkAddress  = Target's link address (NULL if don't care)\r
+ *     TargetProtoAddress = Target's protocol address\r
+ *     Opcode             = ARP opcode (in network byte order)\r
+ * RETURNS:\r
+ *     Pointer to NDIS packet, NULL if there is not enough free resources\r
+ */\r
+{\r
+    PNDIS_PACKET NdisPacket;\r
+    PNDIS_BUFFER NdisBuffer;\r
+    NDIS_STATUS NdisStatus;\r
+    PARP_HEADER Header;\r
+    PVOID DataBuffer;\r
+    ULONG Size;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    /* Prepare ARP packet */\r
+    Size = MaxLLHeaderSize + sizeof(ARP_HEADER) + \r
+        2 * LinkAddressLength + /* Hardware address length */\r
+        2 * ProtoAddressLength; /* Protocol address length */\r
+    Size = MAX(Size, MinLLFrameSize);\r
+\r
+    DataBuffer = ExAllocatePool(NonPagedPool, Size);\r
+    if (!DataBuffer)\r
+        return NULL;\r
+\r
+    /* Allocate NDIS packet */\r
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        ExFreePool(DataBuffer);\r
+        return NULL;\r
+    }\r
+\r
+    /* Allocate NDIS buffer for maximum link level header and ARP packet */\r
+    NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,\r
+        DataBuffer, Size);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        NdisFreePacket(NdisPacket);\r
+        ExFreePool(DataBuffer);\r
+        return NULL;\r
+    }\r
+\r
+    /* Link NDIS buffer into packet */\r
+    NdisChainBufferAtFront(NdisPacket, NdisBuffer);\r
+    RtlZeroMemory(DataBuffer, Size);\r
+    Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);\r
+    Header->HWType       = HardwareType;\r
+    Header->ProtoType    = ProtocolType;\r
+    Header->HWAddrLen    = LinkAddressLength;\r
+    Header->ProtoAddrLen = ProtoAddressLength;\r
+    Header->Opcode       = Opcode; /* Already swapped */\r
+    DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));\r
+\r
+    /* Our hardware address */\r
+    RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);\r
+    (ULONG_PTR)DataBuffer += LinkAddressLength;\r
+\r
+    /* Our protocol address */\r
+    RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);\r
+\r
+    if (TargetLinkAddress) {\r
+        (ULONG_PTR)DataBuffer += ProtoAddressLength;\r
+        /* Target hardware address */\r
+        RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);\r
+        (ULONG_PTR)DataBuffer += LinkAddressLength;\r
+    } else\r
+        /* Don't care about target hardware address */\r
+        (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength);\r
+\r
+    /* Target protocol address */\r
+    RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);\r
+\r
+    return NdisPacket;\r
+}\r
+\r
+\r
+VOID ARPTransmitComplete(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    NDIS_STATUS NdisStatus)\r
+/*\r
+ * FUNCTION: ARP request transmit completion handler\r
+ * ARGUMENTS:\r
+ *     Context    = Pointer to context information (IP_INTERFACE)\r
+ *     Packet     = Pointer to NDIS packet that was sent\r
+ *     NdisStatus = NDIS status of operation\r
+ * NOTES:\r
+ *    This routine is called when an ARP request has been sent\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    FreeNdisPacket(NdisPacket);\r
+}\r
+\r
+\r
+BOOLEAN ARPTransmit(\r
+    PIP_ADDRESS Address,\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Creates an ARP request and transmits it on a network\r
+ * ARGUMENTS:\r
+ *     Address = Pointer to IP address to resolve\r
+ *     NTE     = Pointer to net table entru to use for transmitting request\r
+ * RETURNS:\r
+ *     TRUE if the request was successfully sent, FALSE if not\r
+ */\r
+{\r
+    PIP_INTERFACE Interface;\r
+    PNDIS_PACKET NdisPacket;\r
+    UCHAR ProtoAddrLen;\r
+    USHORT ProtoType;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    Interface = NTE->Interface;\r
+\r
+    switch (Address->Type) {\r
+        case IP_ADDRESS_V4:\r
+            ProtoType    = (USHORT)ETYPE_IPv4; /* IPv4 */\r
+            ProtoAddrLen = 4;                  /* Length of IPv4 address */\r
+            break;\r
+        case IP_ADDRESS_V6:\r
+            ProtoType    = (USHORT)ETYPE_IPv6; /* IPv6 */\r
+            ProtoAddrLen = 16;                 /* Length of IPv6 address */\r
+            break;\r
+        default:\r
+            /* Should not happen */\r
+            return FALSE;\r
+    }\r
+\r
+    NdisPacket = PrepareARPPacket(\r
+        WN2H(0x0001),                    /* FIXME: Ethernet only */\r
+        ProtoType,                       /* Protocol type */\r
+        (UCHAR)Interface->AddressLength, /* Hardware address length */\r
+        (UCHAR)ProtoAddrLen,             /* Protocol address length */\r
+        Interface->Address,              /* Sender's (local) hardware address */\r
+        &NTE->Address->Address,          /* Sender's (local) protocol address */\r
+        NULL,                            /* Don't care */\r
+        &Address->Address,               /* Target's (remote) protocol address */\r
+        ARP_OPCODE_REQUEST);             /* ARP request */\r
+\r
+    PC(NdisPacket)->DLComplete = ARPTransmitComplete;\r
+\r
+    (*Interface->Transmit)(Interface->Context, NdisPacket,\r
+        MaxLLHeaderSize, NULL, LAN_PROTO_ARP);\r
+\r
+    return TRUE;\r
+}\r
+\r
+\r
+VOID ARPReceive(\r
+    PVOID Context,\r
+    PIP_PACKET Packet)\r
+/*\r
+ * FUNCTION: Receives an ARP packet\r
+ * ARGUMENTS:\r
+ *     Context = Pointer to context information (IP_INTERFACE)\r
+ *     Packet  = Pointer to packet\r
+ */\r
+{\r
+    PARP_HEADER Header;\r
+    PIP_ADDRESS Address;\r
+    PVOID SenderHWAddress;\r
+    PVOID SenderProtoAddress;\r
+    PVOID TargetProtoAddress;\r
+    PADDRESS_ENTRY ADE;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+    PNDIS_PACKET NdisPacket;\r
+    PIP_INTERFACE Interface = (PIP_INTERFACE)Context;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    Header = (PARP_HEADER)Packet->Header;\r
+\r
+    /* FIXME: Ethernet only */\r
+    if (WN2H(Header->HWType) != 1)\r
+        return;\r
+\r
+    /* Check protocol type */\r
+    if (Header->ProtoType != ETYPE_IPv4)\r
+        return;\r
+\r
+    SenderHWAddress    = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));\r
+    SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);\r
+\r
+    /* Check if we have the target protocol address */\r
+\r
+    TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +\r
+        Header->ProtoAddrLen + Header->HWAddrLen);\r
+\r
+    Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress));\r
+    ADE = IPLocateADE(Address, ADE_UNICAST);\r
+    if (!ADE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return;\r
+    }\r
+\r
+    /* Check if we know the sender */\r
+\r
+    AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress));\r
+    NCE = NBLocateNeighbor(Address);\r
+    if (NCE) {\r
+        DereferenceObject(Address);\r
+        /* We know the sender. Update the hardware address \r
+           and state in our neighbor address cache */\r
+        NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);\r
+    } else {\r
+        /* The packet had our protocol address as target. The sender\r
+           may want to communicate with us soon, so add his address\r
+           to our address cache */\r
+        NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,\r
+            Header->HWAddrLen, NUD_REACHABLE);\r
+    }\r
+    if (NCE)\r
+        DereferenceObject(NCE)\r
+\r
+    if (Header->Opcode != ARP_OPCODE_REQUEST)\r
+        return;\r
+    \r
+    /* This is a request for our address. Swap the addresses and\r
+       send an ARP reply back to the sender */\r
+    NdisPacket = PrepareARPPacket(\r
+        Header->HWType,                  /* Hardware type */\r
+        Header->ProtoType,               /* Protocol type */\r
+        (UCHAR)Interface->AddressLength, /* Hardware address length */\r
+        (UCHAR)Header->ProtoAddrLen,     /* Protocol address length */\r
+        Interface->Address,              /* Sender's (local) hardware address */\r
+        &ADE->Address->Address,          /* Sender's (local) protocol address */\r
+        SenderHWAddress,                 /* Target's (remote) hardware address */\r
+        SenderProtoAddress,              /* Target's (remote) protocol address */\r
+        ARP_OPCODE_REPLY);               /* ARP reply */\r
+    if (NdisPacket) {\r
+        PC(NdisPacket)->DLComplete = ARPTransmitComplete;\r
+        (*Interface->Transmit)(Interface->Context, NdisPacket,\r
+            MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP);\r
+    }\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/datalink/lan.c b/reactos/drivers/net/tcpip/datalink/lan.c
new file mode 100644 (file)
index 0000000..4476922
--- /dev/null
@@ -0,0 +1,903 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        datalink/lan.c\r
+ * PURPOSE:     Local Area Network media routines\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <lan.h>\r
+#include <address.h>\r
+#include <routines.h>\r
+#include <transmit.h>\r
+#include <receive.h>\r
+#include <arp.h>\r
+\r
+\r
+NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;\r
+BOOLEAN ProtocolRegistered     = FALSE;\r
+PLAN_ADAPTER Adapters          = NULL;\r
+\r
+\r
+NDIS_STATUS NDISCall(\r
+    PLAN_ADAPTER Adapter,\r
+    NDIS_REQUEST_TYPE Type,\r
+    NDIS_OID OID,\r
+    PVOID Buffer,\r
+    UINT Length)\r
+/*\r
+ * FUNCTION: Send a request to NDIS\r
+ * ARGUMENTS:\r
+ *     Adapter     = Pointer to a LAN_ADAPTER structure\r
+ *     Type        = Type of request (Set or Query)\r
+ *     OID         = Value to be set/queried for\r
+ *     Buffer      = Pointer to a buffer to use\r
+ *     Length      = Number of bytes in Buffer\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    NDIS_REQUEST Request;\r
+    NDIS_STATUS NdisStatus;\r
+\r
+    Request.RequestType = Type;\r
+    if (Type == NdisRequestSetInformation) {\r
+        Request.DATA.SET_INFORMATION.Oid                     = OID;\r
+        Request.DATA.SET_INFORMATION.InformationBuffer       = Buffer;\r
+        Request.DATA.SET_INFORMATION.InformationBufferLength = Length;\r
+    } else {\r
+        Request.DATA.QUERY_INFORMATION.Oid                     = OID;\r
+        Request.DATA.QUERY_INFORMATION.InformationBuffer       = Buffer;\r
+        Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;\r
+    }\r
+\r
+    if (Adapter->State != LAN_STATE_RESETTING) {\r
+        NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);\r
+    } else\r
+        NdisStatus = NDIS_STATUS_NOT_ACCEPTED;\r
+\r
+    /* Wait for NDIS to complete the request */\r
+    if (NdisStatus == NDIS_STATUS_PENDING) {\r
+        KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL);\r
+        NdisStatus = Adapter->NdisStatus;\r
+    }\r
+\r
+    return NdisStatus;\r
+}\r
+\r
+\r
+PNDIS_PACKET AllocateTDPacket(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Allocates an NDIS packet for NdisTransferData\r
+ * ARGUMENTS:\r
+ *     Adapter = Pointer to LAN_ADAPTER structure\r
+ * RETURNS:\r
+ *     Pointer to NDIS packet or NULL if there was not enough free\r
+ *     non-paged memory\r
+ */\r
+{\r
+    NDIS_STATUS NdisStatus;\r
+    PNDIS_PACKET NdisPacket;\r
+    PNDIS_BUFFER Buffer;\r
+    PVOID Data;\r
+\r
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS)\r
+        return NULL;\r
+\r
+    Data = ExAllocatePool(NonPagedPool, Adapter->MTU);\r
+    if (!Data) {\r
+        NdisFreePacket(NdisPacket);\r
+        return NULL;\r
+    }\r
+        \r
+    NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        NdisFreePacket(NdisPacket);\r
+        ExFreePool(Data);\r
+        return NULL;\r
+    }\r
+\r
+    NdisChainBufferAtFront(NdisPacket, Buffer);\r
+\r
+    PC(NdisPacket)->Context = NULL; /* End of list */\r
+\r
+    return NdisPacket;\r
+}\r
+\r
+\r
+VOID FreeTDPackets(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Frees transfer data packets\r
+ * ARGUMENTS:\r
+ *     Adapter = Pointer to LAN_ADAPTER structure\r
+ */\r
+{\r
+    PNDIS_PACKET NdisPacket, Next;\r
+\r
+    /* Release transfer data packets */\r
+    NdisPacket = Adapter->TDPackets;\r
+    while (NdisPacket) {\r
+        Next = PC(NdisPacket)->Context;\r
+        FreeNdisPacket(NdisPacket);\r
+        NdisPacket = Next;\r
+    }\r
+    Adapter->TDPackets = NULL;\r
+}\r
+\r
+\r
+VOID FreeAdapter(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure\r
+ * ARGUMENTS:\r
+ *     Adapter = Pointer to LAN_ADAPTER structure to free\r
+ */\r
+{\r
+    FreeTDPackets(Adapter);\r
+    ExFreePool(Adapter);\r
+}\r
+\r
+\r
+VOID ProtocolOpenAdapterComplete(\r
+    NDIS_HANDLE BindingContext,\r
+    NDIS_STATUS Status,\r
+    NDIS_STATUS OpenErrorStatus)\r
+/*\r
+ * FUNCTION: Called by NDIS to complete opening of an adapter\r
+ * ARGUMENTS:\r
+ *     BindingContext  = Pointer to a device context (LAN_ADAPTER)\r
+ *     Status          = Status of the operation\r
+ *     OpenErrorStatus = Additional status information\r
+ */\r
+{\r
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    KeSetEvent(&Adapter->Event, 0, FALSE);\r
+}\r
+\r
+\r
+VOID ProtocolCloseAdapterComplete(\r
+    NDIS_HANDLE BindingContext,\r
+    NDIS_STATUS Status)\r
+/*\r
+ * FUNCTION: Called by NDIS to complete closing an adapter\r
+ * ARGUMENTS:\r
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)\r
+ *     Status         = Status of the operation\r
+ */\r
+{\r
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    Adapter->NdisStatus = Status;\r
+\r
+    KeSetEvent(&Adapter->Event, 0, FALSE);\r
+}\r
+\r
+\r
+VOID ProtocolResetComplete(\r
+    NDIS_HANDLE BindingContext,\r
+    NDIS_STATUS Status)\r
+/*\r
+ * FUNCTION: Called by NDIS to complete resetting an adapter\r
+ * ARGUMENTS:\r
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)\r
+ *     Status         = Status of the operation\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+}\r
+\r
+\r
+VOID ProtocolRequestComplete(\r
+    NDIS_HANDLE BindingContext,\r
+    PNDIS_REQUEST NdisRequest,\r
+    NDIS_STATUS Status)\r
+/*\r
+ * FUNCTION: Called by NDIS to complete a request\r
+ * ARGUMENTS:\r
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)\r
+ *     NdisRequest    = Pointer to an object describing the request\r
+ *     Status         = Status of the operation\r
+ */\r
+{\r
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
+\r
+    /* Save status of request and signal an event */\r
+    Adapter->NdisStatus = Status;\r
+\r
+    KeSetEvent(&Adapter->Event, 0, FALSE);\r
+}\r
+\r
+\r
+VOID ProtocolSendComplete(\r
+    NDIS_HANDLE BindingContext,\r
+    PNDIS_PACKET Packet,\r
+    NDIS_STATUS Status)\r
+/*\r
+ * FUNCTION: Called by NDIS to complete sending process\r
+ * ARGUMENTS:\r
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)\r
+ *     Packet         = Pointer to a packet descriptor\r
+ *     Status         = Status of the operation\r
+ */\r
+{\r
+       PLAN_ADAPTER Adapter = BindingContext;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);\r
+\r
+    (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);\r
+}\r
+\r
+\r
+VOID ProtocolTransferDataComplete(\r
+    NDIS_HANDLE BindingContext,\r
+    PNDIS_PACKET Packet,\r
+    NDIS_STATUS Status,\r
+    UINT BytesTransferred)\r
+/*\r
+ * FUNCTION: Called by NDIS to complete reception of data\r
+ * ARGUMENTS:\r
+ *     BindingContext   = Pointer to a device context (LAN_ADAPTER)\r
+ *     Packet           = Pointer to a packet descriptor\r
+ *     Status           = Status of the operation\r
+ *     BytesTransferred = Number of bytes transferred\r
+ * NOTES:\r
+ *     If the packet was successfully received, determine the protocol\r
+ *     type and pass it to the correct receive handler\r
+ */\r
+{\r
+    UINT PacketType;\r
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
+\r
+    if (Status == NDIS_STATUS_SUCCESS) {\r
+        PNDIS_BUFFER NdisBuffer;\r
+        IP_PACKET IPPacket;\r
+\r
+        NdisGetFirstBufferFromPacket(\r
+            Packet, &NdisBuffer, &IPPacket.Header,\r
+            &IPPacket.ContigSize, &IPPacket.TotalSize);\r
+\r
+        /* Determine which upper layer protocol that should receive\r
+           this packet and pass it to the correct receive handler */\r
+        PacketType = ((PETH_HEADER)IPPacket.Header)->EType;\r
+        switch (PacketType) {\r
+            case ETYPE_IPv4:\r
+            case ETYPE_IPv6:\r
+                IPReceive(Adapter->Context, &IPPacket);\r
+                break;\r
+            case ETYPE_ARP:\r
+                ARPReceive(Adapter->Context, &IPPacket);\r
+            default:\r
+                break;\r
+        }\r
+    }\r
+\r
+    /* Release the packet descriptor */\r
+    KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);\r
+\r
+    PC(Packet)->Context = Adapter->TDPackets;\r
+    Adapter->TDPackets  = Packet;\r
+\r
+    KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);\r
+}\r
+\r
+\r
+NDIS_STATUS ProtocolReceive(\r
+    NDIS_HANDLE BindingContext,\r
+    NDIS_HANDLE MacReceiveContext,\r
+    PVOID HeaderBuffer,\r
+    UINT HeaderBufferSize,\r
+    PVOID LookaheadBuffer,\r
+    UINT LookaheadBufferSize,\r
+    UINT PacketSize)\r
+/*\r
+ * FUNCTION: Called by NDIS when a packet has been received on the physical link\r
+ * ARGUMENTS:\r
+ *     BindingContext      = Pointer to a device context (LAN_ADAPTER)\r
+ *     MacReceiveContext   = Handle used by underlying NIC driver\r
+ *     HeaderBuffer        = Pointer to a buffer containing the packet header\r
+ *     HeaderBufferSize    = Number of bytes in HeaderBuffer\r
+ *     LookaheadBuffer     = Pointer to a buffer containing buffered packet data\r
+ *     LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for\r
+ *     PacketSize          = Overall size of the packet (not including header)\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    USHORT EType;\r
+    UINT PacketType;\r
+    IP_PACKET IPPacket;\r
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;\r
+    PETH_HEADER EHeader  = (PETH_HEADER)HeaderBuffer;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    if ((Adapter->State != LAN_STATE_STARTED) ||\r
+        HeaderBufferSize < Adapter->HeaderSize)\r
+        /* Adapter is not started or the header was too small */\r
+        return NDIS_STATUS_NOT_ACCEPTED;\r
+\r
+    if (Adapter->Media == NdisMedium802_3) {\r
+        /* Ethernet and IEEE 802.3 frames can be destinguished by\r
+           looking at the IEEE 802.3 length field. This field is\r
+           less than or equal to 1500 for a valid IEEE 802.3 frame\r
+           and larger than 1500 is it's a valid Ether-Type value.\r
+           See RFC 1122, section 2.3.3 for more information */\r
+        if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP))\r
+            return NDIS_STATUS_NOT_ACCEPTED;\r
+        /* We use Ether-Type constants to destinguish packets */\r
+        PacketType = EType;\r
+    } else\r
+        /* FIXME: Support other medias */\r
+        return NDIS_STATUS_NOT_ACCEPTED;\r
+\r
+    if (LookaheadBufferSize < PacketSize) {\r
+        NDIS_STATUS NdisStatus;\r
+        PNDIS_PACKET NdisPacket;\r
+        UINT BytesTransferred;\r
+        \r
+        /* Get transfer data packet */\r
+\r
+        KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);\r
+\r
+        NdisPacket = Adapter->TDPackets;\r
+        if (NdisPacket == (PNDIS_PACKET)NULL) {\r
+            /* We don't have a free packet descriptor. Drop the packet */\r
+            KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);\r
+            return NDIS_STATUS_SUCCESS;\r
+        }\r
+        Adapter->TDPackets = PC(NdisPacket)->Context;\r
+\r
+        KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);\r
+\r
+        /* Get the data */\r
+        NdisTransferData(&NdisStatus, Adapter->NdisHandle,\r
+            MacReceiveContext, 0, PacketSize,\r
+            NdisPacket, &BytesTransferred);\r
+        if (NdisStatus != NDIS_STATUS_PENDING)\r
+            ProtocolTransferDataComplete(BindingContext,\r
+                NdisPacket, NdisStatus, BytesTransferred);\r
+\r
+        return NDIS_STATUS_SUCCESS;\r
+    }\r
+\r
+    /* We got all the data in the lookahead buffer */\r
+    RtlZeroMemory(&IPPacket, sizeof(IPPacket));\r
+    IPPacket.Header    = LookaheadBuffer;\r
+    IPPacket.TotalSize = PacketSize;\r
+\r
+    switch (PacketType) {\r
+        case ETYPE_IPv4:\r
+        case ETYPE_IPv6:\r
+            IPReceive(Adapter->Context, &IPPacket);\r
+            break;\r
+        case ETYPE_ARP:\r
+            ARPReceive(Adapter->Context, &IPPacket);\r
+            break;\r
+        default:\r
+            break;\r
+    }\r
+\r
+    return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+VOID ProtocolReceiveComplete(\r
+    NDIS_HANDLE BindingContext)\r
+/*\r
+ * FUNCTION: Called by NDIS when we're done receiving data\r
+ * ARGUMENTS:\r
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+}\r
+\r
+\r
+VOID ProtocolStatus(\r
+    NDIS_HANDLE BindingContext,\r
+    NDIS_STATUS GenerelStatus,\r
+    PVOID StatusBuffer,\r
+    UINT StatusBufferSize)\r
+/*\r
+ * FUNCTION: Called by NDIS when the underlying driver has changed state\r
+ * ARGUMENTS:\r
+ *     BindingContext   = Pointer to a device context (LAN_ADAPTER)\r
+ *     GenerelStatus    = A generel status code\r
+ *     StatusBuffer     = Pointer to a buffer with medium-specific data\r
+ *     StatusBufferSize = Number of bytes in StatusBuffer\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+}\r
+\r
+\r
+VOID ProtocolStatusComplete(\r
+    NDIS_HANDLE NdisBindingContext)\r
+/*\r
+ * FUNCTION: Called by NDIS when a status-change has occurred\r
+ * ARGUMENTS:\r
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+}\r
+\r
+\r
+VOID LANTransmit(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    UINT Offset,\r
+    PVOID LinkAddress,\r
+    USHORT Type)\r
+/*\r
+ * FUNCTION: Transmits a packet\r
+ * ARGUMENTS:\r
+ *     Context     = Pointer to context information (LAN_ADAPTER)\r
+ *     NdisPacket  = Pointer to NDIS packet to send\r
+ *     Offset      = Offset in packet where data starts\r
+ *     LinkAddress = Pointer to link address of destination (NULL = broadcast)\r
+ *     Type        = LAN protocol type (LAN_PROTO_*)\r
+ */\r
+{\r
+    NDIS_STATUS NdisStatus;\r
+    PETH_HEADER EHeader;\r
+    PVOID Data;\r
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    /* NDIS send routines don't have an offset argument so we\r
+       must offset the data in upper layers and adjust the\r
+       packet here. We save the offset in the packet context\r
+       area so it can be undone before we release the packet */\r
+    Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);\r
+    PC(NdisPacket)->DLOffset = Offset;\r
+\r
+    if (Adapter->State == LAN_STATE_STARTED) {\r
+        switch (Adapter->Media) {\r
+        case NdisMedium802_3:\r
+            EHeader = (PETH_HEADER)Data;\r
+    \r
+            if (LinkAddress)\r
+                /* Unicast address */\r
+                RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);\r
+             else\r
+                /* Broadcast address */\r
+                RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);\r
+\r
+            RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);\r
+\r
+            switch (Type) {\r
+                case LAN_PROTO_IPv4:\r
+                    EHeader->EType = ETYPE_IPv4;\r
+                    break;\r
+                case LAN_PROTO_ARP:\r
+                    EHeader->EType = ETYPE_ARP;\r
+                    break;\r
+                case LAN_PROTO_IPv6:\r
+                    EHeader->EType = ETYPE_IPv6;\r
+                    break;\r
+                default:\r
+#if DBG\r
+                    /* Should not happen */\r
+                    TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));\r
+\r
+                    ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE);\r
+#endif\r
+                    return;\r
+            }\r
+            break;\r
+\r
+        default:\r
+            /* FIXME: Support other medias */\r
+            break;\r
+        }\r
+       \r
+        NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);\r
+        if (NdisStatus != NDIS_STATUS_PENDING)\r
+            ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);\r
+    } else\r
+        ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);\r
+}\r
+\r
+\r
+VOID BindAdapter(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Binds a LAN adapter to IP layer\r
+ * ARGUMENTS:\r
+ *     Adapter = Pointer to LAN_ADAPTER structure\r
+ * NOTES:\r
+ *    We set the lookahead buffer size, set the packet filter and\r
+ *    bind the adapter to IP layer\r
+ */\r
+{\r
+    INT i;\r
+    PIP_INTERFACE IF;\r
+    PIP_ADDRESS Address;\r
+    PNDIS_PACKET Packet;\r
+    NDIS_STATUS NdisStatus;\r
+    LLIP_BIND_INFO BindInfo;\r
+    ULONG Lookahead = LOOKAHEAD_SIZE;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    Adapter->State = LAN_STATE_OPENING;\r
+\r
+    NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,\r
+        OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG));\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));\r
+        return;\r
+    }\r
+\r
+    /* Allocate packets for NdisTransferData */\r
+    /* FIXME: How many should we allocate? */\r
+    Adapter->TDPackets = NULL;\r
+    for (i = 0; i < 2; i++) {\r
+        Packet              = AllocateTDPacket(Adapter);\r
+        PC(Packet)->Context = Adapter->TDPackets;\r
+        Adapter->TDPackets  = Packet;\r
+        if (!Packet) {\r
+            TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n"));\r
+            FreeTDPackets(Adapter);\r
+            return;\r
+        }\r
+    }\r
+\r
+    /* Bind the adapter to IP layer */\r
+    BindInfo.Context       = Adapter;\r
+    BindInfo.HeaderSize    = Adapter->HeaderSize;\r
+    BindInfo.MinFrameSize  = Adapter->MinFrameSize;\r
+    BindInfo.MTU           = Adapter->MTU;\r
+    BindInfo.Address       = (PUCHAR)&Adapter->HWAddress;\r
+    BindInfo.AddressLength = Adapter->HWAddressLength;\r
+    BindInfo.Transmit      = LANTransmit;\r
+\r
+    IF = IPCreateInterface(&BindInfo);\r
+    if (!IF) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        FreeTDPackets(Adapter);\r
+        return;\r
+    }\r
+\r
+    /* FIXME: Get address from registry.\r
+       For now just use a private address, eg. 10.0.0.10 */\r
+    Address = AddrBuildIPv4(0x0A00000A);\r
+    if (!Address) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        FreeTDPackets(Adapter);\r
+        IPDestroyInterface(Adapter->Context);\r
+        return;\r
+    }\r
+    /* Create a net table entry for this interface */\r
+    if (!IPCreateNTE(IF, Address, 8)) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        FreeTDPackets(Adapter);\r
+        IPDestroyInterface(IF);\r
+        return;\r
+    }\r
+\r
+    /* Reference the interface for the NTE. The reference for\r
+       the address is just passed on to the NTE */\r
+    ReferenceObject(IF);\r
+\r
+    /* Register interface with IP layer */\r
+    IPRegisterInterface(IF);\r
+\r
+    /* Set packet filter so we can send and receive packets */\r
+    NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,\r
+        OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT));\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));\r
+        FreeTDPackets(Adapter);\r
+        IPDestroyInterface(IF);\r
+        return;\r
+    }\r
+\r
+    Adapter->Context = IF;\r
+\r
+    Adapter->State = LAN_STATE_STARTED;\r
+}\r
+\r
+\r
+VOID UnbindAdapter(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Unbinds a LAN adapter from IP layer\r
+ * ARGUMENTS:\r
+ *     Adapter = Pointer to LAN_ADAPTER structure\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    if (Adapter->State == LAN_STATE_STARTED) {\r
+        PIP_INTERFACE IF = Adapter->Context;\r
+\r
+        IPUnregisterInterface(IF);\r
+\r
+        IPDestroyInterface(IF);\r
+\r
+        /* Free transfer data packets */\r
+        FreeTDPackets(Adapter);\r
+    }\r
+}\r
+\r
+\r
+NDIS_STATUS LANRegisterAdapter(\r
+    PNDIS_STRING AdapterName,\r
+    PLAN_ADAPTER *Adapter)\r
+/*\r
+ * FUNCTION: Registers protocol with an NDIS adapter\r
+ * ARGUMENTS:\r
+ *     AdapterName = Pointer to string with name of adapter to register\r
+ *     Adapter     = Address of pointer to a LAN_ADAPTER structure\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    PLAN_ADAPTER IF;\r
+    NDIS_STATUS NdisStatus;\r
+    NDIS_STATUS OpenStatus;\r
+    UINT MediaIndex;\r
+    NDIS_MEDIUM MediaArray[MAX_MEDIA];\r
+    UINT AddressOID;\r
+    UINT Speed;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));\r
+    if (!IF)\r
+        return NDIS_STATUS_RESOURCES;\r
+\r
+    RtlZeroMemory(IF, sizeof(LAN_ADAPTER));\r
+\r
+    /* Put adapter in stopped state */\r
+    IF->State = LAN_STATE_STOPPED;\r
+\r
+    /* Initialize protecting spin lock */\r
+    KeInitializeSpinLock(&IF->Lock);\r
+\r
+    KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);\r
+\r
+    /* Initialize array with media IDs we support */\r
+    MediaArray[MEDIA_ETH] = NdisMedium802_3;\r
+\r
+    /* Open the adapter. */\r
+    NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex,\r
+        MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL);\r
+\r
+    /* Wait until the adapter is opened */\r
+    if (NdisStatus == NDIS_STATUS_PENDING)\r
+        KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);\r
+    else if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        ExFreePool(IF);\r
+        return NdisStatus;\r
+    }\r
+\r
+    IF->Media = MediaArray[MediaIndex];\r
+\r
+    /* Fill LAN_ADAPTER structure with some adapter specific information */\r
+    switch (IF->Media) {\r
+    case NdisMedium802_3:\r
+        IF->HWAddressLength = IEEE_802_ADDR_LENGTH;\r
+        IF->BCastMask       = BCAST_ETH_MASK;\r
+        IF->BCastCheck      = BCAST_ETH_CHECK;\r
+        IF->BCastOffset     = BCAST_ETH_OFFSET;\r
+        IF->HeaderSize      = sizeof(ETH_HEADER);\r
+        IF->MinFrameSize    = 60;\r
+        AddressOID          = OID_802_3_CURRENT_ADDRESS;\r
+        IF->PacketFilter    = \r
+            NDIS_PACKET_TYPE_BROADCAST |\r
+            NDIS_PACKET_TYPE_DIRECTED  |\r
+            NDIS_PACKET_TYPE_MULTICAST;\r
+        break;\r
+\r
+    default:\r
+        /* Unsupported media */\r
+        TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));\r
+        ExFreePool(IF);\r
+        return NDIS_STATUS_NOT_SUPPORTED;\r
+    }\r
+\r
+    /* Get maximum frame size */\r
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
+        OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT));\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        ExFreePool(IF);\r
+        return NdisStatus;\r
+    }\r
+\r
+    /* Get maximum packet size */\r
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
+        OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT));\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));\r
+        ExFreePool(IF);\r
+        return NdisStatus;\r
+    }\r
+\r
+    /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */\r
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
+        OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT));\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS)\r
+        /* Legacy NIC drivers may not support this query, if it fails we\r
+           assume it can send at least one packet per call to NdisSend(Packets) */\r
+        IF->MaxSendPackets = 1;\r
+\r
+    /* Get current hardware address */\r
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID,\r
+        IF->HWAddress, IF->HWAddressLength);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));\r
+        ExFreePool(IF);\r
+        return NdisStatus;\r
+    }\r
+\r
+    /* Get maximum link speed */\r
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,\r
+        OID_GEN_LINK_SPEED, &Speed, sizeof(UINT));\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));\r
+        ExFreePool(IF);\r
+        return NdisStatus;\r
+    }\r
+\r
+    /* Convert returned link speed to bps (it is in 100bps increments) */\r
+    IF->Speed = Speed * 100L;\r
+\r
+    *Adapter = IF;\r
+\r
+    /* Add adapter to the adapter list */\r
+    IF->Next = Adapters;\r
+    Adapters = IF;\r
+\r
+    /* Bind adapter to IP layer */\r
+    BindAdapter(IF);\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
+\r
+    return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NDIS_STATUS LANUnregisterAdapter(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Unregisters protocol with NDIS adapter\r
+ * ARGUMENTS:\r
+ *     Adapter = Pointer to a LAN_ADAPTER structure\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    NDIS_HANDLE NdisHandle;\r
+    PLAN_ADAPTER IF, PrevIF;\r
+    BOOLEAN Found = FALSE;\r
+    NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    /* Search the adapter list for the specified adapter and remove it */\r
+    IF = Adapters;\r
+    if (IF) {\r
+        if (Adapter != Adapters) {\r
+            PrevIF = IF;\r
+            while ((IF) && (!Found)) {\r
+                if (IF == Adapter) {\r
+                    /* We've found the adapter, now remove it from the list */\r
+                    PrevIF->Next = IF->Next;\r
+                    Found = TRUE;\r
+                }\r
+                PrevIF = IF;\r
+                IF = IF->Next;\r
+            }\r
+        } else {\r
+            Adapters = NULL;\r
+            Found    = TRUE;\r
+        }\r
+    }\r
+    if (!Found) {\r
+        TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n"));\r
+        return NDIS_STATUS_ADAPTER_NOT_FOUND;\r
+    }\r
+\r
+    /* Unbind adapter from IP layer */\r
+    UnbindAdapter(Adapter);\r
+\r
+    KeAcquireSpinLock(&Adapter->Lock, &OldIrql);\r
+    NdisHandle = Adapter->NdisHandle;\r
+    if (NdisHandle) {\r
+        Adapter->NdisHandle = NULL;\r
+        KeReleaseSpinLock(&Adapter->Lock, OldIrql);\r
+\r
+        NdisCloseAdapter(&NdisStatus, NdisHandle);\r
+        if (NdisStatus == NDIS_STATUS_PENDING) {\r
+            KeWaitForSingleObject(&Adapter->Event,\r
+                UserRequest, KernelMode, FALSE, NULL);\r
+            NdisStatus = Adapter->NdisStatus;\r
+        }\r
+    } else\r
+        KeReleaseSpinLock(&Adapter->Lock, OldIrql);\r
+\r
+    FreeAdapter(Adapter);\r
+\r
+    return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS LANRegisterProtocol(\r
+    PSTRING Name)\r
+/*\r
+ * FUNCTION: Registers this protocol driver with NDIS\r
+ * ARGUMENTS:\r
+ *     Name = Name of this protocol driver\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    NDIS_STATUS NdisStatus;\r
+    NDIS_PROTOCOL_CHARACTERISTICS ProtChars;\r
+\r
+    /* Set up protocol characteristics */\r
+    RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));\r
+    ProtChars.MajorNdisVersion            = NDIS_VERSION_MAJOR;\r
+    ProtChars.MinorNdisVersion            = NDIS_VERSION_MINOR;\r
+    ProtChars.Name.Length                 = Name->Length;\r
+    ProtChars.Name.Buffer                 = (PVOID)Name->Buffer;\r
+    ProtChars.OpenAdapterCompleteHandler  = ProtocolOpenAdapterComplete;\r
+    ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;\r
+    ProtChars.ResetCompleteHandler        = ProtocolResetComplete;\r
+    ProtChars.RequestCompleteHandler      = ProtocolRequestComplete;\r
+    ProtChars.SendCompleteHandler         = ProtocolSendComplete;\r
+    ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;\r
+    ProtChars.ReceiveHandler              = ProtocolReceive;\r
+    ProtChars.ReceiveCompleteHandler      = ProtocolReceiveComplete;\r
+    ProtChars.StatusHandler               = ProtocolStatus;\r
+    ProtChars.StatusCompleteHandler       = ProtocolStatusComplete;\r
+\r
+       /* Try to register protocol */\r
+    NdisRegisterProtocol(\r
+        &NdisStatus, &NdisProtocolHandle, &ProtChars,\r
+        sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS)\r
+        return (NTSTATUS)NdisStatus;\r
+\r
+    ProtocolRegistered = TRUE;\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+VOID LANUnregisterProtocol(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Unregisters this protocol driver with NDIS\r
+ * NOTES: Does not care wether we are already registered\r
+ */\r
+{\r
+    if (ProtocolRegistered) {\r
+        NDIS_STATUS NdisStatus;\r
+\r
+        while (Adapters)\r
+            NdisStatus = LANUnregisterAdapter(Adapters);\r
+\r
+        NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);\r
+        ProtocolRegistered = FALSE;\r
+    }\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/datalink/loopback.c b/reactos/drivers/net/tcpip/datalink/loopback.c
new file mode 100644 (file)
index 0000000..d42e499
--- /dev/null
@@ -0,0 +1,224 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        datalink/loopback.c\r
+ * PURPOSE:     Loopback adapter\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <loopback.h>\r
+#include <ip.h>\r
+#include <address.h>\r
+#include <receive.h>\r
+#include <transmit.h>\r
+#include <routines.h>\r
+\r
+\r
+WORK_QUEUE_ITEM  LoopWorkItem;\r
+PIP_INTERFACE    Loopback = NULL;\r
+/* Indicates wether the loopback interface is currently transmitting */\r
+BOOLEAN          LoopBusy = FALSE;\r
+/* Loopback transmit queue */\r
+PNDIS_PACKET     LoopQueueHead = (PNDIS_PACKET)NULL;\r
+PNDIS_PACKET     LoopQueueTail = (PNDIS_PACKET)NULL;\r
+/* Spin lock for protecting loopback transmit queue */\r
+KSPIN_LOCK       LoopLock;\r
+\r
+\r
+VOID RealTransmit(\r
+    PVOID Context)\r
+/*\r
+ * FUNCTION: Transmits one or more packet(s) in loopback queue to ourselves\r
+ * ARGUMENTS:\r
+ *     Context = Pointer to context information (loopback interface)\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PNDIS_PACKET NdisPacket;\r
+    IP_PACKET IPPacket;\r
+    PNDIS_BUFFER Buffer;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);\r
+\r
+    KeAcquireSpinLockAtDpcLevel(&LoopLock);\r
+\r
+    for (;;) {\r
+        /* Get the next packet from the queue (if any) */\r
+        NdisPacket = LoopQueueHead;\r
+        if (!NdisPacket)\r
+            break;\r
+\r
+        LoopQueueHead = *(PNDIS_PACKET*)NdisPacket->MacReserved;\r
+\r
+        KeReleaseSpinLockFromDpcLevel(&LoopLock);\r
+\r
+        IPPacket.NdisPacket = NdisPacket;\r
+\r
+        NdisGetFirstBufferFromPacket(NdisPacket,\r
+                                    &Buffer,\r
+                                    &IPPacket.Header,\r
+                                    &IPPacket.ContigSize,\r
+                                    &IPPacket.TotalSize);\r
+\r
+        IPReceive(Context, &IPPacket);\r
+\r
+        AdjustPacket(NdisPacket, 0, PC(NdisPacket)->DLOffset);\r
+\r
+        PC(NdisPacket)->DLComplete(Context, NdisPacket, NDIS_STATUS_SUCCESS);\r
+\r
+        /* Lower IRQL for a moment to prevent starvation */\r
+        KeLowerIrql(OldIrql);\r
+\r
+        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);\r
+\r
+        KeAcquireSpinLockAtDpcLevel(&LoopLock);\r
+    }\r
+\r
+    LoopBusy = FALSE;\r
+\r
+    KeReleaseSpinLockFromDpcLevel(&LoopLock);\r
+\r
+    KeLowerIrql(OldIrql);\r
+}\r
+\r
+\r
+VOID LoopTransmit(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    UINT Offset,\r
+    PVOID LinkAddress,\r
+    USHORT Type)\r
+/*\r
+ * FUNCTION: Transmits a packet\r
+ * ARGUMENTS:\r
+ *     Context     = Pointer to context information (NULL)\r
+ *     NdisPacket  = Pointer to NDIS packet to send\r
+ *     Offset      = Offset in packet where packet data starts\r
+ *     LinkAddress = Pointer to link address\r
+ *     Type        = LAN protocol type (unused)\r
+ */\r
+{\r
+    PNDIS_PACKET *pNdisPacket;\r
+    KIRQL OldIrql;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    /* NDIS send routines don't have an offset argument so we\r
+       must offset the data in upper layers and adjust the\r
+       packet here. We save the offset in the packet context\r
+       area so it can be undone before we release the packet */\r
+    AdjustPacket(NdisPacket, Offset, 0);\r
+    PC(NdisPacket)->DLOffset = Offset;\r
+\r
+    pNdisPacket  = (PNDIS_PACKET*)NdisPacket->MacReserved;\r
+    *pNdisPacket = NULL;\r
+\r
+    KeAcquireSpinLock(&LoopLock, &OldIrql);\r
+\r
+    /* Add packet to transmit queue */\r
+    if (LoopQueueHead) {\r
+        /* Transmit queue is not empty */\r
+        pNdisPacket  = (PNDIS_PACKET*)LoopQueueTail->MacReserved;\r
+        *pNdisPacket = NdisPacket;\r
+    } else\r
+        /* Transmit queue is empty */\r
+        LoopQueueHead = NdisPacket;\r
+\r
+    LoopQueueTail = NdisPacket;\r
+\r
+    /* If LoopTransmit is not running (or scheduled), schedule it to run */\r
+    if (!LoopBusy) {\r
+        ExQueueWorkItem(&LoopWorkItem, CriticalWorkQueue);\r
+        LoopBusy = TRUE;\r
+    }\r
+\r
+    KeReleaseSpinLock(&LoopLock, OldIrql);\r
+}\r
+\r
+\r
+NDIS_STATUS LoopRegisterAdapter(\r
+    PNDIS_STRING AdapterName,\r
+    PLAN_ADAPTER *Adapter)\r
+/*\r
+ * FUNCTION: Registers loopback adapter\r
+ * ARGUMENTS:\r
+ *     AdapterName = Unused\r
+ *     Adapter     = Unused\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    PIP_ADDRESS Address;\r
+    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    Address = AddrBuildIPv4(LOOPBACK_ADDRESS_IPv4);\r
+    if (Address) {\r
+        LLIP_BIND_INFO BindInfo;\r
+\r
+        /* Bind the adapter to IP layer */\r
+        BindInfo.Context       = NULL;\r
+        BindInfo.HeaderSize    = 0;\r
+        BindInfo.MinFrameSize  = 0;\r
+        BindInfo.MTU           = 16384;\r
+        BindInfo.Address       = NULL;\r
+        BindInfo.AddressLength = 0;\r
+        BindInfo.Transmit      = LoopTransmit;\r
+\r
+        Loopback = IPCreateInterface(&BindInfo);\r
+        if ((Loopback) && (IPCreateNTE(Loopback, Address, 8))) {\r
+            /* Reference the interface for the NTE. The reference for\r
+               the address is just passed on to the NTE */\r
+            ReferenceObject(Loopback);\r
+\r
+            IPRegisterInterface(Loopback);\r
+\r
+            ExInitializeWorkItem(&LoopWorkItem, RealTransmit, Loopback);\r
+\r
+            KeInitializeSpinLock(&LoopLock);\r
+            LoopBusy = FALSE;\r
+        } else\r
+            Status = NDIS_STATUS_RESOURCES;\r
+    } else\r
+        Status = NDIS_STATUS_RESOURCES;\r
+\r
+    if (!NT_SUCCESS(Status))\r
+        LoopUnregisterAdapter(NULL);\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
+\r
+    return Status;\r
+}\r
+\r
+\r
+NDIS_STATUS LoopUnregisterAdapter(\r
+    PLAN_ADAPTER Adapter)\r
+/*\r
+ * FUNCTION: Unregisters loopback adapter\r
+ * ARGUMENTS:\r
+ *     Adapter = Unused\r
+ * RETURNS:\r
+ *     Status of operation\r
+ * NOTES:\r
+ *     Does not care wether we have registered loopback adapter\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    if (Loopback) {\r
+        IPUnregisterInterface(Loopback);\r
+        IPDestroyInterface(Loopback);\r
+        Loopback = NULL;\r
+    }\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
+\r
+    return NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/address.h b/reactos/drivers/net/tcpip/include/address.h
new file mode 100644 (file)
index 0000000..aeb953d
--- /dev/null
@@ -0,0 +1,63 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/address.h\r
+ * PURPOSE:     Address manipulation prototypes\r
+ */\r
+#ifndef __ADDRESS_H\r
+#define __ADDRESS_H\r
+\r
+\r
+/*\r
+ * Initialize an IPv4 style address\r
+ * VOID AddrInitIPv4(\r
+ *     PIP_ADDRESS IPAddress,\r
+ *     IPv4_RAW_ADDRESS RawAddress)\r
+ */\r
+#define AddrInitIPv4(IPAddress, RawAddress)           \\r
+{                                                     \\r
+    (IPAddress)->RefCount            = 1;             \\r
+    (IPAddress)->Type                = IP_ADDRESS_V4; \\r
+    (IPAddress)->Address.IPv4Address = (RawAddress);  \\r
+}\r
+\r
+\r
+BOOLEAN AddrIsUnspecified(\r
+    PIP_ADDRESS Address);\r
+\r
+NTSTATUS AddrGetAddress(\r
+    PTRANSPORT_ADDRESS AddrList,\r
+    PIP_ADDRESS *Address,\r
+    PUSHORT Port,\r
+    PIP_ADDRESS *Cache);\r
+\r
+BOOLEAN AddrIsEqual(\r
+    PIP_ADDRESS Address1,\r
+    PIP_ADDRESS Address2);\r
+\r
+INT AddrCompare(\r
+    PIP_ADDRESS Address1,\r
+    PIP_ADDRESS Address2);\r
+\r
+BOOLEAN AddrIsEqualIPv4(\r
+    PIP_ADDRESS Address1,\r
+    IPv4_RAW_ADDRESS Address2);\r
+\r
+PIP_ADDRESS AddrBuildIPv4(\r
+    IPv4_RAW_ADDRESS Address);\r
+\r
+PADDRESS_ENTRY AddrLocateADEv4(\r
+    IPv4_RAW_ADDRESS Address);\r
+\r
+PADDRESS_FILE AddrSearchFirst(\r
+    PIP_ADDRESS Address,\r
+    USHORT Port,\r
+    USHORT Protocol,\r
+    PAF_SEARCH SearchContext);\r
+\r
+PADDRESS_FILE AddrSearchNext(\r
+    PAF_SEARCH SearchContext);\r
+\r
+#endif /* __ADDRESS_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/arp.h b/reactos/drivers/net/tcpip/include/arp.h
new file mode 100644 (file)
index 0000000..b33ad14
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/arp.h\r
+ * PURPOSE:     Address Resolution Protocol definitions\r
+ */\r
+#ifndef __ARP_H\r
+#define __ARP_H\r
+\r
+typedef struct ARP_HEADER {\r
+    USHORT HWType;       /* Hardware Type */\r
+    USHORT ProtoType;    /* Protocol Type */\r
+    UCHAR  HWAddrLen;    /* Hardware Address Length */\r
+    UCHAR  ProtoAddrLen; /* Protocol Address Length */\r
+    USHORT Opcode;       /* Opcode */\r
+    /* Sender's Hardware Address */\r
+    /* Sender's Protocol Address */\r
+    /* Target's Hardware Address */\r
+    /* Target's Protocol Address */\r
+} ARP_HEADER, *PARP_HEADER;\r
+\r
+/* We swap constants so we can compare values at runtime without swapping them */\r
+#define ARP_OPCODE_REQUEST WH2N(0x0001) /* ARP request */\r
+#define ARP_OPCODE_REPLY   WH2N(0x0002) /* ARP reply */\r
+\r
+\r
+BOOLEAN ARPTransmit(\r
+    PIP_ADDRESS Address,\r
+    PNET_TABLE_ENTRY NTE);\r
+\r
+VOID ARPReceive(\r
+    PVOID Context,\r
+    PIP_PACKET Packet);\r
+\r
+#endif /* __ARP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/checksum.h b/reactos/drivers/net/tcpip/include/checksum.h
new file mode 100644 (file)
index 0000000..5805b51
--- /dev/null
@@ -0,0 +1,27 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/checksum.h\r
+ * PURPOSE:     Checksum routine definitions\r
+ */\r
+#ifndef __CHECKSUM_H\r
+#define __CHECKSUM_H\r
+\r
+\r
+ULONG ChecksumCompute(\r
+    PVOID Data,\r
+    UINT Count,\r
+    ULONG Seed);\r
+\r
+#define IPv4Checksum(Data, Count, Seed)(ChecksumCompute(Data, Count, Seed))\r
+\r
+/*\r
+ * Macro to check for a correct checksum\r
+ * BOOLEAN CorrectChecksum(PVOID Data, UINT Count)\r
+ */\r
+#define CorrectChecksum(Data, Count) \\r
+    (BOOLEAN)(IPv4Checksum(Data, Count, 0) == DH2N(0x0000FFFF))\r
+\r
+#endif /* __CHECKSUM_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/datagram.h b/reactos/drivers/net/tcpip/include/datagram.h
new file mode 100644 (file)
index 0000000..3dd3a79
--- /dev/null
@@ -0,0 +1,49 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/datagram.h\r
+ * PURPOSE:     Datagram types and constants\r
+ */\r
+#ifndef __DATAGRAM_H\r
+#define __DATAGRAM_H\r
+\r
+#include <titypes.h>\r
+\r
+\r
+VOID DGSend(\r
+    PVOID Context,\r
+    PDATAGRAM_SEND_REQUEST SendRequest);\r
+\r
+VOID DGCancelSendRequest(\r
+    PADDRESS_FILE AddrFile,\r
+    PVOID Context);\r
+\r
+VOID DGCancelReceiveRequest(\r
+    PADDRESS_FILE AddrFile,\r
+    PVOID Context);\r
+\r
+NTSTATUS DGSendDatagram(\r
+    PTDI_REQUEST Request,\r
+    PTDI_CONNECTION_INFORMATION ConnInfo,\r
+    PNDIS_BUFFER Buffer,\r
+    ULONG DataSize,\r
+    DATAGRAM_BUILD_ROUTINE Build);\r
+\r
+NTSTATUS DGReceiveDatagram(\r
+    PTDI_REQUEST Request,\r
+    PTDI_CONNECTION_INFORMATION ConnInfo,\r
+    PNDIS_BUFFER Buffer,\r
+    ULONG ReceiveLength,\r
+    ULONG ReceiveFlags,\r
+    PTDI_CONNECTION_INFORMATION ReturnInfo,\r
+    PULONG BytesReceived);\r
+\r
+NTSTATUS DGStartup(\r
+    VOID);\r
+\r
+NTSTATUS DGShutdown(\r
+    VOID);\r
+\r
+#endif /* __DATAGRAM_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/debug.h b/reactos/drivers/net/tcpip/include/debug.h
new file mode 100644 (file)
index 0000000..a296d5f
--- /dev/null
@@ -0,0 +1,99 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/debug.h\r
+ * PURPOSE:     Debugging support macros\r
+ * DEFINES:     DBG     - Enable debug output\r
+ *              NASSERT - Disable assertions\r
+ */\r
+#ifndef __DEBUG_H\r
+#define __DEBUG_H\r
+\r
+#define NORMAL_MASK    0x000000FF\r
+#define SPECIAL_MASK   0xFFFFFF00\r
+#define MIN_TRACE      0x00000001\r
+#define MID_TRACE      0x00000002\r
+#define MAX_TRACE      0x00000003\r
+\r
+#define DEBUG_MEMORY   0x00000100\r
+#define DEBUG_BUFFER   0x00000200\r
+#define DEBUG_IRP      0x00000400\r
+#define DEBUG_REFCOUNT 0x00000800\r
+#define DEBUG_ADDRFILE 0x00001000\r
+#define DEBUG_IP       0x00002000\r
+#define DEBUG_ROUTER   0x00004000\r
+#define DEBUG_RCACHE   0x00008000\r
+#define DEBUG_NCACHE   0x00010000\r
+#define DEBUG_ULTRA    0xFFFFFFFF\r
+\r
+#ifdef DBG\r
+\r
+extern DWORD DebugTraceLevel;\r
+\r
+#ifdef _MSC_VER\r
+\r
+#define TI_DbgPrint(_t_, _x_) \\r
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \\r
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \\r
+        DbgPrint("(%s:%d) ", __FILE__, __LINE__); \\r
+        DbgPrint _x_ ; \\r
+    }\r
+\r
+#else /* _MSC_VER */\r
+\r
+#define TI_DbgPrint(_t_, _x_) \\r
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \\r
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \\r
+        DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \\r
+        DbgPrint _x_ ; \\r
+    }\r
+\r
+#endif /* _MSC_VER */\r
+\r
+#ifdef ASSERT\r
+#undef ASSERT\r
+#endif\r
+\r
+#ifdef NASSERT\r
+#define ASSERT(x)\r
+#else /* NASSERT */\r
+#define ASSERT(x) if (!(x)) { TI_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); }\r
+#endif /* NASSERT */\r
+\r
+#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x))\r
+\r
+#else /* DBG */\r
+\r
+#define TI_DbgPrint(_t_, _x_)\r
+\r
+#define ASSERT_IRQL(x)\r
+#define ASSERT(x)\r
+\r
+#endif /* DBG */\r
+\r
+\r
+#define assert(x) ASSERT(x)\r
+#define assert_irql(x) ASSERT_IRQL(x)\r
+\r
+\r
+#ifdef _MSC_VER\r
+\r
+#define UNIMPLEMENTED \\r
+    TI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \\r
+        but come back another day.\n", __FILE__, __LINE__));\r
+\r
+#else /* _MSC_VER */\r
+\r
+#define UNIMPLEMENTED \\r
+    TI_DbgPrint(MIN_TRACE, ("(%s:%d)(%s) is unimplemented, \\r
+        but come back another day.\n", __FILE__, __LINE__, __FUNCTION__));\r
+\r
+#endif /* _MSC_VER */\r
+\r
+\r
+#define CHECKPOINT \\r
+    do { TI_DbgPrint(MIN_TRACE, ("(%s:%d)\n", __FILE__, __LINE__)); } while(0);\r
+\r
+#endif /* __DEBUG_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/dispatch.h b/reactos/drivers/net/tcpip/include/dispatch.h
new file mode 100644 (file)
index 0000000..9f70485
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/dispatch.h\r
+ * PURPOSE:     Dispatch routine prototypes\r
+ */\r
+#ifndef __DISPATCH_H\r
+#define __DISPATCH_H\r
+\r
+\r
+NTSTATUS DispTdiAccept(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiAssociateAddress(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiConnect(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiDisassociateAddress(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiDisconnect(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiListen(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiQueryInformation(\r
+    PDEVICE_OBJECT DeviceObject,\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiReceive(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiReceiveDatagram(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiSend(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiSendDatagram(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiSetEventHandler(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiSetInformation(\r
+    PIRP Irp);\r
+\r
+NTSTATUS DispTdiQueryInformationEx(\r
+    PIRP Irp,\r
+    PIO_STACK_LOCATION IrpSp);\r
+\r
+NTSTATUS DispTdiSetInformationEx(\r
+    PIRP Irp,\r
+    PIO_STACK_LOCATION IrpSp);\r
+\r
+#endif /* __DISPATCH_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/fileobjs.h b/reactos/drivers/net/tcpip/include/fileobjs.h
new file mode 100644 (file)
index 0000000..e69e5fe
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/fileobjs.h\r
+ * PURPOSE:     File object routine prototypes\r
+ */\r
+#ifndef __FILEOBJS_H\r
+#define __FILEOBJS_H\r
+\r
+\r
+extern LIST_ENTRY AddressFileListHead;\r
+extern KSPIN_LOCK AddressFileListLock;\r
+\r
+\r
+NTSTATUS FileOpenAddress(\r
+    PTDI_REQUEST Request,\r
+    PTA_ADDRESS_IP AddrList,\r
+    USHORT Protocol,\r
+    PVOID Options);\r
+\r
+NTSTATUS FileCloseAddress(\r
+    PTDI_REQUEST Request);\r
+\r
+NTSTATUS FileCloseConnection(\r
+    PTDI_REQUEST Request);\r
+\r
+NTSTATUS FileCloseControlChannel(\r
+    PTDI_REQUEST Request);\r
+\r
+#endif /* __FILEOBJS_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/icmp.h b/reactos/drivers/net/tcpip/include/icmp.h
new file mode 100644 (file)
index 0000000..225e62d
--- /dev/null
@@ -0,0 +1,68 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/icmp.h\r
+ * PURPOSE:     Internet Control Message Protocol definitions\r
+ */\r
+#ifndef __ICMP_H\r
+#define __ICMP_H\r
+\r
+typedef struct ICMP_HEADER {\r
+    UCHAR Type;      /* ICMP message type */\r
+    UCHAR Code;      /* ICMP message code */\r
+    USHORT Checksum; /* ICMP message checksum */\r
+    ULONG Unused;    /* ICMP unused */\r
+} ICMP_HEADER, *PICMP_HEADER;\r
+\r
+/* ICMP message types */\r
+#define ICMP_TYPE_ECHO_REPLY        0  /* Echo reply */\r
+#define ICMP_TYPE_DEST_UNREACH      3  /* Destination unreachable */\r
+#define ICMP_TYPE_SOURCE_QUENCH     4  /* Source quench */\r
+#define ICMP_TYPE_REDIRECT          5  /* Redirect */\r
+#define ICMP_TYPE_ECHO_REQUEST      8  /* Echo request */\r
+#define ICMP_TYPE_TIME_EXCEEDED     11 /* Time exceeded */\r
+#define ICMP_TYPE_PARAMETER         12 /* Parameter problem */\r
+#define ICMP_TYPE_TIMESTAMP_REQUEST 13 /* Timestamp request */\r
+#define ICMP_TYPE_TIMESTAMP_REPLY   14 /* Timestamp reply */\r
+#define ICMP_TYPE_INFO_REQUEST      15 /* Information request */\r
+#define ICMP_TYPE_INFO_REPLY        16 /* Information reply */\r
+\r
+/* ICMP codes for ICMP_TYPE_DEST_UNREACH */\r
+#define ICMP_CODE_DU_NET_UNREACH         0 /* Network unreachable */\r
+#define ICMP_CODE_DU_HOST_UNREACH        1 /* Host unreachable */\r
+#define ICMP_CODE_DU_PROTOCOL_UNREACH    2 /* Protocol unreachable */\r
+#define ICMP_CODE_DU_PORT_UNREACH        3 /* Port unreachable */\r
+#define ICMP_CODE_DU_FRAG_DF_SET         4 /* Fragmentation needed and DF set */\r
+#define ICMP_CODE_DU_SOURCE_ROUTE_FAILED 5 /* Source route failed */\r
+\r
+/* ICMP codes for ICMP_TYPE_REDIRECT */\r
+#define ICMP_CODE_RD_NET      0 /* Redirect datagrams for the network */\r
+#define ICMP_CODE_RD_HOST     1 /* Redirect datagrams for the host */\r
+#define ICMP_CODE_RD_TOS_NET  2 /* Redirect datagrams for the Type of Service and network */\r
+#define ICMP_CODE_RD_TOS_HOST 3 /* Redirect datagrams for the Type of Service and host */\r
+\r
+/* ICMP codes for ICMP_TYPE_TIME_EXCEEDED */\r
+#define ICMP_CODE_TE_TTL        0 /* Time to live exceeded in transit */\r
+#define ICMP_CODE_TE_REASSEMBLY 1 /* Fragment reassembly time exceeded */\r
+\r
+/* ICMP codes for ICMP_TYPE_PARAMETER */\r
+#define ICMP_CODE_TP_POINTER 1 /* Pointer indicates the error */\r
+\r
+\r
+VOID ICMPReceive(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket);\r
+\r
+VOID ICMPTransmit(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket);\r
+\r
+VOID ICMPReply(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket,\r
+       UCHAR Type,\r
+       UCHAR Code);\r
+\r
+#endif /* __ICMP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/info.h b/reactos/drivers/net/tcpip/include/info.h
new file mode 100644 (file)
index 0000000..1fd37d6
--- /dev/null
@@ -0,0 +1,93 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/info.h\r
+ * PURPOSE:     TdiQueryInformation definitions\r
+ */\r
+#ifndef __INFO_H\r
+#define __INFO_H\r
+\r
+\r
+typedef struct IPSNMP_INFO {\r
+       ULONG Forwarding;\r
+       ULONG DefaultTTL;\r
+       ULONG InReceives;\r
+       ULONG InHdrErrors;\r
+       ULONG InAddrErrors;\r
+       ULONG ForwDatagrams;\r
+       ULONG InUnknownProtos;\r
+       ULONG InDiscards;\r
+       ULONG InDelivers;\r
+       ULONG OutRequests;\r
+       ULONG RoutingDiscards;\r
+       ULONG OutDiscards;\r
+       ULONG OutNoRoutes;\r
+       ULONG ReasmTimeout;\r
+       ULONG ReasmReqds;\r
+       ULONG ReasmOks;\r
+       ULONG ReasmFails;\r
+       ULONG FragOks;\r
+       ULONG FragFails;\r
+       ULONG FragCreates;\r
+       ULONG NumIf;\r
+       ULONG NumAddr;\r
+       ULONG NumRoutes;\r
+} IPSNMP_INFO, *PIPSNMP_INFO;\r
+\r
+typedef struct IPADDR_ENTRY {\r
+       ULONG  Addr;\r
+       ULONG  Index;\r
+       ULONG  Mask;\r
+       ULONG  BcastAddr;\r
+       ULONG  ReasmSize;\r
+       USHORT Context;\r
+       USHORT Pad;\r
+} IPADDR_ENTRY, *PIPADDR_ENTRY;\r
+\r
+#define        IP_MIB_STATS_ID           1\r
+#define        IP_MIB_ADDRTABLE_ENTRY_ID 0x102\r
+\r
+#define        MAX_PHYSADDR_SIZE 8\r
+\r
+\r
+/* Only UDP is supported */\r
+#define TDI_SERVICE_FLAGS (TDI_SERVICE_CONNECTIONLESS_MODE | \\r
+                           TDI_SERVICE_BROADCAST_SUPPORTED)\r
+\r
+#define TCP_MIB_STAT_ID     1\r
+#define UDP_MIB_STAT_ID     1\r
+#define TCP_MIB_TABLE_ID    0x101\r
+#define UDP_MIB_TABLE_ID    0x101\r
+\r
+#define TL_INSTANCE 0\r
+\r
+\r
+typedef struct ADDRESS_INFO {\r
+    ULONG LocalAddress;\r
+    ULONG LocalPort;\r
+} ADDRESS_INFO, *PADDRESS_INFO;\r
+\r
+typedef union TDI_INFO {\r
+    TDI_CONNECTION_INFO ConnInfo;\r
+    TDI_ADDRESS_INFO AddrInfo;\r
+    TDI_PROVIDER_INFO ProviderInfo;\r
+    TDI_PROVIDER_STATISTICS ProviderStats;\r
+} TDI_INFO, *PTDI_INFO;\r
+\r
+\r
+TDI_STATUS InfoTdiQueryInformationEx(\r
+    PTDI_REQUEST Request,\r
+    TDIObjectID *ID,\r
+    PNDIS_BUFFER Buffer,\r
+    PUINT BufferSize,\r
+    PVOID Context);\r
+\r
+TDI_STATUS InfoTdiSetInformationEx(\r
+    PTDI_REQUEST Request,\r
+    TDIObjectID *ID,\r
+    PVOID Buffer,\r
+    UINT BufferSize);\r
+\r
+#endif /* __INFO_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/ip.h b/reactos/drivers/net/tcpip/include/ip.h
new file mode 100644 (file)
index 0000000..4cbcd19
--- /dev/null
@@ -0,0 +1,245 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/ip.h\r
+ * PURPOSE:     Internet Protocol related definitions\r
+ */\r
+#ifndef __IP_H\r
+#define __IP_H\r
+\r
+/* Raw IPv4 style address */\r
+typedef ULONG IPv4_RAW_ADDRESS;\r
+typedef IPv4_RAW_ADDRESS *PIPv4_RAW_ADDRESS;\r
+\r
+/* Raw IPv6 style address */\r
+typedef USHORT IPv6_RAW_ADDRESS[8];\r
+typedef IPv6_RAW_ADDRESS *PIPv6_RAW_ADDRESS;\r
+\r
+/* IP style address */\r
+typedef struct IP_ADDRESS {\r
+    ULONG RefCount;                     /* Number of references to this address */\r
+    UCHAR Type;                         /* Type of IP address */\r
+    union {\r
+        IPv4_RAW_ADDRESS IPv4Address;   /* IPv4 address */\r
+        PIPv6_RAW_ADDRESS IPv6Address;  /* IPv6 address */\r
+    } Address;\r
+} IP_ADDRESS, *PIP_ADDRESS;\r
+\r
+/* IP type constants */\r
+#define IP_ADDRESS_V4   0x00 /* IPv4 style address */\r
+#define IP_ADDRESS_V6   0x01 /* IPv6 style address */\r
+\r
+\r
+/* IPv4 header format */\r
+typedef struct IPv4_HEADER {\r
+    UCHAR VerIHL;                /* 4-bit version, 4-bit Internet Header Length */\r
+    UCHAR Tos;                   /* Type of Service */\r
+    USHORT TotalLength;          /* Total Length */\r
+    USHORT Id;                   /* Identification */\r
+    USHORT FlagsFragOfs;         /* 3-bit Flags, 13-bit Fragment Offset */\r
+    UCHAR Ttl;                   /* Time to Live */\r
+    UCHAR Protocol;              /* Protocol */\r
+    USHORT Checksum;             /* Header Checksum */\r
+    IPv4_RAW_ADDRESS SrcAddr;    /* Source Address */\r
+    IPv4_RAW_ADDRESS DstAddr;    /* Destination Address */\r
+} IPv4_HEADER, *PIPv4_HEADER;\r
+\r
+#define IPv4_FRAGOFS_MASK       0x1FFF\r
+#define IPv4_MF_MASK            0x2000\r
+#define IPv4_MAX_HEADER_SIZE    60\r
+\r
+/* Packet completion handler prototype */\r
+typedef VOID (*PACKET_COMPLETION_ROUTINE)(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    NDIS_STATUS NdisStatus);\r
+\r
+/* Structure for an IP packet */\r
+typedef struct IP_PACKET {\r
+    ULONG RefCount;                     /* Reference count for this object */\r
+    UCHAR Type;                         /* Type of IP packet (see IP_ADDRESS_xx above) */\r
+    PVOID Header;                       /* Pointer to IP header for this packet */\r
+    UINT HeaderSize;                    /* Size of IP header */\r
+    PVOID Data;                         /* Current pointer into packet data */\r
+    UINT TotalSize;                     /* Total amount of data in packet (IP header and data) */\r
+    UINT ContigSize;                    /* Number of contiguous bytes left in current buffer */\r
+    UINT Position;                      /* Current logical offset into packet */\r
+    PNDIS_PACKET NdisPacket;            /* Pointer to NDIS packet */\r
+    IP_ADDRESS SrcAddr;                 /* Source address */\r
+    IP_ADDRESS DstAddr;                 /* Destination address */\r
+} IP_PACKET, *PIP_PACKET;\r
+\r
+/* Packet context */\r
+typedef struct PACKET_CONTEXT {\r
+    PACKET_COMPLETION_ROUTINE Complete;   /* Transport level completion handler */\r
+    PVOID Context;                        /* Context information for handler */\r
+    PACKET_COMPLETION_ROUTINE DLComplete; /* Data link level completion handler. Also\r
+                                             used to link to next packet in a queue */\r
+    UINT DLOffset;                        /* Offset where data (IP header) starts */\r
+} PACKET_CONTEXT, *PPACKET_CONTEXT;\r
+\r
+/* The ProtocolReserved field is structured as a PACKET_CONTEXT */\r
+#define PC(Packet) ((PPACKET_CONTEXT)(&Packet->ProtocolReserved))\r
+\r
+\r
+/* Address information a.k.a ADE */\r
+typedef struct _ADDRESS_ENTRY {\r
+    LIST_ENTRY              ListEntry;  /* Entry on list */\r
+    ULONG                   RefCount;   /* Reference count */\r
+    struct _NET_TABLE_ENTRY *NTE;       /* NTE associated with this address */\r
+    UCHAR                   Type;       /* Address type */\r
+    PIP_ADDRESS             Address;    /* Pointer to address identifying this entry */\r
+} ADDRESS_ENTRY, *PADDRESS_ENTRY;\r
+\r
+/* Values for address type */\r
+#define ADE_UNICAST   0x01\r
+#define ADE_MULTICAST 0x02\r
+#define ADE_ADDRMASK  0x03\r
+\r
+/* There is one NTE for each source (unicast) address assigned to an interface */\r
+typedef struct _NET_TABLE_ENTRY {\r
+    LIST_ENTRY                 IFListEntry; /* Entry on interface list */\r
+    LIST_ENTRY                 NTListEntry; /* Entry on net table list */\r
+    struct _IP_INTERFACE       *Interface;  /* Pointer to interface on this net */\r
+    struct _PREFIX_LIST_ENTRY  *PLE;        /* Pointer to prefix list entry for this net */\r
+    ULONG                      RefCount;    /* Reference count */\r
+    PIP_ADDRESS                Address;     /* Pointer to unicast address for this net */\r
+} NET_TABLE_ENTRY, *PNET_TABLE_ENTRY;\r
+\r
+\r
+/* Link layer transmit prototype */\r
+typedef VOID (*LL_TRANSMIT_ROUTINE)(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    UINT Offset,\r
+    PVOID LinkAddress,\r
+    USHORT Type);\r
+\r
+/* Link layer to IP binding information */\r
+typedef struct _LLIP_BIND_INFO {\r
+    PVOID Context;                /* Pointer to link layer context information */\r
+    UINT  HeaderSize;             /* Size of link level header */\r
+    UINT  MinFrameSize;           /* Minimum frame size in bytes */\r
+    UINT  MTU;                    /* Maximum transmission unit */\r
+    PUCHAR Address;               /* Pointer to interface address */\r
+    UINT  AddressLength;          /* Length of address in bytes */\r
+    LL_TRANSMIT_ROUTINE Transmit; /* Transmit function for this interface */\r
+} LLIP_BIND_INFO, *PLLIP_BIND_INFO;\r
+\r
+\r
+/* Information about an IP interface */\r
+typedef struct _IP_INTERFACE {\r
+    LIST_ENTRY ListEntry;         /* Entry on list */\r
+    ULONG RefCount;               /* Reference count */\r
+    KSPIN_LOCK Lock;              /* Spin lock for this object */\r
+    LIST_ENTRY NTEListHead;       /* List of NTEs on this interface */\r
+    LIST_ENTRY ADEListHead;       /* List of ADEs on this interface */\r
+    PVOID Context;                /* Pointer to link layer context information */\r
+    UINT  HeaderSize;             /* Size of link level header */\r
+    UINT  MinFrameSize;           /* Minimum frame size in bytes */\r
+    UINT  MTU;                    /* Maximum transmission unit */\r
+    PUCHAR Address;               /* Pointer to interface address */\r
+    UINT  AddressLength;          /* Length of address in bytes */\r
+    LL_TRANSMIT_ROUTINE Transmit; /* Pointer to transmit function */\r
+} IP_INTERFACE, *PIP_INTERFACE;\r
+\r
+\r
+/* Prefix List Entry */\r
+typedef struct _PREFIX_LIST_ENTRY {\r
+    LIST_ENTRY ListEntry;    /* Entry on list */\r
+    ULONG RefCount;          /* Reference count */\r
+    PIP_INTERFACE Interface; /* Pointer to interface */\r
+    PIP_ADDRESS Prefix;      /* Pointer to prefix */\r
+    UINT PrefixLength;       /* Length of prefix */\r
+} PREFIX_LIST_ENTRY, *PPREFIX_LIST_ENTRY;\r
+\r
+\r
+#define IP_PROTOCOL_TABLE_SIZE 0x100\r
+\r
+typedef VOID (*IP_PROTOCOL_HANDLER)(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket);\r
+\r
+/* Loopback adapter address information (network byte order) */\r
+#define LOOPBACK_ADDRESS_IPv4   ((IPv4_RAW_ADDRESS)DH2N(0x7F000001)) \r
+#define LOOPBACK_BCASTADDR_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0x7F0000FF))\r
+#define LOOPBACK_ADDRMASK_IPv4  ((IPv4_RAW_ADDRESS)DH2N(0xFFFFFF00))\r
+\r
+/* Protocol definitions */\r
+#define IPPROTO_ICMP    1   /* Internet Control Message Protocol */\r
+#define IPPROTO_IGMP    2   /* Internet Group Management Protocol */\r
+#define IPPROTO_TCP     6   /* Transmission Control Protocol */\r
+#define IPPROTO_UDP     17  /* User Datagram Protocol */\r
+\r
+/* Timeout timer constants */\r
+#define IP_TICKS_SECOND 2                   /* Two ticks per second */\r
+#define IP_TIMEOUT (1000 / IP_TICKS_SECOND) /* Timeout in milliseconds */\r
+\r
+\r
+extern LIST_ENTRY InterfaceListHead;\r
+extern KSPIN_LOCK InterfaceListLock;\r
+extern LIST_ENTRY NetTableListHead;\r
+extern KSPIN_LOCK NetTableListLock;\r
+extern LIST_ENTRY PrefixListHead;\r
+extern KSPIN_LOCK PrefixListLock;\r
+extern UINT MaxLLHeaderSize;\r
+extern UINT MinLLFrameSize;\r
+\r
+\r
+PNET_TABLE_ENTRY IPCreateNTE(\r
+    PIP_INTERFACE IF,\r
+    PIP_ADDRESS Address,\r
+    UINT PrefixLength);\r
+\r
+PIP_INTERFACE IPCreateInterface(\r
+    PLLIP_BIND_INFO BindInfo);\r
+\r
+VOID IPDestroyInterface(\r
+    PIP_INTERFACE IF);\r
+\r
+BOOLEAN IPRegisterInterface(\r
+    PIP_INTERFACE IF);\r
+\r
+VOID IPUnregisterInterface(\r
+    PIP_INTERFACE IF);\r
+\r
+PNET_TABLE_ENTRY IPLocateNTEOnInterface(\r
+    PIP_INTERFACE IF,\r
+    PIP_ADDRESS Address,\r
+    PUINT AddressType);\r
+\r
+PNET_TABLE_ENTRY IPLocateNTE(\r
+    PIP_ADDRESS Address,\r
+    PUINT AddressType);\r
+\r
+PADDRESS_ENTRY IPLocateADE(\r
+    PIP_ADDRESS Address,\r
+    UINT AddressType);\r
+\r
+PADDRESS_ENTRY IPGetDefaultADE(\r
+    UINT AddressType);\r
+\r
+VOID IPTimeout(\r
+    PKDPC Dpc,\r
+    PVOID DeferredContext,\r
+    PVOID SystemArgument1,\r
+    PVOID SystemArgument2);\r
+\r
+VOID IPDispatchProtocol(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket);\r
+\r
+VOID IPRegisterProtocol(\r
+    UINT ProtocolNumber,\r
+    IP_PROTOCOL_HANDLER Handler);\r
+\r
+NTSTATUS IPStartup(\r
+    PDRIVER_OBJECT DriverObject,\r
+    PUNICODE_STRING RegistryPath);\r
+\r
+NTSTATUS IPShutdown(\r
+    VOID);\r
+\r
+#endif /* __IP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/lan.h b/reactos/drivers/net/tcpip/include/lan.h
new file mode 100644 (file)
index 0000000..20799d7
--- /dev/null
@@ -0,0 +1,100 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/lan.h\r
+ * PURPOSE:     LAN adapter definitions\r
+ */\r
+#ifndef __LAN_H\r
+#define __LAN_H\r
+\r
+\r
+/* Medias we support */\r
+#define MEDIA_ETH 0\r
+\r
+#define MAX_MEDIA 1\r
+\r
+#define IEEE_802_ADDR_LENGTH 6\r
+\r
+/* Ethernet header layout */\r
+typedef struct ETH_HEADER {\r
+    UCHAR DstAddr[IEEE_802_ADDR_LENGTH]; /* Destination MAC address */\r
+    UCHAR SrcAddr[IEEE_802_ADDR_LENGTH]; /* Source MAC address */\r
+    USHORT EType;                        /* Ethernet protocol type */\r
+} ETH_HEADER, *PETH_HEADER;\r
+\r
+#define MAX_MEDIA_ETH sizeof(ETH_HEADER)\r
+\r
+/* Broadcast masks */\r
+#define BCAST_ETH_MASK 0x01\r
+\r
+/* Broadcast values to check against */\r
+#define BCAST_ETH_CHECK 0x01\r
+\r
+/* Offset of broadcast address */\r
+#define BCAST_ETH_OFFSET 0x00\r
+\r
+/* Per adapter information */\r
+typedef struct LAN_ADAPTER {\r
+    struct LAN_ADAPTER *Next;               /* Pointer to next adapter */\r
+    KSPIN_LOCK Lock;                        /* Lock for this structure */\r
+    UCHAR State;                            /* State of the adapter */\r
+    KEVENT Event;                           /* Opening event */\r
+    PVOID Context;                          /* Upper layer context information */\r
+    NDIS_HANDLE NdisHandle;                 /* NDIS binding handle */\r
+    NDIS_STATUS NdisStatus;                 /* NDIS status of last request */\r
+    NDIS_MEDIUM Media;                      /* Media type */\r
+    UCHAR HWAddress[IEEE_802_ADDR_LENGTH];  /* Local HW address */\r
+    UINT HWAddressLength;                   /* Length of HW address */\r
+    UCHAR BCastMask;                        /* Mask for checking broadcast */\r
+    UCHAR BCastCheck;                       /* Value to check against */\r
+    UCHAR BCastOffset;                      /* Offset in frame to check against */\r
+    UCHAR HeaderSize;                       /* Size of link-level header */\r
+    USHORT MTU;                             /* Maximum Transfer Unit */\r
+    UINT MinFrameSize;                      /* Minimum frame size in bytes */\r
+    UINT MaxPacketSize;                     /* Maximum packet size when sending */\r
+    UINT MaxSendPackets;                    /* Maximum number of packets per send */\r
+    UINT MacOptions;                        /* MAC options for NIC driver/adapter */\r
+    UINT Speed;                             /* Link speed */\r
+    UINT PacketFilter;                      /* Packet filter for this adapter */\r
+    PNDIS_PACKET TDPackets;                 /* Transfer Data packets */\r
+} LAN_ADAPTER, *PLAN_ADAPTER;\r
+\r
+/* LAN adapter state constants */\r
+#define LAN_STATE_OPENING   0\r
+#define LAN_STATE_RESETTING 1\r
+#define LAN_STATE_STARTED   2\r
+#define LAN_STATE_STOPPED   3\r
+\r
+/* Size of out lookahead buffer */\r
+#define LOOKAHEAD_SIZE  128\r
+\r
+/* Ethernet types. We swap constants so we can compare values at runtime\r
+   without swapping them */\r
+#define ETYPE_IPv4 WH2N(0x0800)\r
+#define ETYPE_IPv6 WH2N(0x0000) /* FIXME */\r
+#define ETYPE_ARP  WH2N(0x0806)\r
+\r
+/* Protocols */\r
+#define LAN_PROTO_IPv4 0x0000 /* Internet Protocol version 4 */\r
+#define LAN_PROTO_IPv6 0x0001 /* Internet Protocol version 6 */\r
+#define LAN_PROTO_ARP  0x0002 /* Address Resolution Protocol */\r
+\r
+extern PLAN_ADAPTER Adapters;\r
+\r
+\r
+NDIS_STATUS LANRegisterAdapter(\r
+    PNDIS_STRING AdapterName,\r
+    PLAN_ADAPTER *Adapter);\r
+\r
+NDIS_STATUS LANUnregisterAdapter(\r
+    PLAN_ADAPTER Adapter);\r
+\r
+NTSTATUS LANRegisterProtocol(\r
+    STRING *Name);\r
+\r
+VOID LANUnregisterProtocol(\r
+    VOID);\r
+\r
+#endif /* __LAN_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/loopback.h b/reactos/drivers/net/tcpip/include/loopback.h
new file mode 100644 (file)
index 0000000..abf3e1d
--- /dev/null
@@ -0,0 +1,25 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/loopback.h\r
+ * PURPOSE:     Loopback adapter definitions\r
+ */\r
+#ifndef __LOOPBACK_H\r
+#define __LOOPBACK_H\r
+\r
+#include <lan.h>\r
+\r
+\r
+extern PIP_INTERFACE Loopback;\r
+\r
+\r
+NDIS_STATUS LoopRegisterAdapter(\r
+    PNDIS_STRING AdapterName,\r
+    PLAN_ADAPTER *Adapter);\r
+\r
+NDIS_STATUS LoopUnregisterAdapter(\r
+    PLAN_ADAPTER Adapter);\r
+\r
+#endif /* __LOOPBACK_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/neighbor.h b/reactos/drivers/net/tcpip/include/neighbor.h
new file mode 100644 (file)
index 0000000..a2c50fe
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/neighbor.h\r
+ * PURPOSE:     Neighbor definitions\r
+ */\r
+#ifndef __NEIGHBOR_H\r
+#define __NEIGHBOR_H\r
+\r
+\r
+#define NB_HASHMASK 0xF /* Hash mask for neighbor cache */\r
+\r
+typedef struct NEIGHBOR_CACHE_TABLE {\r
+    struct NEIGHBOR_CACHE_ENTRY *Cache; /* Pointer to cache */\r
+    KSPIN_LOCK Lock;                    /* Protecting lock */\r
+} NEIGHBOR_CACHE_TABLE, *PNEIGHBOR_CACHE_TABLE;\r
+\r
+/* Information about a neighbor */\r
+typedef struct NEIGHBOR_CACHE_ENTRY {\r
+    struct NEIGHBOR_CACHE_ENTRY *Next;  /* Pointer to next entry */\r
+    struct NEIGHBOR_CACHE_TABLE *Table; /* Pointer to table */\r
+    ULONG RefCount;                     /* Number of references */\r
+    UCHAR State;                        /* State of NCE */\r
+    UINT EventTimer;                    /* Ticks since last event */\r
+    UINT EventCount;                    /* Number of events */\r
+    PIP_INTERFACE Interface;            /* Pointer to interface */\r
+    PIP_ADDRESS Address;                /* IP address of neighbor */\r
+    UINT LinkAddressLength;             /* Length of link address */\r
+    PVOID LinkAddress;                  /* Pointer to link address */\r
+    PNDIS_PACKET WaitQueue;             /* Pointer to NDIS packets\r
+                                           waiting to be sent */\r
+} NEIGHBOR_CACHE_ENTRY, *PNEIGHBOR_CACHE_ENTRY;\r
+\r
+/* NCE states */\r
+#define NUD_NONE       0x00\r
+#define NUD_INCOMPLETE 0x01\r
+#define NUD_REACHABLE  0x02\r
+#define NUD_STALE      0x04\r
+#define NUD_DELAY      0x08\r
+#define NUD_PROBE      0x10\r
+#define NUD_FAILED     0x20\r
+#define NUD_NOARP      0x40\r
+#define NUD_PERMANENT  0x80\r
+\r
+#define NUD_IN_TIMER  (NUD_INCOMPLETE | NUD_DELAY | NUD_PROBE)\r
+#define NUD_VALID     (NUD_REACHABLE | NUD_NOARP | NUD_STALE | NUD_DELAY | \\r
+                       NUD_PROBE | NUD_PERMANENT)\r
+#define NUD_CONNECTED (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)\r
+\r
+\r
+/* Maximum number of retransmissions of multicast solicits */\r
+#define MAX_MULTICAST_SOLICIT 3 /* 3 transmissions */\r
+\r
+/* Number of ticks between address resolution messages */\r
+#define RETRANS_TIMER IP_TICKS_SECOND /* One second */\r
+\r
+\r
+extern NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];\r
+\r
+\r
+VOID NBTimeout(\r
+    VOID);\r
+\r
+VOID NBStartup(\r
+    VOID);\r
+\r
+VOID NBShutdown(\r
+    VOID);\r
+\r
+VOID NBSendSolicit(\r
+    PNEIGHBOR_CACHE_ENTRY NCE);\r
+\r
+PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(\r
+    PIP_INTERFACE Interface,\r
+    PIP_ADDRESS Address,\r
+    PVOID LinkAddress,\r
+    UINT LinkAddressLength,\r
+    UCHAR Type);\r
+\r
+VOID NBUpdateNeighbor(\r
+    PNEIGHBOR_CACHE_ENTRY NCE,\r
+    PVOID LinkAddress,\r
+    UCHAR State);\r
+\r
+PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(\r
+    PIP_ADDRESS Address);\r
+\r
+PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor(\r
+    PIP_INTERFACE Interface,\r
+    PIP_ADDRESS Address);\r
+\r
+BOOLEAN NBQueuePacket(\r
+    PNEIGHBOR_CACHE_ENTRY NCE,\r
+    PNDIS_PACKET NdisPacket);\r
+\r
+VOID NBRemoveNeighbor(\r
+    PNEIGHBOR_CACHE_ENTRY NCE);\r
+\r
+#endif /* __NEIGHBOR_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/pool.h b/reactos/drivers/net/tcpip/include/pool.h
new file mode 100644 (file)
index 0000000..653b0a4
--- /dev/null
@@ -0,0 +1,19 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/pool.h\r
+ * PURPOSE:     Prototypes for memory pooling\r
+ */\r
+#ifndef __POOL_H\r
+#define __POOL_H\r
+\r
+\r
+PVOID PoolAllocateBuffer(\r
+    ULONG Size);\r
+\r
+VOID PoolFreeBuffer(\r
+    PVOID Buffer);\r
+\r
+#endif /* __POOL_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/rawip.h b/reactos/drivers/net/tcpip/include/rawip.h
new file mode 100644 (file)
index 0000000..b132229
--- /dev/null
@@ -0,0 +1,24 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/rawip.h\r
+ * PURPOSE:     Raw IP types and constants\r
+ */\r
+#ifndef __RAWIP_H\r
+#define __RAWIP_H\r
+\r
+NTSTATUS RawIPSendDatagram(\r
+    PTDI_REQUEST Request,\r
+    PTDI_CONNECTION_INFORMATION ConnInfo,\r
+    PNDIS_BUFFER Buffer,\r
+    ULONG DataSize);\r
+\r
+NTSTATUS RawIPStartup(\r
+    VOID);\r
+\r
+NTSTATUS RawIPShutdown(\r
+    VOID);\r
+\r
+#endif /* __RAWIP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/receive.h b/reactos/drivers/net/tcpip/include/receive.h
new file mode 100644 (file)
index 0000000..2dab3d4
--- /dev/null
@@ -0,0 +1,61 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/receive.h\r
+ * PURPOSE:     Internet Protocol receive prototypes\r
+ */\r
+#ifndef __RECEIVE_H\r
+#define __RECEIVE_H\r
+\r
+#include <ip.h>\r
+\r
+\r
+/* IP datagram fragment descriptor. Used to store IP datagram fragments */\r
+typedef struct IP_FRAGMENT {\r
+    LIST_ENTRY ListEntry; /* Entry on list */\r
+    PVOID Data;           /* Pointer to fragment data */\r
+    UINT Offset;          /* Offset into datagram where this fragment is */\r
+    UINT Size;            /* Size of this fragment */\r
+} IP_FRAGMENT, *PIP_FRAGMENT;\r
+\r
+/* IP datagram hole descriptor. Used to reassemble IP datagrams */\r
+typedef struct IPDATAGRAM_HOLE {\r
+    LIST_ENTRY ListEntry; /* Entry on list */\r
+    UINT First;           /* Offset of first octet of the hole */\r
+    UINT Last;            /* Offset of last octet of the hole */\r
+} IPDATAGRAM_HOLE, *PIPDATAGRAM_HOLE;\r
+\r
+/* IP datagram reassembly information */\r
+typedef struct IPDATAGRAM_REASSEMBLY {\r
+    LIST_ENTRY ListEntry;        /* Entry on list */\r
+    KSPIN_LOCK Lock;             /* Protecting spin lock */\r
+    ULONG RefCount;              /* Reference count for this object */\r
+    UINT DataSize;               /* Size of datagram data area */\r
+    IP_ADDRESS SrcAddr;          /* Source address */\r
+    IP_ADDRESS DstAddr;          /* Destination address */\r
+    UCHAR Protocol;              /* Internet Protocol number */\r
+    USHORT Id;                   /* Identification number */\r
+    PIPv4_HEADER IPv4Header;     /* Pointer to IP header */\r
+    UINT HeaderSize;             /* Length of IP header */\r
+    LIST_ENTRY FragmentListHead; /* IP fragment list */\r
+    LIST_ENTRY HoleListHead;     /* IP datagram hole list */\r
+} IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY;\r
+\r
+\r
+extern LIST_ENTRY ReassemblyListHead;\r
+extern KSPIN_LOCK ReassemblyListLock;\r
+\r
+\r
+VOID IPFreeReassemblyList(\r
+    VOID);\r
+\r
+VOID IPDatagramReassemblyTimeout(\r
+    VOID);\r
+\r
+VOID IPReceive(\r
+    PVOID Context,\r
+    PIP_PACKET IPPacket);\r
+\r
+#endif /* __RECEIVE_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/route.h b/reactos/drivers/net/tcpip/include/route.h
new file mode 100644 (file)
index 0000000..d2c827c
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/route.h\r
+ * PURPOSE:     Routing cache definitions\r
+ */\r
+#ifndef __ROUTE_H\r
+#define __ROUTE_H\r
+\r
+#include <neighbor.h>\r
+#include <address.h>\r
+#include <router.h>\r
+#include <pool.h>\r
+#include <arp.h>\r
+\r
+\r
+/* Route Cache Node structure.\r
+ * The primary purpose of the RCN is to cache selected source and\r
+ * next-hop addresses. The routing cache is implemented as a binary\r
+ * search tree to provide fast lookups when many RCNs are in the cache.\r
+ */\r
+typedef struct ROUTE_CACHE_NODE {\r
+    struct ROUTE_CACHE_NODE *Parent; /* Pointer to parent */\r
+    struct ROUTE_CACHE_NODE *Left;   /* Pointer to left child */\r
+    struct ROUTE_CACHE_NODE *Right;  /* Pointer to right child */\r
+    /* Memebers above this line must not be moved */\r
+    ULONG RefCount;                  /* Reference count */\r
+    UCHAR State;                     /* RCN state (RCN_STATE_*) */\r
+    IP_ADDRESS Destination;          /* Destination address */\r
+    PNET_TABLE_ENTRY NTE;            /* Preferred NTE */\r
+    PNEIGHBOR_CACHE_ENTRY NCE;       /* Pointer to NCE for first hop (NULL if none) */\r
+    UINT PathMTU;                    /* Path MTU to destination */\r
+} ROUTE_CACHE_NODE, *PROUTE_CACHE_NODE;\r
+\r
+/* RCN states */\r
+#define RCN_STATE_PERMANENT 0x00 /* RCN is permanent (properly local) */\r
+#define RCN_STATE_COMPUTED  0x01 /* RCN is computed */\r
+\r
+\r
+#define IsExternalRCN(RCN) \\r
+    (RCN == ExternalRCN)\r
+\r
+#define IsInternalRCN(RCN) \\r
+    (RCN != ExternalRCN)\r
+\r
+\r
+NTSTATUS RouteStartup(\r
+    VOID);\r
+\r
+NTSTATUS RouteShutdown(\r
+    VOID);\r
+\r
+UINT RouteGetRouteToDestination(\r
+    PIP_ADDRESS Destination,\r
+    PNET_TABLE_ENTRY NTE,\r
+    PROUTE_CACHE_NODE *RCN);\r
+\r
+PROUTE_CACHE_NODE RouteAddRouteToDestination(\r
+    PIP_ADDRESS Destination,\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_INTERFACE IF,\r
+    PNEIGHBOR_CACHE_ENTRY NCE);\r
+\r
+VOID RouteRemoveRouteToDestination(\r
+    PROUTE_CACHE_NODE RCN);\r
+\r
+VOID RouteInvalidateNTE(\r
+    PNET_TABLE_ENTRY NTE);\r
+\r
+VOID RouteInvalidateNCE(\r
+    PNEIGHBOR_CACHE_ENTRY NCE);\r
+\r
+#endif /* __ROUTE_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/router.h b/reactos/drivers/net/tcpip/include/router.h
new file mode 100644 (file)
index 0000000..e8d52ef
--- /dev/null
@@ -0,0 +1,62 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/router.h\r
+ * PURPOSE:     IP routing definitions\r
+ */\r
+#ifndef __ROUTER_H\r
+#define __ROUTER_H\r
+\r
+#include <neighbor.h>\r
+\r
+\r
+/* Forward Information Base Entry */\r
+typedef struct _FIB_ENTRY {\r
+    LIST_ENTRY ListEntry;         /* Entry on list */\r
+    ULONG RefCount;               /* Reference count */\r
+    PIP_ADDRESS NetworkAddress;   /* Address of network */\r
+    PIP_ADDRESS Netmask;          /* Netmask of network */\r
+    PNET_TABLE_ENTRY NTE;         /* Pointer to NTE to use */\r
+    PNEIGHBOR_CACHE_ENTRY Router; /* Pointer to NCE of router to use */\r
+    UINT Metric;                  /* Cost of this route */\r
+} FIB_ENTRY, *PFIB_ENTRY;\r
+\r
+\r
+PNET_TABLE_ENTRY RouterFindBestNTE(\r
+    PIP_INTERFACE Interface,\r
+    PIP_ADDRESS Destination);\r
+\r
+PIP_INTERFACE RouterFindOnLinkInterface(\r
+    PIP_ADDRESS Address,\r
+    PNET_TABLE_ENTRY NTE);\r
+\r
+PFIB_ENTRY RouterAddRoute(\r
+    PIP_ADDRESS NetworkAddress,\r
+    PIP_ADDRESS Netmask,\r
+    PNET_TABLE_ENTRY NTE,\r
+    PNEIGHBOR_CACHE_ENTRY Router,\r
+    UINT Metric);\r
+\r
+PNEIGHBOR_CACHE_ENTRY RouterGetRoute(\r
+    PIP_ADDRESS Destination,\r
+    PNET_TABLE_ENTRY NTE);\r
+\r
+VOID RouterRemoveRoute(\r
+    PFIB_ENTRY FIBE);\r
+\r
+PFIB_ENTRY RouterCreateRouteIPv4(\r
+    IPv4_RAW_ADDRESS NetworkAddress,\r
+    IPv4_RAW_ADDRESS Netmask,\r
+    IPv4_RAW_ADDRESS RouterAddress,\r
+    PNET_TABLE_ENTRY NTE,\r
+    UINT Metric);\r
+\r
+NTSTATUS RouterStartup(\r
+    VOID);\r
+\r
+NTSTATUS RouterShutdown(\r
+    VOID);\r
+\r
+#endif /* __ROUTER_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/routines.h b/reactos/drivers/net/tcpip/include/routines.h
new file mode 100644 (file)
index 0000000..dcd0347
--- /dev/null
@@ -0,0 +1,53 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/routines.h\r
+ * PURPOSE:     Common routine prototypes\r
+ */\r
+#ifndef __ROUTINES_H\r
+#define __ROUTINES_H\r
+\r
+\r
+UINT Random(\r
+    VOID);\r
+\r
+UINT CopyBufferToBufferChain(\r
+    PNDIS_BUFFER DstBuffer,\r
+    UINT DstOffset,\r
+    PUCHAR SrcData,\r
+    UINT Length);\r
+\r
+UINT CopyBufferChainToBuffer(\r
+    PUCHAR DstData,\r
+    PNDIS_BUFFER SrcBuffer,\r
+    UINT SrcOffset,\r
+    UINT Length);\r
+\r
+UINT CopyPacketToBuffer(\r
+    PUCHAR DstData,\r
+    PNDIS_PACKET SrcPacket,\r
+    UINT SrcOffset,\r
+    UINT Length);\r
+\r
+UINT CopyPacketToBufferChain(\r
+    PNDIS_BUFFER DstBuffer,\r
+    UINT DstOffset,\r
+    PNDIS_PACKET SrcPacket,\r
+    UINT SrcOffset,\r
+    UINT Length);\r
+\r
+VOID FreeNdisPacket(\r
+    PNDIS_PACKET Packet);\r
+\r
+PVOID AdjustPacket(\r
+    PNDIS_PACKET Packet,\r
+    UINT Available,\r
+    UINT Needed);\r
+\r
+UINT ResizePacket(\r
+    PNDIS_PACKET Packet,\r
+    UINT Size);\r
+\r
+#endif /* __ROUTINES_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/tcp.h b/reactos/drivers/net/tcpip/include/tcp.h
new file mode 100644 (file)
index 0000000..d58654a
--- /dev/null
@@ -0,0 +1,18 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/tcp.h\r
+ * PURPOSE:     Transmission Control Protocol definitions\r
+ */\r
+#ifndef __TCP_H\r
+#define __TCP_H\r
+\r
+NTSTATUS TCPStartup(\r
+    VOID);\r
+\r
+NTSTATUS TCPShutdown(\r
+    VOID);\r
+\r
+#endif /* __TCP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/tcpip.h b/reactos/drivers/net/tcpip/include/tcpip.h
new file mode 100644 (file)
index 0000000..7a56e2a
--- /dev/null
@@ -0,0 +1,131 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/tcpip.h\r
+ * PURPOSE:     TCP/IP protocol driver definitions\r
+ * NOTES:       Spin lock acquire order:\r
+ *                - Net table list lock\r
+ *                - Interface lock\r
+ *                - Interface list lock\r
+ *                - Prefix list lock\r
+ *                - Neighbor cache lock\r
+ *                - Route cache lock\r
+ */\r
+#ifndef __TCPIP_H\r
+#define __TCPIP_H\r
+\r
+#ifdef _MSC_VER\r
+#include <basetsd.h>\r
+#include <ntddk.h>\r
+#include <windef.h>\r
+#include <ndis.h>\r
+#include <tdikrnl.h>\r
+#include <tdiinfo.h>\r
+#else\r
+#include <ddk/ntddk.h>\r
+#include <net/ndis.h>\r
+#include <net/tdikrnl.h>\r
+#include <net/tdiinfo.h>\r
+#endif\r
+\r
+#include <debug.h>\r
+\r
+\r
+/* Define _NTTEST_ to make test version. Device names are prefixed with\r
+   'NT' to allow the driver to run side by side with MS TCP/IP driver */\r
+#define _NTTEST_\r
+\r
+/* FIXME: The following should be moved to ntddk.h or tdi headers */\r
+#ifndef _MSC_VER\r
+\r
+#ifndef IO_NETWORK_INCREMENT\r
+#define IO_NETWORK_INCREMENT 2\r
+#endif\r
+\r
+#endif\r
+\r
+#ifdef _MSC_VER\r
+/* EXPORTED is already defined ddk/defines.h */\r
+#define EXPORTED __declspec(dllexport)\r
+\r
+#endif\r
+\r
+#include <titypes.h>\r
+#include <ticonsts.h>\r
+#include <udp.h>\r
+\r
+\r
+/* Macros */\r
+\r
+#define MIN(value1, value2) \\r
+    ((value1 < value2)? value1 : value2)\r
+\r
+#define MAX(value1, value2) \\r
+    ((value1 > value2)? value1 : value2)\r
+\r
+\r
+#ifdef i386\r
+\r
+/* DWORD network to host byte order conversion for i386 */\r
+#define DN2H(dw) \\r
+    ((((dw) & 0xFF000000L) >> 24) | \\r
+        (((dw) & 0x00FF0000L) >> 8) | \\r
+        (((dw) & 0x0000FF00L) << 8) | \\r
+        (((dw) & 0x000000FFL) << 24))\r
+\r
+/* DWORD host to network byte order conversion for i386 */\r
+#define DH2N(dw) \\r
+       ((((dw) & 0xFF000000L) >> 24) | \\r
+        (((dw) & 0x00FF0000L) >> 8) | \\r
+        (((dw) & 0x0000FF00L) << 8) | \\r
+        (((dw) & 0x000000FFL) << 24))\r
+\r
+/* WORD network to host order conversion for i386 */\r
+#define WN2H(w) \\r
+       ((((w) & 0xFF00) >> 8) | \\r
+        (((w) & 0x00FF) << 8))\r
+\r
+/* WORD host to network byte order conversion for i386 */\r
+#define WH2N(w) \\r
+       ((((w) & 0xFF00) >> 8) | \\r
+        (((w) & 0x00FF) << 8))\r
+\r
+#else /* i386 */\r
+\r
+/* DWORD network to host byte order conversion for other architectures */\r
+#define DN2H(dw) \\r
+    (dw)\r
+\r
+/* DWORD host to network byte order conversion for other architectures */\r
+#define DH2N(dw) \\r
+    (dw)\r
+\r
+/* WORD network to host order conversion for other architectures */\r
+#define WN2H(w) \\r
+    (w)\r
+\r
+/* WORD host to network byte order conversion for other architectures */\r
+#define WH2N(w) \\r
+    (w)\r
+\r
+#endif /* i386 */\r
+\r
+\r
+/* Global variable */\r
+extern PDEVICE_OBJECT TCPDeviceObject;\r
+extern PDEVICE_OBJECT UDPDeviceObject;\r
+extern PDEVICE_OBJECT IPDeviceObject;\r
+extern PDEVICE_OBJECT RawIPDeviceObject;\r
+extern LIST_ENTRY InterfaceListHead;\r
+extern KSPIN_LOCK InterfaceListLock;\r
+extern LIST_ENTRY AddressFileListHead;\r
+extern KSPIN_LOCK AddressFileListLock;\r
+extern NDIS_HANDLE GlobalPacketPool;\r
+extern NDIS_HANDLE GlobalBufferPool;\r
+extern TDIEntityID *EntityList;\r
+extern ULONG EntityCount;\r
+extern UDP_STATISTICS UDPStats;\r
+\r
+#endif /* __TCPIP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/ticonsts.h b/reactos/drivers/net/tcpip/include/ticonsts.h
new file mode 100644 (file)
index 0000000..2ed7246
--- /dev/null
@@ -0,0 +1,56 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/ticonsts.h\r
+ * PURPOSE:     TCP/IP protocol driver constants\r
+ */\r
+#ifndef __TICONSTS_H\r
+#define __TICONSTS_H\r
+\r
+/* NDIS version this driver supports */\r
+#define NDIS_VERSION_MAJOR 3\r
+#define NDIS_VERSION_MINOR 0\r
+\r
+#ifdef _NTTEST_\r
+/* Name of devices */\r
+#define DD_TCP_DEVICE_NAME      L"\\Device\\NTTcp"\r
+#define DD_UDP_DEVICE_NAME      L"\\Device\\NTUdp"\r
+#define DD_IP_DEVICE_NAME       L"\\Device\\NTIp"\r
+#define DD_RAWIP_DEVICE_NAME    L"\\Device\\NTRawIp"\r
+\r
+/* For NDIS protocol registration */\r
+#define IP_DEVICE_NAME          "\\Device\\NTIp"\r
+#else\r
+#define DD_TCP_DEVICE_NAME      L"\\Device\\Tcp"\r
+#define DD_UDP_DEVICE_NAME      L"\\Device\\Udp"\r
+#define DD_IP_DEVICE_NAME       L"\\Device\\Ip"\r
+#define DD_RAWIP_DEVICE_NAME    L"\\Device\\RawIp"\r
+\r
+/* For NDIS protocol registration */\r
+#define IP_DEVICE_NAME          "\\Device\\Ip"\r
+#endif /* _NTTEST_ */\r
+\r
+/* TCP/UDP/RawIP IOCTL code definitions */\r
+\r
+#define FSCTL_TCP_BASE     FILE_DEVICE_NETWORK\r
+\r
+#define _TCP_CTL_CODE(Function, Method, Access) \\r
+    CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access)\r
+\r
+#define IOCTL_TCP_QUERY_INFORMATION_EX \\r
+    _TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS)\r
+\r
+#define IOCTL_TCP_SET_INFORMATION_EX \\r
+    _TCP_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_ACCESS)\r
+\r
+/* Unique error values for log entries */\r
+#define TI_ERROR_DRIVERENTRY 0\r
+\r
+/* Internal status codes */\r
+#define IP_SUCCESS                 0x0000 /* Successful */\r
+#define IP_NO_RESOURCES            0x0001 /* Not enough free resources */\r
+#define IP_NO_ROUTE_TO_DESTINATION 0x0002 /* No route to destination */\r
+\r
+#endif /* __TICONSTS_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/titypes.h b/reactos/drivers/net/tcpip/include/titypes.h
new file mode 100644 (file)
index 0000000..833d671
--- /dev/null
@@ -0,0 +1,215 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/titypes.h\r
+ * PURPOSE:     TCP/IP protocol driver types\r
+ */\r
+#ifndef __TITYPES_H\r
+#define __TITYPES_H\r
+\r
+#include <ip.h>\r
+\r
+\r
+#ifdef DBG\r
+\r
+#define DEBUG_REFCHECK(Object) {            \\r
+    if ((Object)->RefCount <= 0) {          \\r
+        TI_DbgPrint(MIN_TRACE, ("Object at (0x%X) has invalid reference count (%d).\n", \\r
+            (Object), (Object)->RefCount)); \\r
+        }                                   \\r
+}\r
+\r
+#else\r
+\r
+#define DEBUG_REFCHECK(Object)\r
+\r
+#endif\r
+\r
+\r
+/*\r
+ * VOID ReferenceObject(\r
+ *     PVOID Object)\r
+ */\r
+#define ReferenceObject(Object)                  \\r
+{                                                \\r
+    DEBUG_REFCHECK(Object);                      \\r
+    TI_DbgPrint(DEBUG_REFCOUNT, ("Referencing object at (0x%X). RefCount (%d).\n", \\r
+        (Object), (Object)->RefCount));          \\r
+                                                 \\r
+    InterlockedIncrement(&((Object)->RefCount)); \\r
+}\r
+\r
+/*\r
+ * VOID DereferenceObject(\r
+ *     PVOID Object)\r
+ */\r
+#define DereferenceObject(Object)                         \\r
+{                                                         \\r
+    DEBUG_REFCHECK(Object);                               \\r
+    TI_DbgPrint(DEBUG_REFCOUNT, ("Dereferencing object at (0x%X). RefCount (%d).\n", \\r
+        (Object), (Object)->RefCount));                   \\r
+                                                          \\r
+    if (InterlockedDecrement(&((Object)->RefCount)) == 0) \\r
+        PoolFreeBuffer(Object);                           \\r
+}\r
+\r
+\r
+typedef NTSTATUS (*DATAGRAM_SEND_ROUTINE)(\r
+    PTDI_REQUEST Request,\r
+    PTDI_CONNECTION_INFORMATION ConnInfo,\r
+    PNDIS_BUFFER Buffer,\r
+    ULONG DataSize);\r
+\r
+/* Datagram completion handler prototype */\r
+typedef VOID (*DATAGRAM_COMPLETION_ROUTINE)(\r
+    PVOID Context,\r
+    NDIS_STATUS Status,\r
+    ULONG Count);\r
+\r
+typedef struct _DATAGRAM_RECEIVE_REQUEST {\r
+    LIST_ENTRY ListEntry;                   /* Entry on list */\r
+    PIP_ADDRESS RemoteAddress;              /* Remote address we receive from (NULL means any) */\r
+    USHORT RemotePort;                      /* Remote port we receive from (0 means any) */\r
+    PTDI_CONNECTION_INFORMATION ReturnInfo; /* Return information */\r
+    PNDIS_BUFFER Buffer;                    /* Pointer to receive buffer */\r
+    ULONG BufferSize;                       /* Size of Buffer */\r
+    DATAGRAM_COMPLETION_ROUTINE Complete;   /* Completion routine */\r
+    PVOID Context;                          /* Pointer to context information */\r
+} DATAGRAM_RECEIVE_REQUEST, *PDATAGRAM_RECEIVE_REQUEST;\r
+\r
+/* Datagram build routine prototype */\r
+typedef NTSTATUS (*DATAGRAM_BUILD_ROUTINE)(\r
+    PVOID Context,\r
+    PIP_ADDRESS LocalAddress,\r
+    USHORT LocalPort,\r
+    PIP_PACKET *IPPacket);\r
+\r
+typedef struct _DATAGRAM_SEND_REQUEST {\r
+    LIST_ENTRY ListEntry;                 /* Entry on list */\r
+    PIP_ADDRESS RemoteAddress;            /* Pointer to remote IP address */\r
+    USHORT RemotePort;                    /* Remote port number */\r
+    PNDIS_BUFFER Buffer;                  /* Pointer to NDIS buffer to send */\r
+    DWORD BufferSize;                     /* Size of Buffer */\r
+    DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */\r
+    PVOID Context;                        /* Pointer to context information */\r
+    DATAGRAM_BUILD_ROUTINE Build;         /* Datagram build routine */\r
+} DATAGRAM_SEND_REQUEST, *PDATAGRAM_SEND_REQUEST;\r
+\r
+\r
+/* Transport (TCP/UDP) endpoint context structure. The FileObject->FsContext\r
+   field holds a pointer to this structure */\r
+typedef struct _TRANSPORT_CONTEXT {\r
+    union {\r
+        HANDLE AddressHandle;\r
+        CONNECTION_CONTEXT ConnectionContext;\r
+        HANDLE ControlChannel;\r
+    } Handle;\r
+    ULONG RefCount;\r
+    BOOL CancelIrps;\r
+    KEVENT CleanupEvent;\r
+} TRANSPORT_CONTEXT, *PTRANSPORT_CONTEXT;\r
+\r
+\r
+typedef struct _ADDRESS_FILE {\r
+    LIST_ENTRY ListEntry;                 /* Entry on list */\r
+    KSPIN_LOCK Lock;                      /* Spin lock to manipulate this structure */\r
+    ULONG RefCount;                       /* Number of references to this object */\r
+    USHORT Flags;                         /* Flags for address file (see below) */\r
+    PADDRESS_ENTRY ADE;                   /* Associated address entry */\r
+    USHORT Protocol;                      /* Protocol number */\r
+    USHORT Port;                          /* Network port (network byte order) */\r
+    WORK_QUEUE_ITEM WorkItem;             /* Work queue item handle */\r
+    DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine for delete request */\r
+    PVOID Context;                        /* Delete request context */\r
+    DATAGRAM_SEND_ROUTINE Send;           /* Routine to send a datagram */\r
+    LIST_ENTRY ReceiveQueue;              /* List of outstanding receive requests */\r
+    LIST_ENTRY TransmitQueue;             /* List of outstanding transmit requests */\r
+    PIP_ADDRESS AddrCache;                /* One entry address cache (destination\r
+                                             address of last packet transmitted) */\r
+\r
+    /* The following members are used to control event notification */\r
+\r
+    /* Connection indication handler */\r
+    PTDI_IND_CONNECT ConnectionHandler;\r
+    PVOID ConnectionHandlerContext;\r
+    BOOL RegisteredConnectionHandler;\r
+    /* Disconnect indication handler */\r
+    PTDI_IND_DISCONNECT DisconnectHandler;\r
+    PVOID DisconnectHandlerContext;\r
+    BOOL RegisteredDisconnectHandler;\r
+    /* Receive indication handler */\r
+    PTDI_IND_RECEIVE ReceiveHandler;\r
+    PVOID ReceiveHandlerContext;\r
+    BOOL RegisteredReceiveHandler;\r
+    /* Expedited receive indication handler */\r
+    PTDI_IND_RECEIVE_EXPEDITED ExpeditedReceiveHandler;\r
+    PVOID ExpeditedReceiveHandlerContext;\r
+    BOOL RegisteredExpeditedReceiveHandler;\r
+    /* Receive datagram indication handler */\r
+    PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;\r
+    PVOID ReceiveDatagramHandlerContext;\r
+    BOOL RegisteredReceiveDatagramHandler;\r
+    /* Error indication handler */\r
+    PTDI_IND_ERROR ErrorHandler;\r
+    PVOID ErrorHandlerContext;\r
+    PVOID ErrorHandlerOwner;\r
+    BOOL RegisteredErrorHandler;\r
+} ADDRESS_FILE, *PADDRESS_FILE;\r
+\r
+/* Address File Flag constants */\r
+#define AFF_VALID    0x0001 /* Address file object is valid for use */\r
+#define AFF_BUSY     0x0002 /* Address file object is exclusive to someone */\r
+#define AFF_DELETE   0x0004 /* Address file object is sheduled to be deleted */\r
+#define AFF_SEND     0x0008 /* A send request is pending */\r
+#define AFF_RECEIVE  0x0010 /* A receive request is pending */\r
+#define AFF_PENDING  0x001C /* A request is pending */\r
+\r
+/* Macros for manipulating address file object flags */\r
+\r
+#define AF_IS_VALID(ADF)  ((ADF)->Flags & AFF_VALID)\r
+#define AF_SET_VALID(ADF) ((ADF)->Flags |= AFF_VALID)\r
+#define AF_CLR_VALID(ADF) ((ADF)->Flags &= ~AFF_VALID)\r
+\r
+#define AF_IS_BUSY(ADF)  ((ADF)->Flags & AFF_BUSY)\r
+#define AF_SET_BUSY(ADF) ((ADF)->Flags |= AFF_BUSY)\r
+#define AF_CLR_BUSY(ADF) ((ADF)->Flags &= ~AFF_BUSY)\r
+\r
+#define AF_IS_PENDING(ADF, X)  (ADF->Flags & X)\r
+#define AF_SET_PENDING(ADF, X) (ADF->Flags |= X)\r
+#define AF_CLR_PENDING(ADF, X) (ADF->Flags &= ~X)\r
+\r
+\r
+/* Structure used to search through Address Files */\r
+typedef struct _AF_SEARCH {\r
+    PLIST_ENTRY Next;       /* Next address file to check */\r
+    PIP_ADDRESS Address;    /* Pointer to address to be found */\r
+    USHORT Port;            /* Network port */\r
+    USHORT Protocol;        /* Protocol number */\r
+} AF_SEARCH, *PAF_SEARCH;\r
+\r
+/* Transport connection context structure. The FileObject->FsContext2\r
+   field holds a pointer to this structure */\r
+typedef struct _CONNECTION_ENDPOINT {\r
+    LIST_ENTRY ListEntry;   /* Entry on list */\r
+    KSPIN_LOCK Lock;        /* Spin lock to protect this structure */\r
+    ULONG RefCount;         /* Number of references to this object */\r
+} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;\r
+\r
+/* Transport control channel context structure. The FileObject->FsContext2\r
+   field holds a pointer to this structure */\r
+typedef struct _CONTROL_CHANNEL {\r
+    LIST_ENTRY ListEntry;       /* Entry on list */\r
+    KSPIN_LOCK Lock;            /* Spin lock to protect this structure */\r
+    ULONG RefCount;             /* Number of references to this object */\r
+} CONTROL_CHANNEL, *PCONTROL_CHANNEL;\r
+\r
+typedef struct _TI_QUERY_CONTEXT {\r
+    PIRP Irp;\r
+    PMDL InputMdl;\r
+    PMDL OutputMdl;\r
+    TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;\r
+} TI_QUERY_CONTEXT, *PTI_QUERY_CONTEXT;\r
+\r
+#endif /* __TITYPES_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/transmit.h b/reactos/drivers/net/tcpip/include/transmit.h
new file mode 100644 (file)
index 0000000..c0f8167
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/transmit.h\r
+ * PURPOSE:     Internet Protocol transmit prototypes\r
+ */\r
+#ifndef __TRANSMIT_H\r
+#define __TRANSMIT_H\r
+\r
+#include <neighbor.h>\r
+#include <route.h>\r
+#include <ip.h>\r
+\r
+\r
+/* IP fragment context information */\r
+typedef struct IPFRAGMENT_CONTEXT {\r
+    struct IPFRAGMENT_CONTEXT *Next;    /* Pointer to next in list */\r
+    PNDIS_PACKET Datagram;              /* Pointer to original NDIS packet */\r
+    PVOID DatagramData;                 /* Pointer to datagram data */\r
+    UINT HeaderSize;                    /* IP datagram header size */\r
+    PNDIS_PACKET NdisPacket;            /* Pointer to NDIS packet */\r
+    PNDIS_BUFFER NdisBuffer;            /* Pointer to NDIS buffer */\r
+    PVOID Header;                       /* Pointer to IP header in fragment buffer */\r
+    PVOID Data;                         /* Pointer to fragment data */\r
+    UINT Position;                      /* Current fragment offset */\r
+    UINT BytesLeft;                     /* Number of bytes left to send */\r
+    UINT PathMTU;                       /* Path Maximum Transmission Unit */\r
+    PNEIGHBOR_CACHE_ENTRY NCE;          /* Pointer to NCE to use */\r
+} IPFRAGMENT_CONTEXT, *PIPFRAGMENT_CONTEXT;\r
+\r
+\r
+VOID IPSendComplete(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    NDIS_STATUS NdisStatus);\r
+\r
+NTSTATUS IPSendFragment(\r
+    PNDIS_PACKET NdisPacket,\r
+    PNEIGHBOR_CACHE_ENTRY NCE);\r
+\r
+NTSTATUS IPSendDatagram(\r
+    PIP_PACKET IPPacket,\r
+    PROUTE_CACHE_NODE RCN);\r
+\r
+#endif /* __TRANSMIT_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/include/udp.h b/reactos/drivers/net/tcpip/include/udp.h
new file mode 100644 (file)
index 0000000..919a86b
--- /dev/null
@@ -0,0 +1,68 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        include/udp.h\r
+ * PURPOSE:     User Datagram Protocol definitions\r
+ */\r
+#ifndef __UDP_H\r
+#define __UDP_H\r
+\r
+\r
+/* UDPv4 header structure */\r
+typedef struct UDP_HEADER {\r
+    USHORT SourcePort; /* Source port */\r
+    USHORT DestPort;   /* Destination port */\r
+    USHORT Length;     /* Size of header and data */\r
+    USHORT Checksum;   /* Checksum of datagram */\r
+} UDP_HEADER, *PUDP_HEADER;\r
+\r
+/* UDPv4 pseudo header */\r
+typedef struct UDP_PSEUDO_HEADER {\r
+    ULONG SourceAddress; /* Source address */\r
+    ULONG DestAddress;   /* Destination address */\r
+    UCHAR Zero;          /* Reserved */\r
+    UCHAR Protocol;      /* Protocol */\r
+    USHORT UDPLength;    /* Size of UDP datagram */\r
+} UDP_PSEUDO_HEADER, *PUDP_PSEUDO_HEADER;\r
+\r
+\r
+typedef struct UDP_STATISTICS {\r
+    ULONG InputDatagrams;\r
+    ULONG NumPorts;\r
+    ULONG InputErrors;\r
+    ULONG OutputDatagrams;\r
+    ULONG NumAddresses;\r
+} UDP_STATISTICS, *PUDP_STATISTICS;\r
+\r
+VOID UDPSend(\r
+    PVOID Context,\r
+    PDATAGRAM_SEND_REQUEST SendRequest);\r
+\r
+NTSTATUS UDPSendDatagram(\r
+    PTDI_REQUEST Request,\r
+    PTDI_CONNECTION_INFORMATION ConnInfo,\r
+    PNDIS_BUFFER Buffer,\r
+    ULONG DataSize);\r
+\r
+NTSTATUS UDPReceiveDatagram(\r
+    PTDI_REQUEST Request,\r
+    PTDI_CONNECTION_INFORMATION ConnInfo,\r
+    PNDIS_BUFFER Buffer,\r
+    ULONG ReceiveLength,\r
+    ULONG ReceiveFlags,\r
+    PTDI_CONNECTION_INFORMATION ReturnInfo,\r
+    PULONG BytesReceived);\r
+\r
+VOID UDPReceive(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket);\r
+\r
+NTSTATUS UDPStartup(\r
+    VOID);\r
+\r
+NTSTATUS UDPShutdown(\r
+    VOID);\r
+\r
+#endif /* __UDP_H */\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/makefile b/reactos/drivers/net/tcpip/makefile
new file mode 100644 (file)
index 0000000..db914fa
--- /dev/null
@@ -0,0 +1,132 @@
+# TCPIP.SYS - TCP/IP protocol driver\r
+\r
+TARGETNAME=tcpip\r
+\r
+BASE_CFLAGS = -I./include -I../../../include\r
+\r
+RESOURCE_OBJECT  = $(TARGETNAME).coff\r
+TCPIP_OBJECTS    = tcpip/main.o tcpip/address.o tcpip/checksum.o \\r
+                   tcpip/dispatch.o tcpip/fileobjs.o tcpip/info.o \\r
+                   tcpip/pool.o tcpip/routines.o\r
+DATALINK_OBJECTS = datalink/arp.o datalink/lan.o datalink/loopback.o\r
+NETWORK_OBJECTS  = network/icmp.o network/ip.o network/neighbor.o \\r
+                   network/receive.o network/route.o network/router.o \\r
+                   network/transmit.o\r
+DATAGRAM_OBJECTS = transport/datagram/datagram.o\r
+RAWIP_OBJECTS    = transport/rawip/rawip.o\r
+TCP_OBJECTS      = transport/tcp/tcp.o\r
+UDP_OBJECTS      = transport/udp/udp.o\r
+\r
+all: objects $(TARGETNAME).sys\r
+\r
+objects:\r
+       mkdir objects\r
+\r
+objects/tcpip.o: $(TCPIP_OBJECTS)\r
+       $(LD) -r -o objects/tcpip.o $(TCPIP_OBJECTS)\r
+\r
+objects/datalink.o: $(DATALINK_OBJECTS)\r
+       $(LD) -r -o objects/datalink.o $(DATALINK_OBJECTS)\r
+\r
+objects/network.o: $(NETWORK_OBJECTS)\r
+       $(LD) -r -o objects/network.o $(NETWORK_OBJECTS)\r
+\r
+objects/datagram.o: $(DATAGRAM_OBJECTS)\r
+       $(LD) -r -o objects/datagram.o $(DATAGRAM_OBJECTS)\r
+\r
+objects/rawip.o: $(RAWIP_OBJECTS)\r
+       $(LD) -r -o objects/rawip.o $(RAWIP_OBJECTS)\r
+\r
+objects/tcp.o: $(TCP_OBJECTS)\r
+       $(LD) -r -o objects/tcp.o $(TCP_OBJECTS)\r
+\r
+objects/udp.o: $(UDP_OBJECTS)\r
+       $(LD) -r -o objects/udp.o $(UDP_OBJECTS)\r
+\r
+OBJECTS = objects/tcpip.o objects/datalink.o objects/network.o \\r
+          objects/datagram.o objects/rawip.o objects/tcp.o objects/udp.o \\r
+          $(RESOURCE_OBJECT) \\r
+          ../../../ntoskrnl/ntoskrnl.a ../ndis/ndis.a\r
+\r
+$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h\r
+\r
+ifeq ($(DOSCLI),yes)\r
+CLEAN_FILES = \\r
+               *.o objects\*.o tcpip\*.o datalink\*.o network\*.o \\r
+        transport\datagram\*.o transport\rawip\*.o \\r
+        transport\tcp\*.o transport\udp\*.o $(TARGETNAME).coff \\r
+        $(TARGETNAME).a junk.tmp base.tmp temp.exp \\r
+               $(TARGETNAME).sys $(TARGETNAME).sym\r
+else\r
+CLEAN_FILES = \\r
+               *.o objects/*.o tcpip/*.o datalink/*.o network/*.o \\r
+        transport/datagram/*.o transport/rawip/*.o \\r
+        transport/tcp/*.o transport/udp/*.o $(TARGETNAME).coff \\r
+        $(TARGETNAME).a junk.tmp base.tmp temp.exp \\r
+               $(TARGETNAME).sys $(TARGETNAME).sym\r
+endif\r
+\r
+\r
+$(TARGETNAME).sys: $(OBJECTS)\r
+       $(DLLTOOL) \\r
+               --dllname $(TARGETNAME).sys \\r
+               --def $(TARGETNAME).def \\r
+               --kill-at \\r
+               --output-lib $(TARGETNAME).a\r
+       $(CC) \\r
+        -mdll \\r
+        -specs=../../svc_specs \\r
+        -Wl,-e,_DriverEntry@8 \\r
+        -Wl,--base-file,base.tmp \\r
+        -Wl,--defsym,_end=end \\r
+        -Wl,--defsym,_edata=__data_end__ \\r
+        -Wl,--defsym,_etext=etext \\r
+               $(OBJECTS) \\r
+        -o junk.tmp\r
+       - $(RM) junk.tmp\r
+       $(DLLTOOL) \\r
+        --dllname $(TARGETNAME).sys \\r
+        --base-file base.tmp \\r
+        --output-exp temp.exp \\r
+        --def $(TARGETNAME).edf\r
+       - $(RM) base.tmp\r
+       $(CC) \\r
+        -mdll \\r
+        -specs=../../svc_specs \\r
+        -Wl,--image-base,0x10000 \\r
+        -Wl,-e,_DriverEntry@8 \\r
+        -Wl,temp.exp \\r
+               $(OBJECTS) \\r
+        -o $(TARGETNAME).sys\r
+       - $(RM) temp.exp\r
+       $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym\r
+\r
+clean: $(CLEAN_FILES:%=%_clean)\r
+\r
+$(CLEAN_FILES:%=%_clean): %_clean:\r
+       - $(RM) $*\r
+\r
+.PHONY: clean $(CLEAN_FILES:%=%_clean)\r
+\r
+floppy: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys\r
+\r
+$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys\r
+ifeq ($(DOSCLI),yes)\r
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys\r
+else\r
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys\r
+endif\r
+\r
+dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys\r
+\r
+$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys\r
+ifeq ($(DOSCLI),yes)\r
+       $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys\r
+else\r
+       $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys\r
+endif\r
+\r
+#WITH_DEBUGGING      = yes\r
+#WIN32_LEAN_AND_MEAN = yes\r
+#WARNINGS_ARE_ERRORS = yes\r
+include ../../../rules.mak\r
diff --git a/reactos/drivers/net/tcpip/network/Makefile b/reactos/drivers/net/tcpip/network/Makefile
new file mode 100644 (file)
index 0000000..9c985f5
--- /dev/null
@@ -0,0 +1,7 @@
+#\r
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source\r
+# file to this component.  This file merely indirects to the real make file\r
+# that is shared by all the driver components of the Windows NT DDK\r
+#\r
+\r
+!INCLUDE $(NTMAKEENV)\makefile.def\r
diff --git a/reactos/drivers/net/tcpip/network/SOURCES b/reactos/drivers/net/tcpip/network/SOURCES
new file mode 100644 (file)
index 0000000..0768416
--- /dev/null
@@ -0,0 +1,20 @@
+TARGETNAME=network\r
+TARGETPATH=..\objects\r
+TARGETTYPE=LIBRARY\r
+\r
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \\r
+           $(DDK_LIB_PATH)\ndis.lib\r
+\r
+INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net\r
+\r
+\r
+SOURCES= icmp.c \\r
+                ip.c \\r
+         neighbor.c \\r
+                receive.c \\r
+         route.c \\r
+         router.c \\r
+                transmit.c\r
+\r
+MSC_WARNING_LEVEL=/W3 /WX\r
+\r
diff --git a/reactos/drivers/net/tcpip/network/icmp.c b/reactos/drivers/net/tcpip/network/icmp.c
new file mode 100644 (file)
index 0000000..f75e6b0
--- /dev/null
@@ -0,0 +1,299 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/icmp.c\r
+ * PURPOSE:     Internet Control Message Protocol routines\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <icmp.h>\r
+#include <checksum.h>\r
+#include <routines.h>\r
+#include <transmit.h>\r
+#include <pool.h>\r
+\r
+\r
+VOID SendICMPComplete(\r
+    PVOID Context,\r
+    PNDIS_PACKET Packet,\r
+    NDIS_STATUS NdisStatus)\r
+/*\r
+ * FUNCTION: ICMP datagram transmit completion handler\r
+ * ARGUMENTS:\r
+ *     Context    = Pointer to context infomation (IP_PACKET)\r
+ *     Packet     = Pointer to NDIS packet\r
+ *     NdisStatus = Status of transmit operation\r
+ * NOTES:\r
+ *     This routine is called by IP when a ICMP send completes\r
+ */\r
+{\r
+    PIP_PACKET IPPacket = (PIP_PACKET)Context;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Freeing NDIS packet (%X).\n", Packet));\r
+\r
+    /* Free packet */\r
+    FreeNdisPacket(Packet);\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Freeing IP packet at %X.\n", IPPacket));\r
+\r
+    PoolFreeBuffer(IPPacket);\r
+}\r
+\r
+\r
+PIP_PACKET PrepareICMPPacket(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_ADDRESS Destination,\r
+    UINT DataSize)\r
+/*\r
+ * FUNCTION: Prepares an ICMP packet\r
+ * ARGUMENTS:\r
+ *     NTE         = Pointer to net table entry to use\r
+ *     Destination = Pointer to destination address\r
+ *     DataSize    = Size of dataarea\r
+ * RETURNS:\r
+ *     Pointer to IP packet, NULL if there is not enough free resources\r
+ */\r
+{\r
+    PIP_PACKET IPPacket;\r
+    PNDIS_PACKET NdisPacket;\r
+    PNDIS_BUFFER NdisBuffer;\r
+    NDIS_STATUS NdisStatus;\r
+    PIPv4_HEADER IPHeader;\r
+    PVOID DataBuffer;\r
+    ULONG Size;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called. DataSize = %d.\n", DataSize));\r
+\r
+    /* Prepare ICMP packet */\r
+    IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET));\r
+    if (!IPPacket)\r
+        return NULL;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("IPPacket at %X.\n", IPPacket));\r
+\r
+    Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) +\r
+        sizeof(ICMP_HEADER) + DataSize;\r
+    DataBuffer = ExAllocatePool(NonPagedPool, Size);\r
+    if (!DataBuffer) {\r
+        PoolFreeBuffer(IPPacket);\r
+        return NULL;\r
+    }\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Size = %d, Data at %X.\n", Size, DataBuffer));\r
+\r
+    /* Allocate NDIS packet */\r
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        PoolFreeBuffer(IPPacket);\r
+        ExFreePool(DataBuffer);\r
+        return NULL;\r
+    }\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("NdisPacket at %X.\n", NdisPacket));\r
+\r
+    /* Allocate NDIS buffer for maximum link level header and ICMP packet */\r
+    NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,\r
+        DataBuffer, Size);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        PoolFreeBuffer(IPPacket);\r
+        NdisFreePacket(NdisPacket);\r
+        ExFreePool(DataBuffer);\r
+        return NULL;\r
+    }\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("NdisBuffer at %X.\n", NdisBuffer));\r
+\r
+    /* Link NDIS buffer into packet */\r
+    NdisChainBufferAtFront(NdisPacket, NdisBuffer);\r
+    IPPacket->NdisPacket = NdisPacket;\r
+    IPPacket->Header     = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);\r
+    IPPacket->Data       = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize + sizeof(IPv4_HEADER));\r
+\r
+    IPPacket->HeaderSize = sizeof(IPv4_HEADER);\r
+    IPPacket->TotalSize  = Size - MaxLLHeaderSize;\r
+    RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS));\r
+\r
+    /* Build IPv4 header. FIXME: IPv4 only */\r
+\r
+    IPHeader = (PIPv4_HEADER)IPPacket->Header;\r
+\r
+    /* Version = 4, Length = 5 DWORDs */\r
+    IPHeader->VerIHL = 0x45;\r
+    /* Normal Type-of-Service */\r
+    IPHeader->Tos = 0;\r
+    /* Length of data and header */\r
+    IPHeader->TotalLength = WH2N((USHORT)DataSize +\r
+        sizeof(IPv4_HEADER) + sizeof(ICMP_HEADER));\r
+    /* Identification */\r
+    IPHeader->Id = (USHORT)Random();\r
+    /* One fragment at offset 0 */\r
+    IPHeader->FlagsFragOfs = 0;\r
+    /* Time-to-Live is 128 */\r
+    IPHeader->Ttl = 128;\r
+    /* Internet Control Message Protocol */\r
+    IPHeader->Protocol = IPPROTO_ICMP;\r
+    /* Checksum is 0 (for later calculation of this) */\r
+    IPHeader->Checksum = 0;\r
+    /* Source address */\r
+    IPHeader->SrcAddr = NTE->Address->Address.IPv4Address;\r
+    /* Destination address */\r
+    IPHeader->DstAddr = Destination->Address.IPv4Address;\r
+\r
+    /* Completion handler */\r
+    PC(NdisPacket)->Complete = SendICMPComplete;\r
+    PC(NdisPacket)->Context  = IPPacket;\r
+\r
+    return IPPacket;\r
+}\r
+\r
+\r
+VOID ICMPReceive(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: Receives an ICMP packet\r
+ * ARGUMENTS:\r
+ *     NTE      = Pointer to net table entry which the packet was received on\r
+ *     IPPacket = Pointer to an IP packet that was received\r
+ */\r
+{\r
+    PICMP_HEADER ICMPHeader;\r
+    PIP_PACKET NewPacket;\r
+    UINT DataSize;\r
+    ULONG Checksum;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    ICMPHeader = (PICMP_HEADER)IPPacket->Data;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Size = %d.\n", IPPacket->TotalSize));\r
+\r
+    TI_DbgPrint(MID_TRACE, ("HeaderSize = %d.\n", IPPacket->HeaderSize));\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Type = %d.\n", ICMPHeader->Type));\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Code = %d.\n", ICMPHeader->Code));\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Checksum = %X.\n", ICMPHeader->Checksum));\r
+\r
+    /* Checksum ICMP header and data and compare */\r
+    Checksum = DN2H(IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0));\r
+    if (Checksum != 0xFFFF) {\r
+        TI_DbgPrint(MIN_TRACE, ("Bad ICMP checksum (0x%X).\n", Checksum));\r
+        /* Discard packet */\r
+        return;\r
+    }\r
+\r
+    switch (ICMPHeader->Type) {\r
+    case ICMP_TYPE_ECHO_REQUEST:\r
+        /* Reply with an ICMP echo reply message */\r
+        DataSize  = IPPacket->TotalSize - IPPacket->HeaderSize - sizeof(ICMP_HEADER);\r
+        NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize);\r
+        if (!NewPacket)\r
+            return;\r
+\r
+        /* Copy ICMP header and data into new packet */\r
+        RtlCopyMemory(NewPacket->Data, IPPacket->Data, DataSize  + sizeof(ICMP_HEADER));\r
+        ((PICMP_HEADER)NewPacket->Data)->Type     = ICMP_TYPE_ECHO_REPLY;\r
+        ((PICMP_HEADER)NewPacket->Data)->Code     = 0;\r
+        ((PICMP_HEADER)NewPacket->Data)->Checksum = 0;\r
+\r
+        ICMPTransmit(NTE, NewPacket);\r
+\r
+        TI_DbgPrint(MID_TRACE, ("Echo reply sent.\n"));\r
+\r
+        return;\r
+    default:\r
+        TI_DbgPrint(MID_TRACE, ("Discarded ICMP datagram of unknown type.\n"));\r
+        /* Discard packet */\r
+        break;\r
+    }\r
+}\r
+\r
+\r
+VOID ICMPTransmit(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: Transmits an ICMP packet\r
+ * ARGUMENTS:\r
+ *     NTE      = Pointer to net table entry to use (NULL if don't care)\r
+ *     IPPacket = Pointer to IP packet to transmit\r
+ */\r
+{\r
+    PROUTE_CACHE_NODE RCN;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
+\r
+    /* Calculate checksum of ICMP header and data */\r
+    ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT)\r
+        IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0);\r
+\r
+    /* Get a route to the destination address */\r
+    if (RouteGetRouteToDestination(&IPPacket->DstAddr, NTE, &RCN) == IP_SUCCESS) {\r
+        /* Send the packet */\r
+        if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) {\r
+            FreeNdisPacket(IPPacket->NdisPacket);\r
+            PoolFreeBuffer(IPPacket);\r
+        }\r
+        /* We're done with the RCN */\r
+        DereferenceObject(RCN);\r
+    } else {\r
+        TI_DbgPrint(MIN_TRACE, ("RCN at 0x%X.\n", RCN));\r
+\r
+        /* No route to destination (or no free resources) */\r
+        TI_DbgPrint(MIN_TRACE, ("No route to destination address 0x%X.\n",\r
+            IPPacket->DstAddr.Address.IPv4Address));\r
+        /* Discard packet */\r
+        FreeNdisPacket(IPPacket->NdisPacket);\r
+        PoolFreeBuffer(IPPacket);\r
+    }\r
+}\r
+\r
+\r
+VOID ICMPReply(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket,\r
+       UCHAR Type,\r
+       UCHAR Code)\r
+/*\r
+ * FUNCTION: Transmits an ICMP packet in response to an incoming packet\r
+ * ARGUMENTS:\r
+ *     NTE      = Pointer to net table entry to use\r
+ *     IPPacket = Pointer to IP packet that was received\r
+ *     Type     = ICMP message type\r
+ *     Code     = ICMP message code\r
+ * NOTES:\r
+ *     We have received a packet from someone and is unable to\r
+ *     process it due to error(s) in the packet or we have run out\r
+ *     of resources. We transmit an ICMP message to the host to\r
+ *     notify him of the problem\r
+ */\r
+{\r
+    UINT DataSize;\r
+    PIP_PACKET NewPacket;\r
+\r
+    TI_DbgPrint(MID_TRACE, ("Called (Type=%d, Code=%d).\n", Type, Code));\r
+\r
+    DataSize = IPPacket->TotalSize;\r
+    if ((DataSize) > (576 - sizeof(IPv4_HEADER) - sizeof(ICMP_HEADER)))\r
+        DataSize = 576;\r
+\r
+    NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize);\r
+    if (!NewPacket)\r
+        return;\r
+\r
+    RtlCopyMemory((PVOID)((ULONG_PTR)NewPacket->Data + sizeof(ICMP_HEADER)),\r
+        IPPacket->Header, DataSize);\r
+    ((PICMP_HEADER)NewPacket->Data)->Type     = Type;\r
+    ((PICMP_HEADER)NewPacket->Data)->Code     = Code;\r
+    ((PICMP_HEADER)NewPacket->Data)->Checksum = 0;\r
+\r
+    ICMPTransmit(NTE, NewPacket);\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/network/ip.c b/reactos/drivers/net/tcpip/network/ip.c
new file mode 100644 (file)
index 0000000..f15449c
--- /dev/null
@@ -0,0 +1,979 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/ip.c\r
+ * PURPOSE:     Internet Protocol module\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <ip.h>\r
+#include <loopback.h>\r
+#include <neighbor.h>\r
+#include <receive.h>\r
+#include <address.h>\r
+#include <route.h>\r
+#include <icmp.h>\r
+#include <pool.h>\r
+\r
+\r
+KTIMER IPTimer;\r
+KDPC IPTimeoutDpc;\r
+LIST_ENTRY InterfaceListHead;\r
+KSPIN_LOCK InterfaceListLock;\r
+LIST_ENTRY NetTableListHead;\r
+KSPIN_LOCK NetTableListLock;\r
+LIST_ENTRY PrefixListHead;\r
+KSPIN_LOCK PrefixListLock;\r
+UINT MaxLLHeaderSize; /* Largest maximum header size */\r
+UINT MinLLFrameSize;  /* Largest minimum frame size */\r
+BOOLEAN IPInitialized = FALSE;\r
+\r
+IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];\r
+\r
+\r
+PADDRESS_ENTRY CreateADE(\r
+    PIP_INTERFACE IF,\r
+    PIP_ADDRESS Address,\r
+    UCHAR Type,\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Creates an address entry and binds it to an interface\r
+ * ARGUMENTS:\r
+ *     IF      = Pointer to interface\r
+ *     Address = Pointer to referenced interface address\r
+ *     Type    = Type of address (ADE_*)\r
+ *     NTE     = Pointer to net table entry\r
+ * RETURNS:\r
+ *     Pointer to ADE, NULL if there was not enough free resources\r
+ * NOTES:\r
+ *     The interface lock must be held when called. The address entry\r
+ *     retains a reference to the provided address and NTE. The caller\r
+ *     is responsible for referencing the these before calling.\r
+ *     As long as you have referenced an ADE you can safely use the\r
+ *     address and NTE as the ADE references both\r
+ */\r
+{\r
+    PADDRESS_ENTRY ADE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  Type (0x%X)  NTE (0x%X).\n",\r
+        IF, Address, Type, NTE));\r
+\r
+    /* Allocate space for an ADE and set it up */\r
+    ADE = PoolAllocateBuffer(sizeof(ADDRESS_ENTRY));\r
+    if (!ADE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    ADE->RefCount = 1;\r
+    ADE->NTE      = NTE;\r
+    ADE->Type     = Type;\r
+    ADE->Address  = Address;\r
+\r
+    /* Add ADE to the list on the interface */\r
+    InsertTailList(&IF->ADEListHead, &ADE->ListEntry);\r
+\r
+    return ADE;\r
+}\r
+\r
+\r
+VOID DestroyADE(\r
+    PIP_INTERFACE IF,\r
+    PADDRESS_ENTRY ADE)\r
+/*\r
+ * FUNCTION: Destroys an address entry\r
+ * ARGUMENTS:\r
+ *     IF  = Pointer to interface\r
+ *     ADE = Pointer to address entry\r
+ * NOTES:\r
+ *     The interface lock must be held when called\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  ADE (0x%X).\n", IF, ADE));\r
+\r
+    /* Unlink the address entry from the list */\r
+    RemoveEntryList(&ADE->ListEntry);\r
+\r
+    /* Dereference the address */\r
+    DereferenceObject(ADE->Address);\r
+\r
+    /* Dereference the NTE */\r
+    DereferenceObject(ADE->NTE);\r
+\r
+#ifdef DBG\r
+    ADE->RefCount--;\r
+\r
+    if (ADE->RefCount != 0) {\r
+        TI_DbgPrint(MIN_TRACE, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE, ADE->RefCount));\r
+    }\r
+#endif\r
+\r
+    /* And free the ADE */\r
+    PoolFreeBuffer(ADE);\r
+    TI_DbgPrint(MIN_TRACE, ("Check.\n"));\r
+}\r
+\r
+\r
+VOID DestroyADEs(\r
+    PIP_INTERFACE IF)\r
+/*\r
+ * FUNCTION: Destroys all address entries on an interface\r
+ * ARGUMENTS:\r
+ *     IF  = Pointer to interface\r
+ * NOTES:\r
+ *     The interface lock must be held when called\r
+ */\r
+{\r
+    PLIST_ENTRY CurrentEntry;\r
+    PLIST_ENTRY NextEntry;\r
+    PADDRESS_ENTRY Current;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));\r
+\r
+    /* Search the list and remove every ADE we find */\r
+    CurrentEntry = IF->ADEListHead.Flink;\r
+    while (CurrentEntry != &IF->ADEListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);\r
+        /* Destroy the ADE */\r
+        DestroyADE(IF, Current);\r
+        CurrentEntry = NextEntry;\r
+    }\r
+}\r
+\r
+\r
+PPREFIX_LIST_ENTRY CreatePLE(\r
+    PIP_INTERFACE IF,\r
+    PIP_ADDRESS Prefix,\r
+    UINT Length)\r
+/*\r
+ * FUNCTION: Creates a prefix list entry and binds it to an interface\r
+ * ARGUMENTS:\r
+ *     IF     = Pointer to interface\r
+ *     Prefix = Pointer to prefix\r
+ *     Length = Length of prefix\r
+ * RETURNS:\r
+ *     Pointer to PLE, NULL if there was not enough free resources\r
+ * NOTES:\r
+ *     The prefix list entry retains a reference to the interface and\r
+ *     the provided address.  The caller is responsible for providing\r
+ *     these references\r
+ */\r
+{\r
+    PPREFIX_LIST_ENTRY PLE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Prefix (0x%X)  Length (%d).\n", IF, Prefix, Length));\r
+\r
+    /* Allocate space for an PLE and set it up */\r
+    PLE = PoolAllocateBuffer(sizeof(PREFIX_LIST_ENTRY));\r
+    if (!PLE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    PLE->RefCount     = 1;\r
+    PLE->Interface    = IF;\r
+    PLE->Prefix       = Prefix;\r
+    PLE->PrefixLength = Length;\r
+\r
+    /* Add PLE to the global prefix list */\r
+    ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock);\r
+\r
+    return PLE;\r
+}\r
+\r
+\r
+VOID DestroyPLE(\r
+    PPREFIX_LIST_ENTRY PLE)\r
+/*\r
+ * FUNCTION: Destroys an prefix list entry\r
+ * ARGUMENTS:\r
+ *     PLE = Pointer to prefix list entry\r
+ * NOTES:\r
+ *     The prefix list lock must be held when called\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE));\r
+\r
+    /* Unlink the prefix list entry from the list */\r
+    RemoveEntryList(&PLE->ListEntry);\r
+\r
+    /* Dereference the address */\r
+    DereferenceObject(PLE->Prefix);\r
+\r
+    /* Dereference the interface */\r
+    DereferenceObject(PLE->Interface);\r
+\r
+#ifdef DBG\r
+    PLE->RefCount--;\r
+\r
+    if (PLE->RefCount != 0) {\r
+        TI_DbgPrint(MIN_TRACE, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE, PLE->RefCount));\r
+    }\r
+#endif\r
+\r
+    /* And free the PLE */\r
+    PoolFreeBuffer(PLE);\r
+}\r
+\r
+\r
+VOID DestroyPLEs(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Destroys all prefix list entries\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PLIST_ENTRY NextEntry;\r
+    PPREFIX_LIST_ENTRY Current;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called.\n"));\r
+\r
+    KeAcquireSpinLock(&PrefixListLock, &OldIrql);\r
+\r
+    /* Search the list and remove every PLE we find */\r
+    CurrentEntry = PrefixListHead.Flink;\r
+    while (CurrentEntry != &PrefixListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);\r
+        /* Destroy the PLE */\r
+        DestroyPLE(Current);\r
+        CurrentEntry = NextEntry;\r
+    }\r
+    KeReleaseSpinLock(&PrefixListLock, OldIrql);\r
+}\r
+\r
+\r
+PNET_TABLE_ENTRY IPCreateNTE(\r
+    PIP_INTERFACE IF,\r
+    PIP_ADDRESS Address,\r
+    UINT PrefixLength)\r
+/*\r
+ * FUNCTION: Creates a net table entry and binds it to an interface\r
+ * ARGUMENTS:\r
+ *     IF           = Pointer to interface\r
+ *     Address      = Pointer to interface address\r
+ *     PrefixLength = Length of prefix\r
+ * RETURNS:\r
+ *     Pointer to NTE, NULL if there was not enough free resources\r
+ * NOTES:\r
+ *     The interface lock must be held when called.\r
+ *     The net table entry retains a reference to the interface and\r
+ *     the provided address. The caller is responsible for providing\r
+ *     these references\r
+ */\r
+{\r
+    PNET_TABLE_ENTRY NTE;\r
+    PADDRESS_ENTRY ADE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  PrefixLength (%d).\n", IF, Address, PrefixLength));\r
+\r
+    /* Allocate room for an NTE */\r
+    NTE = PoolAllocateBuffer(sizeof(NET_TABLE_ENTRY));\r
+    if (!NTE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    NTE->Interface = IF;\r
+\r
+    /* One reference is for beeing alive and one reference is for the ADE */\r
+    NTE->RefCount = 2;\r
+\r
+    NTE->Address = Address;\r
+    /* One reference is for NTE, one reference is given to the\r
+       address entry, and one reference is given to the prefix\r
+       list entry */\r
+    ReferenceObject(Address);\r
+    ReferenceObject(Address);\r
+    ReferenceObject(Address);\r
+\r
+    /* Create an address entry and add it to the list */\r
+    ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);\r
+    if (!ADE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        PoolFreeBuffer(NTE);\r
+        return NULL;\r
+    }\r
+\r
+    /* Create a prefix list entry for unicast address */\r
+    NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);\r
+    if (!NTE->PLE) {\r
+        DestroyADE(IF, ADE);\r
+        PoolFreeBuffer(NTE);\r
+        return NULL;\r
+    }\r
+\r
+    /* Reference the interface for the prefix list entry */\r
+    ReferenceObject(IF);\r
+\r
+    /* Add NTE to the list on the interface */\r
+    InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);\r
+\r
+    /* Add NTE to the global net table list */\r
+    ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);\r
+\r
+    return NTE;\r
+}\r
+\r
+\r
+VOID DestroyNTE(\r
+    PIP_INTERFACE IF,\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Destroys a net table entry\r
+ * ARGUMENTS:\r
+ *     IF  = Pointer to interface\r
+ *     NTE = Pointer to net table entry\r
+ * NOTES:\r
+ *     The net table list lock must be held when called\r
+ *     The interface lock must be held when called\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  NTE (0x%X).\n", IF, NTE));\r
+\r
+    /* Invalidate the prefix list entry for this NTE */\r
+    KeAcquireSpinLock(&PrefixListLock, &OldIrql);\r
+    DestroyPLE(NTE->PLE);\r
+    KeReleaseSpinLock(&PrefixListLock, OldIrql);\r
+\r
+    /* Remove NTE from the interface list */\r
+    RemoveEntryList(&NTE->IFListEntry);\r
+    /* Remove NTE from the net table list */\r
+    RemoveEntryList(&NTE->NTListEntry);\r
+    /* Dereference the objects that are referenced */\r
+    DereferenceObject(NTE->Address);\r
+    DereferenceObject(NTE->Interface);\r
+#ifdef DBG\r
+    NTE->RefCount--;\r
+\r
+    if (NTE->RefCount != 0) {\r
+        TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount));\r
+    }\r
+#endif\r
+    /* And free the NTE */\r
+    PoolFreeBuffer(NTE);\r
+}\r
+\r
+\r
+VOID DestroyNTEs(\r
+    PIP_INTERFACE IF)\r
+/*\r
+ * FUNCTION: Destroys all net table entries on an interface\r
+ * ARGUMENTS:\r
+ *     IF  = Pointer to interface\r
+ * NOTES:\r
+ *     The net table list lock must be held when called\r
+ *     The interface lock may be held when called\r
+ */\r
+{\r
+    PLIST_ENTRY CurrentEntry;\r
+    PLIST_ENTRY NextEntry;\r
+    PNET_TABLE_ENTRY Current;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));\r
+\r
+    /* Search the list and remove every NTE we find */\r
+    CurrentEntry = IF->NTEListHead.Flink;\r
+    while (CurrentEntry != &IF->NTEListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);\r
+        /* Destroy the NTE */\r
+        DestroyNTE(IF, Current);\r
+        CurrentEntry = NextEntry;\r
+    }\r
+}\r
+\r
+\r
+PNET_TABLE_ENTRY IPLocateNTEOnInterface(\r
+    PIP_INTERFACE IF,\r
+    PIP_ADDRESS Address,\r
+    PUINT AddressType)\r
+/*\r
+ * FUNCTION: Locates an NTE on an interface\r
+ * ARGUMENTS:\r
+ *     IF          = Pointer to interface\r
+ *     Address     = Pointer to IP address\r
+ *     AddressType = Address of type of IP address\r
+ * NOTES:\r
+ *     If found, the NTE is referenced for the caller. The caller is\r
+ *     responsible for dereferencing after use\r
+ * RETURNS:\r
+ *     Pointer to net table entry, NULL if none was found\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PADDRESS_ENTRY Current;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  AddressType (0x%X).\n",\r
+        IF, Address, AddressType));\r
+\r
+    KeAcquireSpinLock(&IF->Lock, &OldIrql);\r
+\r
+    /* Search the list and return the NTE if found */\r
+    CurrentEntry = IF->ADEListHead.Flink;\r
+    while (CurrentEntry != &IF->ADEListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);\r
+        if (AddrIsEqual(Address, Current->Address)) {\r
+            ReferenceObject(Current->NTE);\r
+            *AddressType = Current->Type;\r
+            KeReleaseSpinLock(&IF->Lock, OldIrql);\r
+            return Current->NTE;\r
+        }\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    KeReleaseSpinLock(&IF->Lock, OldIrql);\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+PNET_TABLE_ENTRY IPLocateNTE(\r
+    PIP_ADDRESS Address,\r
+    PUINT AddressType)\r
+/*\r
+ * FUNCTION: Locates an NTE for the network Address is on \r
+ * ARGUMENTS:\r
+ *     Address     = Pointer to an address to find associated NTE of\r
+ *     AddressType = Address of address type\r
+ * NOTES:\r
+ *     If found the NTE is referenced for the caller. The caller is\r
+ *     responsible for dereferencing after use\r
+ * RETURNS:\r
+ *     Pointer to NTE if the address was found, NULL if not.\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PNET_TABLE_ENTRY Current;\r
+    PNET_TABLE_ENTRY NTE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X)  AddressType (0x%X).\n",\r
+        Address, AddressType));\r
+    \r
+    KeAcquireSpinLock(&NetTableListLock, &OldIrql);\r
+\r
+    /* Search the list and return the NTE if found */\r
+    CurrentEntry = NetTableListHead.Flink;\r
+    while (CurrentEntry != &NetTableListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry);\r
+        NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType);\r
+        if (NTE) {\r
+            ReferenceObject(NTE);\r
+            KeReleaseSpinLock(&NetTableListLock, OldIrql);\r
+            return NTE;\r
+        }\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    KeReleaseSpinLock(&NetTableListLock, OldIrql);\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+PADDRESS_ENTRY IPLocateADE(\r
+    PIP_ADDRESS Address,\r
+    UINT AddressType)\r
+/*\r
+ * FUNCTION: Locates an ADE for the address\r
+ * ARGUMENTS:\r
+ *     Address     = Pointer to an address to find associated ADE of\r
+ *     AddressType = Type of address\r
+ * RETURNS:\r
+ *     Pointer to ADE if the address was found, NULL if not.\r
+ * NOTES:\r
+ *     If found the ADE is referenced for the caller. The caller is\r
+ *     responsible for dereferencing after use\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentIFEntry;\r
+    PLIST_ENTRY CurrentADEEntry;\r
+    PIP_INTERFACE CurrentIF;\r
+    PADDRESS_ENTRY CurrentADE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X)  AddressType (0x%X).\n",\r
+        Address, AddressType));\r
+\r
+    KeAcquireSpinLock(&InterfaceListLock, &OldIrql);\r
+\r
+    /* Search the interface list */\r
+    CurrentIFEntry = InterfaceListHead.Flink;\r
+    while (CurrentIFEntry != &InterfaceListHead) {\r
+           CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);\r
+\r
+        /* Search the address entry list and return the ADE if found */\r
+        CurrentADEEntry = CurrentIF->ADEListHead.Flink;\r
+        while (CurrentADEEntry != &CurrentIF->ADEListHead) {\r
+               CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);\r
+            if ((AddrIsEqual(Address, CurrentADE->Address)) && \r
+                (CurrentADE->Type == AddressType)) {\r
+                ReferenceObject(CurrentADE);\r
+                KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
+                return CurrentADE;\r
+            }\r
+            CurrentADEEntry = CurrentADEEntry->Flink;\r
+        }\r
+        CurrentIFEntry = CurrentIFEntry->Flink;\r
+    }\r
+\r
+    KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+PADDRESS_ENTRY IPGetDefaultADE(\r
+    UINT AddressType)\r
+/*\r
+ * FUNCTION: Returns a default address entry\r
+ * ARGUMENTS:\r
+ *     AddressType = Type of address\r
+ * RETURNS:\r
+ *     Pointer to ADE if found, NULL if not.\r
+ * NOTES:\r
+ *     Loopback interface is only considered if it is the only interface.\r
+ *     If found, the address entry is referenced\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentIFEntry;\r
+    PLIST_ENTRY CurrentADEEntry;\r
+    PIP_INTERFACE CurrentIF;\r
+    PADDRESS_ENTRY CurrentADE;\r
+#if 0\r
+    BOOLEAN LoopbackIsRegistered = FALSE;\r
+#endif\r
+    TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));\r
+\r
+    KeAcquireSpinLock(&InterfaceListLock, &OldIrql);\r
+\r
+    /* Search the interface list */\r
+    CurrentIFEntry = InterfaceListHead.Flink;\r
+    while (CurrentIFEntry != &InterfaceListHead) {\r
+           CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);\r
+#if 0\r
+        if (CurrentIF != Loopback) {\r
+#endif\r
+            /* Search the address entry list and return the first appropriate ADE found */\r
+            CurrentADEEntry = CurrentIF->ADEListHead.Flink;\r
+            while (CurrentADEEntry != &CurrentIF->ADEListHead) {\r
+                   CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);\r
+                if (CurrentADE->Type == AddressType)\r
+                    ReferenceObject(CurrentADE);\r
+                    KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
+                    return CurrentADE;\r
+                }\r
+                CurrentADEEntry = CurrentADEEntry->Flink;\r
+#if 0\r
+        } else\r
+            LoopbackIsRegistered = TRUE;\r
+#endif\r
+        CurrentIFEntry = CurrentIFEntry->Flink;\r
+    }\r
+#if 0\r
+    /* No address was found. Use loopback interface if available */\r
+    if (LoopbackIsRegistered) {\r
+        CurrentADEEntry = Loopback->ADEListHead.Flink;\r
+        while (CurrentADEEntry != &Loopback->ADEListHead) {\r
+               CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);\r
+            if (CurrentADE->Type == AddressType) {\r
+                ReferenceObject(CurrentADE);\r
+                KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
+                return CurrentADE;\r
+            }\r
+            CurrentADEEntry = CurrentADEEntry->Flink;\r
+        }\r
+    }\r
+#endif\r
+    KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+VOID IPTimeout(\r
+    PKDPC Dpc,\r
+    PVOID DeferredContext,\r
+    PVOID SystemArgument1,\r
+    PVOID SystemArgument2)\r
+/*\r
+ * FUNCTION: Timeout DPC\r
+ * ARGUMENTS:\r
+ *     Dpc             = Pointer to our DPC object\r
+ *     DeferredContext = Pointer to context information (unused)\r
+ *     SystemArgument1 = Unused\r
+ *     SystemArgument2 = Unused\r
+ * NOTES:\r
+ *     This routine is dispatched once in a while to do maintainance jobs\r
+ */\r
+{\r
+    /* Check if datagram fragments have taken too long to assemble */\r
+    IPDatagramReassemblyTimeout();\r
+\r
+    /* Clean possible outdated cached neighbor addresses */\r
+    NBTimeout();\r
+}\r
+\r
+\r
+VOID IPDispatchProtocol(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: IP protocol dispatcher\r
+ * ARGUMENTS:\r
+ *     NTE      = Pointer to net table entry which the packet was received on\r
+ *     IPPacket = Pointer to an IP packet that was received\r
+ * NOTES:\r
+ *     This routine examines the IP header and passes the packet on to the\r
+ *     right upper level protocol receive handler\r
+ */\r
+{\r
+    UINT Protocol;\r
+\r
+    switch (IPPacket->Type) {\r
+    case IP_ADDRESS_V4:\r
+        Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;\r
+        break;\r
+    case IP_ADDRESS_V6:\r
+        /* FIXME: IPv6 adresses not supported */\r
+        TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));\r
+        return;\r
+    default:\r
+        Protocol = 0;\r
+    }\r
+\r
+    /* Call the appropriate protocol handler */\r
+    (*ProtocolTable[Protocol])(NTE, IPPacket);\r
+}\r
+\r
+\r
+PIP_INTERFACE IPCreateInterface(\r
+    PLLIP_BIND_INFO BindInfo)\r
+/*\r
+ * FUNCTION: Creates an IP interface\r
+ * ARGUMENTS:\r
+ *     BindInfo = Pointer to link layer to IP binding information\r
+ * RETURNS:\r
+ *     Pointer to IP_INTERFACE structure, NULL if there was\r
+ *     not enough free resources\r
+ */\r
+{\r
+    PIP_INTERFACE IF;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));\r
+\r
+    IF = PoolAllocateBuffer(sizeof(IP_INTERFACE));\r
+    if (!IF) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    IF->RefCount      = 1;\r
+    IF->Context       = BindInfo->Context;\r
+    IF->HeaderSize    = BindInfo->HeaderSize;\r
+       if (IF->HeaderSize > MaxLLHeaderSize)\r
+               MaxLLHeaderSize = IF->HeaderSize;\r
+\r
+    IF->MinFrameSize  = BindInfo->MinFrameSize;\r
+       if (IF->MinFrameSize > MinLLFrameSize)\r
+               MinLLFrameSize = IF->MinFrameSize;\r
+\r
+    IF->MTU           = BindInfo->MTU;\r
+    IF->Address       = BindInfo->Address;\r
+    IF->AddressLength = BindInfo->AddressLength;\r
+    IF->Transmit      = BindInfo->Transmit;\r
+\r
+    InitializeListHead(&IF->ADEListHead);\r
+    InitializeListHead(&IF->NTEListHead);\r
+\r
+    KeInitializeSpinLock(&IF->Lock);\r
+\r
+    return IF;\r
+}\r
+\r
+\r
+VOID IPDestroyInterface(\r
+    PIP_INTERFACE IF)\r
+/*\r
+ * FUNCTION: Destroys an IP interface\r
+ * ARGUMENTS:\r
+ *     IF = Pointer to interface to destroy\r
+ */\r
+{\r
+    KIRQL OldIrql1;\r
+    KIRQL OldIrql2;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));\r
+\r
+    KeAcquireSpinLock(&NetTableListLock, &OldIrql1);\r
+    KeAcquireSpinLock(&IF->Lock, &OldIrql2);\r
+    DestroyADEs(IF);\r
+    DestroyNTEs(IF);\r
+    KeReleaseSpinLock(&IF->Lock, OldIrql2);\r
+    KeReleaseSpinLock(&NetTableListLock, OldIrql1);\r
+\r
+#ifdef DBG\r
+    IF->RefCount--;\r
+\r
+    if (IF->RefCount != 0) {\r
+        TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount));\r
+    }\r
+#endif\r
+    PoolFreeBuffer(IF);\r
+}\r
+\r
+\r
+BOOLEAN IPRegisterInterface(\r
+    PIP_INTERFACE IF)\r
+/*\r
+ * FUNCTION: Registers an IP interface with IP layer\r
+ * ARGUMENTS:\r
+ *     IF = Pointer to interface to register\r
+ * RETURNS;\r
+ *     TRUE if interface was successfully registered, FALSE if not\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PNET_TABLE_ENTRY Current;\r
+    PROUTE_CACHE_NODE RCN;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));\r
+\r
+    KeAcquireSpinLock(&IF->Lock, &OldIrql);\r
+\r
+    /* Add routes to all NTEs on this interface */\r
+    CurrentEntry = IF->NTEListHead.Flink;\r
+    while (CurrentEntry != &IF->NTEListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);\r
+\r
+        /* Add a permanent neighbor for this NTE */\r
+        ReferenceObject(Current->Address);\r
+        NCE = NBAddNeighbor(IF, Current->Address, IF->Address,\r
+            IF->AddressLength, NUD_PERMANENT);\r
+        if (!NCE) {\r
+            TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));\r
+            DereferenceObject(Current->Address);\r
+            KeReleaseSpinLock(&IF->Lock, OldIrql);\r
+            return FALSE;\r
+        }\r
+        RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);\r
+        if (!RCN) {\r
+            TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));\r
+            DereferenceObject(Current->Address);\r
+            KeReleaseSpinLock(&IF->Lock, OldIrql);\r
+            return FALSE;\r
+        }\r
+        /* Don't need this any more since the route cache references the NCE */\r
+        DereferenceObject(NCE);\r
+\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    /* Add interface to the global interface list */\r
+    ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock);\r
+\r
+    KeReleaseSpinLock(&IF->Lock, OldIrql);\r
+\r
+    return TRUE;\r
+}\r
+\r
+\r
+VOID IPUnregisterInterface(\r
+    PIP_INTERFACE IF)\r
+/*\r
+ * FUNCTION: Unregisters an IP interface with IP layer\r
+ * ARGUMENTS:\r
+ *     IF = Pointer to interface to unregister\r
+ */\r
+{\r
+    KIRQL OldIrql1;\r
+    KIRQL OldIrql2;\r
+    KIRQL OldIrql3;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PNET_TABLE_ENTRY Current;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));\r
+\r
+    KeAcquireSpinLock(&NetTableListLock, &OldIrql1);\r
+    KeAcquireSpinLock(&IF->Lock, &OldIrql2);\r
+\r
+    /* Remove routes to all NTEs on this interface */\r
+    CurrentEntry = IF->NTEListHead.Flink;\r
+    while (CurrentEntry != &IF->NTEListHead) {\r
+        Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);\r
+\r
+        /* Remove NTE from global net table list */\r
+        RemoveEntryList(&Current->NTListEntry);\r
+\r
+        /* Remove all references from route cache to NTE */\r
+        RouteInvalidateNTE(Current);\r
+\r
+        /* Remove permanent NCE, but first we have to find it */\r
+        NCE = NBLocateNeighbor(Current->Address);\r
+        if (NCE) {\r
+            DereferenceObject(NCE);\r
+            NBRemoveNeighbor(NCE);\r
+        }\r
+\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    KeAcquireSpinLock(&InterfaceListLock, &OldIrql3);\r
+    /* Ouch...three spinlocks acquired! Fortunately\r
+       we don't unregister interfaces very often */\r
+    RemoveEntryList(&IF->ListEntry);\r
+    KeReleaseSpinLock(&InterfaceListLock, OldIrql3);\r
+\r
+    KeReleaseSpinLock(&IF->Lock, OldIrql2);\r
+    KeReleaseSpinLock(&NetTableListLock, OldIrql1);\r
+}\r
+\r
+\r
+VOID IPRegisterProtocol(\r
+    UINT ProtocolNumber,\r
+    IP_PROTOCOL_HANDLER Handler)\r
+/*\r
+ * FUNCTION: Registers a handler for an IP protocol number\r
+ * ARGUMENTS:\r
+ *     ProtocolNumber = Internet Protocol number for which to register handler\r
+ *     Handler        = Pointer to handler to be called when a packet is received\r
+ * NOTES:\r
+ *     To unregister a protocol handler, call this function with Handler = NULL\r
+ */\r
+{\r
+#ifdef DBG\r
+    if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)\r
+        TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));\r
+#endif\r
+\r
+    ProtocolTable[ProtocolNumber] = Handler;\r
+}\r
+\r
+\r
+VOID DefaultProtocolHandler(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: Default handler for Internet protocols\r
+ * ARGUMENTS:\r
+ *     NTE      = Pointer to net table entry which the packet was received on\r
+ *     IPPacket = Pointer to an IP packet that was received\r
+ */\r
+{\r
+    TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));\r
+}\r
+\r
+\r
+NTSTATUS IPStartup(\r
+    PDRIVER_OBJECT DriverObject,\r
+    PUNICODE_STRING RegistryPath)\r
+/*\r
+ * FUNCTION: Initializes the IP subsystem\r
+ * ARGUMENTS:\r
+ *     DriverObject = Pointer to a driver object for this driver\r
+ *     RegistryPath = Our registry node for configuration parameters\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    UINT i;\r
+    LARGE_INTEGER DueTime;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+       MaxLLHeaderSize = 0;\r
+    MinLLFrameSize  = 0;\r
+\r
+    /* Start routing subsystem */\r
+    RouterStartup();\r
+\r
+    /* Start route cache subsystem */\r
+    RouteStartup();\r
+\r
+    /* Start neighbor cache subsystem */\r
+    NBStartup();\r
+\r
+    /* Fill the protocol dispatch table with pointers\r
+       to the default protocol handler */\r
+    for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)\r
+        IPRegisterProtocol(i, DefaultProtocolHandler);\r
+\r
+    /* Register network level protocol receive handlers */\r
+    IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);\r
+\r
+    /* Initialize NTE list and protecting lock */\r
+    InitializeListHead(&NetTableListHead);\r
+    KeInitializeSpinLock(&NetTableListLock);\r
+\r
+    /* Initialize reassembly list and protecting lock */\r
+    InitializeListHead(&ReassemblyListHead);\r
+    KeInitializeSpinLock(&ReassemblyListLock);\r
+\r
+    /* Initialize the prefix list and protecting lock */\r
+    InitializeListHead(&PrefixListHead);\r
+    KeInitializeSpinLock(&PrefixListLock);\r
+\r
+    /* Initialize our periodic timer and its associated DPC object. When the\r
+       timer expires, the IPTimeout deferred procedure call (DPC) is queued */\r
+    KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL);\r
+    KeInitializeTimer(&IPTimer);\r
+\r
+    /* Start the periodic timer with an initial and periodic\r
+       relative expiration time of IP_TIMEOUT milliseconds */\r
+    DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000;\r
+    KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc);\r
+\r
+    IPInitialized = TRUE;\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS IPShutdown(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Shuts down the IP subsystem\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    if (!IPInitialized)\r
+        return STATUS_SUCCESS;\r
+\r
+    /* Cancel timer */\r
+    KeCancelTimer(&IPTimer);\r
+\r
+    /* Shutdown neighbor cache subsystem */\r
+    NBShutdown();\r
+\r
+    /* Shutdown route cache subsystem */\r
+    RouteShutdown();\r
+\r
+    /* Shutdown routing subsystem */\r
+    RouterShutdown();\r
+\r
+    IPFreeReassemblyList();\r
+\r
+    /* Clear prefix list */\r
+    DestroyPLEs();\r
+\r
+    IPInitialized = FALSE;\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/network/neighbor.c b/reactos/drivers/net/tcpip/network/neighbor.c
new file mode 100644 (file)
index 0000000..2e17cb4
--- /dev/null
@@ -0,0 +1,506 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/neighbor.c\r
+ * PURPOSE:     Neighbor address cache\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <neighbor.h>\r
+#include <routines.h>\r
+#include <neighbor.h>\r
+#include <transmit.h>\r
+#include <address.h>\r
+#include <route.h>\r
+#include <pool.h>\r
+#include <arp.h>\r
+#include <ip.h>\r
+\r
+\r
+NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];\r
+\r
+\r
+VOID NCETimeout(\r
+    PNEIGHBOR_CACHE_ENTRY NCE)\r
+/*\r
+ * FUNCTION: Neighbor cache entry timeout handler\r
+ * NOTES:\r
+ *     The neighbor cache lock must be held\r
+ */\r
+{\r
+    PNDIS_PACKET NdisPacket, Next;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("NCE->State is (0x%X).\n", NCE->State));\r
+\r
+    switch (NCE->State) {\r
+    case NUD_INCOMPLETE:\r
+        /* Retransmission timer expired */\r
+        if (NCE->EventCount++ > MAX_MULTICAST_SOLICIT) {\r
+            /* We have retransmitted too many times */\r
+\r
+            /* Calling IPSendComplete with cache lock held is not\r
+               a great thing to do. We don't get here very often\r
+               so maybe it's not that big a problem */\r
+\r
+            /* Flush packet queue */\r
+            NdisPacket = NCE->WaitQueue;\r
+            while (NdisPacket) {\r
+                Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;\r
+                IPSendComplete((PVOID)NCE->Interface, NdisPacket,\r
+                    NDIS_STATUS_REQUEST_ABORTED);\r
+                NdisPacket = Next;\r
+            }\r
+            NCE->WaitQueue = NULL;\r
+\r
+            NCE->EventCount = 0;\r
+\r
+            /* Remove route cache entries with references to this NCE.\r
+               Remember that neighbor cache lock is taken before\r
+               route cache lock */\r
+            RouteInvalidateNCE(NCE);\r
+        } else\r
+            /* Retransmit request */\r
+            NBSendSolicit(NCE);\r
+        break;\r
+\r
+    case NUD_DELAY:\r
+        /* FIXME: Delayed state */\r
+        TI_DbgPrint(DEBUG_NCACHE, ("NCE delay state.\n"));\r
+        break;\r
+\r
+    case NUD_PROBE:\r
+        /* FIXME: Probe state */\r
+        TI_DbgPrint(DEBUG_NCACHE, ("NCE probe state.\n"));\r
+        break;\r
+\r
+    default:\r
+        /* Should not happen since other states don't use the event timer */\r
+        TI_DbgPrint(MIN_TRACE, ("Invalid NCE state (%d).\n", NCE->State));\r
+        break;\r
+    }\r
+}\r
+\r
+\r
+VOID NBTimeout(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Neighbor address cache timeout handler\r
+ * NOTES:\r
+ *     This routine is called by IPTimeout to remove outdated cache\r
+ *     entries.\r
+ */\r
+{\r
+    UINT i;\r
+    KIRQL OldIrql;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+\r
+    for (i = 0; i <= NB_HASHMASK; i++) {\r
+        KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);\r
+\r
+        for (NCE = NeighborCache[i].Cache;\r
+            NCE != NULL; NCE = NCE->Next) {\r
+            /* Check if event timer is running */\r
+            if (NCE->EventTimer != 0)  {\r
+                if (--NCE->EventTimer == 0) {\r
+                    /* Call timeout handler for NCE */\r
+                    NCETimeout(NCE);\r
+                }\r
+            }\r
+        }\r
+\r
+        KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);\r
+    }\r
+}\r
+\r
+\r
+VOID NBStartup(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Starts the neighbor cache\r
+ */\r
+{\r
+       UINT i;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called.\n"));\r
+\r
+    for (i = 0; i <= NB_HASHMASK; i++) {\r
+        NeighborCache[i].Cache = NULL;\r
+        KeInitializeSpinLock(&NeighborCache[i].Lock);\r
+    }\r
+}\r
+\r
+\r
+VOID NBShutdown(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Shuts down the neighbor cache\r
+ */\r
+{\r
+       UINT i;\r
+    KIRQL OldIrql;\r
+    PNDIS_PACKET NdisPacket, Next;\r
+    PNEIGHBOR_CACHE_ENTRY CurNCE, NextNCE;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called.\n"));\r
+\r
+    /* Remove possible entries from the cache */\r
+    for (i = 0; i <= NB_HASHMASK; i++) {\r
+        KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);\r
+\r
+        CurNCE = NeighborCache[i].Cache;\r
+        while (CurNCE) {\r
+            NextNCE = CurNCE->Next;\r
+\r
+            /* Remove all references from route cache */\r
+            RouteInvalidateNCE(CurNCE);\r
+\r
+            /* Flush wait queue */\r
+            NdisPacket = CurNCE->WaitQueue;\r
+            while (NdisPacket) {\r
+                Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;\r
+                FreeNdisPacket(NdisPacket);\r
+                NdisPacket = Next;\r
+            }\r
+\r
+#if DBG\r
+            if (CurNCE->RefCount != 1) {\r
+                TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 1).\n", CurNCE, CurNCE->RefCount));\r
+            }\r
+#endif\r
+\r
+            /* Remove reference for being alive */\r
+            DereferenceObject(CurNCE);\r
+\r
+            CurNCE = NextNCE;\r
+        }\r
+        NeighborCache[i].Cache = NULL;\r
+\r
+        KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);\r
+    }\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
+}\r
+\r
+\r
+VOID NBSendSolicit(\r
+    PNEIGHBOR_CACHE_ENTRY NCE)\r
+/*\r
+ * FUNCTION: Sends a neighbor solicitation message\r
+ * ARGUMENTS:\r
+ *     NCE = Pointer to NCE of neighbor to solicit\r
+ * NOTES:\r
+ *     May be called with lock held on NCE's table\r
+ */\r
+{\r
+    PLIST_ENTRY CurrentEntry;\r
+    PNET_TABLE_ENTRY NTE;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));\r
+\r
+    if (NCE->State == NUD_INCOMPLETE) {\r
+        /* This is the first solicitation of this neighbor. Broadcast\r
+           a request for the neighbor */\r
+\r
+        /* FIXME: Choose first NTE. We might want to give an NTE as argument */\r
+        CurrentEntry = NCE->Interface->NTEListHead.Flink;\r
+        if (!IsListEmpty(CurrentEntry)) {\r
+            NTE = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);\r
+            ARPTransmit(NCE->Address, NTE);\r
+        } else {\r
+            TI_DbgPrint(MIN_TRACE, ("Interface at 0x%X has zero NTE.\n", NCE->Interface));\r
+        }\r
+    } else {\r
+        /* FIXME: Unicast solicitation since we have a cached address */\r
+        TI_DbgPrint(MIN_TRACE, ("Uninplemented unicast solicitation.\n"));\r
+    }\r
+}\r
+\r
+\r
+PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(\r
+    PIP_INTERFACE Interface,\r
+    PIP_ADDRESS Address,\r
+    PVOID LinkAddress,\r
+    UINT LinkAddressLength,\r
+    UCHAR State)\r
+/*\r
+ * FUNCTION: Adds a neighbor to the neighbor cache\r
+ * ARGUMENTS:\r
+ *     Interface         = Pointer to interface\r
+ *     Address           = Pointer to IP address\r
+ *     LinkAddress       = Pointer to link address (may be NULL)\r
+ *     LinkAddressLength = Length of link address\r
+ *     State             = State of NCE\r
+ * RETURNS:\r
+ *     Pointer to NCE, NULL there is not enough free resources\r
+ * NOTES:\r
+ *     The NCE if referenced for the caller if created. The NCE retains\r
+ *     a reference to the IP address if it is created, the caller is\r
+ *     responsible for providing this reference\r
+ */\r
+{\r
+    ULONG HashValue;\r
+    KIRQL OldIrql;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. Interface (0x%X)  Address (0x%X)  "\r
+        "LinkAddress (0x%X)  LinkAddressLength (%d)  State (0x%X)\n",\r
+        Interface, Address, LinkAddress, LinkAddressLength, State));\r
+\r
+    NCE = PoolAllocateBuffer(sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength);\r
+    if (!NCE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    /* Reference once for beeing alive and once for the caller */\r
+    NCE->RefCount  = 2;\r
+    NCE->Interface = Interface;\r
+    NCE->Address   = Address;\r
+    NCE->LinkAddressLength = LinkAddressLength;\r
+    NCE->LinkAddress       = (PVOID)((ULONG_PTR)NCE + sizeof(NEIGHBOR_CACHE_ENTRY));\r
+    if (LinkAddress)\r
+        RtlCopyMemory(NCE->LinkAddress, LinkAddress, LinkAddressLength);\r
+    NCE->State      = State;\r
+    NCE->EventTimer = 0; /* Not in use */\r
+    NCE->WaitQueue  = NULL;\r
+\r
+    HashValue  = *(PULONG)&Address->Address;\r
+    HashValue ^= HashValue >> 16;\r
+    HashValue ^= HashValue >> 8;\r
+    HashValue ^= HashValue >> 4;\r
+    HashValue &= NB_HASHMASK;\r
+\r
+    NCE->Table = &NeighborCache[HashValue];\r
+\r
+    KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);\r
+\r
+    NCE->Next = NeighborCache[HashValue].Cache;\r
+    NeighborCache[HashValue].Cache = NCE;\r
+\r
+    KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);\r
+\r
+    return NCE;\r
+}\r
+\r
+\r
+VOID NBUpdateNeighbor(\r
+    PNEIGHBOR_CACHE_ENTRY NCE,\r
+    PVOID LinkAddress,\r
+    UCHAR State)\r
+/*\r
+ * FUNCTION: Update link address information in NCE\r
+ * ARGUMENTS:\r
+ *     NCE         = Pointer to NCE to update\r
+ *     LinkAddress = Pointer to link address\r
+ *     State       = State of NCE\r
+ * NOTES:\r
+ *     The link address and state is updated. Any waiting packets are sent\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PNDIS_PACKET Current;\r
+    PNDIS_PACKET Next;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X)  LinkAddress (0x%X)  State (0x%X).\n", NCE, LinkAddress, State));\r
+\r
+    KeAcquireSpinLock(&NCE->Table->Lock, &OldIrql);\r
+\r
+    RtlCopyMemory(NCE->LinkAddress, LinkAddress, NCE->LinkAddressLength);\r
+    NCE->State     = State;\r
+    Current        = NCE->WaitQueue;\r
+    NCE->WaitQueue = NULL;\r
+\r
+    KeReleaseSpinLock(&NCE->Table->Lock, OldIrql);\r
+#if 1\r
+    /* Send any waiting packets */\r
+    while (Current) {\r
+        /* Our link to the next packet is broken by the\r
+           datalink layer code so we must save it here */\r
+        Next = (PNDIS_PACKET)PC(Current)->DLComplete;\r
+        IPSendFragment(Current, NCE);\r
+        Current = Next;\r
+    }\r
+#endif\r
+}\r
+\r
+\r
+PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(\r
+    PIP_ADDRESS Address)\r
+/*\r
+ * FUNCTION: Locates a neighbor in the neighbor cache\r
+ * ARGUMENTS:\r
+ *     Address = Pointer to IP address\r
+ * RETURNS:\r
+ *     Pointer to NCE, NULL if not found\r
+ * NOTES:\r
+ *     If the NCE is found, it is referenced. The caller is\r
+ *     responsible for dereferencing it again after use\r
+ */\r
+{\r
+    UINT HashValue;\r
+    KIRQL OldIrql;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. Address (0x%X).\n", Address));\r
+\r
+    HashValue  = *(PULONG)&Address->Address;\r
+    HashValue ^= HashValue >> 16;\r
+    HashValue ^= HashValue >> 8;\r
+    HashValue ^= HashValue >> 4;\r
+    HashValue &= NB_HASHMASK;\r
+\r
+    KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);\r
+\r
+    NCE = NeighborCache[HashValue].Cache;\r
+\r
+    while ((NCE) && (!AddrIsEqual(Address, NCE->Address)))\r
+        NCE = NCE->Next;\r
+\r
+    if (NCE)\r
+        ReferenceObject(NCE);\r
+\r
+    KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
+\r
+    return NCE;\r
+}\r
+\r
+\r
+PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor(\r
+    PIP_INTERFACE Interface,\r
+    PIP_ADDRESS Address)\r
+/*\r
+ * FUNCTION: Tries to find a neighbor and if unsuccesful, creates a new NCE\r
+ * ARGUMENTS:\r
+ *     Interface = Pointer to interface to use (if NCE is not found)\r
+ *     Address   = Pointer to IP address\r
+ * RETURNS:\r
+ *     Pointer to NCE, NULL if there is not enough free resources\r
+ * NOTES:\r
+ *     The NCE is referenced if found or created. The caller is\r
+ *     responsible for dereferencing it again after use\r
+ */\r
+{\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. Interface (0x%X)  Address (0x%X).\n", Interface, Address));\r
+\r
+    NCE = NBLocateNeighbor(Address);\r
+    if (!NCE) {\r
+        ReferenceObject(Address);\r
+        NCE = NBAddNeighbor(Interface, Address, NULL, \r
+            Interface->AddressLength, NUD_INCOMPLETE);\r
+        NCE->EventTimer = 1;\r
+        NCE->EventCount = 0;\r
+    }\r
+\r
+    return NCE;\r
+}\r
+\r
+\r
+BOOLEAN NBQueuePacket(\r
+    PNEIGHBOR_CACHE_ENTRY NCE,\r
+    PNDIS_PACKET NdisPacket)\r
+/*\r
+ * FUNCTION: Queues a packet on an NCE for later transmission\r
+ * ARGUMENTS:\r
+ *     NCE        = Pointer to NCE to queue packet on\r
+ *     NdisPacket = Pointer to NDIS packet to queue\r
+ * RETURNS:\r
+ *     TRUE if the packet was successfully queued, FALSE if not\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PKSPIN_LOCK Lock;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X)  NdisPacket (0x%X).\n", NCE, NdisPacket));\r
+\r
+    /* FIXME: Should we limit the number of queued packets? */\r
+\r
+    Lock = &NCE->Table->Lock;\r
+\r
+    KeAcquireSpinLock(Lock, &OldIrql);\r
+\r
+    /* Use data link level completion handler pointer to link\r
+       queued packets together */\r
+    PC(NdisPacket)->DLComplete = (PACKET_COMPLETION_ROUTINE)NCE->WaitQueue;\r
+    NCE->WaitQueue = NdisPacket;\r
+\r
+    KeReleaseSpinLock(Lock, OldIrql);\r
+\r
+    return TRUE;\r
+}\r
+\r
+\r
+VOID NBRemoveNeighbor(\r
+    PNEIGHBOR_CACHE_ENTRY NCE)\r
+/*\r
+ * FUNCTION: Removes a neighbor from the neighbor cache\r
+ * ARGUMENTS:\r
+ *     NCE = Pointer to NCE to remove from cache\r
+ * NOTES:\r
+ *     The NCE must be in a safe state\r
+ */\r
+{\r
+    ULONG HashValue;\r
+    KIRQL OldIrql;\r
+    PNEIGHBOR_CACHE_ENTRY *PrevNCE;\r
+    PNEIGHBOR_CACHE_ENTRY CurNCE;\r
+    PNDIS_PACKET NdisPacket, Next;\r
+\r
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));\r
+\r
+       HashValue  = *(PULONG)(&NCE->Address->Address);\r
+    HashValue ^= HashValue >> 16;\r
+       HashValue ^= HashValue >> 8;\r
+       HashValue ^= HashValue >> 4;\r
+       HashValue &= NB_HASHMASK;\r
+\r
+    KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);\r
+\r
+    /* Search the list and remove the NCE from the list if found */\r
+    for (PrevNCE = &NeighborCache[HashValue].Cache;\r
+        (CurNCE  = *PrevNCE) != NULL;\r
+        PrevNCE  = &CurNCE->Next) {\r
+        if (CurNCE == NCE) {\r
+            /* Found it, now unlink it from the list */\r
+            *PrevNCE = CurNCE->Next;\r
+\r
+            /* Purge wait queue */\r
+            NdisPacket = CurNCE->WaitQueue;\r
+            while (NdisPacket) {\r
+                Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;\r
+                FreeNdisPacket(NdisPacket);\r
+                NdisPacket = Next;\r
+            }\r
+\r
+            /* Remove all references from route cache */\r
+            RouteInvalidateNCE(CurNCE);\r
+\r
+            /* Remove reference to the address */\r
+            DereferenceObject(CurNCE->Address);\r
+\r
+#if DBG\r
+            CurNCE->RefCount--;\r
+\r
+            if (CurNCE->RefCount != 0) {\r
+                TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 0).\n", CurNCE, CurNCE->RefCount));\r
+            }\r
+#endif\r
+            PoolFreeBuffer(CurNCE);\r
+            \r
+            KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);\r
+\r
+            return;\r
+        }\r
+    }\r
+\r
+    KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/network/receive.c b/reactos/drivers/net/tcpip/network/receive.c
new file mode 100644 (file)
index 0000000..679a899
--- /dev/null
@@ -0,0 +1,638 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/receive.c\r
+ * PURPOSE:     Internet Protocol receive routines\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * NOTES:       The IP datagram reassembly algorithm is taken from\r
+ *              from RFC 815\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <receive.h>\r
+#include <routines.h>\r
+#include <checksum.h>\r
+#include <transmit.h>\r
+#include <address.h>\r
+#include <pool.h>\r
+#include <route.h>\r
+\r
+\r
+LIST_ENTRY ReassemblyListHead;\r
+KSPIN_LOCK ReassemblyListLock;\r
+\r
+\r
+PIPDATAGRAM_HOLE CreateHoleDescriptor(\r
+    ULONG First,\r
+    ULONG Last)\r
+/*\r
+ * FUNCTION: Returns a pointer to a IP datagram hole descriptor\r
+ * ARGUMENTS:\r
+ *     First = Offset of first octet of the hole\r
+ *     Last  = Offset of last octet of the hole\r
+ * RETURNS:\r
+ *     Pointer to descriptor, NULL if there was not enough free\r
+ *     resources\r
+ */\r
+{\r
+    PIPDATAGRAM_HOLE Hole;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Called. First (%d)  Last (%d).\n", First, Last));\r
+\r
+    Hole = PoolAllocateBuffer(sizeof(IPDATAGRAM_HOLE));\r
+    if (!Hole) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    Hole->First = First;\r
+    Hole->Last  = Last;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));\r
+\r
+    return Hole;\r
+}\r
+\r
+\r
+VOID FreeIPDR(\r
+    PIPDATAGRAM_REASSEMBLY IPDR)\r
+/*\r
+ * FUNCTION: Frees an IP datagram reassembly structure\r
+ * ARGUMENTS:\r
+ *     IPDR = Pointer to IP datagram reassembly structure\r
+ */\r
+{\r
+    PLIST_ENTRY CurrentEntry;\r
+    PLIST_ENTRY NextEntry;\r
+    PIPDATAGRAM_HOLE CurrentH;\r
+    PIP_FRAGMENT CurrentF;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));\r
+\r
+    /* Free all descriptors */\r
+    CurrentEntry = IPDR->HoleListHead.Flink;\r
+    while (CurrentEntry != &IPDR->HoleListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);\r
+        /* Unlink it from the list */\r
+        RemoveEntryList(CurrentEntry);\r
+           \r
+        TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));\r
+\r
+        /* And free the hole descriptor */\r
+        PoolFreeBuffer(CurrentH);\r
+\r
+        CurrentEntry = NextEntry;\r
+    }\r
+\r
+    /* Free all fragments */\r
+    CurrentEntry = IPDR->FragmentListHead.Flink;\r
+    while (CurrentEntry != &IPDR->FragmentListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);\r
+        /* Unlink it from the list */\r
+        RemoveEntryList(CurrentEntry);\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data));\r
+\r
+        /* Free the fragment data buffer */\r
+        ExFreePool(CurrentF->Data);\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));\r
+\r
+        /* And free the fragment descriptor */\r
+        PoolFreeBuffer(CurrentF);\r
+        CurrentEntry = NextEntry;\r
+    }\r
+\r
+    /* Free resources for the header, if it exists */\r
+    if (IPDR->IPv4Header) {\r
+        TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header));\r
+        ExFreePool(IPDR->IPv4Header);\r
+    }\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));\r
+\r
+    PoolFreeBuffer(IPDR);\r
+}\r
+\r
+\r
+VOID RemoveIPDR(\r
+    PIPDATAGRAM_REASSEMBLY IPDR)\r
+/*\r
+ * FUNCTION: Removes an IP datagram reassembly structure from the global list\r
+ * ARGUMENTS:\r
+ *     IPDR = Pointer to IP datagram reassembly structure\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));\r
+\r
+    KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);\r
+    RemoveEntryList(&IPDR->ListEntry);\r
+    KeReleaseSpinLock(&ReassemblyListLock, OldIrql);\r
+}\r
+\r
+\r
+PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: Returns a pointer to an IP datagram reassembly structure\r
+ * ARGUMENTS:\r
+ *     IPPacket = Pointer to IP packet\r
+ * NOTES:\r
+ *     A datagram is identified by four paramters, which are\r
+ *     Source and destination address, protocol number and\r
+ *     identification number\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PIPDATAGRAM_REASSEMBLY Current;\r
+    PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));\r
+\r
+    KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);\r
+\r
+    /* FIXME: Assume IPv4 */\r
+\r
+    CurrentEntry = ReassemblyListHead.Flink;\r
+    while (CurrentEntry != &ReassemblyListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);\r
+        if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&\r
+            (Header->Id == Current->Id) &&\r
+            (Header->Protocol == Current->Protocol) &&\r
+            (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {\r
+            KeReleaseSpinLock(&ReassemblyListLock, OldIrql);\r
+\r
+            return Current;\r
+        }\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    KeReleaseSpinLock(&ReassemblyListLock, OldIrql);\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+PIP_PACKET ReassembleDatagram(\r
+    PIPDATAGRAM_REASSEMBLY IPDR)\r
+/*\r
+ * FUNCTION: Reassembles an IP datagram\r
+ * ARGUMENTS:\r
+ *     IPDR = Pointer to IP datagram reassembly structure\r
+ * NOTES:\r
+ *     This routine concatenates fragments into a complete IP datagram.\r
+ *     The lock is held when this routine is called\r
+ * RETURNS:\r
+ *     Pointer to IP packet, NULL if there was not enough free resources\r
+ */\r
+{\r
+    PIP_PACKET IPPacket;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PIP_FRAGMENT Current;\r
+    PVOID Data;\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));\r
+\r
+    IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET));\r
+    if (!IPPacket) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+       /* FIXME: Assume IPv4 */\r
+\r
+       IPPacket->Type       = IP_ADDRESS_V4;\r
+    IPPacket->RefCount   = 1;\r
+    IPPacket->TotalSize  = IPDR->HeaderSize + IPDR->DataSize;\r
+    IPPacket->HeaderSize = IPDR->HeaderSize;\r
+    IPPacket->Position   = IPDR->HeaderSize;\r
+\r
+    RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));\r
+    RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));\r
+\r
+    /* Allocate space for full IP datagram */\r
+    IPPacket->Header = ExAllocatePool(NonPagedPool, IPPacket->TotalSize);\r
+    if (!IPPacket->Header) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        PoolFreeBuffer(IPPacket);\r
+        return NULL;\r
+    }\r
+\r
+    /* Copy the header into the buffer */\r
+    RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);\r
+\r
+       Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);\r
+    IPPacket->Data = Data;\r
+\r
+    /* Copy data from all fragments into buffer */\r
+    CurrentEntry = IPDR->FragmentListHead.Flink;\r
+    while (CurrentEntry != &IPDR->FragmentListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",\r
+            Current->Size, Data, Current->Offset));\r
+        /* Copy fragment data to the destination buffer at the correct offset */\r
+        RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset),\r
+                      Current->Data,\r
+                      Current->Size);\r
+\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    return IPPacket;\r
+}\r
+\r
+\r
+__inline VOID Cleanup(\r
+    PKSPIN_LOCK Lock,\r
+    KIRQL OldIrql,\r
+    PIPDATAGRAM_REASSEMBLY IPDR,\r
+    PVOID Buffer OPTIONAL)\r
+/*\r
+ * FUNCTION: Performs cleaning operations on errors\r
+ * ARGUMENTS:\r
+ *     Lock     = Pointer to spin lock to be released\r
+ *     OldIrql  = Value of IRQL when spin lock was acquired\r
+ *     IPDR     = Pointer to IP datagram reassembly structure to free\r
+ *     Buffer   = Optional pointer to a buffer to free\r
+ */\r
+{\r
+    TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+\r
+    KeReleaseSpinLock(Lock, OldIrql);\r
+    RemoveIPDR(IPDR);\r
+    FreeIPDR(IPDR);\r
+    if (Buffer)\r
+        PoolFreeBuffer(Buffer);\r
+}\r
+\r
+\r
+VOID ProcessFragment(\r
+    PIP_INTERFACE IF,\r
+    PIP_PACKET IPPacket,\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Processes an IP datagram or fragment\r
+ * ARGUMENTS:\r
+ *     IF       = Pointer to IP interface packet was receive on\r
+ *     IPPacket = Pointer to IP packet\r
+ *     NTE      = Pointer to NTE packet was received on\r
+ * NOTES:\r
+ *     This routine reassembles fragments and, if a whole datagram can\r
+ *     be assembled, passes the datagram on to the IP protocol dispatcher\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PIPDATAGRAM_REASSEMBLY IPDR;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PIPDATAGRAM_HOLE Hole, NewHole;\r
+    USHORT FragFirst;\r
+    USHORT FragLast;\r
+    BOOLEAN MoreFragments;\r
+    PIPv4_HEADER IPv4Header;\r
+    PIP_PACKET Datagram;\r
+    PIP_FRAGMENT Fragment;\r
+\r
+    /* FIXME: Assume IPv4 */\r
+\r
+    IPv4Header = (PIPv4_HEADER)IPPacket->Header;\r
+\r
+    /* Check if we already have an reassembly structure for this datagram */\r
+    IPDR = GetReassemblyInfo(IPPacket);\r
+    if (IPDR) {\r
+        TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));\r
+        /* We have a reassembly structure */\r
+        KeAcquireSpinLock(&IPDR->Lock, &OldIrql);\r
+        CurrentEntry = IPDR->HoleListHead.Flink;\r
+        Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);\r
+    } else {\r
+        TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));\r
+\r
+        /* We don't have a reassembly structure, create one */\r
+        IPDR = PoolAllocateBuffer(sizeof(IPDATAGRAM_REASSEMBLY));\r
+        if (!IPDR) {\r
+            /* We don't have the resources to process this packet, discard it */\r
+            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+            return;\r
+        }\r
+\r
+        /* Create a descriptor spanning from zero to infinity.\r
+           Actually, we use a value slightly greater than the\r
+           maximum number of octets an IP datagram can contain */\r
+        Hole = CreateHoleDescriptor(0, 65536);\r
+        if (!Hole) {\r
+            /* We don't have the resources to process this packet, discard it */\r
+            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+            PoolFreeBuffer(IPDR);\r
+            return;\r
+        }\r
+        AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);\r
+        AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);\r
+        IPDR->Id         = IPv4Header->Id;\r
+        IPDR->Protocol   = IPv4Header->Protocol;\r
+        IPDR->IPv4Header = NULL;\r
+        InitializeListHead(&IPDR->FragmentListHead);\r
+        InitializeListHead(&IPDR->HoleListHead);\r
+        InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);\r
+        CurrentEntry = IPDR->HoleListHead.Flink;\r
+\r
+        KeInitializeSpinLock(&IPDR->Lock);\r
+\r
+        KeAcquireSpinLock(&IPDR->Lock, &OldIrql);\r
+\r
+        /* Update the reassembly list */\r
+        ExInterlockedInsertTailList(&ReassemblyListHead,\r
+                                    &IPDR->ListEntry,\r
+                                    &ReassemblyListLock);\r
+    }\r
+\r
+    FragFirst     = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;\r
+    FragLast      = FragFirst + WN2H(IPv4Header->TotalLength);\r
+    MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;\r
+\r
+    for (;;) {\r
+        if (CurrentEntry == &IPDR->HoleListHead)\r
+            /* No more entries */\r
+            break;\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",\r
+            FragFirst, FragLast, Hole->First, Hole->Last));\r
+\r
+        if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {\r
+            TI_DbgPrint(MID_TRACE, ("No overlap.\n"));\r
+            /* The fragment does not overlap with the hole, try next\r
+               descriptor in the list */\r
+\r
+            CurrentEntry = CurrentEntry->Flink;\r
+            if (CurrentEntry != &IPDR->HoleListHead)\r
+                Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);\r
+            continue;\r
+        }\r
+\r
+        /* The fragment overlap with the hole, unlink the descriptor */\r
+        RemoveEntryList(CurrentEntry);\r
+\r
+        if (FragFirst > Hole->First) {\r
+            NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);\r
+            if (!NewHole) {\r
+                /* We don't have the resources to process this packet, discard it */\r
+                Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);\r
+                return;\r
+            }\r
+\r
+            /* Put the new descriptor in the list */\r
+            InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);\r
+        }\r
+\r
+        if ((FragLast < Hole->Last) && (MoreFragments)) {\r
+            /* We can reuse the descriptor for the new hole */\r
+                       Hole->First = FragLast + 1;\r
+\r
+                       /* Put the new hole descriptor in the list */\r
+            InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);\r
+        } else\r
+            PoolFreeBuffer(Hole);\r
+\r
+        /* If this is the first fragment, save the IP header */\r
+        if (FragFirst == 0) {\r
+            IPDR->IPv4Header = ExAllocatePool(NonPagedPool, IPPacket->HeaderSize);\r
+            if (!IPDR->IPv4Header) {\r
+                /* We don't have the resources to process this packet, discard it */\r
+                Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);\r
+                return;\r
+            }\r
+\r
+            TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "\r
+                "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize));\r
+\r
+            RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);\r
+            IPDR->HeaderSize = IPPacket->HeaderSize;\r
+        }\r
+\r
+        /* Create a buffer, copy the data into it and put it\r
+           in the fragment list */\r
+\r
+        Fragment = PoolAllocateBuffer(sizeof(IP_FRAGMENT));\r
+        if (!Fragment) {\r
+            /* We don't have the resources to process this packet, discard it */\r
+            Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);\r
+            return;\r
+        }\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));\r
+\r
+        Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;\r
+        Fragment->Data = ExAllocatePool(NonPagedPool, Fragment->Size);\r
+        if (!Fragment->Data) {\r
+            /* We don't have the resources to process this packet, discard it */\r
+            Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);\r
+            return;\r
+        }\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X)  Size (%d).\n",\r
+            Fragment->Data, Fragment->Size));\r
+\r
+        /* Copy datagram data into fragment buffer */\r
+        CopyPacketToBuffer(Fragment->Data,\r
+                           IPPacket->NdisPacket,\r
+                           IPPacket->Position,\r
+                           Fragment->Size);\r
+        Fragment->Offset = FragFirst;\r
+\r
+        /* If this is the last fragment, compute and save the datagram data size */\r
+        if (!MoreFragments)\r
+            IPDR->DataSize = FragFirst + Fragment->Size;\r
+\r
+        /* Put the fragment in the list */\r
+        InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);\r
+               break;\r
+    }\r
+\r
+    TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));\r
+\r
+    if (IsListEmpty(&IPDR->HoleListHead)) {\r
+        /* Hole list is empty which means a complete datagram can be assembled.\r
+           Assemble the datagram and pass it to an upper layer protocol */\r
+\r
+        TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));\r
+\r
+        Datagram = ReassembleDatagram(IPDR);\r
+               KeReleaseSpinLock(&IPDR->Lock, OldIrql);\r
+\r
+        RemoveIPDR(IPDR);\r
+        FreeIPDR(IPDR);\r
+\r
+        if (!Datagram) {\r
+            /* Not enough free resources, discard the packet */\r
+            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+            return;\r
+        }\r
+\r
+        /* Give the packet to the protocol dispatcher */\r
+        IPDispatchProtocol(NTE, Datagram);\r
+\r
+        /* We're done with this datagram */\r
+        ExFreePool(Datagram->Header);\r
+        PoolFreeBuffer(Datagram);\r
+    } else\r
+        KeReleaseSpinLock(&IPDR->Lock, OldIrql);\r
+}\r
+\r
+\r
+VOID IPFreeReassemblyList(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Frees all IP datagram reassembly structures in the list\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PIPDATAGRAM_REASSEMBLY Current;\r
+\r
+    KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);\r
+\r
+    CurrentEntry = ReassemblyListHead.Flink;\r
+    while (CurrentEntry != &ReassemblyListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);\r
+        /* Unlink it from the list */\r
+        RemoveEntryList(CurrentEntry);\r
+           \r
+        /* And free the descriptor */\r
+        FreeIPDR(Current);\r
+\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    KeReleaseSpinLock(&ReassemblyListLock, OldIrql);\r
+}\r
+\r
+\r
+VOID IPDatagramReassemblyTimeout(\r
+    VOID)\r
+/*\r
+ * FUNCTION: IP datagram reassembly timeout handler\r
+ * NOTES:\r
+ *     This routine is called by IPTimeout to free any resources used\r
+ *     to hold IP fragments that are being reassembled to form a\r
+ *     complete IP datagram\r
+ */\r
+{\r
+}\r
+\r
+\r
+VOID IPv4Receive(\r
+    PVOID Context,\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: Receives an IPv4 datagram (or fragment)\r
+ * ARGUMENTS:\r
+ *     Context  = Pointer to context information (IP_INTERFACE)\r
+ *     IPPacket = Pointer to IP packet\r
+ */\r
+{\r
+//    PNEIGHBOR_CACHE_ENTRY NCE;\r
+    PNET_TABLE_ENTRY NTE;\r
+    UINT AddressType;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Received IPv4 datagram.\n"));\r
+\r
+    IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2;\r
+\r
+    if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Datagram received with incorrect header size (%d).\n",\r
+            IPPacket->HeaderSize));\r
+        /* Discard packet */\r
+        return;\r
+    }\r
+\r
+    /* Checksum IPv4 header */\r
+    if (!CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {\r
+        TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n",\r
+            WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));\r
+        /* Discard packet */\r
+        return;\r
+    }\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("TotalSize (datalink) is (%d).\n", IPPacket->TotalSize));\r
+\r
+    IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("TotalSize (IPv4) is (%d).\n", IPPacket->TotalSize));\r
+\r
+       AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);\r
+       AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);\r
+\r
+    IPPacket->Position = IPPacket->HeaderSize;\r
+    IPPacket->Data     = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize);\r
+\r
+    /* FIXME: Possibly forward packets with multicast addresses */\r
+\r
+    /* FIXME: Should we allow packets to be received on the wrong interface? */\r
+#if 0\r
+    NTE = IPLocateNTE(&IPPacket->DstAddr, &AddressType);\r
+#else\r
+    NTE = IPLocateNTEOnInterface((PIP_INTERFACE)Context, &IPPacket->DstAddr, &AddressType);\r
+#endif\r
+    if (NTE) {\r
+        /* This packet is destined for us */\r
+        ProcessFragment((PIP_INTERFACE)Context, IPPacket, NTE);\r
+        /* Done with this NTE */\r
+        DereferenceObject(NTE);\r
+    } else {\r
+        /* This packet is not destined for us. If we are a router,\r
+           try to find a route and forward the packet */\r
+\r
+        /* FIXME: Check if acting as a router */\r
+#if 0\r
+        NCE = RouteFindRouter(&IPPacket->DstAddr, NULL);\r
+        if (NCE) {\r
+            /* FIXME: Possibly fragment datagram */\r
+            /* Forward the packet */\r
+            IPSendFragment(IPPacket, NCE);\r
+        } else {\r
+            TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",\r
+                IPPacket->DstAddr.Address.IPv4Address));\r
+\r
+            /* FIXME: Send ICMP error code */\r
+        }\r
+#endif\r
+    }\r
+}\r
+\r
+\r
+VOID IPReceive(\r
+    PVOID Context,\r
+    PIP_PACKET IPPacket)\r
+/*\r
+ * FUNCTION: Receives an IP datagram (or fragment)\r
+ * ARGUMENTS:\r
+ *     Context  = Pointer to context information (IP_INTERFACE)\r
+ *     IPPacket = Pointer to IP packet\r
+ */\r
+{\r
+    UINT Version;\r
+\r
+    /* Check that IP header has a supported version */\r
+    Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);\r
+    switch (Version) {\r
+    case 4:\r
+        IPPacket->Type = IP_ADDRESS_V4;\r
+        IPv4Receive(Context, IPPacket);\r
+        break;\r
+    case 6:\r
+        IPPacket->Type = IP_ADDRESS_V6;\r
+        TI_DbgPrint(MIN_TRACE, ("Datagram of type IPv6 discarded.\n"));\r
+        return;\r
+    default:\r
+        TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));\r
+        return;\r
+    }\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/network/route.c b/reactos/drivers/net/tcpip/network/route.c
new file mode 100644 (file)
index 0000000..f113b0b
--- /dev/null
@@ -0,0 +1,665 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/route.c\r
+ * PURPOSE:     Route cache\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * NOTES:       The route cache is implemented as a binary search\r
+ *              tree to obtain fast searches\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <route.h>\r
+#include <router.h>\r
+\r
+\r
+/* This RCN is shared by all external nodes. It complicates things,\r
+   but the memory.requirements are reduced by approximately 50%.\r
+   The RCN is protected by the route cache spin lock */\r
+PROUTE_CACHE_NODE ExternalRCN;\r
+PROUTE_CACHE_NODE RouteCache;\r
+KSPIN_LOCK RouteCacheLock;\r
+\r
+\r
+#if DBG\r
+VOID PrintTree(\r
+    PROUTE_CACHE_NODE Node)\r
+/*\r
+ * FUNCTION: Prints all nodes on tree\r
+ * ARGUMENTS:\r
+ *     Node = Pointer to root node of tree\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held.\r
+ */\r
+{\r
+    if (IsInternalRCN(Node)) {\r
+        /* Traverse left subtree */\r
+        PrintTree(Node->Left);\r
+\r
+        /* Traverse right subtree */\r
+        PrintTree(Node->Right);\r
+\r
+        /* Finally check the node itself */\r
+        TI_DbgPrint(MIN_TRACE, ("(Internal) Self,Parent,Left,Right,Data = (%08X, %08X, %08X, %08X, %08X).\n",\r
+            Node, Node->Parent, Node->Left, Node->Right, (ULONG_PTR)Node->Destination.Address.IPv4Address));\r
+    } else\r
+        TI_DbgPrint(MIN_TRACE, ("(External) Self,Parent,Left,Right = (%08X, %08X, %08X, %08X).\n",\r
+            Node, Node->Parent, Node->Left, Node->Right));\r
+}\r
+#endif\r
+\r
+\r
+VOID RemoveAboveExternal(VOID)\r
+/*\r
+ * FUNCTION: Removes the parent node of the selected external node from the route cache tree\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held.\r
+ *     ExternalRCN->Parent must be initialized\r
+ */\r
+{\r
+    PROUTE_CACHE_NODE Parent;\r
+    PROUTE_CACHE_NODE Sibling;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));\r
+\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+\r
+    Parent = ExternalRCN->Parent;\r
+    /* Find sibling of external node */\r
+    if (ExternalRCN == Parent->Left)\r
+        Sibling = Parent->Right;\r
+    else\r
+        Sibling = Parent->Left;\r
+\r
+    /* Replace parent node with sibling of external node */\r
+    if (Parent != RouteCache) {\r
+        if (Parent->Parent->Left == Parent)\r
+            Parent->Parent->Left = Sibling;\r
+        else\r
+            Parent->Parent->Right = Sibling;\r
+        /* Give sibling a new parent */\r
+        Sibling->Parent = Parent->Parent;\r
+    } else {\r
+        /* This is the root we're removing */\r
+        RouteCache      = Sibling;\r
+        Sibling->Parent = NULL;\r
+    }\r
+\r
+    DereferenceObject(Parent);\r
+\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+}\r
+\r
+\r
+PROUTE_CACHE_NODE SearchRouteCache(\r
+    PIP_ADDRESS Destination,\r
+    PROUTE_CACHE_NODE Node)\r
+/*\r
+ * FUNCTION: Searches route cache for a RCN for a destination address\r
+ * ARGUMENTS:\r
+ *     Destination = Pointer to destination address (key)\r
+ *     Node        = Pointer to start route cache node\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held\r
+ * RETURNS:\r
+ *     Pointer to internal node if a matching node was found, or\r
+ *     external node where it should be if none was found\r
+ */\r
+{\r
+    INT Value;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)  Node (0x%X)\n", Destination, Node));\r
+\r
+    /* Is this an external node? */\r
+    if (IsExternalRCN(Node))\r
+        return Node;\r
+\r
+    /* Is it this node we are looking for? */\r
+    Value = AddrCompare(Destination, &Node->Destination);\r
+    if (Value == 0)\r
+        return Node;\r
+\r
+    /* Traverse down the left subtree if the key is smaller than\r
+       the key of the node, otherwise traverse the right subtree */\r
+    if (Value < 0) {\r
+        Node->Left->Parent = Node;\r
+        ExternalRCN->Left  = (PROUTE_CACHE_NODE)&Node->Left;\r
+        return SearchRouteCache(Destination, Node->Left);\r
+    } else {\r
+        Node->Right->Parent = Node;\r
+        ExternalRCN->Left   = (PROUTE_CACHE_NODE)&Node->Right;\r
+        return SearchRouteCache(Destination, Node->Right);\r
+    }\r
+}\r
+\r
+\r
+PROUTE_CACHE_NODE ExpandExternalRCN(VOID)\r
+/*\r
+ * FUNCTION: Expands an external route cache node\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held.\r
+ *     We cheat a little here to save memory. We don't actually allocate memory\r
+ *     for external nodes. We wait until they're turned into internal nodes.\r
+ *     ExternalRCN->Parent must be initialized\r
+ *     ExternalRCN->Left must be a pointer to the correct child link of it's parent\r
+ * RETURNS:\r
+ *     Pointer to new internal node if the external node was expanded, NULL if not\r
+ */\r
+{\r
+    PROUTE_CACHE_NODE RCN;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));\r
+\r
+    RCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE));\r
+    if (!RCN) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    if (ExternalRCN->Left)\r
+        /* Register RCN as a child with it's parent */\r
+        *(PROUTE_CACHE_NODE*)ExternalRCN->Left = RCN;\r
+\r
+    RCN->Parent = ExternalRCN->Parent;\r
+    RCN->Left   = ExternalRCN;\r
+    RCN->Right  = ExternalRCN;\r
+\r
+    return RCN;\r
+}\r
+\r
+#if 0\r
+VOID SwapRCN(\r
+    PROUTE_CACHE_NODE *Node1,\r
+    PROUTE_CACHE_NODE *Node2)\r
+/*\r
+ * FUNCTION: Swaps two nodes\r
+ * ARGUMENTS:\r
+ *     Node1 = Address of pointer to first node\r
+ *     Node2 = Address of pointer to second node\r
+ */\r
+{\r
+    PROUTE_CACHE_NODE Temp;\r
+\r
+    Temp  = *Node2;\r
+    *Node2 = *Node1;\r
+    *Node1 = Temp;\r
+}\r
+#endif\r
+\r
+/*\r
+ * FUNCTION: Removes a route to a destination\r
+ * ARGUMENTS:\r
+ *     RCN = Pointer to route cache node to remove\r
+ * NOTES:\r
+ *     Internal version. Route cache lock must be held\r
+ */\r
+VOID RemoveRouteToDestination(\r
+    PROUTE_CACHE_NODE RCN)\r
+{\r
+    PROUTE_CACHE_NODE RemNode, Parent, SwapNode;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN));\r
+\r
+    if (IsExternalRCN(RCN->Left)) {\r
+        /* Left node is external */\r
+        RemNode         = RCN->Left;\r
+        RemNode->Parent = RCN;\r
+    } else if (IsExternalRCN(RCN->Right)) {\r
+        /* Right node is external */\r
+        RemNode         = RCN->Right;\r
+        RemNode->Parent = RCN;\r
+    } else {\r
+        /* The node has internal children */\r
+#if 0\r
+        /* Normally we would replace\r
+           the item of RCN with the item of the leftmost external\r
+           node on the right subtree of RCN. This we cannot do here\r
+           because there may be references directly to that node.\r
+           Instead we swap pointer values (parent, left and right)\r
+           of the two nodes */\r
+#endif\r
+        RemNode = RCN->Right;\r
+        do {\r
+            Parent  = RemNode;\r
+            RemNode = RemNode->Left;\r
+        } while (IsInternalRCN(RemNode));\r
+        RemNode->Parent = Parent;\r
+\r
+        SwapNode = RemNode->Parent;\r
+#if 0\r
+        if (RCN != RouteCache) {\r
+            /* Set SwapNode to be child of RCN's parent instead of RCN */\r
+            Parent = RCN->Parent;\r
+            if (RCN == Parent->Left)\r
+                Parent->Left = SwapNode;\r
+            else\r
+                Parent->Right = SwapNode;\r
+        } else\r
+            /* SwapNode is the new cache root */\r
+            RouteCache = SwapNode;\r
+\r
+        /* Set RCN to be child of SwapNode's parent instead of SwapNode */\r
+        Parent = SwapNode->Parent;\r
+        if (SwapNode == Parent->Left)\r
+            Parent->Left = RCN;\r
+        else\r
+            Parent->Right = RCN;\r
+\r
+        /* Swap parents */\r
+        SwapRCN(&SwapNode->Parent, &RCN->Parent);\r
+        /* Swap children */\r
+        SwapRCN(&SwapNode->Left, &RCN->Left);\r
+        SwapRCN(&SwapNode->Right, &RCN->Right);\r
+#endif\r
+    }\r
+    \r
+    /* Dereference NTE and NCE */\r
+    DereferenceObject(RCN->NTE);\r
+    DereferenceObject(RCN->NCE);\r
+\r
+    ExternalRCN->Parent = RemNode->Parent;\r
+\r
+    RemoveAboveExternal();\r
+}\r
+\r
+\r
+VOID InvalidateNTEOnSubtree(\r
+    PNET_TABLE_ENTRY NTE,\r
+    PROUTE_CACHE_NODE Node)\r
+/*\r
+ * FUNCTION: Removes all RCNs with references to an NTE on a subtree\r
+ * ARGUMENNTS:\r
+ *     NTE  = Pointer to NTE to invalidate\r
+ *     Node = Pointer to RCN to start removing nodes at\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held.\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X)  Node (0x%X).\n", NTE, Node));\r
+\r
+    if (IsInternalRCN(Node)) {\r
+        /* Traverse left subtree */\r
+        InvalidateNTEOnSubtree(NTE, Node->Left);\r
+\r
+        /* Traverse right subtree */\r
+        InvalidateNTEOnSubtree(NTE, Node->Right);\r
+\r
+        /* Finally check the node itself */\r
+        if (Node->NTE == NTE)\r
+            RemoveRouteToDestination(Node);\r
+    }\r
+}\r
+\r
+\r
+VOID InvalidateNCEOnSubtree(\r
+    PNEIGHBOR_CACHE_ENTRY NCE,\r
+    PROUTE_CACHE_NODE Node)\r
+/*\r
+ * FUNCTION: Removes all RCNs with references to an NCE on a subtree\r
+ * ARGUMENNTS:\r
+ *     NCE  = Pointer to NCE to invalidate\r
+ *     Node = Pointer to RCN to start removing nodes at\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X)  Node (0x%X).\n", NCE, Node));\r
+\r
+    if (IsInternalRCN(Node)) {\r
+        /* Traverse left subtree */\r
+        InvalidateNCEOnSubtree(NCE, Node->Left);\r
+\r
+        /* Traverse right subtree */\r
+        InvalidateNCEOnSubtree(NCE, Node->Right);\r
+\r
+        /* Finally check the node itself */\r
+        if (Node->NCE == NCE)\r
+            RemoveRouteToDestination(Node);\r
+    }\r
+}\r
+\r
+\r
+VOID RemoveSubtree(\r
+    PROUTE_CACHE_NODE Node)\r
+/*\r
+ * FUNCTION: Removes a subtree from the tree using recursion\r
+ * ARGUMENNTS:\r
+ *     Node = Pointer to RCN to start removing nodes at\r
+ * NOTES:\r
+ *     This function must be called with the route cache lock held\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Node (0x%X).\n", Node));\r
+\r
+    if (IsInternalRCN(Node)) {\r
+        /* Traverse left subtree */\r
+        RemoveSubtree(Node->Left);\r
+\r
+        /* Traverse right subtree */\r
+        RemoveSubtree(Node->Right);\r
+\r
+        /* Finally remove the node itself */\r
+\r
+        /* It's an internal node, so dereference NTE and NCE */\r
+        DereferenceObject(Node->NTE);\r
+        DereferenceObject(Node->NCE);\r
+\r
+#if DBG\r
+        if (Node->RefCount != 1)\r
+            TI_DbgPrint(MIN_TRACE, ("RCN at (0x%X) has (%d) references (should be 1).\n", Node, Node->RefCount));\r
+#endif\r
+\r
+        /* Remove reference for being alive */\r
+        DereferenceObject(Node);\r
+    }\r
+}\r
+\r
+\r
+NTSTATUS RouteStartup(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Initializes the routing subsystem\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));\r
+\r
+    /* Initialize the pseudo external route cache node */\r
+    ExternalRCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE));\r
+    if (!ExternalRCN) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return STATUS_INSUFFICIENT_RESOURCES;\r
+    }\r
+    ExternalRCN->Parent = NULL;\r
+    ExternalRCN->Left   = NULL;\r
+    ExternalRCN->Right  = NULL;\r
+\r
+    /* Initialize the route cache root */\r
+    RouteCache = ExternalRCN;\r
+\r
+    KeInitializeSpinLock(&RouteCacheLock);\r
+\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS RouteShutdown(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Shuts down the routing subsystem\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));\r
+\r
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+    /* Clear route cache */\r
+    RemoveSubtree(RouteCache);\r
+\r
+    PoolFreeBuffer(ExternalRCN);\r
+\r
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+UINT RouteGetRouteToDestination(\r
+    PIP_ADDRESS Destination,\r
+    PNET_TABLE_ENTRY NTE,\r
+    PROUTE_CACHE_NODE *RCN)\r
+/*\r
+ * FUNCTION: Locates an RCN describing a route to a destination address\r
+ * ARGUMENTS:\r
+ *     Destination = Pointer to destination address to find route to\r
+ *     NTE         = Pointer to NTE describing net to send on\r
+ *                   (NULL means routing module choose NTE to send on)\r
+ *     RCN         = Address of pointer to an RCN\r
+ * RETURNS:\r
+ *     Status of operation\r
+ * NOTES:\r
+ *     The RCN is referenced for the caller. The caller is responsible\r
+ *     for dereferencing it after use\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PROUTE_CACHE_NODE RCN2;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+    PIP_INTERFACE Interface;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)  NTE (0x%X).\n", Destination, NTE));\r
+\r
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);\r
+\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+\r
+    ExternalRCN->Left = NULL;\r
+    RCN2 = SearchRouteCache(Destination, RouteCache);\r
+    if (IsExternalRCN(RCN2)) {\r
+        /* No route was found in the cache */\r
+\r
+        /* Check if the destination is on-link */\r
+        Interface = RouterFindOnLinkInterface(Destination, NTE);\r
+        if (Interface) {\r
+            if (!NTE) {\r
+                NTE = RouterFindBestNTE(Interface, Destination);\r
+                if (!NTE) {\r
+                    /* We cannot get to the specified destination. Return error */\r
+                    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+                    return IP_NO_ROUTE_TO_DESTINATION;\r
+                }\r
+            } else\r
+                ReferenceObject(NTE);\r
+\r
+            /* The destination address is on-link. Check our neighbor cache */\r
+            NCE = NBFindOrCreateNeighbor(Interface, Destination);\r
+            if (!NCE) {\r
+                DereferenceObject(NTE);\r
+                KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+                return IP_NO_RESOURCES;\r
+            }\r
+        } else {\r
+            /* Destination is not on any subnets we're on. Find a router to use */\r
+            NCE = RouterGetRoute(Destination, NTE);\r
+            if (!NCE) {\r
+                /* We cannot get to the specified destination. Return error */\r
+                KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+                return IP_NO_ROUTE_TO_DESTINATION;\r
+            }\r
+        }\r
+\r
+        /* Add the new route to the route cache */\r
+        if (RCN2 == RouteCache) {\r
+            RCN2       = ExpandExternalRCN();\r
+            RouteCache = RCN2;\r
+        } else\r
+            RCN2 = ExpandExternalRCN();\r
+        if (!RCN2) {\r
+            DereferenceObject(NTE);\r
+            DereferenceObject(NCE);\r
+            KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+            return IP_NO_RESOURCES;\r
+        }\r
+\r
+        RCN2->RefCount    = 1;\r
+        RCN2->State       = RCN_STATE_COMPUTED;\r
+        RCN2->NTE         = NTE;\r
+        RtlCopyMemory(&RCN2->Destination, Destination, sizeof(IP_ADDRESS));\r
+        RCN2->PathMTU     = NCE->Interface->MTU;\r
+        RCN2->NCE         = NCE;\r
+\r
+        /* The route cache node references the NTE and the NCE. The\r
+           NTE was referenced before and NCE is already referenced by\r
+           RouteGetRoute() or NBFindOrCreateNeighbor() so we don't\r
+           reference them here */\r
+    }\r
+\r
+    /* Reference the RCN for the user */\r
+    ReferenceObject(RCN2);\r
+\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+\r
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+\r
+    *RCN = RCN2;\r
+\r
+    return IP_SUCCESS;\r
+}\r
+\r
+\r
+PROUTE_CACHE_NODE RouteAddRouteToDestination(\r
+    PIP_ADDRESS Destination,\r
+    PNET_TABLE_ENTRY NTE,\r
+    PIP_INTERFACE IF,\r
+    PNEIGHBOR_CACHE_ENTRY NCE)\r
+/*\r
+ * FUNCTION: Adds a (permanent) route to a destination\r
+ * ARGUMENTS:\r
+ *     Destination = Pointer to destination address\r
+ *     NTE         = Pointer to net table entry\r
+ *     IF          = Pointer to interface to use\r
+ *     NCE         = Pointer to first hop to destination\r
+ * RETURNS:\r
+ *     Pointer to RCN if the route was added, NULL if not.\r
+ *     There can be at most one RCN per destination address / interface pair\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PROUTE_CACHE_NODE RCN;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)  NTE (0x%X)  IF (0x%X)  NCE (0x%X).\n", Destination, NTE, IF, NCE));\r
+\r
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);\r
+\r
+    /* Locate an external RCN we can expand */\r
+    RCN               = RouteCache;\r
+    ExternalRCN->Left = NULL;\r
+    for (;;) {\r
+        RCN = SearchRouteCache(Destination, RCN);\r
+        if (IsInternalRCN(RCN)) {\r
+            ExternalRCN->Left = (PROUTE_CACHE_NODE)&RCN->Right;\r
+            /* This is an internal node, continue the search to the right */\r
+            RCN = RCN->Right;\r
+        } else\r
+            /* This is an external node, we've found an empty spot */\r
+            break;\r
+    }\r
+\r
+    /* Expand the external node */\r
+    if (RCN == RouteCache) {\r
+        RCN        = ExpandExternalRCN();\r
+        RouteCache = RCN;\r
+    } else\r
+        RCN = ExpandExternalRCN();\r
+    if (!RCN) {\r
+        KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+        return NULL;\r
+    }\r
+\r
+    /* Initialize the newly created internal node */\r
+\r
+    /* Reference once for beeing alive */\r
+    RCN->RefCount    = 1;\r
+    RCN->State       = RCN_STATE_PERMANENT;\r
+    RCN->NTE         = NTE;\r
+    RtlCopyMemory(&RCN->Destination, Destination, sizeof(IP_ADDRESS));\r
+    RCN->PathMTU     = IF->MTU;\r
+    RCN->NCE         = NCE;\r
+\r
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+\r
+    /* The route cache node references the NTE and the NCE */\r
+    ReferenceObject(NTE);\r
+    if (NCE)\r
+        ReferenceObject(NCE);\r
+\r
+#if 0\r
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n"));\r
+    PrintTree(RouteCache);\r
+#endif\r
+\r
+    return RCN;\r
+}\r
+\r
+\r
+VOID RouteRemoveRouteToDestination(\r
+    PROUTE_CACHE_NODE RCN)\r
+/*\r
+ * FUNCTION: Removes a route to a destination\r
+ * ARGUMENTS:\r
+ *     RCN = Pointer to route cache node to remove\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN));\r
+\r
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);\r
+\r
+    RemoveRouteToDestination(RCN);\r
+\r
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+}\r
+\r
+\r
+VOID RouteInvalidateNTE(\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Removes all RCNs with references to an NTE\r
+ * ARGUMENTS:\r
+ *     NTE = Pointer to net table entry to invalidate\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X).\n", NTE));\r
+\r
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);\r
+    InvalidateNTEOnSubtree(NTE, RouteCache);\r
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+}\r
+\r
+\r
+VOID RouteInvalidateNCE(\r
+    PNEIGHBOR_CACHE_ENTRY NCE)\r
+/*\r
+ * FUNCTION: Removes all RCNs with references to an NCE\r
+ * ARGUMENTS:\r
+ *     NCE = Pointer to neighbor cache entry to invalidate\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X).\n", NCE));\r
+\r
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);\r
+    InvalidateNCEOnSubtree(NCE, RouteCache);\r
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/network/router.c b/reactos/drivers/net/tcpip/network/router.c
new file mode 100644 (file)
index 0000000..1791dc4
--- /dev/null
@@ -0,0 +1,500 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/router.c\r
+ * PURPOSE:     IP routing subsystem\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <address.h>\r
+#include <router.h>\r
+#include <pool.h>\r
+\r
+\r
+LIST_ENTRY FIBListHead;\r
+KSPIN_LOCK FIBLock;\r
+\r
+\r
+VOID DestroyFIBE(\r
+    PFIB_ENTRY FIBE)\r
+/*\r
+ * FUNCTION: Destroys an forward information base entry\r
+ * ARGUMENTS:\r
+ *     FIBE = Pointer to FIB entry\r
+ * NOTES:\r
+ *     The forward information base lock must be held when called\r
+ */\r
+{\r
+    /* Unlink the FIB entry from the list */\r
+    RemoveEntryList(&FIBE->ListEntry);\r
+\r
+    /* Dereference the referenced objects */\r
+    DereferenceObject(FIBE->NetworkAddress);\r
+    DereferenceObject(FIBE->Netmask);\r
+    DereferenceObject(FIBE->Router);\r
+    DereferenceObject(FIBE->NTE);\r
+\r
+#ifdef DBG\r
+    FIBE->RefCount--;\r
+\r
+    if (FIBE->RefCount != 0) {\r
+        TI_DbgPrint(MIN_TRACE, ("FIB entry at (0x%X) has (%d) references (Should be 0).\n", FIBE, FIBE->RefCount));\r
+    }\r
+#endif\r
+\r
+    /* And free the FIB entry */\r
+    PoolFreeBuffer(FIBE);\r
+}\r
+\r
+\r
+VOID DestroyFIBEs(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Destroys all forward information base entries\r
+ * NOTES:\r
+ *     The forward information base lock must be held when called\r
+ */\r
+{\r
+    PLIST_ENTRY CurrentEntry;\r
+    PLIST_ENTRY NextEntry;\r
+    PFIB_ENTRY Current;\r
+\r
+    /* Search the list and remove every FIB entry we find */\r
+    CurrentEntry = FIBListHead.Flink;\r
+    while (CurrentEntry != &FIBListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);\r
+        /* Destroy the FIB entry */\r
+        DestroyFIBE(Current);\r
+        CurrentEntry = NextEntry;\r
+    }\r
+}\r
+\r
+\r
+UINT CommonPrefixLength(\r
+    PIP_ADDRESS Address1,\r
+    PIP_ADDRESS Address2)\r
+/*\r
+ * FUNCTION: Computes the length of the longest prefix common to two addresses\r
+ * ARGUMENTS:\r
+ *     Address1 = Pointer to first address\r
+ *     Address2 = Pointer to second address\r
+ * NOTES:\r
+ *     The two addresses must be of the same type\r
+ * RETURNS:\r
+ *     Length of longest common prefix\r
+ */\r
+{\r
+    PUCHAR Addr1, Addr2;\r
+    UINT Size;\r
+    UINT i, j;\r
+    UINT Bitmask;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Address1 (0x%X)  Address2 (0x%X).\n", Address1, Address2));\r
+\r
+    if (Address1->Type == IP_ADDRESS_V4)\r
+        Size = sizeof(IPv4_RAW_ADDRESS);\r
+    else\r
+        Size = sizeof(IPv6_RAW_ADDRESS);\r
+\r
+    Addr1 = (PUCHAR)&Address1->Address;\r
+    Addr2 = (PUCHAR)&Address2->Address;\r
+\r
+    /* Find first non-matching byte */\r
+    for (i = 0; ; i++) {\r
+        if (i == Size)\r
+            return 8 * i; /* The two addresses are equal */\r
+\r
+        if (Addr1[i] != Addr2[i])\r
+            break;\r
+    }\r
+\r
+    /* Find first non-matching bit */\r
+    Bitmask = 0x80;\r
+    for (j = 0; ; j++) {\r
+        if ((Addr1[i] & Bitmask) != (Addr2[i] & Bitmask))\r
+            break;\r
+        Bitmask >>= 1;\r
+    }\r
+\r
+    return 8 * i + j;\r
+}\r
+\r
+\r
+BOOLEAN HasPrefix(\r
+    PIP_ADDRESS Address,\r
+    PIP_ADDRESS Prefix,\r
+    UINT Length)\r
+/*\r
+ * FUNCTION: Determines wether an address has an given prefix\r
+ * ARGUMENTS:\r
+ *     Address = Pointer to address to use\r
+ *     Prefix  = Pointer to prefix to check for\r
+ *     Length  = Length of prefix\r
+ * RETURNS:\r
+ *     TRUE if the address has the prefix, FALSE if not\r
+ * NOTES:\r
+ *     The two addresses must be of the same type\r
+ */\r
+{\r
+    PUCHAR pAddress = (PUCHAR)&Address->Address;\r
+    PUCHAR pPrefix  = (PUCHAR)&Prefix->Address;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X)  Prefix (0x%X)  Length (%d).\n", Address, Prefix, Length));\r
+\r
+    /* Check that initial integral bytes match */\r
+    while (Length > 8) {\r
+        if (*pAddress++ != *pPrefix++)\r
+            return FALSE;\r
+        Length -= 8;\r
+    } \r
+\r
+    /* Check any remaining bits */\r
+    if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length))))\r
+        return FALSE;\r
+\r
+    return TRUE;\r
+}\r
+\r
+\r
+PNET_TABLE_ENTRY RouterFindBestNTE(\r
+    PIP_INTERFACE Interface,\r
+    PIP_ADDRESS Destination)\r
+/*\r
+ * FUNCTION: Checks all on-link prefixes to find out if an address is on-link\r
+ * ARGUMENTS:\r
+ *     Interface   = Pointer to interface to use\r
+ *     Destination = Pointer to destination address\r
+ * NOTES:\r
+ *     If found the NTE if referenced\r
+ * RETURNS:\r
+ *     Pointer to NTE if found, NULL if not\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PNET_TABLE_ENTRY Current;\r
+    UINT Length, BestLength  = 0;\r
+    PNET_TABLE_ENTRY BestNTE = NULL;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Interface (0x%X)  Destination (0x%X).\n", Interface, Destination));\r
+\r
+    KeAcquireSpinLock(&Interface->Lock, &OldIrql);\r
+\r
+    CurrentEntry = Interface->NTEListHead.Flink;\r
+    while (CurrentEntry != &Interface->NTEListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);\r
+\r
+        Length = CommonPrefixLength(Destination, Current->Address);\r
+        if (BestNTE) {\r
+            if (Length > BestLength) {\r
+                /* This seems to be a better NTE */\r
+                DereferenceObject(BestNTE);\r
+                ReferenceObject(Current);\r
+                BestNTE    = Current;\r
+                BestLength = Length;\r
+            }\r
+        } else {\r
+            /* First suitable NTE found, save it */\r
+            ReferenceObject(Current);\r
+            BestNTE    = Current;\r
+            BestLength = Length;\r
+        }\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    KeReleaseSpinLock(&Interface->Lock, OldIrql);\r
+\r
+    return BestNTE;\r
+}\r
+\r
+\r
+PIP_INTERFACE RouterFindOnLinkInterface(\r
+    PIP_ADDRESS Address,\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Checks all on-link prefixes to find out if an address is on-link\r
+ * ARGUMENTS:\r
+ *     Address = Pointer to address to check\r
+ *     NTE     = Pointer to NTE to check (NULL = check all interfaces)\r
+ * RETURNS:\r
+ *     Pointer to interface if address is on-link, NULL if not\r
+ */\r
+{\r
+    PLIST_ENTRY CurrentEntry;\r
+    PPREFIX_LIST_ENTRY Current;\r
+\r
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X)  NTE (0x%X).\n", Address, NTE));\r
+\r
+    CurrentEntry = PrefixListHead.Flink;\r
+    while (CurrentEntry != &PrefixListHead) {\r
+           Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);\r
+\r
+        if (HasPrefix(Address, Current->Prefix, Current->PrefixLength) &&\r
+            ((!NTE) || (NTE->Interface == Current->Interface)))\r
+            return Current->Interface;\r
+\r
+        CurrentEntry = CurrentEntry->Flink;\r
+    }\r
+\r
+    return NULL;\r
+}\r
+\r
+\r
+PFIB_ENTRY RouterAddRoute(\r
+    PIP_ADDRESS NetworkAddress,\r
+    PIP_ADDRESS Netmask,\r
+    PNET_TABLE_ENTRY NTE,\r
+    PNEIGHBOR_CACHE_ENTRY Router,\r
+    UINT Metric)\r
+/*\r
+ * FUNCTION: Adds a route to the Forward Information Base (FIB)\r
+ * ARGUMENTS:\r
+ *     NetworkAddress = Pointer to address of network\r
+ *     Netmask        = Pointer to netmask of network\r
+ *     NTE            = Pointer to NTE to use\r
+ *     Router         = Pointer to NCE of router to use\r
+ *     Metric         = Cost of this route\r
+ * RETURNS:\r
+ *     Pointer to FIB entry if the route was added, NULL if not\r
+ * NOTES:\r
+ *     The FIB entry references the NetworkAddress, Netmask, NTE and\r
+ *     the NCE of the router. The caller is responsible for providing\r
+ *     these references\r
+ */\r
+{\r
+    PFIB_ENTRY FIBE;\r
+\r
+    TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X)  Netmask (0x%X)  NTE (0x%X)  "\r
+        "Router (0x%X)  Metric (%d).\n", NetworkAddress, Netmask, NTE, Router, Metric));\r
+\r
+    FIBE = PoolAllocateBuffer(sizeof(FIB_ENTRY));\r
+    if (!FIBE) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    FIBE->NetworkAddress = NetworkAddress;\r
+    FIBE->Netmask        = Netmask;\r
+    FIBE->NTE            = NTE;\r
+    FIBE->Router         = Router;\r
+    FIBE->Metric         = Metric;\r
+\r
+    /* Add FIB to the forward information base */\r
+    ExInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock);\r
+\r
+    return FIBE;\r
+}\r
+\r
+\r
+PNEIGHBOR_CACHE_ENTRY RouterGetRoute(\r
+    PIP_ADDRESS Destination,\r
+    PNET_TABLE_ENTRY NTE)\r
+/*\r
+ * FUNCTION: Finds a router to use to get to Destination\r
+ * ARGUMENTS:\r
+ *     Destination = Pointer to destination address (NULL means don't care)\r
+ *     NTE         = Pointer to NTE describing net to send on\r
+ *                   (NULL means don't care)\r
+ * RETURNS:\r
+ *     Pointer to NCE for router, NULL if none was found\r
+ * NOTES:\r
+ *     If found the NCE is referenced\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+    PLIST_ENTRY CurrentEntry;\r
+    PLIST_ENTRY NextEntry;\r
+    PFIB_ENTRY Current;\r
+    UCHAR State, BestState = 0;\r
+    UINT Length, BestLength = 0;\r
+    PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL;\r
+\r
+    TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X)  NTE (0x%X).\n", Destination, NTE));\r
+\r
+    KeAcquireSpinLock(&FIBLock, &OldIrql);\r
+\r
+    CurrentEntry = FIBListHead.Flink;\r
+    while (CurrentEntry != &FIBListHead) {\r
+        NextEntry = CurrentEntry->Flink;\r
+           Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);\r
+\r
+        NCE   = Current->Router;\r
+        State = NCE->State;\r
+\r
+        if ((!NTE) || (NTE->Interface == NCE->Interface)) {\r
+            if (Destination)\r
+                Length = CommonPrefixLength(Destination, NCE->Address);\r
+            else\r
+                Length = 0;\r
+\r
+            if (BestNCE) {\r
+                if ((State  > BestState)  || \r
+                    ((State == BestState) &&\r
+                    (Length > BestLength))) {\r
+                    /* This seems to be a better router */\r
+                    DereferenceObject(BestNCE);\r
+                    ReferenceObject(NCE);\r
+                    BestNCE    = NCE;\r
+                    BestLength = Length;\r
+                    BestState  = State;\r
+                }\r
+            } else {\r
+                /* First suitable router found, save it */\r
+                ReferenceObject(NCE);\r
+                BestNCE    = NCE;\r
+                BestLength = Length;\r
+                BestState  = State;\r
+            }\r
+        }\r
+        CurrentEntry = NextEntry;\r
+    }\r
+\r
+    KeReleaseSpinLock(&FIBLock, OldIrql);\r
+\r
+    return BestNCE;\r
+}\r
+\r
+\r
+VOID RouterRemoveRoute(\r
+    PFIB_ENTRY FIBE)\r
+/*\r
+ * FUNCTION: Removes a route from the Forward Information Base (FIB)\r
+ * ARGUMENTS:\r
+ *     FIBE = Pointer to FIB entry describing route\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+\r
+    TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE));\r
+\r
+    KeAcquireSpinLock(&FIBLock, &OldIrql);\r
+    DestroyFIBE(FIBE);\r
+    KeReleaseSpinLock(&FIBLock, OldIrql);\r
+}\r
+\r
+\r
+PFIB_ENTRY RouterCreateRouteIPv4(\r
+    IPv4_RAW_ADDRESS NetworkAddress,\r
+    IPv4_RAW_ADDRESS Netmask,\r
+    IPv4_RAW_ADDRESS RouterAddress,\r
+    PNET_TABLE_ENTRY NTE,\r
+    UINT Metric)\r
+/*\r
+ * FUNCTION: Creates a route with IPv4 addresses as parameters\r
+ * ARGUMENTS:\r
+ *     NetworkAddress = Address of network\r
+ *     Netmask        = Netmask of network\r
+ *     RouterAddress  = Address of router to use\r
+ *     NTE            = Pointer to NTE to use\r
+ *     Metric         = Cost of this route\r
+ * RETURNS:\r
+ *     Pointer to FIB entry if the route was created, NULL if not.\r
+ *     The FIB entry references the NTE. The caller is responsible\r
+ *     for providing this reference\r
+ */\r
+{\r
+    PIP_ADDRESS pNetworkAddress;\r
+    PIP_ADDRESS pNetmask;\r
+    PIP_ADDRESS pRouterAddress;\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+    PFIB_ENTRY FIBE;\r
+\r
+    pNetworkAddress = AddrBuildIPv4(NetworkAddress);\r
+    if (!NetworkAddress) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        return NULL;\r
+    }\r
+\r
+    pNetmask = AddrBuildIPv4(Netmask);\r
+    if (!Netmask) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        DereferenceObject(pNetworkAddress);\r
+        return NULL;\r
+    }\r
+\r
+    pRouterAddress = AddrBuildIPv4(RouterAddress);\r
+    if (!RouterAddress) {\r
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
+        DereferenceObject(pNetworkAddress);\r
+        DereferenceObject(pNetmask);\r
+        return NULL;\r
+    }\r
+\r
+    /* The NCE references RouterAddress. The NCE is referenced for us */\r
+    NCE = NBAddNeighbor(NTE->Interface,\r
+                        pRouterAddress,\r
+                        NULL,\r
+                        NTE->Interface->AddressLength,\r
+                        NUD_PROBE);\r
+    if (!NCE) {\r
+        /* Not enough free resources */\r
+        DereferenceObject(pNetworkAddress);\r
+        DereferenceObject(pNetmask);\r
+        DereferenceObject(pRouterAddress);\r
+        return NULL;\r
+    }\r
+\r
+    ReferenceObject(pNetworkAddress);\r
+    ReferenceObject(pNetmask);\r
+    FIBE = RouterAddRoute(pNetworkAddress, pNetmask, NTE, NCE, 1);\r
+    if (!FIBE) {\r
+        /* Not enough free resources */\r
+        NBRemoveNeighbor(NCE);\r
+        PoolFreeBuffer(pNetworkAddress);\r
+        PoolFreeBuffer(pNetmask);\r
+        PoolFreeBuffer(pRouterAddress);\r
+    }\r
+\r
+    return FIBE;\r
+}\r
+\r
+\r
+NTSTATUS RouterStartup(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Initializes the routing subsystem\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    TI_DbgPrint(DEBUG_ROUTER, ("Called.\n"));\r
+\r
+    /* Initialize the Forward Information Base */\r
+    InitializeListHead(&FIBListHead);\r
+    KeInitializeSpinLock(&FIBLock);\r
+\r
+#if 0\r
+    /* TEST: Create a test route */\r
+    /* Network is 10.0.0.0  */\r
+    /* Netmask is 255.0.0.0 */\r
+    /* Router is 10.0.0.1   */\r
+    RouterCreateRouteIPv4(0x0000000A, 0x000000FF, 0x0100000A, NTE?, 1);\r
+#endif\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS RouterShutdown(\r
+    VOID)\r
+/*\r
+ * FUNCTION: Shuts down the routing subsystem\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    KIRQL OldIrql;\r
+\r
+    TI_DbgPrint(DEBUG_ROUTER, ("Called.\n"));\r
+\r
+    /* Clear Forward Information Base */\r
+    KeAcquireSpinLock(&FIBLock, &OldIrql);\r
+    DestroyFIBEs();\r
+    KeReleaseSpinLock(&FIBLock, OldIrql);\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/network/transmit.c b/reactos/drivers/net/tcpip/network/transmit.c
new file mode 100644 (file)
index 0000000..cb3c4f5
--- /dev/null
@@ -0,0 +1,328 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        network/transmit.c\r
+ * PURPOSE:     Internet Protocol transmit routines\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/08-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <transmit.h>\r
+#include <routines.h>\r
+#include <checksum.h>\r
+#include <pool.h>\r
+#include <arp.h>\r
+#include <lan.h>\r
+\r
+\r
+BOOLEAN PrepareNextFragment(\r
+    PIPFRAGMENT_CONTEXT IFC)\r
+/*\r
+ * FUNCTION: Prepares the next fragment of an IP datagram for transmission\r
+ * ARGUMENTS:\r
+ *     IFC = Pointer to IP fragment context\r
+ * RETURNS:\r
+ *     TRUE if a fragment was prepared for transmission, FALSE if\r
+ *     there are no more fragments to send\r
+ */\r
+{\r
+    UINT MaxData;\r
+    UINT DataSize;\r
+    PIPv4_HEADER Header;\r
+    BOOLEAN MoreFragments;\r
+    USHORT FragOfs;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    if (IFC->BytesLeft != 0) {\r
+\r
+        TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n"));\r
+\r
+        MaxData  = IFC->PathMTU - IFC->HeaderSize;\r
+        /* Make fragment a multiplum of 64bit */\r
+        MaxData -= MaxData % 8;\r
+        if (IFC->BytesLeft > MaxData) {\r
+            DataSize      = MaxData;\r
+            MoreFragments = TRUE;\r
+        } else {\r
+            DataSize      = IFC->BytesLeft;\r
+            MoreFragments = FALSE;\r
+        }\r
+\r
+        RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize);\r
+\r
+        FragOfs = (USHORT)IFC->Position; // Swap?\r
+        if (MoreFragments)\r
+            FragOfs |= IPv4_MF_MASK;\r
+        else\r
+            FragOfs &= ~IPv4_MF_MASK;\r
+\r
+        Header = IFC->Header;\r
+        Header->FlagsFragOfs = FragOfs;\r
+\r
+        /* FIXME: Handle options */\r
+\r
+        /* Calculate checksum of IP header */\r
+        Header->Checksum = 0;\r
+        Header->Checksum = (USHORT)IPv4Checksum(Header, IFC->HeaderSize, 0);\r
+\r
+        /* Update pointers */\r
+        (ULONG_PTR)IFC->DatagramData += DataSize;\r
+        IFC->Position  += DataSize;\r
+        IFC->BytesLeft -= DataSize;\r
+\r
+        return TRUE;\r
+    } else {\r
+        TI_DbgPrint(MAX_TRACE, ("No more fragments.\n"));\r
+        return FALSE;\r
+    }\r
+}\r
+\r
+\r
+NTSTATUS SendFragments(\r
+    PIP_PACKET IPPacket,\r
+    PNEIGHBOR_CACHE_ENTRY NCE,\r
+    UINT PathMTU)\r
+/*\r
+ * FUNCTION: Fragments and sends the first fragment of an IP datagram\r
+ * ARGUMENTS:\r
+ *     IPPacket  = Pointer to an IP packet\r
+ *     NCE       = Pointer to NCE for first hop to destination\r
+ *     PathMTU   = Size of Maximum Transmission Unit of path\r
+ * RETURNS:\r
+ *     Status of operation\r
+ * NOTES:\r
+ *     IP datagram is larger than PathMTU when this is called\r
+ */\r
+{\r
+    PIPFRAGMENT_CONTEXT IFC;\r
+    NDIS_STATUS NdisStatus;\r
+    PVOID Data;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    IFC = PoolAllocateBuffer(sizeof(IPFRAGMENT_CONTEXT));\r
+    if (!IFC)\r
+        return STATUS_INSUFFICIENT_RESOURCES;\r
+\r
+    /* We allocate a buffer for a PathMTU sized packet and reuse\r
+       it for all fragments */\r
+    Data = ExAllocatePool(NonPagedPool, MaxLLHeaderSize + PathMTU);\r
+    if (!IFC->Header) {\r
+        PoolFreeBuffer(IFC);\r
+        return STATUS_INSUFFICIENT_RESOURCES;\r
+    }\r
+\r
+    /* Allocate NDIS packet */\r
+    NdisAllocatePacket(&NdisStatus, &IFC->NdisPacket, GlobalPacketPool);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        ExFreePool(Data);\r
+        PoolFreeBuffer(IFC);\r
+        return STATUS_INSUFFICIENT_RESOURCES;\r
+    }\r
+\r
+    /* Allocate NDIS buffer */\r
+    NdisAllocateBuffer(&NdisStatus, &IFC->NdisBuffer,\r
+        GlobalBufferPool, Data, MaxLLHeaderSize + PathMTU);\r
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
+        NdisFreePacket(IFC->NdisPacket);\r
+        ExFreePool(Data);\r
+        PoolFreeBuffer(IFC);\r
+        return STATUS_INSUFFICIENT_RESOURCES;\r
+    }\r
+\r
+    /* Link NDIS buffer into packet */\r
+    NdisChainBufferAtFront(IFC->NdisPacket, IFC->NdisBuffer);\r
+\r
+    IFC->Header       = (PVOID)((ULONG_PTR)Data + MaxLLHeaderSize);\r
+    IFC->Datagram     = IPPacket->NdisPacket;\r
+    IFC->DatagramData = IPPacket->Header;\r
+    IFC->HeaderSize   = IPPacket->HeaderSize;\r
+    IFC->PathMTU      = PathMTU;\r
+    IFC->NCE          = NCE;\r
+    IFC->Position     = 0;\r
+    IFC->BytesLeft    = IPPacket->TotalSize - IPPacket->HeaderSize;\r
+    IFC->Data         = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize);\r
+\r
+    PC(IFC->NdisPacket)->DLComplete = IPSendComplete;\r
+    /* Set upper layer completion function to NULL to indicate that\r
+       this packet is an IP datagram fragment and thus we should\r
+       check for more fragments to send. If this is NULL the\r
+       Context field is a pointer to an IPFRAGMENT_CONTEXT structure */\r
+    PC(IFC->NdisPacket)->Complete = NULL;\r
+    PC(IFC->NdisPacket)->Context  = IFC;\r
+\r
+    /* Copy IP datagram header to fragment buffer */\r
+    RtlCopyMemory(IFC->Header, IPPacket->Header, IPPacket->HeaderSize);\r
+\r
+    /* Prepare next fragment for transmission and send it */\r
+\r
+    PrepareNextFragment(IFC);\r
+\r
+    IPSendFragment(IFC->NdisPacket, NCE);\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+VOID IPSendComplete(\r
+    PVOID Context,\r
+    PNDIS_PACKET NdisPacket,\r
+    NDIS_STATUS NdisStatus)\r
+/*\r
+ * FUNCTION: IP datagram fragment send completion handler\r
+ * ARGUMENTS:\r
+ *     Context    = Pointer to context information (IP_INTERFACE)\r
+ *     Packet     = Pointer to NDIS packet that was sent\r
+ *     NdisStatus = NDIS status of operation\r
+ * NOTES:\r
+ *    This routine is called when an IP datagram fragment has been sent\r
+ */\r
+{\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    /* FIXME: Stop sending fragments and cleanup datagram buffers if\r
+       there was an error */\r
+\r
+    if (PC(NdisPacket)->Complete)\r
+        /* This datagram was only one fragment long so call completion handler now */\r
+        (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus);\r
+    else {\r
+        /* This was one of many fragments of an IP datagram. Prepare\r
+           next fragment and send it or if there are no more fragments,\r
+           call upper layer completion routine */\r
+\r
+        PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)PC(NdisPacket)->Context;\r
+\r
+        if (PrepareNextFragment(IFC)) {\r
+            /* A fragment was prepared for transmission, so send it */\r
+            IPSendFragment(IFC->NdisPacket, IFC->NCE);\r
+        } else {\r
+            TI_DbgPrint(MAX_TRACE, ("Calling completion handler.\n"));\r
+\r
+            /* There are no more fragments to transmit, so call completion handler */\r
+            NdisPacket = IFC->Datagram;\r
+            FreeNdisPacket(IFC->NdisPacket);\r
+            PoolFreeBuffer(IFC);\r
+            (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus);\r
+        }\r
+    }\r
+}\r
+\r
+\r
+NTSTATUS IPSendFragment(\r
+    PNDIS_PACKET NdisPacket,\r
+    PNEIGHBOR_CACHE_ENTRY NCE)\r
+/*\r
+ * FUNCTION: Sends an IP datagram fragment to a neighbor\r
+ * ARGUMENTS:\r
+ *     NdisPacket = Pointer to an NDIS packet containing fragment\r
+ *     NCE        = Pointer to NCE for first hop to destination\r
+ * RETURNS:\r
+ *     Status of operation\r
+ * NOTES:\r
+ *     Lowest level IP send routine\r
+ */\r
+{\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State));\r
+\r
+    switch (NCE->State) {\r
+    case NUD_PERMANENT:\r
+        /* Neighbor is always valid */\r
+        break;\r
+\r
+    case NUD_REACHABLE:\r
+        /* Neighbor is reachable */\r
+        \r
+        /* FIXME: Set reachable timer */\r
+\r
+        break;\r
+\r
+    case NUD_STALE:\r
+        /* Enter delay state and send packet */\r
+\r
+        /* FIXME: Enter delay state */\r
+\r
+        break;\r
+\r
+    case NUD_DELAY:\r
+    case NUD_PROBE:\r
+        /* In these states we send the packet and hope the neighbor\r
+           hasn't changed hardware address */\r
+        break;\r
+\r
+    case NUD_INCOMPLETE:\r
+        TI_DbgPrint(MAX_TRACE, ("Queueing packet.\n"));\r
+\r
+        /* We don't know the hardware address of the first hop to\r
+           the destination. Queue the packet on the NCE and return */\r
+        NBQueuePacket(NCE, NdisPacket);\r
+\r
+        return STATUS_SUCCESS;\r
+    default:\r
+        /* Should not happen */\r
+        TI_DbgPrint(MIN_TRACE, ("Unknown NCE state.\n"));\r
+\r
+        return STATUS_SUCCESS;\r
+    }\r
+\r
+    PC(NdisPacket)->DLComplete = IPSendComplete;\r
+    (*NCE->Interface->Transmit)(NCE->Interface->Context, NdisPacket,\r
+        MaxLLHeaderSize, NCE->LinkAddress, LAN_PROTO_IPv4);\r
+\r
+    return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+NTSTATUS IPSendDatagram(\r
+    PIP_PACKET IPPacket,\r
+    PROUTE_CACHE_NODE RCN)\r
+/*\r
+ * FUNCTION: Sends an IP datagram to a remote address\r
+ * ARGUMENTS:\r
+ *     IPPacket = Pointer to an IP packet\r
+ *     RCN      = Pointer to route cache node\r
+ * RETURNS:\r
+ *     Status of operation\r
+ * NOTES:\r
+ *     This is the highest level IP send routine. It possibly breaks the packet\r
+ *     into two or more fragments before passing it on to the next lower level\r
+ *     send routine (IPSendFragment)\r
+ */\r
+{\r
+    PNEIGHBOR_CACHE_ENTRY NCE;\r
+    UINT PathMTU;\r
+\r
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
+\r
+    NCE = RCN->NCE;\r
+\r
+#if DBG\r
+    if (!NCE) {\r
+        TI_DbgPrint(MIN_TRACE, ("No NCE to use.\n"));\r
+        FreeNdisPacket(IPPacket->NdisPacket);\r
+        return STATUS_SUCCESS;\r
+    }\r
+#endif\r
+\r
+    /* Fetch path MTU now, because it may change */\r
+    PathMTU = RCN->PathMTU;\r
+    if (IPPacket->TotalSize > PathMTU) {\r
+        return SendFragments(IPPacket, NCE, PathMTU);\r
+    } else {\r
+        /* Calculate checksum of IP header */\r
+        ((PIPv4_HEADER)IPPacket->Header)->Checksum = 0;\r
+\r
+        ((PIPv4_HEADER)IPPacket->Header)->Checksum = (USHORT)\r
+            IPv4Checksum(IPPacket->Header, IPPacket->HeaderSize, 0);\r
+\r
+        TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n", WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength)));\r
+\r
+        return IPSendFragment(IPPacket->NdisPacket, NCE);\r
+    }\r
+}\r
+\r
+/* EOF */\r
diff --git a/reactos/drivers/net/tcpip/readme.txt b/reactos/drivers/net/tcpip/readme.txt
new file mode 100644 (file)
index 0000000..a4f061e
--- /dev/null
@@ -0,0 +1,19 @@
+Build instructions for TCP/IP protocol driver\r
+---------------------------------------------\r
+\r
+Building with Visual C++ and Windows NT DDK:\r
+\r
+Variables:\r
+%BASEDIR%     = path to NT4 DDK (e.g. c:\ntddk)\r
+%DDKBUILDENV% = DDK build environment (free or checked)\r
+\r
+DDK environment variables must be set! (run setenv.bat)\r
+\r
+    - Create the directory objects/i386/%DDKBUILDENV%\r
+    - Run "build" to build the driver\r
+\r
+\r
+Building with Mingw32 and ReactOS include files:\r
+\r
+    - Build NDIS.SYS (i.e. "make ndis")\r
+    - Run "make tcpip" FROM THE ReactOS ROOT DIRECTORY to build the driver\r
diff --git a/reactos/drivers/net/tcpip/tcpip.def b/reactos/drivers/net/tcpip/tcpip.def
new file mode 100644 (file)
index 0000000..43b9506
--- /dev/null
@@ -0,0 +1,32 @@
+; TCPIP.SYS - TCP/IP protocol driver\r
+\r
+LIBRARY tcpip.sys\r
+\r
+EXPORTS\r
+;FreeIprBuff\r
+;GetIFAndLink\r
+IPAddInterface@20\r
+;IPAllocBuff\r
+IPDelInterface@4\r
+;IPDelayedNdisReEnumerateBindings\r
+;IPDeregisterARP\r
+;IPDisableSniffer\r
+;IPEnableSniffer\r
+;IPFreeBuff\r
+;IPGetAddrType\r
+;IPGetBestInterface\r
+;IPGetInfo\r
+;IPInjectPkt\r
+;IPProxyNdisRequest\r
+;IPRegisterARP\r
+;IPRegisterProtocol\r
+;IPSetIPSecStatus\r
+;IPTransmit\r
+LookupRoute@8\r
+;LookupRouteInformation\r
+;SendICMPErr\r
+;SetIPSecPtr\r
+;UnSetIPSecPtr\r
+;UnSetIPSecSendPtr\r
+\r
+; EOF\r
diff --git a/reactos/drivers/net/tcpip/tcpip.edf b/reactos/drivers/net/tcpip/tcpip.edf
new file mode 100644 (file)
index 0000000..08f8b9b
--- /dev/null
@@ -0,0 +1,32 @@
+; TCPIP.SYS - TCP/IP protocol driver\r
+\r
+LIBRARY tcpip.sys\r
+\r
+EXPORTS\r
+;FreeIprBuff\r
+;GetIFAndLink\r
+IPAddInterface=IPAddInterface@20\r
+;IPAllocBuff\r
+IPDelInterface=IPDelInterface@4\r
+;IPDelayedNdisReEnumerateBindings\r
+;IPDeregisterARP\r
+;IPDisableSniffer\r
+;IPEnableSniffer\r
+;IPFreeBuff\r
+;IPGetAddrType\r
+;IPGetBestInterface\r
+;IPGetInfo\r
+;IPInjectPkt\r
+;IPProxyNdisRequest\r
+;IPRegisterARP\r
+;IPRegisterProtocol\r
+;IPSetIPSecStatus\r
+;IPTransmit\r
+LookupRoute=LookupRoute@8\r
+;LookupRouteInformation\r
+;SendICMPErr\r
+;SetIPSecPtr\r
+;UnSetIPSecPtr\r
+;UnSetIPSecSendPtr\r
+\r
+; EOF\r
diff --git a/reactos/drivers/net/tcpip/tcpip.rc b/reactos/drivers/net/tcpip/tcpip.rc
new file mode 100644 (file)
index 0000000..484b00d
--- /dev/null
@@ -0,0 +1,38 @@
+#include <defines.h>\r
+#include <reactos/resource.h>\r
+\r
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\r
+\r
+VS_VERSION_INFO VERSIONINFO\r
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD\r
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD\r
+       FILEFLAGSMASK   0x3fL\r
+#ifdef _DEBUG\r
+       FILEFLAGS       0x1L\r
+#else\r
+       FILEFLAGS       0x0L\r
+#endif\r
+       FILEOS          0x40004L\r
+       FILETYPE        0x2L\r
+       FILESUBTYPE     0x0L\r
+BEGIN\r
+    BLOCK "StringFileInfo"\r
+    BEGIN\r
+        BLOCK "040904b0"\r
+        BEGIN\r
+            VALUE "CompanyName",         RES_STR_COMPANY_NAME\r
+            VALUE "FileDescription",  "TCP/IP protocol driver\0"\r
+            VALUE "FileVersion",         "0.0.0\0"\r
+            VALUE "InternalName",        "tcpip\0"\r
+            VALUE "LegalCopyright",      RES_STR_LEGAL_COPYRIGHT\r
+            VALUE "OriginalFilename", "tcpip.sys\0"\r
+            VALUE "ProductName",         RES_STR_PRODUCT_NAME\r
+            VALUE "ProductVersion",      RES_STR_PRODUCT_VERSION\r
+        END\r
+    END\r
+    BLOCK "VarFileInfo"\r
+    BEGIN\r
+        VALUE "Translation", 0x409, 1200\r
+    END\r
+END\r
+\r
diff --git a/reactos/drivers/net/tcpip/tcpip/Copy of info.c b/reactos/drivers/net/tcpip/tcpip/Copy of info.c
new file mode 100644 (file)
index 0000000..6241e53
--- /dev/null
@@ -0,0 +1,335 @@
+/*\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS TCP/IP protocol driver\r
+ * FILE:        tcpip/info.c\r
+ * PURPOSE:     TDI query and set information routines\r
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
+ * REVISIONS:\r
+ *   CSH 01/07-2000 Created\r
+ */\r
+#include <tcpip.h>\r
+#include <routines.h>\r
+#include <info.h>\r
+\r
+\r
+TDI_STATUS IPTdiQueryInformationEx(\r
+    PTDI_REQUEST Request,\r
+    TDIObjectID *ID,\r
+    PNDIS_BUFFER Buffer,\r
+    PUINT BufferSize,\r
+    PVOID Context)\r
+/*\r
+ * FUNCTION: Returns extended information about network layer\r
+ * ARGUMENTS:\r
+ *     Request    = Pointer to TDI request structure for the request\r
+ *     ID         = TDI object ID\r
+ *     Buffer     = Pointer to buffer with data to use. \r
+ *     BufferSize = Pointer to buffer with size of Buffer. On return\r
+ *                  this is filled with number of bytes returned\r
+ *     Context    = Pointer to context buffer\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    IPADDR_ENTRY IpAddress;\r
+    IPSNMP_INFO SnmpInfo;\r
+    PADDRESS_ENTRY ADE;\r
+    PIP_INTERFACE IF;\r
+    ULONG Temp;\r
+    UINT Count;\r
+    ULONG Entity;\r
+    KIRQL OldIrql;\r
+    UINT BufSize = *BufferSize;\r
+\r
+    /* Make return parameters consistent every time */\r
+    *BufferSize = 0;\r
+\r
+    Entity = ID->toi_entity.tei_entity;\r
+    if (Entity != CL_NL_ENTITY) {\r
+        /* We can't handle this entity */\r
+        return TDI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (ID->toi_entity.tei_instance != TL_INSTANCE)\r
+        /* We only support a single instance */\r
+        return TDI_INVALID_REQUEST;\r
+    if (ID->toi_class == INFO_CLASS_GENERIC) {\r
+        if (ID->toi_type == INFO_TYPE_PROVIDER && \r
+            ID->toi_id == ENTITY_TYPE_ID) {\r
+\r
+            if (BufSize < sizeof(ULONG))\r
+                return TDI_BUFFER_TOO_SMALL;\r
+            Temp = CL_NL_IP;\r
+\r
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG));\r
+\r
+            return TDI_SUCCESS;\r
+        }\r
+        return TDI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if (ID->toi_class == INFO_CLASS_PROTOCOL) {\r
+        if (ID->toi_type != INFO_TYPE_PROVIDER)\r
+            return TDI_INVALID_PARAMETER;\r
+\r
+        switch (ID->toi_id) {\r
+        case IP_MIB_ADDRTABLE_ENTRY_ID:\r
+            Temp = 0;\r
+\r
+            KeAcquireSpinLock(&InterfaceLock, &OldIrql);\r
+/*\r
+    /* Search the interface list */\r
+    CurrentIFEntry = InterfaceListHead.Flink;\r
+    while (CurrentIFEntry != &InterfaceListHead) {\r
+           CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);\r
+        if (CurrentIF != Loopback) {\r
+            /* Search the address entry list and return the first appropriate ADE found */\r
+            CurrentADEEntry = CurrentIF->ADEListHead.Flink;\r
+            while (CurrentADEEntry != &CurrentIF->ADEListHead) {\r
+                   CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);\r
+                if (CurrentADE->Type == AddressType)\r
+                    ReferenceAddress(CurrentADE->Address);\r
+                    KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
+                    return CurrentADE;\r
+                }\r
+                CurrentADEEntry = CurrentADEEntry->Flink;\r
+        } else\r
+            LoopbackIsRegistered = TRUE;\r
+        CurrentIFEntry = CurrentIFEntry->Flink;\r
+    }\r
+\r
+\r
+            */\r
+            for (IF = InterfaceList; IF != NULL; IF = IF->Next) {\r
+                if (Temp + sizeof(IPADDR_ENTRY) > BufSize) {\r
+                    KeReleaseSpinLock(&InterfaceLock, OldIrql);\r
+                    return TDI_BUFFER_TOO_SMALL;\r
+                }\r
+\r
+                IpAddress.Addr      = 0;\r
+                IpAddress.BcastAddr = 0;\r
+                IpAddress.Mask      = 0;\r
+                /* Locate the diffrent addresses and put them the right place */\r
+                for (ADE = IF->ADE; ADE != NULL; ADE = ADE->Next) {\r
+                    switch (ADE->Type) {\r
+                    case ADE_UNICAST  : IpAddress.Addr      = ADE->Address->Address.IPv4Address;\r
+                    case ADE_MULTICAST: IpAddress.BcastAddr = ADE->Address->Address.IPv4Address;\r
+                    case ADE_ADDRMASK : IpAddress.Mask      = ADE->Address->Address.IPv4Address;\r
+                    }\r
+                }\r
+                /* Pack the address information into IPADDR_ENTRY structure */\r
+                IpAddress.Index     = 0;\r
+                IpAddress.ReasmSize = 0;\r
+                IpAddress.Context   = 0;\r
+                IpAddress.Pad       = 0;\r
+\r
+                Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY));\r
+\r
+                Temp += sizeof(IPADDR_ENTRY);\r
+            }\r
+            KeReleaseSpinLock(&InterfaceLock, OldIrql);\r
+            return TDI_SUCCESS;\r
+\r
+        case IP_MIB_STATS_ID:\r
+            if (BufSize < sizeof(IPSNMP_INFO))\r
+                return TDI_BUFFER_TOO_SMALL;\r
+\r
+            RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO));\r
+\r
+            /* Count number of addresses */\r
+            Count = 0;\r
+            KeAcquireSpinLock(&InterfaceLock, &OldIrql);\r
+            for (IF = InterfaceList; IF != NULL; IF = IF->Next)\r
+                Count++;\r
+            KeReleaseSpinLock(&InterfaceLock, OldIrql);\r
+\r
+            SnmpInfo.NumAddr = Count;\r
+\r
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO));\r
+\r
+            return TDI_SUCCESS;\r
+\r
+        default:\r
+            /* We can't handle this ID */\r
+            return TDI_INVALID_PARAMETER;\r
+        }\r
+    }\r
+\r
+    return TDI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+TDI_STATUS InfoTdiQueryInformationEx(\r
+    PTDI_REQUEST Request,\r
+    TDIObjectID *ID,\r
+    PNDIS_BUFFER Buffer,\r
+    PUINT BufferSize,\r
+    PVOID Context)\r
+/*\r
+ * FUNCTION: Returns extended information\r
+ * ARGUMENTS:\r
+ *     Request    = Pointer to TDI request structure for the request\r
+ *     ID         = TDI object ID\r
+ *     Buffer     = Pointer to buffer with data to use\r
+ *     BufferSize = Pointer to buffer with size of Buffer. On return\r
+ *                  this is filled with number of bytes returned\r
+ *     Context    = Pointer to context buffer\r
+ * RETURNS:\r
+ *     Status of operation\r
+ */\r
+{\r
+    PADDRESS_FILE AddrFile;\r
+    PADDRESS_ENTRY ADE;\r
+    ADDRESS_INFO Info;\r
+    KIRQL OldIrql;\r
+    UINT Entity;\r
+    UINT Count;\r
+    UINT Size;\r
+    ULONG Temp;\r
+    UINT Offset = 0;\r
+    UINT BufSize = *BufferSize;\r
+\r
+    /* Check wether it is a query for a list of entities */\r
+    Entity = ID->toi_entity.tei_entity;\r
+    if (Entity == GENERIC_ENTITY) {\r
+        if (ID->toi_class  != INFO_CLASS_GENERIC ||\r
+            ID->toi_type != INFO_TYPE_PROVIDER ||\r
+            ID->toi_id != ENTITY_LIST_ID)\r
+            return TDI_INVALID_PARAMETER;\r
+\r
+        *BufferSize = 0;\r
+\r
+        Size = EntityCount * sizeof(TDIEntityID);\r
+        if (BufSize < Size)\r
+            /* The buffer is too small to contain requested data */\r
+            return TDI_BUFFER_TOO_SMALL;\r
+\r
+        /* Return entity list */\r
+        Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size);\r
+\r
+        *BufferSize = Size;\r
+\r
+        return TDI_SUCCESS;\r
+    }\r
+\r
+    if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) {\r
+        /* We can't handle this entity, pass it on */\r
+        return IPTdiQueryInformationEx(\r
+            Request, ID, Buffer, BufferSize, Context);\r
+    }\r
+\r
+    /* Make return parameters consistent every time */\r
+    *BufferSize = 0;\r
+\r
+    if (ID->toi_entity.tei_instance != TL_INSTANCE)\r
+        /* We only support a single instance */\r
+        return TDI_INVALID_REQUEST;\r
+\r
+    if (ID->toi_class == INFO_CLASS_GENERIC) {\r
+\r
+        if (ID->toi_type != INFO_TYPE_PROVIDER ||\r
+            ID->toi_id != ENTITY_TYPE_ID)\r
+            return TDI_INVALID_PARAMETER;\r
+\r
+        if (BufSize < sizeof(ULONG))\r
+            return TDI_BUFFER_TOO_SMALL;\r
+\r
+        if (Entity == CL_TL_ENTITY)\r
+            Temp = CL_TL_UDP;\r
+        else if (Entity == CO_TL_ENTITY)\r
+            Temp = CO_TL_TCP;\r
+        else\r
+            return TDI_INVALID_PARAMETER;\r
+\r
+        Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG));\r
+\r
+        return TDI_SUCCESS;\r
+    }\r
+\r
+    if (ID->toi_class == INFO_CLASS_PROTOCOL) {\r
+\r
+        if (ID->toi_type != INFO_TYPE_PROVIDER)\r
+            return TDI_INVALID_PARAMETER;\r
+\r
+        switch (ID->toi_id) {\r
+        case UDP_MIB_STAT_ID:\r
+            if (Entity != CL_TL_ENTITY)\r
+                return TDI_INVALID_PARAMETER;\r
+\r
+            if (BufSize < sizeof(UDPStats))\r
+                return TDI_BUFFER_TOO_SMALL;\r
+\r
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS));\r
+\r
+            return TDI_SUCCESS;\r
+\r
+        case UDP_MIB_TABLE_ID:\r
+            if (Entity != CL_TL_ENTITY)\r
+                return TDI_INVALID_PARAMETER;\r
+\r
+            Offset = 0;\r
+\r
+            KeAcquireSpinLock(&AddressFileLock, &OldIrql);\r
+\r
+            for (AddrFile = AddressFileList;\r
+                AddrFile->Next != NULL;\r
+                AddrFile = AddrFile->Next) {\r
+\r
+                if (Offset + sizeof(ADDRESS_INFO) > BufSize) {\r
+                    KeReleaseSpinLock(&AddressFileLock, OldIrql);\r
+                    *BufferSize = Offset;\r
+                    return TDI_BUFFER_OVERFLOW;\r
+                }\r
+\r
+                for (ADE = AddrFile->ADE; ADE != NULL; ADE = ADE->Next) {\r
+                    /* We only care about IPv4 unicast address */\r
+                    if ((ADE->Type == ADE_UNICAST) &&\r
+                        (ADE->Address->Type == IP_ADDRESS_V4))\r
+                        Info.LocalAddress = ADE->Address->Address.IPv4Address;\r
+                }\r
+\r
+                Info.LocalPort = AddrFile->Port;\r
+\r
+                Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO));\r
+\r
+                Offset += Count;\r
+            }\r
+\r
+            KeReleaseSpinLock(&AddressFileLock, OldIrql);\r
+\r
+            *BufferSize = Offset;\r
+\r
+            return STATUS_SUCCESS;\r
+\r
+        default:\r
+            /* We can't handle this ID */\r
+            return TDI_INVALID_PARAMETER;\r
+        }\r
+    }\r
+\r
+    return TDI_INVALID_PARAMETER;\r
+}\r
+\r
+\r
+TDI_STATUS InfoTdiSetInformationEx(\r
+    PTDI_RE