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

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

index 394f718..efaaa56 100644 (file)
@@ -34,11 +34,16 @@ LOADERS = dos
 #
 # Select the device drivers and filesystems you want
 #
 #
 # Select the device drivers and filesystems you want
 #
-DEVICE_DRIVERS = blue ide keyboard null parallel serial vidport floppy
-# DEVICE_DRIVERS = beep event floppy ide_test mouse sound test test1
-FS_DRIVERS = vfat minix
+DEVICE_DRIVERS = vga blue ide keyboard null parallel serial vidport
+# DEVICE_DRIVERS = beep event floppy ide_test mouse sound test test1\r
+\r
+FS_DRIVERS = vfat
 # FS_DRIVERS = minix ext2 template
 # FS_DRIVERS = minix ext2 template
-KERNEL_SERVICES = $(DEVICE_DRIVERS) $(FS_DRIVERS)
+\r
+# ndis tdi tcpip tditest\r
+NET_DRIVERS = ndis tcpip tditest\r
+\r
+KERNEL_SERVICES = $(DEVICE_DRIVERS) $(FS_DRIVERS) $(NET_DRIVERS)\r
 
 APPS = args hello shell test cat bench apc shm lpc thread event file gditest \
        pteb consume
 
 APPS = args hello shell test cat bench apc shm lpc thread event file gditest \
        pteb consume
@@ -54,7 +59,7 @@ clean: buildno_clean $(COMPONENTS:%=%_clean) $(DLLS:%=%_clean) $(LOADERS:%=%_cle
        
 .PHONY: clean
 
        
 .PHONY: clean
 
-install_floppy: make_floppy_dirs autoexec_floppy $(COMPONENTS:%=%_floppy) \
+floppy: make_floppy_dirs autoexec_floppy $(COMPONENTS:%=%_floppy) \
         $(DLLS:%=%_floppy) $(LOADERS:%=%_floppy) \
         $(KERNEL_SERVICES:%=%_floppy) $(SUBSYS:%=%_floppy) \
         $(APPS:%=%_floppy)
         $(DLLS:%=%_floppy) $(LOADERS:%=%_floppy) \
         $(KERNEL_SERVICES:%=%_floppy) $(SUBSYS:%=%_floppy) \
         $(APPS:%=%_floppy)
@@ -155,6 +160,15 @@ $(FS_DRIVERS:%=%_dist): %_dist:
 
 .PHONY: $(FS_DRIVERS) $(FS_DRIVERS:%=%_clean) $(FS_DRIVERS:%=%_floppy) \
         $(FS_DRIVERS:%=%_dist)
 
 .PHONY: $(FS_DRIVERS) $(FS_DRIVERS:%=%_clean) $(FS_DRIVERS:%=%_floppy) \
         $(FS_DRIVERS:%=%_dist)
+\r
+$(NET_DRIVERS): %:\r
+       make -C services/net/$*\r
+\r
+$(NET_DRIVERS:%=%_clean): %_clean:\r
+       make -C services/net/$* clean\r
+\r
+.PHONY: $(NET_DRIVERS) $(NET_DRIVERS:%=%_clean)\r
+\r
 
 #
 # Kernel loaders
 
 #
 # Kernel loaders
index a49d00e..de50bbd 100644 (file)
@@ -1,5 +1,5 @@
-DIRS= datalink \\r
-      network \\r
-      transport \\r
-      tcpip\r
-\r
+DIRS= datalink \
+      network \
+      transport \
+      tcpip
+
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index b941923..25571ac 100644 (file)
@@ -1,13 +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
+TARGETNAME=datalink
+TARGETPATH=..\objects
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net
+SOURCES= arp.c \
+                lan.c \
+         loopback.c
+
+MSC_WARNING_LEVEL=/W3 /WX
index 83d2490..6121918 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        datalink/arp.c
+ * PURPOSE:     Address Resolution Protocol routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <arp.h>
+#include <routines.h>
+#include <neighbor.h>
+#include <address.h>
+#include <pool.h>
+#include <lan.h>
+
+
+PNDIS_PACKET PrepareARPPacket(
+    USHORT HardwareType,
+    USHORT ProtocolType,
+    UCHAR LinkAddressLength,
+    UCHAR ProtoAddressLength,
+    PVOID SenderLinkAddress,
+    PVOID SenderProtoAddress,
+    PVOID TargetLinkAddress,
+    PVOID TargetProtoAddress,
+    USHORT Opcode)
+/*
+ * FUNCTION: Prepares an ARP packet
+ * ARGUMENTS:
+ *     HardwareType       = Hardware type (in network byte order)
+ *     ProtocolType       = Protocol type (in network byte order)
+ *     LinkAddressLength  = Length of link address fields
+ *     ProtoAddressLength = Length of protocol address fields
+ *     SenderLinkAddress  = Sender's link address
+ *     SenderProtoAddress = Sender's protocol address
+ *     TargetLinkAddress  = Target's link address (NULL if don't care)
+ *     TargetProtoAddress = Target's protocol address
+ *     Opcode             = ARP opcode (in network byte order)
+ * RETURNS:
+ *     Pointer to NDIS packet, NULL if there is not enough free resources
+ */
+{
+    PNDIS_PACKET NdisPacket;
+    PNDIS_BUFFER NdisBuffer;
+    NDIS_STATUS NdisStatus;
+    PARP_HEADER Header;
+    PVOID DataBuffer;
+    ULONG Size;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    /* Prepare ARP packet */
+    Size = MaxLLHeaderSize + sizeof(ARP_HEADER) + 
+        2 * LinkAddressLength + /* Hardware address length */
+        2 * ProtoAddressLength; /* Protocol address length */
+    Size = MAX(Size, MinLLFrameSize);
+
+    DataBuffer = ExAllocatePool(NonPagedPool, Size);
+    if (!DataBuffer)
+        return NULL;
+
+    /* Allocate NDIS packet */
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        ExFreePool(DataBuffer);
+        return NULL;
+    }
+
+    /* Allocate NDIS buffer for maximum link level header and ARP packet */
+    NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,
+        DataBuffer, Size);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        NdisFreePacket(NdisPacket);
+        ExFreePool(DataBuffer);
+        return NULL;
+    }
+
+    /* Link NDIS buffer into packet */
+    NdisChainBufferAtFront(NdisPacket, NdisBuffer);
+    RtlZeroMemory(DataBuffer, Size);
+    Header = (PARP_HEADER)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);
+    Header->HWType       = HardwareType;
+    Header->ProtoType    = ProtocolType;
+    Header->HWAddrLen    = LinkAddressLength;
+    Header->ProtoAddrLen = ProtoAddressLength;
+    Header->Opcode       = Opcode; /* Already swapped */
+    DataBuffer = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
+
+    /* Our hardware address */
+    RtlCopyMemory(DataBuffer, SenderLinkAddress, LinkAddressLength);
+    (ULONG_PTR)DataBuffer += LinkAddressLength;
+
+    /* Our protocol address */
+    RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);
+
+    if (TargetLinkAddress) {
+        (ULONG_PTR)DataBuffer += ProtoAddressLength;
+        /* Target hardware address */
+        RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);
+        (ULONG_PTR)DataBuffer += LinkAddressLength;
+    } else
+        /* Don't care about target hardware address */
+        (ULONG_PTR)DataBuffer += (ProtoAddressLength + LinkAddressLength);
+
+    /* Target protocol address */
+    RtlCopyMemory(DataBuffer, TargetProtoAddress, ProtoAddressLength);
+
+    return NdisPacket;
+}
+
+
+VOID ARPTransmitComplete(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    NDIS_STATUS NdisStatus)
+/*
+ * FUNCTION: ARP request transmit completion handler
+ * ARGUMENTS:
+ *     Context    = Pointer to context information (IP_INTERFACE)
+ *     Packet     = Pointer to NDIS packet that was sent
+ *     NdisStatus = NDIS status of operation
+ * NOTES:
+ *    This routine is called when an ARP request has been sent
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    FreeNdisPacket(NdisPacket);
+}
+
+
+BOOLEAN ARPTransmit(
+    PIP_ADDRESS Address,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Creates an ARP request and transmits it on a network
+ * ARGUMENTS:
+ *     Address = Pointer to IP address to resolve
+ *     NTE     = Pointer to net table entru to use for transmitting request
+ * RETURNS:
+ *     TRUE if the request was successfully sent, FALSE if not
+ */
+{
+    PIP_INTERFACE Interface;
+    PNDIS_PACKET NdisPacket;
+    UCHAR ProtoAddrLen;
+    USHORT ProtoType;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Interface = NTE->Interface;
+
+    switch (Address->Type) {
+        case IP_ADDRESS_V4:
+            ProtoType    = (USHORT)ETYPE_IPv4; /* IPv4 */
+            ProtoAddrLen = 4;                  /* Length of IPv4 address */
+            break;
+        case IP_ADDRESS_V6:
+            ProtoType    = (USHORT)ETYPE_IPv6; /* IPv6 */
+            ProtoAddrLen = 16;                 /* Length of IPv6 address */
+            break;
+        default:
+            /* Should not happen */
+            return FALSE;
+    }
+
+    NdisPacket = PrepareARPPacket(
+        WN2H(0x0001),                    /* FIXME: Ethernet only */
+        ProtoType,                       /* Protocol type */
+        (UCHAR)Interface->AddressLength, /* Hardware address length */
+        (UCHAR)ProtoAddrLen,             /* Protocol address length */
+        Interface->Address,              /* Sender's (local) hardware address */
+        &NTE->Address->Address,          /* Sender's (local) protocol address */
+        NULL,                            /* Don't care */
+        &Address->Address,               /* Target's (remote) protocol address */
+        ARP_OPCODE_REQUEST);             /* ARP request */
+
+    PC(NdisPacket)->DLComplete = ARPTransmitComplete;
+
+    (*Interface->Transmit)(Interface->Context, NdisPacket,
+        MaxLLHeaderSize, NULL, LAN_PROTO_ARP);
+
+    return TRUE;
+}
+
+
+VOID ARPReceive(
+    PVOID Context,
+    PIP_PACKET Packet)
+/*
+ * FUNCTION: Receives an ARP packet
+ * ARGUMENTS:
+ *     Context = Pointer to context information (IP_INTERFACE)
+ *     Packet  = Pointer to packet
+ */
+{
+    PARP_HEADER Header;
+    PIP_ADDRESS Address;
+    PVOID SenderHWAddress;
+    PVOID SenderProtoAddress;
+    PVOID TargetProtoAddress;
+    PADDRESS_ENTRY ADE;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+    PNDIS_PACKET NdisPacket;
+    PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Header = (PARP_HEADER)Packet->Header;
+
+    /* FIXME: Ethernet only */
+    if (WN2H(Header->HWType) != 1)
+        return;
+
+    /* Check protocol type */
+    if (Header->ProtoType != ETYPE_IPv4)
+        return;
+
+    SenderHWAddress    = (PVOID)((ULONG_PTR)Header + sizeof(ARP_HEADER));
+    SenderProtoAddress = (PVOID)((ULONG_PTR)SenderHWAddress + Header->HWAddrLen);
+
+    /* Check if we have the target protocol address */
+
+    TargetProtoAddress = (PVOID)((ULONG_PTR)SenderProtoAddress +
+        Header->ProtoAddrLen + Header->HWAddrLen);
+
+    Address = AddrBuildIPv4(*(PULONG)(TargetProtoAddress));
+    ADE = IPLocateADE(Address, ADE_UNICAST);
+    if (!ADE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return;
+    }
+
+    /* Check if we know the sender */
+
+    AddrInitIPv4(Address, *(PULONG)(SenderProtoAddress));
+    NCE = NBLocateNeighbor(Address);
+    if (NCE) {
+        DereferenceObject(Address);
+        /* We know the sender. Update the hardware address 
+           and state in our neighbor address cache */
+        NBUpdateNeighbor(NCE, SenderHWAddress, NUD_REACHABLE);
+    } else {
+        /* The packet had our protocol address as target. The sender
+           may want to communicate with us soon, so add his address
+           to our address cache */
+        NCE = NBAddNeighbor(Interface, Address, SenderHWAddress,
+            Header->HWAddrLen, NUD_REACHABLE);
+    }
+    if (NCE)
+        DereferenceObject(NCE)
+
+    if (Header->Opcode != ARP_OPCODE_REQUEST)
+        return;
+    
+    /* This is a request for our address. Swap the addresses and
+       send an ARP reply back to the sender */
+    NdisPacket = PrepareARPPacket(
+        Header->HWType,                  /* Hardware type */
+        Header->ProtoType,               /* Protocol type */
+        (UCHAR)Interface->AddressLength, /* Hardware address length */
+        (UCHAR)Header->ProtoAddrLen,     /* Protocol address length */
+        Interface->Address,              /* Sender's (local) hardware address */
+        &ADE->Address->Address,          /* Sender's (local) protocol address */
+        SenderHWAddress,                 /* Target's (remote) hardware address */
+        SenderProtoAddress,              /* Target's (remote) protocol address */
+        ARP_OPCODE_REPLY);               /* ARP reply */
+    if (NdisPacket) {
+        PC(NdisPacket)->DLComplete = ARPTransmitComplete;
+        (*Interface->Transmit)(Interface->Context, NdisPacket,
+            MaxLLHeaderSize, SenderHWAddress, LAN_PROTO_ARP);
+    }
+}
+
+/* EOF */
index 4476922..df15ca9 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        datalink/lan.c
+ * PURPOSE:     Local Area Network media routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <lan.h>
+#include <address.h>
+#include <routines.h>
+#include <transmit.h>
+#include <receive.h>
+#include <arp.h>
+
+
+NDIS_HANDLE NdisProtocolHandle = (NDIS_HANDLE)NULL;
+BOOLEAN ProtocolRegistered     = FALSE;
+PLAN_ADAPTER Adapters          = NULL;
+
+
+NDIS_STATUS NDISCall(
+    PLAN_ADAPTER Adapter,
+    NDIS_REQUEST_TYPE Type,
+    NDIS_OID OID,
+    PVOID Buffer,
+    UINT Length)
+/*
+ * FUNCTION: Send a request to NDIS
+ * ARGUMENTS:
+ *     Adapter     = Pointer to a LAN_ADAPTER structure
+ *     Type        = Type of request (Set or Query)
+ *     OID         = Value to be set/queried for
+ *     Buffer      = Pointer to a buffer to use
+ *     Length      = Number of bytes in Buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_REQUEST Request;
+    NDIS_STATUS NdisStatus;
+
+    Request.RequestType = Type;
+    if (Type == NdisRequestSetInformation) {
+        Request.DATA.SET_INFORMATION.Oid                     = OID;
+        Request.DATA.SET_INFORMATION.InformationBuffer       = Buffer;
+        Request.DATA.SET_INFORMATION.InformationBufferLength = Length;
+    } else {
+        Request.DATA.QUERY_INFORMATION.Oid                     = OID;
+        Request.DATA.QUERY_INFORMATION.InformationBuffer       = Buffer;
+        Request.DATA.QUERY_INFORMATION.InformationBufferLength = Length;
+    }
+
+    if (Adapter->State != LAN_STATE_RESETTING) {
+        NdisRequest(&NdisStatus, Adapter->NdisHandle, &Request);
+    } else
+        NdisStatus = NDIS_STATUS_NOT_ACCEPTED;
+
+    /* Wait for NDIS to complete the request */
+    if (NdisStatus == NDIS_STATUS_PENDING) {
+        KeWaitForSingleObject(&Adapter->Event, UserRequest, KernelMode, FALSE, NULL);
+        NdisStatus = Adapter->NdisStatus;
+    }
+
+    return NdisStatus;
+}
+
+
+PNDIS_PACKET AllocateTDPacket(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Allocates an NDIS packet for NdisTransferData
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure
+ * RETURNS:
+ *     Pointer to NDIS packet or NULL if there was not enough free
+ *     non-paged memory
+ */
+{
+    NDIS_STATUS NdisStatus;
+    PNDIS_PACKET NdisPacket;
+    PNDIS_BUFFER Buffer;
+    PVOID Data;
+
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS)
+        return NULL;
+
+    Data = ExAllocatePool(NonPagedPool, Adapter->MTU);
+    if (!Data) {
+        NdisFreePacket(NdisPacket);
+        return NULL;
+    }
+        
+    NdisAllocateBuffer(&NdisStatus, &Buffer, GlobalBufferPool, Data, Adapter->MTU);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        NdisFreePacket(NdisPacket);
+        ExFreePool(Data);
+        return NULL;
+    }
+
+    NdisChainBufferAtFront(NdisPacket, Buffer);
+
+    PC(NdisPacket)->Context = NULL; /* End of list */
+
+    return NdisPacket;
+}
+
+
+VOID FreeTDPackets(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees transfer data packets
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure
+ */
+{
+    PNDIS_PACKET NdisPacket, Next;
+
+    /* Release transfer data packets */
+    NdisPacket = Adapter->TDPackets;
+    while (NdisPacket) {
+        Next = PC(NdisPacket)->Context;
+        FreeNdisPacket(NdisPacket);
+        NdisPacket = Next;
+    }
+    Adapter->TDPackets = NULL;
+}
+
+
+VOID FreeAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Frees memory for a LAN_ADAPTER structure
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure to free
+ */
+{
+    FreeTDPackets(Adapter);
+    ExFreePool(Adapter);
+}
+
+
+VOID ProtocolOpenAdapterComplete(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS Status,
+    NDIS_STATUS OpenErrorStatus)
+/*
+ * FUNCTION: Called by NDIS to complete opening of an adapter
+ * ARGUMENTS:
+ *     BindingContext  = Pointer to a device context (LAN_ADAPTER)
+ *     Status          = Status of the operation
+ *     OpenErrorStatus = Additional status information
+ */
+{
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID ProtocolCloseAdapterComplete(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete closing an adapter
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     Status         = Status of the operation
+ */
+{
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Adapter->NdisStatus = Status;
+
+    KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID ProtocolResetComplete(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete resetting an adapter
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     Status         = Status of the operation
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID ProtocolRequestComplete(
+    NDIS_HANDLE BindingContext,
+    PNDIS_REQUEST NdisRequest,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete a request
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     NdisRequest    = Pointer to an object describing the request
+ *     Status         = Status of the operation
+ */
+{
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    /* Save status of request and signal an event */
+    Adapter->NdisStatus = Status;
+
+    KeSetEvent(&Adapter->Event, 0, FALSE);
+}
+
+
+VOID ProtocolSendComplete(
+    NDIS_HANDLE BindingContext,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS Status)
+/*
+ * FUNCTION: Called by NDIS to complete sending process
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ *     Packet         = Pointer to a packet descriptor
+ *     Status         = Status of the operation
+ */
+{
+       PLAN_ADAPTER Adapter = BindingContext;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    AdjustPacket(Packet, Adapter->HeaderSize, PC(Packet)->DLOffset);
+
+    (*PC(Packet)->DLComplete)(Adapter->Context, Packet, Status);
+}
+
+
+VOID ProtocolTransferDataComplete(
+    NDIS_HANDLE BindingContext,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS Status,
+    UINT BytesTransferred)
+/*
+ * FUNCTION: Called by NDIS to complete reception of data
+ * ARGUMENTS:
+ *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
+ *     Packet           = Pointer to a packet descriptor
+ *     Status           = Status of the operation
+ *     BytesTransferred = Number of bytes transferred
+ * NOTES:
+ *     If the packet was successfully received, determine the protocol
+ *     type and pass it to the correct receive handler
+ */
+{
+    UINT PacketType;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+
+    if (Status == NDIS_STATUS_SUCCESS) {
+        PNDIS_BUFFER NdisBuffer;
+        IP_PACKET IPPacket;
+
+        NdisGetFirstBufferFromPacket(
+            Packet, &NdisBuffer, &IPPacket.Header,
+            &IPPacket.ContigSize, &IPPacket.TotalSize);
+
+        /* Determine which upper layer protocol that should receive
+           this packet and pass it to the correct receive handler */
+        PacketType = ((PETH_HEADER)IPPacket.Header)->EType;
+        switch (PacketType) {
+            case ETYPE_IPv4:
+            case ETYPE_IPv6:
+                IPReceive(Adapter->Context, &IPPacket);
+                break;
+            case ETYPE_ARP:
+                ARPReceive(Adapter->Context, &IPPacket);
+            default:
+                break;
+        }
+    }
+
+    /* Release the packet descriptor */
+    KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+
+    PC(Packet)->Context = Adapter->TDPackets;
+    Adapter->TDPackets  = Packet;
+
+    KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+}
+
+
+NDIS_STATUS ProtocolReceive(
+    NDIS_HANDLE BindingContext,
+    NDIS_HANDLE MacReceiveContext,
+    PVOID HeaderBuffer,
+    UINT HeaderBufferSize,
+    PVOID LookaheadBuffer,
+    UINT LookaheadBufferSize,
+    UINT PacketSize)
+/*
+ * FUNCTION: Called by NDIS when a packet has been received on the physical link
+ * ARGUMENTS:
+ *     BindingContext      = Pointer to a device context (LAN_ADAPTER)
+ *     MacReceiveContext   = Handle used by underlying NIC driver
+ *     HeaderBuffer        = Pointer to a buffer containing the packet header
+ *     HeaderBufferSize    = Number of bytes in HeaderBuffer
+ *     LookaheadBuffer     = Pointer to a buffer containing buffered packet data
+ *     LookaheadBufferSize = Size of LookaheadBuffer. May be less than asked for
+ *     PacketSize          = Overall size of the packet (not including header)
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    USHORT EType;
+    UINT PacketType;
+    IP_PACKET IPPacket;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)BindingContext;
+    PETH_HEADER EHeader  = (PETH_HEADER)HeaderBuffer;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    if ((Adapter->State != LAN_STATE_STARTED) ||
+        HeaderBufferSize < Adapter->HeaderSize)
+        /* Adapter is not started or the header was too small */
+        return NDIS_STATUS_NOT_ACCEPTED;
+
+    if (Adapter->Media == NdisMedium802_3) {
+        /* Ethernet and IEEE 802.3 frames can be destinguished by
+           looking at the IEEE 802.3 length field. This field is
+           less than or equal to 1500 for a valid IEEE 802.3 frame
+           and larger than 1500 is it's a valid Ether-Type value.
+           See RFC 1122, section 2.3.3 for more information */
+        if (((EType = EHeader->EType) != ETYPE_IPv4) && (EType != ETYPE_ARP))
+            return NDIS_STATUS_NOT_ACCEPTED;
+        /* We use Ether-Type constants to destinguish packets */
+        PacketType = EType;
+    } else
+        /* FIXME: Support other medias */
+        return NDIS_STATUS_NOT_ACCEPTED;
+
+    if (LookaheadBufferSize < PacketSize) {
+        NDIS_STATUS NdisStatus;
+        PNDIS_PACKET NdisPacket;
+        UINT BytesTransferred;
+        
+        /* Get transfer data packet */
+
+        KeAcquireSpinLockAtDpcLevel(&Adapter->Lock);
+
+        NdisPacket = Adapter->TDPackets;
+        if (NdisPacket == (PNDIS_PACKET)NULL) {
+            /* We don't have a free packet descriptor. Drop the packet */
+            KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+            return NDIS_STATUS_SUCCESS;
+        }
+        Adapter->TDPackets = PC(NdisPacket)->Context;
+
+        KeReleaseSpinLockFromDpcLevel(&Adapter->Lock);
+
+        /* Get the data */
+        NdisTransferData(&NdisStatus, Adapter->NdisHandle,
+            MacReceiveContext, 0, PacketSize,
+            NdisPacket, &BytesTransferred);
+        if (NdisStatus != NDIS_STATUS_PENDING)
+            ProtocolTransferDataComplete(BindingContext,
+                NdisPacket, NdisStatus, BytesTransferred);
+
+        return NDIS_STATUS_SUCCESS;
+    }
+
+    /* We got all the data in the lookahead buffer */
+    RtlZeroMemory(&IPPacket, sizeof(IPPacket));
+    IPPacket.Header    = LookaheadBuffer;
+    IPPacket.TotalSize = PacketSize;
+
+    switch (PacketType) {
+        case ETYPE_IPv4:
+        case ETYPE_IPv6:
+            IPReceive(Adapter->Context, &IPPacket);
+            break;
+        case ETYPE_ARP:
+            ARPReceive(Adapter->Context, &IPPacket);
+            break;
+        default:
+            break;
+    }
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID ProtocolReceiveComplete(
+    NDIS_HANDLE BindingContext)
+/*
+ * FUNCTION: Called by NDIS when we're done receiving data
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID ProtocolStatus(
+    NDIS_HANDLE BindingContext,
+    NDIS_STATUS GenerelStatus,
+    PVOID StatusBuffer,
+    UINT StatusBufferSize)
+/*
+ * FUNCTION: Called by NDIS when the underlying driver has changed state
+ * ARGUMENTS:
+ *     BindingContext   = Pointer to a device context (LAN_ADAPTER)
+ *     GenerelStatus    = A generel status code
+ *     StatusBuffer     = Pointer to a buffer with medium-specific data
+ *     StatusBufferSize = Number of bytes in StatusBuffer
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID ProtocolStatusComplete(
+    NDIS_HANDLE NdisBindingContext)
+/*
+ * FUNCTION: Called by NDIS when a status-change has occurred
+ * ARGUMENTS:
+ *     BindingContext = Pointer to a device context (LAN_ADAPTER)
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+}
+
+
+VOID LANTransmit(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    UINT Offset,
+    PVOID LinkAddress,
+    USHORT Type)
+/*
+ * FUNCTION: Transmits a packet
+ * ARGUMENTS:
+ *     Context     = Pointer to context information (LAN_ADAPTER)
+ *     NdisPacket  = Pointer to NDIS packet to send
+ *     Offset      = Offset in packet where data starts
+ *     LinkAddress = Pointer to link address of destination (NULL = broadcast)
+ *     Type        = LAN protocol type (LAN_PROTO_*)
+ */
+{
+    NDIS_STATUS NdisStatus;
+    PETH_HEADER EHeader;
+    PVOID Data;
+    PLAN_ADAPTER Adapter = (PLAN_ADAPTER)Context;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* NDIS send routines don't have an offset argument so we
+       must offset the data in upper layers and adjust the
+       packet here. We save the offset in the packet context
+       area so it can be undone before we release the packet */
+    Data = AdjustPacket(NdisPacket, Offset, Adapter->HeaderSize);
+    PC(NdisPacket)->DLOffset = Offset;
+
+    if (Adapter->State == LAN_STATE_STARTED) {
+        switch (Adapter->Media) {
+        case NdisMedium802_3:
+            EHeader = (PETH_HEADER)Data;
+    
+            if (LinkAddress)
+                /* Unicast address */
+                RtlCopyMemory(EHeader->DstAddr, LinkAddress, IEEE_802_ADDR_LENGTH);
+             else
+                /* Broadcast address */
+                RtlFillMemory(EHeader->DstAddr, IEEE_802_ADDR_LENGTH, 0xFF);
+
+            RtlCopyMemory(EHeader->SrcAddr, Adapter->HWAddress, IEEE_802_ADDR_LENGTH);
+
+            switch (Type) {
+                case LAN_PROTO_IPv4:
+                    EHeader->EType = ETYPE_IPv4;
+                    break;
+                case LAN_PROTO_ARP:
+                    EHeader->EType = ETYPE_ARP;
+                    break;
+                case LAN_PROTO_IPv6:
+                    EHeader->EType = ETYPE_IPv6;
+                    break;
+                default:
+#if DBG
+                    /* Should not happen */
+                    TI_DbgPrint(MIN_TRACE, ("Unknown LAN protocol.\n"));
+
+                    ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_FAILURE);
+#endif
+                    return;
+            }
+            break;
+
+        default:
+            /* FIXME: Support other medias */
+            break;
+        }
+       
+        NdisSend(&NdisStatus, Adapter->NdisHandle, NdisPacket);
+        if (NdisStatus != NDIS_STATUS_PENDING)
+            ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NdisStatus);
+    } else
+        ProtocolSendComplete((NDIS_HANDLE)Context, NdisPacket, NDIS_STATUS_CLOSED);
+}
+
+
+VOID BindAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Binds a LAN adapter to IP layer
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure
+ * NOTES:
+ *    We set the lookahead buffer size, set the packet filter and
+ *    bind the adapter to IP layer
+ */
+{
+    INT i;
+    PIP_INTERFACE IF;
+    PIP_ADDRESS Address;
+    PNDIS_PACKET Packet;
+    NDIS_STATUS NdisStatus;
+    LLIP_BIND_INFO BindInfo;
+    ULONG Lookahead = LOOKAHEAD_SIZE;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Adapter->State = LAN_STATE_OPENING;
+
+    NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,
+        OID_GEN_CURRENT_LOOKAHEAD, &Lookahead, sizeof(ULONG));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MID_TRACE, ("Could not set lookahead buffer size (0x%X).\n", NdisStatus));
+        return;
+    }
+
+    /* Allocate packets for NdisTransferData */
+    /* FIXME: How many should we allocate? */
+    Adapter->TDPackets = NULL;
+    for (i = 0; i < 2; i++) {
+        Packet              = AllocateTDPacket(Adapter);
+        PC(Packet)->Context = Adapter->TDPackets;
+        Adapter->TDPackets  = Packet;
+        if (!Packet) {
+            TI_DbgPrint(MID_TRACE, ("Could not allocate transfer data packet (out of resources).\n"));
+            FreeTDPackets(Adapter);
+            return;
+        }
+    }
+
+    /* Bind the adapter to IP layer */
+    BindInfo.Context       = Adapter;
+    BindInfo.HeaderSize    = Adapter->HeaderSize;
+    BindInfo.MinFrameSize  = Adapter->MinFrameSize;
+    BindInfo.MTU           = Adapter->MTU;
+    BindInfo.Address       = (PUCHAR)&Adapter->HWAddress;
+    BindInfo.AddressLength = Adapter->HWAddressLength;
+    BindInfo.Transmit      = LANTransmit;
+
+    IF = IPCreateInterface(&BindInfo);
+    if (!IF) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        FreeTDPackets(Adapter);
+        return;
+    }
+
+    /* FIXME: Get address from registry.
+       For now just use a private address, eg. 10.0.0.10 */
+    Address = AddrBuildIPv4(0x0A00000A);
+    if (!Address) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        FreeTDPackets(Adapter);
+        IPDestroyInterface(Adapter->Context);
+        return;
+    }
+    /* Create a net table entry for this interface */
+    if (!IPCreateNTE(IF, Address, 8)) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        FreeTDPackets(Adapter);
+        IPDestroyInterface(IF);
+        return;
+    }
+
+    /* Reference the interface for the NTE. The reference for
+       the address is just passed on to the NTE */
+    ReferenceObject(IF);
+
+    /* Register interface with IP layer */
+    IPRegisterInterface(IF);
+
+    /* Set packet filter so we can send and receive packets */
+    NdisStatus = NDISCall(Adapter, NdisRequestSetInformation,
+        OID_GEN_CURRENT_PACKET_FILTER, &Adapter->PacketFilter, sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MID_TRACE, ("Could not set packet filter (0x%X).\n", NdisStatus));
+        FreeTDPackets(Adapter);
+        IPDestroyInterface(IF);
+        return;
+    }
+
+    Adapter->Context = IF;
+
+    Adapter->State = LAN_STATE_STARTED;
+}
+
+
+VOID UnbindAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unbinds a LAN adapter from IP layer
+ * ARGUMENTS:
+ *     Adapter = Pointer to LAN_ADAPTER structure
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    if (Adapter->State == LAN_STATE_STARTED) {
+        PIP_INTERFACE IF = Adapter->Context;
+
+        IPUnregisterInterface(IF);
+
+        IPDestroyInterface(IF);
+
+        /* Free transfer data packets */
+        FreeTDPackets(Adapter);
+    }
+}
+
+
+NDIS_STATUS LANRegisterAdapter(
+    PNDIS_STRING AdapterName,
+    PLAN_ADAPTER *Adapter)
+/*
+ * FUNCTION: Registers protocol with an NDIS adapter
+ * ARGUMENTS:
+ *     AdapterName = Pointer to string with name of adapter to register
+ *     Adapter     = Address of pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PLAN_ADAPTER IF;
+    NDIS_STATUS NdisStatus;
+    NDIS_STATUS OpenStatus;
+    UINT MediaIndex;
+    NDIS_MEDIUM MediaArray[MAX_MEDIA];
+    UINT AddressOID;
+    UINT Speed;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    IF = ExAllocatePool(NonPagedPool, sizeof(LAN_ADAPTER));
+    if (!IF)
+        return NDIS_STATUS_RESOURCES;
+
+    RtlZeroMemory(IF, sizeof(LAN_ADAPTER));
+
+    /* Put adapter in stopped state */
+    IF->State = LAN_STATE_STOPPED;
+
+    /* Initialize protecting spin lock */
+    KeInitializeSpinLock(&IF->Lock);
+
+    KeInitializeEvent(&IF->Event, SynchronizationEvent, FALSE);
+
+    /* Initialize array with media IDs we support */
+    MediaArray[MEDIA_ETH] = NdisMedium802_3;
+
+    /* Open the adapter. */
+    NdisOpenAdapter(&NdisStatus, &OpenStatus, &IF->NdisHandle, &MediaIndex,
+        MediaArray, MAX_MEDIA, NdisProtocolHandle, IF, AdapterName, 0, NULL);
+
+    /* Wait until the adapter is opened */
+    if (NdisStatus == NDIS_STATUS_PENDING)
+        KeWaitForSingleObject(&IF->Event, UserRequest, KernelMode, FALSE, NULL);
+    else if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        ExFreePool(IF);
+        return NdisStatus;
+    }
+
+    IF->Media = MediaArray[MediaIndex];
+
+    /* Fill LAN_ADAPTER structure with some adapter specific information */
+    switch (IF->Media) {
+    case NdisMedium802_3:
+        IF->HWAddressLength = IEEE_802_ADDR_LENGTH;
+        IF->BCastMask       = BCAST_ETH_MASK;
+        IF->BCastCheck      = BCAST_ETH_CHECK;
+        IF->BCastOffset     = BCAST_ETH_OFFSET;
+        IF->HeaderSize      = sizeof(ETH_HEADER);
+        IF->MinFrameSize    = 60;
+        AddressOID          = OID_802_3_CURRENT_ADDRESS;
+        IF->PacketFilter    = 
+            NDIS_PACKET_TYPE_BROADCAST |
+            NDIS_PACKET_TYPE_DIRECTED  |
+            NDIS_PACKET_TYPE_MULTICAST;
+        break;
+
+    default:
+        /* Unsupported media */
+        TI_DbgPrint(MIN_TRACE, ("Unsupported media.\n"));
+        ExFreePool(IF);
+        return NDIS_STATUS_NOT_SUPPORTED;
+    }
+
+    /* Get maximum frame size */
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+        OID_GEN_MAXIMUM_FRAME_SIZE, &IF->MTU, sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        ExFreePool(IF);
+        return NdisStatus;
+    }
+
+    /* Get maximum packet size */
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+        OID_GEN_MAXIMUM_TOTAL_SIZE, &IF->MaxPacketSize, sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MIN_TRACE, ("Query for maximum packet size failed.\n"));
+        ExFreePool(IF);
+        return NdisStatus;
+    }
+
+    /* Get maximum number of packets we can pass to NdisSend(Packets) at one time */
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+        OID_GEN_MAXIMUM_SEND_PACKETS, &IF->MaxSendPackets, sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS)
+        /* Legacy NIC drivers may not support this query, if it fails we
+           assume it can send at least one packet per call to NdisSend(Packets) */
+        IF->MaxSendPackets = 1;
+
+    /* Get current hardware address */
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation, AddressOID,
+        IF->HWAddress, IF->HWAddressLength);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MIN_TRACE, ("Query for current hardware address failed.\n"));
+        ExFreePool(IF);
+        return NdisStatus;
+    }
+
+    /* Get maximum link speed */
+    NdisStatus = NDISCall(IF, NdisRequestQueryInformation,
+        OID_GEN_LINK_SPEED, &Speed, sizeof(UINT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MIN_TRACE, ("Query for maximum link speed failed.\n"));
+        ExFreePool(IF);
+        return NdisStatus;
+    }
+
+    /* Convert returned link speed to bps (it is in 100bps increments) */
+    IF->Speed = Speed * 100L;
+
+    *Adapter = IF;
+
+    /* Add adapter to the adapter list */
+    IF->Next = Adapters;
+    Adapters = IF;
+
+    /* Bind adapter to IP layer */
+    BindAdapter(IF);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS LANUnregisterAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unregisters protocol with NDIS adapter
+ * ARGUMENTS:
+ *     Adapter = Pointer to a LAN_ADAPTER structure
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    KIRQL OldIrql;
+    NDIS_HANDLE NdisHandle;
+    PLAN_ADAPTER IF, PrevIF;
+    BOOLEAN Found = FALSE;
+    NDIS_STATUS NdisStatus = NDIS_STATUS_SUCCESS;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Search the adapter list for the specified adapter and remove it */
+    IF = Adapters;
+    if (IF) {
+        if (Adapter != Adapters) {
+            PrevIF = IF;
+            while ((IF) && (!Found)) {
+                if (IF == Adapter) {
+                    /* We've found the adapter, now remove it from the list */
+                    PrevIF->Next = IF->Next;
+                    Found = TRUE;
+                }
+                PrevIF = IF;
+                IF = IF->Next;
+            }
+        } else {
+            Adapters = NULL;
+            Found    = TRUE;
+        }
+    }
+    if (!Found) {
+        TI_DbgPrint(MIN_TRACE, ("Leaving (adapter was not in list).\n"));
+        return NDIS_STATUS_ADAPTER_NOT_FOUND;
+    }
+
+    /* Unbind adapter from IP layer */
+    UnbindAdapter(Adapter);
+
+    KeAcquireSpinLock(&Adapter->Lock, &OldIrql);
+    NdisHandle = Adapter->NdisHandle;
+    if (NdisHandle) {
+        Adapter->NdisHandle = NULL;
+        KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+        NdisCloseAdapter(&NdisStatus, NdisHandle);
+        if (NdisStatus == NDIS_STATUS_PENDING) {
+            KeWaitForSingleObject(&Adapter->Event,
+                UserRequest, KernelMode, FALSE, NULL);
+            NdisStatus = Adapter->NdisStatus;
+        }
+    } else
+        KeReleaseSpinLock(&Adapter->Lock, OldIrql);
+
+    FreeAdapter(Adapter);
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NTSTATUS LANRegisterProtocol(
+    PSTRING Name)
+/*
+ * FUNCTION: Registers this protocol driver with NDIS
+ * ARGUMENTS:
+ *     Name = Name of this protocol driver
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_STATUS NdisStatus;
+    NDIS_PROTOCOL_CHARACTERISTICS ProtChars;
+
+    /* Set up protocol characteristics */
+    RtlZeroMemory(&ProtChars, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));
+    ProtChars.MajorNdisVersion            = NDIS_VERSION_MAJOR;
+    ProtChars.MinorNdisVersion            = NDIS_VERSION_MINOR;
+    ProtChars.Name.Length                 = Name->Length;
+    ProtChars.Name.Buffer                 = (PVOID)Name->Buffer;
+    ProtChars.OpenAdapterCompleteHandler  = ProtocolOpenAdapterComplete;
+    ProtChars.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;
+    ProtChars.ResetCompleteHandler        = ProtocolResetComplete;
+    ProtChars.RequestCompleteHandler      = ProtocolRequestComplete;
+    ProtChars.SendCompleteHandler         = ProtocolSendComplete;
+    ProtChars.TransferDataCompleteHandler = ProtocolTransferDataComplete;
+    ProtChars.ReceiveHandler              = ProtocolReceive;
+    ProtChars.ReceiveCompleteHandler      = ProtocolReceiveComplete;
+    ProtChars.StatusHandler               = ProtocolStatus;
+    ProtChars.StatusCompleteHandler       = ProtocolStatusComplete;
+
+       /* Try to register protocol */
+    NdisRegisterProtocol(
+        &NdisStatus, &NdisProtocolHandle, &ProtChars,
+        sizeof(NDIS_PROTOCOL_CHARACTERISTICS) + Name->Length);
+    if (NdisStatus != NDIS_STATUS_SUCCESS)
+        return (NTSTATUS)NdisStatus;
+
+    ProtocolRegistered = TRUE;
+
+    return STATUS_SUCCESS;
+}
+
+
+VOID LANUnregisterProtocol(
+    VOID)
+/*
+ * FUNCTION: Unregisters this protocol driver with NDIS
+ * NOTES: Does not care wether we are already registered
+ */
+{
+    if (ProtocolRegistered) {
+        NDIS_STATUS NdisStatus;
+
+        while (Adapters)
+            NdisStatus = LANUnregisterAdapter(Adapters);
+
+        NdisDeregisterProtocol(&NdisStatus, NdisProtocolHandle);
+        ProtocolRegistered = FALSE;
+    }
+}
+
+/* EOF */
index d42e499..309f98d 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        datalink/loopback.c
+ * PURPOSE:     Loopback adapter
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <loopback.h>
+#include <ip.h>
+#include <address.h>
+#include <receive.h>
+#include <transmit.h>
+#include <routines.h>
+
+
+WORK_QUEUE_ITEM  LoopWorkItem;
+PIP_INTERFACE    Loopback = NULL;
+/* Indicates wether the loopback interface is currently transmitting */
+BOOLEAN          LoopBusy = FALSE;
+/* Loopback transmit queue */
+PNDIS_PACKET     LoopQueueHead = (PNDIS_PACKET)NULL;
+PNDIS_PACKET     LoopQueueTail = (PNDIS_PACKET)NULL;
+/* Spin lock for protecting loopback transmit queue */
+KSPIN_LOCK       LoopLock;
+
+
+VOID RealTransmit(
+    PVOID Context)
+/*
+ * FUNCTION: Transmits one or more packet(s) in loopback queue to ourselves
+ * ARGUMENTS:
+ *     Context = Pointer to context information (loopback interface)
+ */
+{
+    KIRQL OldIrql;
+    PNDIS_PACKET NdisPacket;
+    IP_PACKET IPPacket;
+    PNDIS_BUFFER Buffer;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+    KeAcquireSpinLockAtDpcLevel(&LoopLock);
+
+    for (;;) {
+        /* Get the next packet from the queue (if any) */
+        NdisPacket = LoopQueueHead;
+        if (!NdisPacket)
+            break;
+
+        LoopQueueHead = *(PNDIS_PACKET*)NdisPacket->MacReserved;
+
+        KeReleaseSpinLockFromDpcLevel(&LoopLock);
+
+        IPPacket.NdisPacket = NdisPacket;
+
+        NdisGetFirstBufferFromPacket(NdisPacket,
+                                    &Buffer,
+                                    &IPPacket.Header,
+                                    &IPPacket.ContigSize,
+                                    &IPPacket.TotalSize);
+
+        IPReceive(Context, &IPPacket);
+
+        AdjustPacket(NdisPacket, 0, PC(NdisPacket)->DLOffset);
+
+        PC(NdisPacket)->DLComplete(Context, NdisPacket, NDIS_STATUS_SUCCESS);
+
+        /* Lower IRQL for a moment to prevent starvation */
+        KeLowerIrql(OldIrql);
+
+        KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+        KeAcquireSpinLockAtDpcLevel(&LoopLock);
+    }
+
+    LoopBusy = FALSE;
+
+    KeReleaseSpinLockFromDpcLevel(&LoopLock);
+
+    KeLowerIrql(OldIrql);
+}
+
+
+VOID LoopTransmit(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    UINT Offset,
+    PVOID LinkAddress,
+    USHORT Type)
+/*
+ * FUNCTION: Transmits a packet
+ * ARGUMENTS:
+ *     Context     = Pointer to context information (NULL)
+ *     NdisPacket  = Pointer to NDIS packet to send
+ *     Offset      = Offset in packet where packet data starts
+ *     LinkAddress = Pointer to link address
+ *     Type        = LAN protocol type (unused)
+ */
+{
+    PNDIS_PACKET *pNdisPacket;
+    KIRQL OldIrql;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* NDIS send routines don't have an offset argument so we
+       must offset the data in upper layers and adjust the
+       packet here. We save the offset in the packet context
+       area so it can be undone before we release the packet */
+    AdjustPacket(NdisPacket, Offset, 0);
+    PC(NdisPacket)->DLOffset = Offset;
+
+    pNdisPacket  = (PNDIS_PACKET*)NdisPacket->MacReserved;
+    *pNdisPacket = NULL;
+
+    KeAcquireSpinLock(&LoopLock, &OldIrql);
+
+    /* Add packet to transmit queue */
+    if (LoopQueueHead) {
+        /* Transmit queue is not empty */
+        pNdisPacket  = (PNDIS_PACKET*)LoopQueueTail->MacReserved;
+        *pNdisPacket = NdisPacket;
+    } else
+        /* Transmit queue is empty */
+        LoopQueueHead = NdisPacket;
+
+    LoopQueueTail = NdisPacket;
+
+    /* If LoopTransmit is not running (or scheduled), schedule it to run */
+    if (!LoopBusy) {
+        ExQueueWorkItem(&LoopWorkItem, CriticalWorkQueue);
+        LoopBusy = TRUE;
+    }
+
+    KeReleaseSpinLock(&LoopLock, OldIrql);
+}
+
+
+NDIS_STATUS LoopRegisterAdapter(
+    PNDIS_STRING AdapterName,
+    PLAN_ADAPTER *Adapter)
+/*
+ * FUNCTION: Registers loopback adapter
+ * ARGUMENTS:
+ *     AdapterName = Unused
+ *     Adapter     = Unused
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIP_ADDRESS Address;
+    NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    Address = AddrBuildIPv4(LOOPBACK_ADDRESS_IPv4);
+    if (Address) {
+        LLIP_BIND_INFO BindInfo;
+
+        /* Bind the adapter to IP layer */
+        BindInfo.Context       = NULL;
+        BindInfo.HeaderSize    = 0;
+        BindInfo.MinFrameSize  = 0;
+        BindInfo.MTU           = 16384;
+        BindInfo.Address       = NULL;
+        BindInfo.AddressLength = 0;
+        BindInfo.Transmit      = LoopTransmit;
+
+        Loopback = IPCreateInterface(&BindInfo);
+        if ((Loopback) && (IPCreateNTE(Loopback, Address, 8))) {
+            /* Reference the interface for the NTE. The reference for
+               the address is just passed on to the NTE */
+            ReferenceObject(Loopback);
+
+            IPRegisterInterface(Loopback);
+
+            ExInitializeWorkItem(&LoopWorkItem, RealTransmit, Loopback);
+
+            KeInitializeSpinLock(&LoopLock);
+            LoopBusy = FALSE;
+        } else
+            Status = NDIS_STATUS_RESOURCES;
+    } else
+        Status = NDIS_STATUS_RESOURCES;
+
+    if (!NT_SUCCESS(Status))
+        LoopUnregisterAdapter(NULL);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return Status;
+}
+
+
+NDIS_STATUS LoopUnregisterAdapter(
+    PLAN_ADAPTER Adapter)
+/*
+ * FUNCTION: Unregisters loopback adapter
+ * ARGUMENTS:
+ *     Adapter = Unused
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     Does not care wether we have registered loopback adapter
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    if (Loopback) {
+        IPUnregisterInterface(Loopback);
+        IPDestroyInterface(Loopback);
+        Loopback = NULL;
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+/* EOF */
index aeb953d..c883591 100644 (file)
@@ -1,63 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/address.h
+ * PURPOSE:     Address manipulation prototypes
+ */
+#ifndef __ADDRESS_H
+#define __ADDRESS_H
+
+
+/*
+ * Initialize an IPv4 style address
+ * VOID AddrInitIPv4(
+ *     PIP_ADDRESS IPAddress,
+ *     IPv4_RAW_ADDRESS RawAddress)
+ */
+#define AddrInitIPv4(IPAddress, RawAddress)           \
+{                                                     \
+    (IPAddress)->RefCount            = 1;             \
+    (IPAddress)->Type                = IP_ADDRESS_V4; \
+    (IPAddress)->Address.IPv4Address = (RawAddress);  \
+}
+
+
+BOOLEAN AddrIsUnspecified(
+    PIP_ADDRESS Address);
+
+NTSTATUS AddrGetAddress(
+    PTRANSPORT_ADDRESS AddrList,
+    PIP_ADDRESS *Address,
+    PUSHORT Port,
+    PIP_ADDRESS *Cache);
+
+BOOLEAN AddrIsEqual(
+    PIP_ADDRESS Address1,
+    PIP_ADDRESS Address2);
+
+INT AddrCompare(
+    PIP_ADDRESS Address1,
+    PIP_ADDRESS Address2);
+
+BOOLEAN AddrIsEqualIPv4(
+    PIP_ADDRESS Address1,
+    IPv4_RAW_ADDRESS Address2);
+
+PIP_ADDRESS AddrBuildIPv4(
+    IPv4_RAW_ADDRESS Address);
+
+PADDRESS_ENTRY AddrLocateADEv4(
+    IPv4_RAW_ADDRESS Address);
+
+PADDRESS_FILE AddrSearchFirst(
+    PIP_ADDRESS Address,
+    USHORT Port,
+    USHORT Protocol,
+    PAF_SEARCH SearchContext);
+
+PADDRESS_FILE AddrSearchNext(
+    PAF_SEARCH SearchContext);
+
+#endif /* __ADDRESS_H */
+
+/* EOF */
index b33ad14..bd1c6bf 100644 (file)
@@ -1,37 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/arp.h
+ * PURPOSE:     Address Resolution Protocol definitions
+ */
+#ifndef __ARP_H
+#define __ARP_H
+
+typedef struct ARP_HEADER {
+    USHORT HWType;       /* Hardware Type */
+    USHORT ProtoType;    /* Protocol Type */
+    UCHAR  HWAddrLen;    /* Hardware Address Length */
+    UCHAR  ProtoAddrLen; /* Protocol Address Length */
+    USHORT Opcode;       /* Opcode */
+    /* Sender's Hardware Address */
+    /* Sender's Protocol Address */
+    /* Target's Hardware Address */
+    /* Target's Protocol Address */
+} ARP_HEADER, *PARP_HEADER;
+
+/* We swap constants so we can compare values at runtime without swapping them */
+#define ARP_OPCODE_REQUEST WH2N(0x0001) /* ARP request */
+#define ARP_OPCODE_REPLY   WH2N(0x0002) /* ARP reply */
+
+
+BOOLEAN ARPTransmit(
+    PIP_ADDRESS Address,
+    PNET_TABLE_ENTRY NTE);
+
+VOID ARPReceive(
+    PVOID Context,
+    PIP_PACKET Packet);
+
+#endif /* __ARP_H */
+
+/* EOF */
index 5805b51..e23c0a5 100644 (file)
@@ -1,27 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/checksum.h
+ * PURPOSE:     Checksum routine definitions
+ */
+#ifndef __CHECKSUM_H
+#define __CHECKSUM_H
+
+
+ULONG ChecksumCompute(
+    PVOID Data,
+    UINT Count,
+    ULONG Seed);
+
+#define IPv4Checksum(Data, Count, Seed)(ChecksumCompute(Data, Count, Seed))
+
+/*
+ * Macro to check for a correct checksum
+ * BOOLEAN CorrectChecksum(PVOID Data, UINT Count)
+ */
+#define CorrectChecksum(Data, Count) \
+    (BOOLEAN)(IPv4Checksum(Data, Count, 0) == DH2N(0x0000FFFF))
+
+#endif /* __CHECKSUM_H */
+
+/* EOF */
index 3dd3a79..9dc7e65 100644 (file)
@@ -1,49 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/datagram.h
+ * PURPOSE:     Datagram types and constants
+ */
+#ifndef __DATAGRAM_H
+#define __DATAGRAM_H
+
+#include <titypes.h>
+
+
+VOID DGSend(
+    PVOID Context,
+    PDATAGRAM_SEND_REQUEST SendRequest);
+
+VOID DGCancelSendRequest(
+    PADDRESS_FILE AddrFile,
+    PVOID Context);
+
+VOID DGCancelReceiveRequest(
+    PADDRESS_FILE AddrFile,
+    PVOID Context);
+
+NTSTATUS DGSendDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize,
+    DATAGRAM_BUILD_ROUTINE Build);
+
+NTSTATUS DGReceiveDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG ReceiveLength,
+    ULONG ReceiveFlags,
+    PTDI_CONNECTION_INFORMATION ReturnInfo,
+    PULONG BytesReceived);
+
+NTSTATUS DGStartup(
+    VOID);
+
+NTSTATUS DGShutdown(
+    VOID);
+
+#endif /* __DATAGRAM_H */
+
+/* EOF */
index a296d5f..b86b620 100644 (file)
@@ -1,99 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/debug.h
+ * PURPOSE:     Debugging support macros
+ * DEFINES:     DBG     - Enable debug output
+ *              NASSERT - Disable assertions
+ */
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#define NORMAL_MASK    0x000000FF
+#define SPECIAL_MASK   0xFFFFFF00
+#define MIN_TRACE      0x00000001
+#define MID_TRACE      0x00000002
+#define MAX_TRACE      0x00000003
+
+#define DEBUG_MEMORY   0x00000100
+#define DEBUG_BUFFER   0x00000200
+#define DEBUG_IRP      0x00000400
+#define DEBUG_REFCOUNT 0x00000800
+#define DEBUG_ADDRFILE 0x00001000
+#define DEBUG_IP       0x00002000
+#define DEBUG_ROUTER   0x00004000
+#define DEBUG_RCACHE   0x00008000
+#define DEBUG_NCACHE   0x00010000
+#define DEBUG_ULTRA    0xFFFFFFFF
+
+#ifdef DBG
+
+extern DWORD DebugTraceLevel;
+
+#ifdef _MSC_VER
+
+#define TI_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d) ", __FILE__, __LINE__); \
+        DbgPrint _x_ ; \
+    }
+
+#else /* _MSC_VER */
+
+#define TI_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
+        DbgPrint _x_ ; \
+    }
+
+#endif /* _MSC_VER */
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef NASSERT
+#define ASSERT(x)
+#else /* NASSERT */
+#define ASSERT(x) if (!(x)) { TI_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); }
+#endif /* NASSERT */
+
+#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x))
+
+#else /* DBG */
+
+#define TI_DbgPrint(_t_, _x_)
+
+#define ASSERT_IRQL(x)
+#define ASSERT(x)
+
+#endif /* DBG */
+
+
+#define assert(x) ASSERT(x)
+#define assert_irql(x) ASSERT_IRQL(x)
+
+
+#ifdef _MSC_VER
+
+#define UNIMPLEMENTED \
+    TI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \
+        but come back another day.\n", __FILE__, __LINE__));
+
+#else /* _MSC_VER */
+
+#define UNIMPLEMENTED \
+    TI_DbgPrint(MIN_TRACE, ("(%s:%d)(%s) is unimplemented, \
+        but come back another day.\n", __FILE__, __LINE__, __FUNCTION__));
+
+#endif /* _MSC_VER */
+
+
+#define CHECKPOINT \
+    do { TI_DbgPrint(MIN_TRACE, ("(%s:%d)\n", __FILE__, __LINE__)); } while(0);
+
+#endif /* __DEBUG_H */
+
+/* EOF */
index 9f70485..5108ff5 100644 (file)
@@ -1,61 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/dispatch.h
+ * PURPOSE:     Dispatch routine prototypes
+ */
+#ifndef __DISPATCH_H
+#define __DISPATCH_H
+
+
+NTSTATUS DispTdiAccept(
+    PIRP Irp);
+
+NTSTATUS DispTdiAssociateAddress(
+    PIRP Irp);
+
+NTSTATUS DispTdiConnect(
+    PIRP Irp);
+
+NTSTATUS DispTdiDisassociateAddress(
+    PIRP Irp);
+
+NTSTATUS DispTdiDisconnect(
+    PIRP Irp);
+
+NTSTATUS DispTdiListen(
+    PIRP Irp);
+
+NTSTATUS DispTdiQueryInformation(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp);
+
+NTSTATUS DispTdiReceive(
+    PIRP Irp);
+
+NTSTATUS DispTdiReceiveDatagram(
+    PIRP Irp);
+
+NTSTATUS DispTdiSend(
+    PIRP Irp);
+
+NTSTATUS DispTdiSendDatagram(
+    PIRP Irp);
+
+NTSTATUS DispTdiSetEventHandler(
+    PIRP Irp);
+
+NTSTATUS DispTdiSetInformation(
+    PIRP Irp);
+
+NTSTATUS DispTdiQueryInformationEx(
+    PIRP Irp,
+    PIO_STACK_LOCATION IrpSp);
+
+NTSTATUS DispTdiSetInformationEx(
+    PIRP Irp,
+    PIO_STACK_LOCATION IrpSp);
+
+#endif /* __DISPATCH_H */
+
+/* EOF */
index e69e5fe..caef8e8 100644 (file)
@@ -1,32 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/fileobjs.h
+ * PURPOSE:     File object routine prototypes
+ */
+#ifndef __FILEOBJS_H
+#define __FILEOBJS_H
+
+
+extern LIST_ENTRY AddressFileListHead;
+extern KSPIN_LOCK AddressFileListLock;
+
+
+NTSTATUS FileOpenAddress(
+    PTDI_REQUEST Request,
+    PTA_ADDRESS_IP AddrList,
+    USHORT Protocol,
+    PVOID Options);
+
+NTSTATUS FileCloseAddress(
+    PTDI_REQUEST Request);
+
+NTSTATUS FileCloseConnection(
+    PTDI_REQUEST Request);
+
+NTSTATUS FileCloseControlChannel(
+    PTDI_REQUEST Request);
+
+#endif /* __FILEOBJS_H */
+
+/* EOF */
index 225e62d..10bd22c 100644 (file)
@@ -1,68 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/icmp.h
+ * PURPOSE:     Internet Control Message Protocol definitions
+ */
+#ifndef __ICMP_H
+#define __ICMP_H
+
+typedef struct ICMP_HEADER {
+    UCHAR Type;      /* ICMP message type */
+    UCHAR Code;      /* ICMP message code */
+    USHORT Checksum; /* ICMP message checksum */
+    ULONG Unused;    /* ICMP unused */
+} ICMP_HEADER, *PICMP_HEADER;
+
+/* ICMP message types */
+#define ICMP_TYPE_ECHO_REPLY        0  /* Echo reply */
+#define ICMP_TYPE_DEST_UNREACH      3  /* Destination unreachable */
+#define ICMP_TYPE_SOURCE_QUENCH     4  /* Source quench */
+#define ICMP_TYPE_REDIRECT          5  /* Redirect */
+#define ICMP_TYPE_ECHO_REQUEST      8  /* Echo request */
+#define ICMP_TYPE_TIME_EXCEEDED     11 /* Time exceeded */
+#define ICMP_TYPE_PARAMETER         12 /* Parameter problem */
+#define ICMP_TYPE_TIMESTAMP_REQUEST 13 /* Timestamp request */
+#define ICMP_TYPE_TIMESTAMP_REPLY   14 /* Timestamp reply */
+#define ICMP_TYPE_INFO_REQUEST      15 /* Information request */
+#define ICMP_TYPE_INFO_REPLY        16 /* Information reply */
+
+/* ICMP codes for ICMP_TYPE_DEST_UNREACH */
+#define ICMP_CODE_DU_NET_UNREACH         0 /* Network unreachable */
+#define ICMP_CODE_DU_HOST_UNREACH        1 /* Host unreachable */
+#define ICMP_CODE_DU_PROTOCOL_UNREACH    2 /* Protocol unreachable */
+#define ICMP_CODE_DU_PORT_UNREACH        3 /* Port unreachable */
+#define ICMP_CODE_DU_FRAG_DF_SET         4 /* Fragmentation needed and DF set */
+#define ICMP_CODE_DU_SOURCE_ROUTE_FAILED 5 /* Source route failed */
+
+/* ICMP codes for ICMP_TYPE_REDIRECT */
+#define ICMP_CODE_RD_NET      0 /* Redirect datagrams for the network */
+#define ICMP_CODE_RD_HOST     1 /* Redirect datagrams for the host */
+#define ICMP_CODE_RD_TOS_NET  2 /* Redirect datagrams for the Type of Service and network */
+#define ICMP_CODE_RD_TOS_HOST 3 /* Redirect datagrams for the Type of Service and host */
+
+/* ICMP codes for ICMP_TYPE_TIME_EXCEEDED */
+#define ICMP_CODE_TE_TTL        0 /* Time to live exceeded in transit */
+#define ICMP_CODE_TE_REASSEMBLY 1 /* Fragment reassembly time exceeded */
+
+/* ICMP codes for ICMP_TYPE_PARAMETER */
+#define ICMP_CODE_TP_POINTER 1 /* Pointer indicates the error */
+
+
+VOID ICMPReceive(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket);
+
+VOID ICMPTransmit(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket);
+
+VOID ICMPReply(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket,
+       UCHAR Type,
+       UCHAR Code);
+
+#endif /* __ICMP_H */
+
+/* EOF */
index 1fd37d6..a1b4f67 100644 (file)
@@ -1,93 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/info.h
+ * PURPOSE:     TdiQueryInformation definitions
+ */
+#ifndef __INFO_H
+#define __INFO_H
+
+
+typedef struct IPSNMP_INFO {
+       ULONG Forwarding;
+       ULONG DefaultTTL;
+       ULONG InReceives;
+       ULONG InHdrErrors;
+       ULONG InAddrErrors;
+       ULONG ForwDatagrams;
+       ULONG InUnknownProtos;
+       ULONG InDiscards;
+       ULONG InDelivers;
+       ULONG OutRequests;
+       ULONG RoutingDiscards;
+       ULONG OutDiscards;
+       ULONG OutNoRoutes;
+       ULONG ReasmTimeout;
+       ULONG ReasmReqds;
+       ULONG ReasmOks;
+       ULONG ReasmFails;
+       ULONG FragOks;
+       ULONG FragFails;
+       ULONG FragCreates;
+       ULONG NumIf;
+       ULONG NumAddr;
+       ULONG NumRoutes;
+} IPSNMP_INFO, *PIPSNMP_INFO;
+
+typedef struct IPADDR_ENTRY {
+       ULONG  Addr;
+       ULONG  Index;
+       ULONG  Mask;
+       ULONG  BcastAddr;
+       ULONG  ReasmSize;
+       USHORT Context;
+       USHORT Pad;
+} IPADDR_ENTRY, *PIPADDR_ENTRY;
+
+#define        IP_MIB_STATS_ID           1
+#define        IP_MIB_ADDRTABLE_ENTRY_ID 0x102
+
+#define        MAX_PHYSADDR_SIZE 8
+
+
+/* Only UDP is supported */
+#define TDI_SERVICE_FLAGS (TDI_SERVICE_CONNECTIONLESS_MODE | \
+                           TDI_SERVICE_BROADCAST_SUPPORTED)
+
+#define TCP_MIB_STAT_ID     1
+#define UDP_MIB_STAT_ID     1
+#define TCP_MIB_TABLE_ID    0x101
+#define UDP_MIB_TABLE_ID    0x101
+
+#define TL_INSTANCE 0
+
+
+typedef struct ADDRESS_INFO {
+    ULONG LocalAddress;
+    ULONG LocalPort;
+} ADDRESS_INFO, *PADDRESS_INFO;
+
+typedef union TDI_INFO {
+    TDI_CONNECTION_INFO ConnInfo;
+    TDI_ADDRESS_INFO AddrInfo;
+    TDI_PROVIDER_INFO ProviderInfo;
+    TDI_PROVIDER_STATISTICS ProviderStats;
+} TDI_INFO, *PTDI_INFO;
+
+
+TDI_STATUS InfoTdiQueryInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PNDIS_BUFFER Buffer,
+    PUINT BufferSize,
+    PVOID Context);
+
+TDI_STATUS InfoTdiSetInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PVOID Buffer,
+    UINT BufferSize);
+
+#endif /* __INFO_H */
+
+/* EOF */
index 4cbcd19..3ee693a 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/ip.h
+ * PURPOSE:     Internet Protocol related definitions
+ */
+#ifndef __IP_H
+#define __IP_H
+
+/* Raw IPv4 style address */
+typedef ULONG IPv4_RAW_ADDRESS;
+typedef IPv4_RAW_ADDRESS *PIPv4_RAW_ADDRESS;
+
+/* Raw IPv6 style address */
+typedef USHORT IPv6_RAW_ADDRESS[8];
+typedef IPv6_RAW_ADDRESS *PIPv6_RAW_ADDRESS;
+
+/* IP style address */
+typedef struct IP_ADDRESS {
+    ULONG RefCount;                     /* Number of references to this address */
+    UCHAR Type;                         /* Type of IP address */
+    union {
+        IPv4_RAW_ADDRESS IPv4Address;   /* IPv4 address */
+        PIPv6_RAW_ADDRESS IPv6Address;  /* IPv6 address */
+    } Address;
+} IP_ADDRESS, *PIP_ADDRESS;
+
+/* IP type constants */
+#define IP_ADDRESS_V4   0x00 /* IPv4 style address */
+#define IP_ADDRESS_V6   0x01 /* IPv6 style address */
+
+
+/* IPv4 header format */
+typedef struct IPv4_HEADER {
+    UCHAR VerIHL;                /* 4-bit version, 4-bit Internet Header Length */
+    UCHAR Tos;                   /* Type of Service */
+    USHORT TotalLength;          /* Total Length */
+    USHORT Id;                   /* Identification */
+    USHORT FlagsFragOfs;         /* 3-bit Flags, 13-bit Fragment Offset */
+    UCHAR Ttl;                   /* Time to Live */
+    UCHAR Protocol;              /* Protocol */
+    USHORT Checksum;             /* Header Checksum */
+    IPv4_RAW_ADDRESS SrcAddr;    /* Source Address */
+    IPv4_RAW_ADDRESS DstAddr;    /* Destination Address */
+} IPv4_HEADER, *PIPv4_HEADER;
+
+#define IPv4_FRAGOFS_MASK       0x1FFF
+#define IPv4_MF_MASK            0x2000
+#define IPv4_MAX_HEADER_SIZE    60
+
+/* Packet completion handler prototype */
+typedef VOID (*PACKET_COMPLETION_ROUTINE)(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    NDIS_STATUS NdisStatus);
+
+/* Structure for an IP packet */
+typedef struct IP_PACKET {
+    ULONG RefCount;                     /* Reference count for this object */
+    UCHAR Type;                         /* Type of IP packet (see IP_ADDRESS_xx above) */
+    PVOID Header;                       /* Pointer to IP header for this packet */
+    UINT HeaderSize;                    /* Size of IP header */
+    PVOID Data;                         /* Current pointer into packet data */
+    UINT TotalSize;                     /* Total amount of data in packet (IP header and data) */
+    UINT ContigSize;                    /* Number of contiguous bytes left in current buffer */
+    UINT Position;                      /* Current logical offset into packet */
+    PNDIS_PACKET NdisPacket;            /* Pointer to NDIS packet */
+    IP_ADDRESS SrcAddr;                 /* Source address */
+    IP_ADDRESS DstAddr;                 /* Destination address */
+} IP_PACKET, *PIP_PACKET;
+
+/* Packet context */
+typedef struct PACKET_CONTEXT {
+    PACKET_COMPLETION_ROUTINE Complete;   /* Transport level completion handler */
+    PVOID Context;                        /* Context information for handler */
+    PACKET_COMPLETION_ROUTINE DLComplete; /* Data link level completion handler. Also
+                                             used to link to next packet in a queue */
+    UINT DLOffset;                        /* Offset where data (IP header) starts */
+} PACKET_CONTEXT, *PPACKET_CONTEXT;
+
+/* The ProtocolReserved field is structured as a PACKET_CONTEXT */
+#define PC(Packet) ((PPACKET_CONTEXT)(&Packet->ProtocolReserved))
+
+
+/* Address information a.k.a ADE */
+typedef struct _ADDRESS_ENTRY {
+    LIST_ENTRY              ListEntry;  /* Entry on list */
+    ULONG                   RefCount;   /* Reference count */
+    struct _NET_TABLE_ENTRY *NTE;       /* NTE associated with this address */
+    UCHAR                   Type;       /* Address type */
+    PIP_ADDRESS             Address;    /* Pointer to address identifying this entry */
+} ADDRESS_ENTRY, *PADDRESS_ENTRY;
+
+/* Values for address type */
+#define ADE_UNICAST   0x01
+#define ADE_MULTICAST 0x02
+#define ADE_ADDRMASK  0x03
+
+/* There is one NTE for each source (unicast) address assigned to an interface */
+typedef struct _NET_TABLE_ENTRY {
+    LIST_ENTRY                 IFListEntry; /* Entry on interface list */
+    LIST_ENTRY                 NTListEntry; /* Entry on net table list */
+    struct _IP_INTERFACE       *Interface;  /* Pointer to interface on this net */
+    struct _PREFIX_LIST_ENTRY  *PLE;        /* Pointer to prefix list entry for this net */
+    ULONG                      RefCount;    /* Reference count */
+    PIP_ADDRESS                Address;     /* Pointer to unicast address for this net */
+} NET_TABLE_ENTRY, *PNET_TABLE_ENTRY;
+
+
+/* Link layer transmit prototype */
+typedef VOID (*LL_TRANSMIT_ROUTINE)(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    UINT Offset,
+    PVOID LinkAddress,
+    USHORT Type);
+
+/* Link layer to IP binding information */
+typedef struct _LLIP_BIND_INFO {
+    PVOID Context;                /* Pointer to link layer context information */
+    UINT  HeaderSize;             /* Size of link level header */
+    UINT  MinFrameSize;           /* Minimum frame size in bytes */
+    UINT  MTU;                    /* Maximum transmission unit */
+    PUCHAR Address;               /* Pointer to interface address */
+    UINT  AddressLength;          /* Length of address in bytes */
+    LL_TRANSMIT_ROUTINE Transmit; /* Transmit function for this interface */
+} LLIP_BIND_INFO, *PLLIP_BIND_INFO;
+
+
+/* Information about an IP interface */
+typedef struct _IP_INTERFACE {
+    LIST_ENTRY ListEntry;         /* Entry on list */
+    ULONG RefCount;               /* Reference count */
+    KSPIN_LOCK Lock;              /* Spin lock for this object */
+    LIST_ENTRY NTEListHead;       /* List of NTEs on this interface */
+    LIST_ENTRY ADEListHead;       /* List of ADEs on this interface */
+    PVOID Context;                /* Pointer to link layer context information */
+    UINT  HeaderSize;             /* Size of link level header */
+    UINT  MinFrameSize;           /* Minimum frame size in bytes */
+    UINT  MTU;                    /* Maximum transmission unit */
+    PUCHAR Address;               /* Pointer to interface address */
+    UINT  AddressLength;          /* Length of address in bytes */
+    LL_TRANSMIT_ROUTINE Transmit; /* Pointer to transmit function */
+} IP_INTERFACE, *PIP_INTERFACE;
+
+
+/* Prefix List Entry */
+typedef struct _PREFIX_LIST_ENTRY {
+    LIST_ENTRY ListEntry;    /* Entry on list */
+    ULONG RefCount;          /* Reference count */
+    PIP_INTERFACE Interface; /* Pointer to interface */
+    PIP_ADDRESS Prefix;      /* Pointer to prefix */
+    UINT PrefixLength;       /* Length of prefix */
+} PREFIX_LIST_ENTRY, *PPREFIX_LIST_ENTRY;
+
+
+#define IP_PROTOCOL_TABLE_SIZE 0x100
+
+typedef VOID (*IP_PROTOCOL_HANDLER)(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket);
+
+/* Loopback adapter address information (network byte order) */
+#define LOOPBACK_ADDRESS_IPv4   ((IPv4_RAW_ADDRESS)DH2N(0x7F000001)) 
+#define LOOPBACK_BCASTADDR_IPv4 ((IPv4_RAW_ADDRESS)DH2N(0x7F0000FF))
+#define LOOPBACK_ADDRMASK_IPv4  ((IPv4_RAW_ADDRESS)DH2N(0xFFFFFF00))
+
+/* Protocol definitions */
+#define IPPROTO_ICMP    1   /* Internet Control Message Protocol */
+#define IPPROTO_IGMP    2   /* Internet Group Management Protocol */
+#define IPPROTO_TCP     6   /* Transmission Control Protocol */
+#define IPPROTO_UDP     17  /* User Datagram Protocol */
+
+/* Timeout timer constants */
+#define IP_TICKS_SECOND 2                   /* Two ticks per second */
+#define IP_TIMEOUT (1000 / IP_TICKS_SECOND) /* Timeout in milliseconds */
+
+
+extern LIST_ENTRY InterfaceListHead;
+extern KSPIN_LOCK InterfaceListLock;
+extern LIST_ENTRY NetTableListHead;
+extern KSPIN_LOCK NetTableListLock;
+extern LIST_ENTRY PrefixListHead;
+extern KSPIN_LOCK PrefixListLock;
+extern UINT MaxLLHeaderSize;
+extern UINT MinLLFrameSize;
+
+
+PNET_TABLE_ENTRY IPCreateNTE(
+    PIP_INTERFACE IF,
+    PIP_ADDRESS Address,
+    UINT PrefixLength);
+
+PIP_INTERFACE IPCreateInterface(
+    PLLIP_BIND_INFO BindInfo);
+
+VOID IPDestroyInterface(
+    PIP_INTERFACE IF);
+
+BOOLEAN IPRegisterInterface(
+    PIP_INTERFACE IF);
+
+VOID IPUnregisterInterface(
+    PIP_INTERFACE IF);
+
+PNET_TABLE_ENTRY IPLocateNTEOnInterface(
+    PIP_INTERFACE IF,
+    PIP_ADDRESS Address,
+    PUINT AddressType);
+
+PNET_TABLE_ENTRY IPLocateNTE(
+    PIP_ADDRESS Address,
+    PUINT AddressType);
+
+PADDRESS_ENTRY IPLocateADE(
+    PIP_ADDRESS Address,
+    UINT AddressType);
+
+PADDRESS_ENTRY IPGetDefaultADE(
+    UINT AddressType);
+
+VOID IPTimeout(
+    PKDPC Dpc,
+    PVOID DeferredContext,
+    PVOID SystemArgument1,
+    PVOID SystemArgument2);
+
+VOID IPDispatchProtocol(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket);
+
+VOID IPRegisterProtocol(
+    UINT ProtocolNumber,
+    IP_PROTOCOL_HANDLER Handler);
+
+NTSTATUS IPStartup(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath);
+
+NTSTATUS IPShutdown(
+    VOID);
+
+#endif /* __IP_H */
+
+/* EOF */
index 20799d7..87b06f8 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/lan.h
+ * PURPOSE:     LAN adapter definitions
+ */
+#ifndef __LAN_H
+#define __LAN_H
+
+
+/* Medias we support */
+#define MEDIA_ETH 0
+
+#define MAX_MEDIA 1
+
+#define IEEE_802_ADDR_LENGTH 6
+
+/* Ethernet header layout */
+typedef struct ETH_HEADER {
+    UCHAR DstAddr[IEEE_802_ADDR_LENGTH]; /* Destination MAC address */
+    UCHAR SrcAddr[IEEE_802_ADDR_LENGTH]; /* Source MAC address */
+    USHORT EType;                        /* Ethernet protocol type */
+} ETH_HEADER, *PETH_HEADER;
+
+#define MAX_MEDIA_ETH sizeof(ETH_HEADER)
+
+/* Broadcast masks */
+#define BCAST_ETH_MASK 0x01
+
+/* Broadcast values to check against */
+#define BCAST_ETH_CHECK 0x01
+
+/* Offset of broadcast address */
+#define BCAST_ETH_OFFSET 0x00
+
+/* Per adapter information */
+typedef struct LAN_ADAPTER {
+    struct LAN_ADAPTER *Next;               /* Pointer to next adapter */
+    KSPIN_LOCK Lock;                        /* Lock for this structure */
+    UCHAR State;                            /* State of the adapter */
+    KEVENT Event;                           /* Opening event */
+    PVOID Context;                          /* Upper layer context information */
+    NDIS_HANDLE NdisHandle;                 /* NDIS binding handle */
+    NDIS_STATUS NdisStatus;                 /* NDIS status of last request */
+    NDIS_MEDIUM Media;                      /* Media type */
+    UCHAR HWAddress[IEEE_802_ADDR_LENGTH];  /* Local HW address */
+    UINT HWAddressLength;                   /* Length of HW address */
+    UCHAR BCastMask;                        /* Mask for checking broadcast */
+    UCHAR BCastCheck;                       /* Value to check against */
+    UCHAR BCastOffset;                      /* Offset in frame to check against */
+    UCHAR HeaderSize;                       /* Size of link-level header */
+    USHORT MTU;                             /* Maximum Transfer Unit */
+    UINT MinFrameSize;                      /* Minimum frame size in bytes */
+    UINT MaxPacketSize;                     /* Maximum packet size when sending */
+    UINT MaxSendPackets;                    /* Maximum number of packets per send */
+    UINT MacOptions;                        /* MAC options for NIC driver/adapter */
+    UINT Speed;                             /* Link speed */
+    UINT PacketFilter;                      /* Packet filter for this adapter */
+    PNDIS_PACKET TDPackets;                 /* Transfer Data packets */
+} LAN_ADAPTER, *PLAN_ADAPTER;
+
+/* LAN adapter state constants */
+#define LAN_STATE_OPENING   0
+#define LAN_STATE_RESETTING 1
+#define LAN_STATE_STARTED   2
+#define LAN_STATE_STOPPED   3
+
+/* Size of out lookahead buffer */
+#define LOOKAHEAD_SIZE  128
+
+/* Ethernet types. We swap constants so we can compare values at runtime
+   without swapping them */
+#define ETYPE_IPv4 WH2N(0x0800)
+#define ETYPE_IPv6 WH2N(0x0000) /* FIXME */
+#define ETYPE_ARP  WH2N(0x0806)
+
+/* Protocols */
+#define LAN_PROTO_IPv4 0x0000 /* Internet Protocol version 4 */
+#define LAN_PROTO_IPv6 0x0001 /* Internet Protocol version 6 */
+#define LAN_PROTO_ARP  0x0002 /* Address Resolution Protocol */
+
+extern PLAN_ADAPTER Adapters;
+
+
+NDIS_STATUS LANRegisterAdapter(
+    PNDIS_STRING AdapterName,
+    PLAN_ADAPTER *Adapter);
+
+NDIS_STATUS LANUnregisterAdapter(
+    PLAN_ADAPTER Adapter);
+
+NTSTATUS LANRegisterProtocol(
+    STRING *Name);
+
+VOID LANUnregisterProtocol(
+    VOID);
+
+#endif /* __LAN_H */
+
+/* EOF */
index abf3e1d..e5c31c4 100644 (file)
@@ -1,25 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/loopback.h
+ * PURPOSE:     Loopback adapter definitions
+ */
+#ifndef __LOOPBACK_H
+#define __LOOPBACK_H
+
+#include <lan.h>
+
+
+extern PIP_INTERFACE Loopback;
+
+
+NDIS_STATUS LoopRegisterAdapter(
+    PNDIS_STRING AdapterName,
+    PLAN_ADAPTER *Adapter);
+
+NDIS_STATUS LoopUnregisterAdapter(
+    PLAN_ADAPTER Adapter);
+
+#endif /* __LOOPBACK_H */
+
+/* EOF */
index a2c50fe..460c25e 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/neighbor.h
+ * PURPOSE:     Neighbor definitions
+ */
+#ifndef __NEIGHBOR_H
+#define __NEIGHBOR_H
+
+
+#define NB_HASHMASK 0xF /* Hash mask for neighbor cache */
+
+typedef struct NEIGHBOR_CACHE_TABLE {
+    struct NEIGHBOR_CACHE_ENTRY *Cache; /* Pointer to cache */
+    KSPIN_LOCK Lock;                    /* Protecting lock */
+} NEIGHBOR_CACHE_TABLE, *PNEIGHBOR_CACHE_TABLE;
+
+/* Information about a neighbor */
+typedef struct NEIGHBOR_CACHE_ENTRY {
+    struct NEIGHBOR_CACHE_ENTRY *Next;  /* Pointer to next entry */
+    struct NEIGHBOR_CACHE_TABLE *Table; /* Pointer to table */
+    ULONG RefCount;                     /* Number of references */
+    UCHAR State;                        /* State of NCE */
+    UINT EventTimer;                    /* Ticks since last event */
+    UINT EventCount;                    /* Number of events */
+    PIP_INTERFACE Interface;            /* Pointer to interface */
+    PIP_ADDRESS Address;                /* IP address of neighbor */
+    UINT LinkAddressLength;             /* Length of link address */
+    PVOID LinkAddress;                  /* Pointer to link address */
+    PNDIS_PACKET WaitQueue;             /* Pointer to NDIS packets
+                                           waiting to be sent */
+} NEIGHBOR_CACHE_ENTRY, *PNEIGHBOR_CACHE_ENTRY;
+
+/* NCE states */
+#define NUD_NONE       0x00
+#define NUD_INCOMPLETE 0x01
+#define NUD_REACHABLE  0x02
+#define NUD_STALE      0x04
+#define NUD_DELAY      0x08
+#define NUD_PROBE      0x10
+#define NUD_FAILED     0x20
+#define NUD_NOARP      0x40
+#define NUD_PERMANENT  0x80
+
+#define NUD_IN_TIMER  (NUD_INCOMPLETE | NUD_DELAY | NUD_PROBE)
+#define NUD_VALID     (NUD_REACHABLE | NUD_NOARP | NUD_STALE | NUD_DELAY | \
+                       NUD_PROBE | NUD_PERMANENT)
+#define NUD_CONNECTED (NUD_PERMANENT | NUD_NOARP | NUD_REACHABLE)
+
+
+/* Maximum number of retransmissions of multicast solicits */
+#define MAX_MULTICAST_SOLICIT 3 /* 3 transmissions */
+
+/* Number of ticks between address resolution messages */
+#define RETRANS_TIMER IP_TICKS_SECOND /* One second */
+
+
+extern NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];
+
+
+VOID NBTimeout(
+    VOID);
+
+VOID NBStartup(
+    VOID);
+
+VOID NBShutdown(
+    VOID);
+
+VOID NBSendSolicit(
+    PNEIGHBOR_CACHE_ENTRY NCE);
+
+PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(
+    PIP_INTERFACE Interface,
+    PIP_ADDRESS Address,
+    PVOID LinkAddress,
+    UINT LinkAddressLength,
+    UCHAR Type);
+
+VOID NBUpdateNeighbor(
+    PNEIGHBOR_CACHE_ENTRY NCE,
+    PVOID LinkAddress,
+    UCHAR State);
+
+PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(
+    PIP_ADDRESS Address);
+
+PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor(
+    PIP_INTERFACE Interface,
+    PIP_ADDRESS Address);
+
+BOOLEAN NBQueuePacket(
+    PNEIGHBOR_CACHE_ENTRY NCE,
+    PNDIS_PACKET NdisPacket);
+
+VOID NBRemoveNeighbor(
+    PNEIGHBOR_CACHE_ENTRY NCE);
+
+#endif /* __NEIGHBOR_H */
+
+/* EOF */
index 653b0a4..04b088a 100644 (file)
@@ -1,19 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/pool.h
+ * PURPOSE:     Prototypes for memory pooling
+ */
+#ifndef __POOL_H
+#define __POOL_H
+
+
+PVOID PoolAllocateBuffer(
+    ULONG Size);
+
+VOID PoolFreeBuffer(
+    PVOID Buffer);
+
+#endif /* __POOL_H */
+
+/* EOF */
index b132229..0029ef1 100644 (file)
@@ -1,24 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/rawip.h
+ * PURPOSE:     Raw IP types and constants
+ */
+#ifndef __RAWIP_H
+#define __RAWIP_H
+
+NTSTATUS RawIPSendDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize);
+
+NTSTATUS RawIPStartup(
+    VOID);
+
+NTSTATUS RawIPShutdown(
+    VOID);
+
+#endif /* __RAWIP_H */
+
+/* EOF */
index 2dab3d4..36dcac2 100644 (file)
@@ -1,61 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/receive.h
+ * PURPOSE:     Internet Protocol receive prototypes
+ */
+#ifndef __RECEIVE_H
+#define __RECEIVE_H
+
+#include <ip.h>
+
+
+/* IP datagram fragment descriptor. Used to store IP datagram fragments */
+typedef struct IP_FRAGMENT {
+    LIST_ENTRY ListEntry; /* Entry on list */
+    PVOID Data;           /* Pointer to fragment data */
+    UINT Offset;          /* Offset into datagram where this fragment is */
+    UINT Size;            /* Size of this fragment */
+} IP_FRAGMENT, *PIP_FRAGMENT;
+
+/* IP datagram hole descriptor. Used to reassemble IP datagrams */
+typedef struct IPDATAGRAM_HOLE {
+    LIST_ENTRY ListEntry; /* Entry on list */
+    UINT First;           /* Offset of first octet of the hole */
+    UINT Last;            /* Offset of last octet of the hole */
+} IPDATAGRAM_HOLE, *PIPDATAGRAM_HOLE;
+
+/* IP datagram reassembly information */
+typedef struct IPDATAGRAM_REASSEMBLY {
+    LIST_ENTRY ListEntry;        /* Entry on list */
+    KSPIN_LOCK Lock;             /* Protecting spin lock */
+    ULONG RefCount;              /* Reference count for this object */
+    UINT DataSize;               /* Size of datagram data area */
+    IP_ADDRESS SrcAddr;          /* Source address */
+    IP_ADDRESS DstAddr;          /* Destination address */
+    UCHAR Protocol;              /* Internet Protocol number */
+    USHORT Id;                   /* Identification number */
+    PIPv4_HEADER IPv4Header;     /* Pointer to IP header */
+    UINT HeaderSize;             /* Length of IP header */
+    LIST_ENTRY FragmentListHead; /* IP fragment list */
+    LIST_ENTRY HoleListHead;     /* IP datagram hole list */
+} IPDATAGRAM_REASSEMBLY, *PIPDATAGRAM_REASSEMBLY;
+
+
+extern LIST_ENTRY ReassemblyListHead;
+extern KSPIN_LOCK ReassemblyListLock;
+
+
+VOID IPFreeReassemblyList(
+    VOID);
+
+VOID IPDatagramReassemblyTimeout(
+    VOID);
+
+VOID IPReceive(
+    PVOID Context,
+    PIP_PACKET IPPacket);
+
+#endif /* __RECEIVE_H */
+
+/* EOF */
index d2c827c..c6c7d2c 100644 (file)
@@ -1,75 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/route.h
+ * PURPOSE:     Routing cache definitions
+ */
+#ifndef __ROUTE_H
+#define __ROUTE_H
+
+#include <neighbor.h>
+#include <address.h>
+#include <router.h>
+#include <pool.h>
+#include <arp.h>
+
+
+/* Route Cache Node structure.
+ * The primary purpose of the RCN is to cache selected source and
+ * next-hop addresses. The routing cache is implemented as a binary
+ * search tree to provide fast lookups when many RCNs are in the cache.
+ */
+typedef struct ROUTE_CACHE_NODE {
+    struct ROUTE_CACHE_NODE *Parent; /* Pointer to parent */
+    struct ROUTE_CACHE_NODE *Left;   /* Pointer to left child */
+    struct ROUTE_CACHE_NODE *Right;  /* Pointer to right child */
+    /* Memebers above this line must not be moved */
+    ULONG RefCount;                  /* Reference count */
+    UCHAR State;                     /* RCN state (RCN_STATE_*) */
+    IP_ADDRESS Destination;          /* Destination address */
+    PNET_TABLE_ENTRY NTE;            /* Preferred NTE */
+    PNEIGHBOR_CACHE_ENTRY NCE;       /* Pointer to NCE for first hop (NULL if none) */
+    UINT PathMTU;                    /* Path MTU to destination */
+} ROUTE_CACHE_NODE, *PROUTE_CACHE_NODE;
+
+/* RCN states */
+#define RCN_STATE_PERMANENT 0x00 /* RCN is permanent (properly local) */
+#define RCN_STATE_COMPUTED  0x01 /* RCN is computed */
+
+
+#define IsExternalRCN(RCN) \
+    (RCN == ExternalRCN)
+
+#define IsInternalRCN(RCN) \
+    (RCN != ExternalRCN)
+
+
+NTSTATUS RouteStartup(
+    VOID);
+
+NTSTATUS RouteShutdown(
+    VOID);
+
+UINT RouteGetRouteToDestination(
+    PIP_ADDRESS Destination,
+    PNET_TABLE_ENTRY NTE,
+    PROUTE_CACHE_NODE *RCN);
+
+PROUTE_CACHE_NODE RouteAddRouteToDestination(
+    PIP_ADDRESS Destination,
+    PNET_TABLE_ENTRY NTE,
+    PIP_INTERFACE IF,
+    PNEIGHBOR_CACHE_ENTRY NCE);
+
+VOID RouteRemoveRouteToDestination(
+    PROUTE_CACHE_NODE RCN);
+
+VOID RouteInvalidateNTE(
+    PNET_TABLE_ENTRY NTE);
+
+VOID RouteInvalidateNCE(
+    PNEIGHBOR_CACHE_ENTRY NCE);
+
+#endif /* __ROUTE_H */
+
+/* EOF */
index e8d52ef..c585f83 100644 (file)
@@ -1,62 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/router.h
+ * PURPOSE:     IP routing definitions
+ */
+#ifndef __ROUTER_H
+#define __ROUTER_H
+
+#include <neighbor.h>
+
+
+/* Forward Information Base Entry */
+typedef struct _FIB_ENTRY {
+    LIST_ENTRY ListEntry;         /* Entry on list */
+    ULONG RefCount;               /* Reference count */
+    PIP_ADDRESS NetworkAddress;   /* Address of network */
+    PIP_ADDRESS Netmask;          /* Netmask of network */
+    PNET_TABLE_ENTRY NTE;         /* Pointer to NTE to use */
+    PNEIGHBOR_CACHE_ENTRY Router; /* Pointer to NCE of router to use */
+    UINT Metric;                  /* Cost of this route */
+} FIB_ENTRY, *PFIB_ENTRY;
+
+
+PNET_TABLE_ENTRY RouterFindBestNTE(
+    PIP_INTERFACE Interface,
+    PIP_ADDRESS Destination);
+
+PIP_INTERFACE RouterFindOnLinkInterface(
+    PIP_ADDRESS Address,
+    PNET_TABLE_ENTRY NTE);
+
+PFIB_ENTRY RouterAddRoute(
+    PIP_ADDRESS NetworkAddress,
+    PIP_ADDRESS Netmask,
+    PNET_TABLE_ENTRY NTE,
+    PNEIGHBOR_CACHE_ENTRY Router,
+    UINT Metric);
+
+PNEIGHBOR_CACHE_ENTRY RouterGetRoute(
+    PIP_ADDRESS Destination,
+    PNET_TABLE_ENTRY NTE);
+
+VOID RouterRemoveRoute(
+    PFIB_ENTRY FIBE);
+
+PFIB_ENTRY RouterCreateRouteIPv4(
+    IPv4_RAW_ADDRESS NetworkAddress,
+    IPv4_RAW_ADDRESS Netmask,
+    IPv4_RAW_ADDRESS RouterAddress,
+    PNET_TABLE_ENTRY NTE,
+    UINT Metric);
+
+NTSTATUS RouterStartup(
+    VOID);
+
+NTSTATUS RouterShutdown(
+    VOID);
+
+#endif /* __ROUTER_H */
+
+/* EOF */
index dcd0347..b73f27e 100644 (file)
@@ -1,53 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/routines.h
+ * PURPOSE:     Common routine prototypes
+ */
+#ifndef __ROUTINES_H
+#define __ROUTINES_H
+
+
+UINT Random(
+    VOID);
+
+UINT CopyBufferToBufferChain(
+    PNDIS_BUFFER DstBuffer,
+    UINT DstOffset,
+    PUCHAR SrcData,
+    UINT Length);
+
+UINT CopyBufferChainToBuffer(
+    PUCHAR DstData,
+    PNDIS_BUFFER SrcBuffer,
+    UINT SrcOffset,
+    UINT Length);
+
+UINT CopyPacketToBuffer(
+    PUCHAR DstData,
+    PNDIS_PACKET SrcPacket,
+    UINT SrcOffset,
+    UINT Length);
+
+UINT CopyPacketToBufferChain(
+    PNDIS_BUFFER DstBuffer,
+    UINT DstOffset,
+    PNDIS_PACKET SrcPacket,
+    UINT SrcOffset,
+    UINT Length);
+
+VOID FreeNdisPacket(
+    PNDIS_PACKET Packet);
+
+PVOID AdjustPacket(
+    PNDIS_PACKET Packet,
+    UINT Available,
+    UINT Needed);
+
+UINT ResizePacket(
+    PNDIS_PACKET Packet,
+    UINT Size);
+
+#endif /* __ROUTINES_H */
+
+/* EOF */
index d58654a..22e38ef 100644 (file)
@@ -1,18 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/tcp.h
+ * PURPOSE:     Transmission Control Protocol definitions
+ */
+#ifndef __TCP_H
+#define __TCP_H
+
+NTSTATUS TCPStartup(
+    VOID);
+
+NTSTATUS TCPShutdown(
+    VOID);
+
+#endif /* __TCP_H */
+
+/* EOF */
index 7a56e2a..1c3eb02 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/tcpip.h
+ * PURPOSE:     TCP/IP protocol driver definitions
+ * NOTES:       Spin lock acquire order:
+ *                - Net table list lock
+ *                - Interface lock
+ *                - Interface list lock
+ *                - Prefix list lock
+ *                - Neighbor cache lock
+ *                - Route cache lock
+ */
+#ifndef __TCPIP_H
+#define __TCPIP_H
+
+#ifdef _MSC_VER
+#include <basetsd.h>
+#include <ntddk.h>
+#include <windef.h>
+#include <ndis.h>
+#include <tdikrnl.h>
+#include <tdiinfo.h>
+#else
+#include <ddk/ntddk.h>
+#include <net/ndis.h>
+#include <net/tdikrnl.h>
+#include <net/tdiinfo.h>
+#endif
+
+#include <debug.h>
+
+
+/* Define _NTTEST_ to make test version. Device names are prefixed with
+   'NT' to allow the driver to run side by side with MS TCP/IP driver */
+#define _NTTEST_
+
+/* FIXME: The following should be moved to ntddk.h or tdi headers */
+#ifndef _MSC_VER
+
+#ifndef IO_NETWORK_INCREMENT
+#define IO_NETWORK_INCREMENT 2
+#endif
+
+#endif
+
+#ifdef _MSC_VER
+/* EXPORTED is already defined ddk/defines.h */
+#define EXPORTED __declspec(dllexport)
+
+#endif
+
+#include <titypes.h>
+#include <ticonsts.h>
+#include <udp.h>
+
+
+/* Macros */
+
+#define MIN(value1, value2) \
+    ((value1 < value2)? value1 : value2)
+
+#define MAX(value1, value2) \
+    ((value1 > value2)? value1 : value2)
+
+
+#ifdef i386
+
+/* DWORD network to host byte order conversion for i386 */
+#define DN2H(dw) \
+    ((((dw) & 0xFF000000L) >> 24) | \
+        (((dw) & 0x00FF0000L) >> 8) | \
+        (((dw) & 0x0000FF00L) << 8) | \
+        (((dw) & 0x000000FFL) << 24))
+
+/* DWORD host to network byte order conversion for i386 */
+#define DH2N(dw) \
+       ((((dw) & 0xFF000000L) >> 24) | \
+        (((dw) & 0x00FF0000L) >> 8) | \
+        (((dw) & 0x0000FF00L) << 8) | \
+        (((dw) & 0x000000FFL) << 24))
+
+/* WORD network to host order conversion for i386 */
+#define WN2H(w) \
+       ((((w) & 0xFF00) >> 8) | \
+        (((w) & 0x00FF) << 8))
+
+/* WORD host to network byte order conversion for i386 */
+#define WH2N(w) \
+       ((((w) & 0xFF00) >> 8) | \
+        (((w) & 0x00FF) << 8))
+
+#else /* i386 */
+
+/* DWORD network to host byte order conversion for other architectures */
+#define DN2H(dw) \
+    (dw)
+
+/* DWORD host to network byte order conversion for other architectures */
+#define DH2N(dw) \
+    (dw)
+
+/* WORD network to host order conversion for other architectures */
+#define WN2H(w) \
+    (w)
+
+/* WORD host to network byte order conversion for other architectures */
+#define WH2N(w) \
+    (w)
+
+#endif /* i386 */
+
+
+/* Global variable */
+extern PDEVICE_OBJECT TCPDeviceObject;
+extern PDEVICE_OBJECT UDPDeviceObject;
+extern PDEVICE_OBJECT IPDeviceObject;
+extern PDEVICE_OBJECT RawIPDeviceObject;
+extern LIST_ENTRY InterfaceListHead;
+extern KSPIN_LOCK InterfaceListLock;
+extern LIST_ENTRY AddressFileListHead;
+extern KSPIN_LOCK AddressFileListLock;
+extern NDIS_HANDLE GlobalPacketPool;
+extern NDIS_HANDLE GlobalBufferPool;
+extern TDIEntityID *EntityList;
+extern ULONG EntityCount;
+extern UDP_STATISTICS UDPStats;
+
+#endif /* __TCPIP_H */
+
+/* EOF */
index 2ed7246..d73436c 100644 (file)
@@ -1,56 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/ticonsts.h
+ * PURPOSE:     TCP/IP protocol driver constants
+ */
+#ifndef __TICONSTS_H
+#define __TICONSTS_H
+
+/* NDIS version this driver supports */
+#define NDIS_VERSION_MAJOR 3
+#define NDIS_VERSION_MINOR 0
+
+#ifdef _NTTEST_
+/* Name of devices */
+#define DD_TCP_DEVICE_NAME      L"\\Device\\NTTcp"
+#define DD_UDP_DEVICE_NAME      L"\\Device\\NTUdp"
+#define DD_IP_DEVICE_NAME       L"\\Device\\NTIp"
+#define DD_RAWIP_DEVICE_NAME    L"\\Device\\NTRawIp"
+
+/* For NDIS protocol registration */
+#define IP_DEVICE_NAME          "\\Device\\NTIp"
+#else
+#define DD_TCP_DEVICE_NAME      L"\\Device\\Tcp"
+#define DD_UDP_DEVICE_NAME      L"\\Device\\Udp"
+#define DD_IP_DEVICE_NAME       L"\\Device\\Ip"
+#define DD_RAWIP_DEVICE_NAME    L"\\Device\\RawIp"
+
+/* For NDIS protocol registration */
+#define IP_DEVICE_NAME          "\\Device\\Ip"
+#endif /* _NTTEST_ */
+
+/* TCP/UDP/RawIP IOCTL code definitions */
+
+#define FSCTL_TCP_BASE     FILE_DEVICE_NETWORK
+
+#define _TCP_CTL_CODE(Function, Method, Access) \
+    CTL_CODE(FSCTL_TCP_BASE, Function, Method, Access)
+
+#define IOCTL_TCP_QUERY_INFORMATION_EX \
+    _TCP_CTL_CODE(0, METHOD_NEITHER, FILE_ANY_ACCESS)
+
+#define IOCTL_TCP_SET_INFORMATION_EX \
+    _TCP_CTL_CODE(1, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+/* Unique error values for log entries */
+#define TI_ERROR_DRIVERENTRY 0
+
+/* Internal status codes */
+#define IP_SUCCESS                 0x0000 /* Successful */
+#define IP_NO_RESOURCES            0x0001 /* Not enough free resources */
+#define IP_NO_ROUTE_TO_DESTINATION 0x0002 /* No route to destination */
+
+#endif /* __TICONSTS_H */
+
+/* EOF */
index 833d671..998b90d 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/titypes.h
+ * PURPOSE:     TCP/IP protocol driver types
+ */
+#ifndef __TITYPES_H
+#define __TITYPES_H
+
+#include <ip.h>
+
+
+#ifdef DBG
+
+#define DEBUG_REFCHECK(Object) {            \
+    if ((Object)->RefCount <= 0) {          \
+        TI_DbgPrint(MIN_TRACE, ("Object at (0x%X) has invalid reference count (%d).\n", \
+            (Object), (Object)->RefCount)); \
+        }                                   \
+}
+
+#else
+
+#define DEBUG_REFCHECK(Object)
+
+#endif
+
+
+/*
+ * VOID ReferenceObject(
+ *     PVOID Object)
+ */
+#define ReferenceObject(Object)                  \
+{                                                \
+    DEBUG_REFCHECK(Object);                      \
+    TI_DbgPrint(DEBUG_REFCOUNT, ("Referencing object at (0x%X). RefCount (%d).\n", \
+        (Object), (Object)->RefCount));          \
+                                                 \
+    InterlockedIncrement(&((Object)->RefCount)); \
+}
+
+/*
+ * VOID DereferenceObject(
+ *     PVOID Object)
+ */
+#define DereferenceObject(Object)                         \
+{                                                         \
+    DEBUG_REFCHECK(Object);                               \
+    TI_DbgPrint(DEBUG_REFCOUNT, ("Dereferencing object at (0x%X). RefCount (%d).\n", \
+        (Object), (Object)->RefCount));                   \
+                                                          \
+    if (InterlockedDecrement(&((Object)->RefCount)) == 0) \
+        PoolFreeBuffer(Object);                           \
+}
+
+
+typedef NTSTATUS (*DATAGRAM_SEND_ROUTINE)(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize);
+
+/* Datagram completion handler prototype */
+typedef VOID (*DATAGRAM_COMPLETION_ROUTINE)(
+    PVOID Context,
+    NDIS_STATUS Status,
+    ULONG Count);
+
+typedef struct _DATAGRAM_RECEIVE_REQUEST {
+    LIST_ENTRY ListEntry;                   /* Entry on list */
+    PIP_ADDRESS RemoteAddress;              /* Remote address we receive from (NULL means any) */
+    USHORT RemotePort;                      /* Remote port we receive from (0 means any) */
+    PTDI_CONNECTION_INFORMATION ReturnInfo; /* Return information */
+    PNDIS_BUFFER Buffer;                    /* Pointer to receive buffer */
+    ULONG BufferSize;                       /* Size of Buffer */
+    DATAGRAM_COMPLETION_ROUTINE Complete;   /* Completion routine */
+    PVOID Context;                          /* Pointer to context information */
+} DATAGRAM_RECEIVE_REQUEST, *PDATAGRAM_RECEIVE_REQUEST;
+
+/* Datagram build routine prototype */
+typedef NTSTATUS (*DATAGRAM_BUILD_ROUTINE)(
+    PVOID Context,
+    PIP_ADDRESS LocalAddress,
+    USHORT LocalPort,
+    PIP_PACKET *IPPacket);
+
+typedef struct _DATAGRAM_SEND_REQUEST {
+    LIST_ENTRY ListEntry;                 /* Entry on list */
+    PIP_ADDRESS RemoteAddress;            /* Pointer to remote IP address */
+    USHORT RemotePort;                    /* Remote port number */
+    PNDIS_BUFFER Buffer;                  /* Pointer to NDIS buffer to send */
+    DWORD BufferSize;                     /* Size of Buffer */
+    DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine */
+    PVOID Context;                        /* Pointer to context information */
+    DATAGRAM_BUILD_ROUTINE Build;         /* Datagram build routine */
+} DATAGRAM_SEND_REQUEST, *PDATAGRAM_SEND_REQUEST;
+
+
+/* Transport (TCP/UDP) endpoint context structure. The FileObject->FsContext
+   field holds a pointer to this structure */
+typedef struct _TRANSPORT_CONTEXT {
+    union {
+        HANDLE AddressHandle;
+        CONNECTION_CONTEXT ConnectionContext;
+        HANDLE ControlChannel;
+    } Handle;
+    ULONG RefCount;
+    BOOL CancelIrps;
+    KEVENT CleanupEvent;
+} TRANSPORT_CONTEXT, *PTRANSPORT_CONTEXT;
+
+
+typedef struct _ADDRESS_FILE {
+    LIST_ENTRY ListEntry;                 /* Entry on list */
+    KSPIN_LOCK Lock;                      /* Spin lock to manipulate this structure */
+    ULONG RefCount;                       /* Number of references to this object */
+    USHORT Flags;                         /* Flags for address file (see below) */
+    PADDRESS_ENTRY ADE;                   /* Associated address entry */
+    USHORT Protocol;                      /* Protocol number */
+    USHORT Port;                          /* Network port (network byte order) */
+    WORK_QUEUE_ITEM WorkItem;             /* Work queue item handle */
+    DATAGRAM_COMPLETION_ROUTINE Complete; /* Completion routine for delete request */
+    PVOID Context;                        /* Delete request context */
+    DATAGRAM_SEND_ROUTINE Send;           /* Routine to send a datagram */
+    LIST_ENTRY ReceiveQueue;              /* List of outstanding receive requests */
+    LIST_ENTRY TransmitQueue;             /* List of outstanding transmit requests */
+    PIP_ADDRESS AddrCache;                /* One entry address cache (destination
+                                             address of last packet transmitted) */
+
+    /* The following members are used to control event notification */
+
+    /* Connection indication handler */
+    PTDI_IND_CONNECT ConnectionHandler;
+    PVOID ConnectionHandlerContext;
+    BOOL RegisteredConnectionHandler;
+    /* Disconnect indication handler */
+    PTDI_IND_DISCONNECT DisconnectHandler;
+    PVOID DisconnectHandlerContext;
+    BOOL RegisteredDisconnectHandler;
+    /* Receive indication handler */
+    PTDI_IND_RECEIVE ReceiveHandler;
+    PVOID ReceiveHandlerContext;
+    BOOL RegisteredReceiveHandler;
+    /* Expedited receive indication handler */
+    PTDI_IND_RECEIVE_EXPEDITED ExpeditedReceiveHandler;
+    PVOID ExpeditedReceiveHandlerContext;
+    BOOL RegisteredExpeditedReceiveHandler;
+    /* Receive datagram indication handler */
+    PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
+    PVOID ReceiveDatagramHandlerContext;
+    BOOL RegisteredReceiveDatagramHandler;
+    /* Error indication handler */
+    PTDI_IND_ERROR ErrorHandler;
+    PVOID ErrorHandlerContext;
+    PVOID ErrorHandlerOwner;
+    BOOL RegisteredErrorHandler;
+} ADDRESS_FILE, *PADDRESS_FILE;
+
+/* Address File Flag constants */
+#define AFF_VALID    0x0001 /* Address file object is valid for use */
+#define AFF_BUSY     0x0002 /* Address file object is exclusive to someone */
+#define AFF_DELETE   0x0004 /* Address file object is sheduled to be deleted */
+#define AFF_SEND     0x0008 /* A send request is pending */
+#define AFF_RECEIVE  0x0010 /* A receive request is pending */
+#define AFF_PENDING  0x001C /* A request is pending */
+
+/* Macros for manipulating address file object flags */
+
+#define AF_IS_VALID(ADF)  ((ADF)->Flags & AFF_VALID)
+#define AF_SET_VALID(ADF) ((ADF)->Flags |= AFF_VALID)
+#define AF_CLR_VALID(ADF) ((ADF)->Flags &= ~AFF_VALID)
+
+#define AF_IS_BUSY(ADF)  ((ADF)->Flags & AFF_BUSY)
+#define AF_SET_BUSY(ADF) ((ADF)->Flags |= AFF_BUSY)
+#define AF_CLR_BUSY(ADF) ((ADF)->Flags &= ~AFF_BUSY)
+
+#define AF_IS_PENDING(ADF, X)  (ADF->Flags & X)
+#define AF_SET_PENDING(ADF, X) (ADF->Flags |= X)
+#define AF_CLR_PENDING(ADF, X) (ADF->Flags &= ~X)
+
+
+/* Structure used to search through Address Files */
+typedef struct _AF_SEARCH {
+    PLIST_ENTRY Next;       /* Next address file to check */
+    PIP_ADDRESS Address;    /* Pointer to address to be found */
+    USHORT Port;            /* Network port */
+    USHORT Protocol;        /* Protocol number */
+} AF_SEARCH, *PAF_SEARCH;
+
+/* Transport connection context structure. The FileObject->FsContext2
+   field holds a pointer to this structure */
+typedef struct _CONNECTION_ENDPOINT {
+    LIST_ENTRY ListEntry;   /* Entry on list */
+    KSPIN_LOCK Lock;        /* Spin lock to protect this structure */
+    ULONG RefCount;         /* Number of references to this object */
+} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;
+
+/* Transport control channel context structure. The FileObject->FsContext2
+   field holds a pointer to this structure */
+typedef struct _CONTROL_CHANNEL {
+    LIST_ENTRY ListEntry;       /* Entry on list */
+    KSPIN_LOCK Lock;            /* Spin lock to protect this structure */
+    ULONG RefCount;             /* Number of references to this object */
+} CONTROL_CHANNEL, *PCONTROL_CHANNEL;
+
+typedef struct _TI_QUERY_CONTEXT {
+    PIRP Irp;
+    PMDL InputMdl;
+    PMDL OutputMdl;
+    TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
+} TI_QUERY_CONTEXT, *PTI_QUERY_CONTEXT;
+
+#endif /* __TITYPES_H */
+
+/* EOF */
index c0f8167..618e632 100644 (file)
@@ -1,47 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/transmit.h
+ * PURPOSE:     Internet Protocol transmit prototypes
+ */
+#ifndef __TRANSMIT_H
+#define __TRANSMIT_H
+
+#include <neighbor.h>
+#include <route.h>
+#include <ip.h>
+
+
+/* IP fragment context information */
+typedef struct IPFRAGMENT_CONTEXT {
+    struct IPFRAGMENT_CONTEXT *Next;    /* Pointer to next in list */
+    PNDIS_PACKET Datagram;              /* Pointer to original NDIS packet */
+    PVOID DatagramData;                 /* Pointer to datagram data */
+    UINT HeaderSize;                    /* IP datagram header size */
+    PNDIS_PACKET NdisPacket;            /* Pointer to NDIS packet */
+    PNDIS_BUFFER NdisBuffer;            /* Pointer to NDIS buffer */
+    PVOID Header;                       /* Pointer to IP header in fragment buffer */
+    PVOID Data;                         /* Pointer to fragment data */
+    UINT Position;                      /* Current fragment offset */
+    UINT BytesLeft;                     /* Number of bytes left to send */
+    UINT PathMTU;                       /* Path Maximum Transmission Unit */
+    PNEIGHBOR_CACHE_ENTRY NCE;          /* Pointer to NCE to use */
+} IPFRAGMENT_CONTEXT, *PIPFRAGMENT_CONTEXT;
+
+
+VOID IPSendComplete(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    NDIS_STATUS NdisStatus);
+
+NTSTATUS IPSendFragment(
+    PNDIS_PACKET NdisPacket,
+    PNEIGHBOR_CACHE_ENTRY NCE);
+
+NTSTATUS IPSendDatagram(
+    PIP_PACKET IPPacket,
+    PROUTE_CACHE_NODE RCN);
+
+#endif /* __TRANSMIT_H */
+
+/* EOF */
index 919a86b..c289575 100644 (file)
@@ -1,68 +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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        include/udp.h
+ * PURPOSE:     User Datagram Protocol definitions
+ */
+#ifndef __UDP_H
+#define __UDP_H
+
+
+/* UDPv4 header structure */
+typedef struct UDP_HEADER {
+    USHORT SourcePort; /* Source port */
+    USHORT DestPort;   /* Destination port */
+    USHORT Length;     /* Size of header and data */
+    USHORT Checksum;   /* Checksum of datagram */
+} UDP_HEADER, *PUDP_HEADER;
+
+/* UDPv4 pseudo header */
+typedef struct UDP_PSEUDO_HEADER {
+    ULONG SourceAddress; /* Source address */
+    ULONG DestAddress;   /* Destination address */
+    UCHAR Zero;          /* Reserved */
+    UCHAR Protocol;      /* Protocol */
+    USHORT UDPLength;    /* Size of UDP datagram */
+} UDP_PSEUDO_HEADER, *PUDP_PSEUDO_HEADER;
+
+
+typedef struct UDP_STATISTICS {
+    ULONG InputDatagrams;
+    ULONG NumPorts;
+    ULONG InputErrors;
+    ULONG OutputDatagrams;
+    ULONG NumAddresses;
+} UDP_STATISTICS, *PUDP_STATISTICS;
+
+VOID UDPSend(
+    PVOID Context,
+    PDATAGRAM_SEND_REQUEST SendRequest);
+
+NTSTATUS UDPSendDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize);
+
+NTSTATUS UDPReceiveDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG ReceiveLength,
+    ULONG ReceiveFlags,
+    PTDI_CONNECTION_INFORMATION ReturnInfo,
+    PULONG BytesReceived);
+
+VOID UDPReceive(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket);
+
+NTSTATUS UDPStartup(
+    VOID);
+
+NTSTATUS UDPShutdown(
+    VOID);
+
+#endif /* __UDP_H */
+
+/* EOF */
index db914fa..b6e4d7f 100644 (file)
-# 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
+# TCPIP.SYS - TCP/IP protocol driver
+
+TARGETNAME=tcpip
+
+BASE_CFLAGS = -I./include -I../../../include
+
+RESOURCE_OBJECT  = $(TARGETNAME).coff
+TCPIP_OBJECTS    = tcpip/main.o tcpip/address.o tcpip/checksum.o \
+                   tcpip/dispatch.o tcpip/fileobjs.o tcpip/info.o \
+                   tcpip/pool.o tcpip/routines.o
+DATALINK_OBJECTS = datalink/arp.o datalink/lan.o datalink/loopback.o
+NETWORK_OBJECTS  = network/icmp.o network/ip.o network/neighbor.o \
+                   network/receive.o network/route.o network/router.o \
+                   network/transmit.o
+DATAGRAM_OBJECTS = transport/datagram/datagram.o
+RAWIP_OBJECTS    = transport/rawip/rawip.o
+TCP_OBJECTS      = transport/tcp/tcp.o
+UDP_OBJECTS      = transport/udp/udp.o
+
+all: objects $(TARGETNAME).sys
+
+objects:
+       mkdir objects
+
+objects/tcpip.o: $(TCPIP_OBJECTS)
+       $(LD) -r -o objects/tcpip.o $(TCPIP_OBJECTS)
+
+objects/datalink.o: $(DATALINK_OBJECTS)
+       $(LD) -r -o objects/datalink.o $(DATALINK_OBJECTS)
+
+objects/network.o: $(NETWORK_OBJECTS)
+       $(LD) -r -o objects/network.o $(NETWORK_OBJECTS)
+
+objects/datagram.o: $(DATAGRAM_OBJECTS)
+       $(LD) -r -o objects/datagram.o $(DATAGRAM_OBJECTS)
+
+objects/rawip.o: $(RAWIP_OBJECTS)
+       $(LD) -r -o objects/rawip.o $(RAWIP_OBJECTS)
+
+objects/tcp.o: $(TCP_OBJECTS)
+       $(LD) -r -o objects/tcp.o $(TCP_OBJECTS)
+
+objects/udp.o: $(UDP_OBJECTS)
+       $(LD) -r -o objects/udp.o $(UDP_OBJECTS)
+
+OBJECTS = objects/tcpip.o objects/datalink.o objects/network.o \
+          objects/datagram.o objects/rawip.o objects/tcp.o objects/udp.o \
+          $(RESOURCE_OBJECT) \
+          ../../../ntoskrnl/ntoskrnl.a ../ndis/ndis.a
+
+$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h
+
+ifeq ($(DOSCLI),yes)
+CLEAN_FILES = \
+               *.o objects\*.o tcpip\*.o datalink\*.o network\*.o \
+        transport\datagram\*.o transport\rawip\*.o \
+        transport\tcp\*.o transport\udp\*.o $(TARGETNAME).coff \
+        $(TARGETNAME).a junk.tmp base.tmp temp.exp \
+               $(TARGETNAME).sys $(TARGETNAME).sym
+else
+CLEAN_FILES = \
+               *.o objects/*.o tcpip/*.o datalink/*.o network/*.o \
+        transport/datagram/*.o transport/rawip/*.o \
+        transport/tcp/*.o transport/udp/*.o $(TARGETNAME).coff \
+        $(TARGETNAME).a junk.tmp base.tmp temp.exp \
+               $(TARGETNAME).sys $(TARGETNAME).sym
+endif
+
+
+$(TARGETNAME).sys: $(OBJECTS)
+       $(DLLTOOL) \
+               --dllname $(TARGETNAME).sys \
+               --def $(TARGETNAME).def \
+               --kill-at \
+               --output-lib $(TARGETNAME).a
+       $(CC) \
+        -mdll \
+        -specs=../../svc_specs \
+        -Wl,-e,_DriverEntry@8 \
+        -Wl,--base-file,base.tmp \
+        -Wl,--defsym,_end=end \
+        -Wl,--defsym,_edata=__data_end__ \
+        -Wl,--defsym,_etext=etext \
+               $(OBJECTS) \
+        -o junk.tmp
+       - $(RM) junk.tmp
+       $(DLLTOOL) \
+        --dllname $(TARGETNAME).sys \
+        --base-file base.tmp \
+        --output-exp temp.exp \
+        --def $(TARGETNAME).edf
+       - $(RM) base.tmp
+       $(CC) \
+        -mdll \
+        -specs=../../svc_specs \
+        -Wl,--image-base,0x10000 \
+        -Wl,-e,_DriverEntry@8 \
+        -Wl,temp.exp \
+               $(OBJECTS) \
+        -o $(TARGETNAME).sys
+       - $(RM) temp.exp
+       $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym
+
+clean: $(CLEAN_FILES:%=%_clean)
+
+$(CLEAN_FILES:%=%_clean): %_clean:
+       - $(RM) $*
+
+.PHONY: clean $(CLEAN_FILES:%=%_clean)
+
+floppy: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys
+
+$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys
+ifeq ($(DOSCLI),yes)
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys
+else
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys
+endif
+
+dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys
+
+$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys
+ifeq ($(DOSCLI),yes)
+       $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys
+else
+       $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys
+endif
+
+#WITH_DEBUGGING      = yes
+#WIN32_LEAN_AND_MEAN = yes
+#WARNINGS_ARE_ERRORS = yes
+include ../../../rules.mak
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index 0768416..3723ad5 100644 (file)
@@ -1,20 +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
+TARGETNAME=network
+TARGETPATH=..\objects
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net
+
+
+SOURCES= icmp.c \
+                ip.c \
+         neighbor.c \
+                receive.c \
+         route.c \
+         router.c \
+                transmit.c
+
+MSC_WARNING_LEVEL=/W3 /WX
+
index f75e6b0..297d69d 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/icmp.c
+ * PURPOSE:     Internet Control Message Protocol routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <icmp.h>
+#include <checksum.h>
+#include <routines.h>
+#include <transmit.h>
+#include <pool.h>
+
+
+VOID SendICMPComplete(
+    PVOID Context,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS NdisStatus)
+/*
+ * FUNCTION: ICMP datagram transmit completion handler
+ * ARGUMENTS:
+ *     Context    = Pointer to context infomation (IP_PACKET)
+ *     Packet     = Pointer to NDIS packet
+ *     NdisStatus = Status of transmit operation
+ * NOTES:
+ *     This routine is called by IP when a ICMP send completes
+ */
+{
+    PIP_PACKET IPPacket = (PIP_PACKET)Context;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    TI_DbgPrint(MAX_TRACE, ("Freeing NDIS packet (%X).\n", Packet));
+
+    /* Free packet */
+    FreeNdisPacket(Packet);
+
+    TI_DbgPrint(MAX_TRACE, ("Freeing IP packet at %X.\n", IPPacket));
+
+    PoolFreeBuffer(IPPacket);
+}
+
+
+PIP_PACKET PrepareICMPPacket(
+    PNET_TABLE_ENTRY NTE,
+    PIP_ADDRESS Destination,
+    UINT DataSize)
+/*
+ * FUNCTION: Prepares an ICMP packet
+ * ARGUMENTS:
+ *     NTE         = Pointer to net table entry to use
+ *     Destination = Pointer to destination address
+ *     DataSize    = Size of dataarea
+ * RETURNS:
+ *     Pointer to IP packet, NULL if there is not enough free resources
+ */
+{
+    PIP_PACKET IPPacket;
+    PNDIS_PACKET NdisPacket;
+    PNDIS_BUFFER NdisBuffer;
+    NDIS_STATUS NdisStatus;
+    PIPv4_HEADER IPHeader;
+    PVOID DataBuffer;
+    ULONG Size;
+
+    TI_DbgPrint(MAX_TRACE, ("Called. DataSize = %d.\n", DataSize));
+
+    /* Prepare ICMP packet */
+    IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET));
+    if (!IPPacket)
+        return NULL;
+
+    TI_DbgPrint(MAX_TRACE, ("IPPacket at %X.\n", IPPacket));
+
+    Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) +
+        sizeof(ICMP_HEADER) + DataSize;
+    DataBuffer = ExAllocatePool(NonPagedPool, Size);
+    if (!DataBuffer) {
+        PoolFreeBuffer(IPPacket);
+        return NULL;
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("Size = %d, Data at %X.\n", Size, DataBuffer));
+
+    /* Allocate NDIS packet */
+    NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        PoolFreeBuffer(IPPacket);
+        ExFreePool(DataBuffer);
+        return NULL;
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("NdisPacket at %X.\n", NdisPacket));
+
+    /* Allocate NDIS buffer for maximum link level header and ICMP packet */
+    NdisAllocateBuffer(&NdisStatus, &NdisBuffer, GlobalBufferPool,
+        DataBuffer, Size);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        PoolFreeBuffer(IPPacket);
+        NdisFreePacket(NdisPacket);
+        ExFreePool(DataBuffer);
+        return NULL;
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("NdisBuffer at %X.\n", NdisBuffer));
+
+    /* Link NDIS buffer into packet */
+    NdisChainBufferAtFront(NdisPacket, NdisBuffer);
+    IPPacket->NdisPacket = NdisPacket;
+    IPPacket->Header     = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize);
+    IPPacket->Data       = (PVOID)((ULONG_PTR)DataBuffer + MaxLLHeaderSize + sizeof(IPv4_HEADER));
+
+    IPPacket->HeaderSize = sizeof(IPv4_HEADER);
+    IPPacket->TotalSize  = Size - MaxLLHeaderSize;
+    RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS));
+
+    /* Build IPv4 header. FIXME: IPv4 only */
+
+    IPHeader = (PIPv4_HEADER)IPPacket->Header;
+
+    /* Version = 4, Length = 5 DWORDs */
+    IPHeader->VerIHL = 0x45;
+    /* Normal Type-of-Service */
+    IPHeader->Tos = 0;
+    /* Length of data and header */
+    IPHeader->TotalLength = WH2N((USHORT)DataSize +
+        sizeof(IPv4_HEADER) + sizeof(ICMP_HEADER));
+    /* Identification */
+    IPHeader->Id = (USHORT)Random();
+    /* One fragment at offset 0 */
+    IPHeader->FlagsFragOfs = 0;
+    /* Time-to-Live is 128 */
+    IPHeader->Ttl = 128;
+    /* Internet Control Message Protocol */
+    IPHeader->Protocol = IPPROTO_ICMP;
+    /* Checksum is 0 (for later calculation of this) */
+    IPHeader->Checksum = 0;
+    /* Source address */
+    IPHeader->SrcAddr = NTE->Address->Address.IPv4Address;
+    /* Destination address */
+    IPHeader->DstAddr = Destination->Address.IPv4Address;
+
+    /* Completion handler */
+    PC(NdisPacket)->Complete = SendICMPComplete;
+    PC(NdisPacket)->Context  = IPPacket;
+
+    return IPPacket;
+}
+
+
+VOID ICMPReceive(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives an ICMP packet
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry which the packet was received on
+ *     IPPacket = Pointer to an IP packet that was received
+ */
+{
+    PICMP_HEADER ICMPHeader;
+    PIP_PACKET NewPacket;
+    UINT DataSize;
+    ULONG Checksum;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    ICMPHeader = (PICMP_HEADER)IPPacket->Data;
+
+    TI_DbgPrint(MID_TRACE, ("Size = %d.\n", IPPacket->TotalSize));
+
+    TI_DbgPrint(MID_TRACE, ("HeaderSize = %d.\n", IPPacket->HeaderSize));
+
+    TI_DbgPrint(MID_TRACE, ("Type = %d.\n", ICMPHeader->Type));
+
+    TI_DbgPrint(MID_TRACE, ("Code = %d.\n", ICMPHeader->Code));
+
+    TI_DbgPrint(MID_TRACE, ("Checksum = %X.\n", ICMPHeader->Checksum));
+
+    /* Checksum ICMP header and data and compare */
+    Checksum = DN2H(IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0));
+    if (Checksum != 0xFFFF) {
+        TI_DbgPrint(MIN_TRACE, ("Bad ICMP checksum (0x%X).\n", Checksum));
+        /* Discard packet */
+        return;
+    }
+
+    switch (ICMPHeader->Type) {
+    case ICMP_TYPE_ECHO_REQUEST:
+        /* Reply with an ICMP echo reply message */
+        DataSize  = IPPacket->TotalSize - IPPacket->HeaderSize - sizeof(ICMP_HEADER);
+        NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize);
+        if (!NewPacket)
+            return;
+
+        /* Copy ICMP header and data into new packet */
+        RtlCopyMemory(NewPacket->Data, IPPacket->Data, DataSize  + sizeof(ICMP_HEADER));
+        ((PICMP_HEADER)NewPacket->Data)->Type     = ICMP_TYPE_ECHO_REPLY;
+        ((PICMP_HEADER)NewPacket->Data)->Code     = 0;
+        ((PICMP_HEADER)NewPacket->Data)->Checksum = 0;
+
+        ICMPTransmit(NTE, NewPacket);
+
+        TI_DbgPrint(MID_TRACE, ("Echo reply sent.\n"));
+
+        return;
+    default:
+        TI_DbgPrint(MID_TRACE, ("Discarded ICMP datagram of unknown type.\n"));
+        /* Discard packet */
+        break;
+    }
+}
+
+
+VOID ICMPTransmit(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Transmits an ICMP packet
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry to use (NULL if don't care)
+ *     IPPacket = Pointer to IP packet to transmit
+ */
+{
+    PROUTE_CACHE_NODE RCN;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    /* Calculate checksum of ICMP header and data */
+    ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT)
+        IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0);
+
+    /* Get a route to the destination address */
+    if (RouteGetRouteToDestination(&IPPacket->DstAddr, NTE, &RCN) == IP_SUCCESS) {
+        /* Send the packet */
+        if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) {
+            FreeNdisPacket(IPPacket->NdisPacket);
+            PoolFreeBuffer(IPPacket);
+        }
+        /* We're done with the RCN */
+        DereferenceObject(RCN);
+    } else {
+        TI_DbgPrint(MIN_TRACE, ("RCN at 0x%X.\n", RCN));
+
+        /* No route to destination (or no free resources) */
+        TI_DbgPrint(MIN_TRACE, ("No route to destination address 0x%X.\n",
+            IPPacket->DstAddr.Address.IPv4Address));
+        /* Discard packet */
+        FreeNdisPacket(IPPacket->NdisPacket);
+        PoolFreeBuffer(IPPacket);
+    }
+}
+
+
+VOID ICMPReply(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket,
+       UCHAR Type,
+       UCHAR Code)
+/*
+ * FUNCTION: Transmits an ICMP packet in response to an incoming packet
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry to use
+ *     IPPacket = Pointer to IP packet that was received
+ *     Type     = ICMP message type
+ *     Code     = ICMP message code
+ * NOTES:
+ *     We have received a packet from someone and is unable to
+ *     process it due to error(s) in the packet or we have run out
+ *     of resources. We transmit an ICMP message to the host to
+ *     notify him of the problem
+ */
+{
+    UINT DataSize;
+    PIP_PACKET NewPacket;
+
+    TI_DbgPrint(MID_TRACE, ("Called (Type=%d, Code=%d).\n", Type, Code));
+
+    DataSize = IPPacket->TotalSize;
+    if ((DataSize) > (576 - sizeof(IPv4_HEADER) - sizeof(ICMP_HEADER)))
+        DataSize = 576;
+
+    NewPacket = PrepareICMPPacket(NTE, &IPPacket->SrcAddr, DataSize);
+    if (!NewPacket)
+        return;
+
+    RtlCopyMemory((PVOID)((ULONG_PTR)NewPacket->Data + sizeof(ICMP_HEADER)),
+        IPPacket->Header, DataSize);
+    ((PICMP_HEADER)NewPacket->Data)->Type     = Type;
+    ((PICMP_HEADER)NewPacket->Data)->Code     = Code;
+    ((PICMP_HEADER)NewPacket->Data)->Checksum = 0;
+
+    ICMPTransmit(NTE, NewPacket);
+}
+
+/* EOF */
index f15449c..1ea5af9 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/ip.c
+ * PURPOSE:     Internet Protocol module
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <ip.h>
+#include <loopback.h>
+#include <neighbor.h>
+#include <receive.h>
+#include <address.h>
+#include <route.h>
+#include <icmp.h>
+#include <pool.h>
+
+
+KTIMER IPTimer;
+KDPC IPTimeoutDpc;
+LIST_ENTRY InterfaceListHead;
+KSPIN_LOCK InterfaceListLock;
+LIST_ENTRY NetTableListHead;
+KSPIN_LOCK NetTableListLock;
+LIST_ENTRY PrefixListHead;
+KSPIN_LOCK PrefixListLock;
+UINT MaxLLHeaderSize; /* Largest maximum header size */
+UINT MinLLFrameSize;  /* Largest minimum frame size */
+BOOLEAN IPInitialized = FALSE;
+
+IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
+
+
+PADDRESS_ENTRY CreateADE(
+    PIP_INTERFACE IF,
+    PIP_ADDRESS Address,
+    UCHAR Type,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Creates an address entry and binds it to an interface
+ * ARGUMENTS:
+ *     IF      = Pointer to interface
+ *     Address = Pointer to referenced interface address
+ *     Type    = Type of address (ADE_*)
+ *     NTE     = Pointer to net table entry
+ * RETURNS:
+ *     Pointer to ADE, NULL if there was not enough free resources
+ * NOTES:
+ *     The interface lock must be held when called. The address entry
+ *     retains a reference to the provided address and NTE. The caller
+ *     is responsible for referencing the these before calling.
+ *     As long as you have referenced an ADE you can safely use the
+ *     address and NTE as the ADE references both
+ */
+{
+    PADDRESS_ENTRY ADE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  Type (0x%X)  NTE (0x%X).\n",
+        IF, Address, Type, NTE));
+
+    /* Allocate space for an ADE and set it up */
+    ADE = PoolAllocateBuffer(sizeof(ADDRESS_ENTRY));
+    if (!ADE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    ADE->RefCount = 1;
+    ADE->NTE      = NTE;
+    ADE->Type     = Type;
+    ADE->Address  = Address;
+
+    /* Add ADE to the list on the interface */
+    InsertTailList(&IF->ADEListHead, &ADE->ListEntry);
+
+    return ADE;
+}
+
+
+VOID DestroyADE(
+    PIP_INTERFACE IF,
+    PADDRESS_ENTRY ADE)
+/*
+ * FUNCTION: Destroys an address entry
+ * ARGUMENTS:
+ *     IF  = Pointer to interface
+ *     ADE = Pointer to address entry
+ * NOTES:
+ *     The interface lock must be held when called
+ */
+{
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  ADE (0x%X).\n", IF, ADE));
+
+    /* Unlink the address entry from the list */
+    RemoveEntryList(&ADE->ListEntry);
+
+    /* Dereference the address */
+    DereferenceObject(ADE->Address);
+
+    /* Dereference the NTE */
+    DereferenceObject(ADE->NTE);
+
+#ifdef DBG
+    ADE->RefCount--;
+
+    if (ADE->RefCount != 0) {
+        TI_DbgPrint(MIN_TRACE, ("Address entry at (0x%X) has (%d) references (should be 0).\n", ADE, ADE->RefCount));
+    }
+#endif
+
+    /* And free the ADE */
+    PoolFreeBuffer(ADE);
+    TI_DbgPrint(MIN_TRACE, ("Check.\n"));
+}
+
+
+VOID DestroyADEs(
+    PIP_INTERFACE IF)
+/*
+ * FUNCTION: Destroys all address entries on an interface
+ * ARGUMENTS:
+ *     IF  = Pointer to interface
+ * NOTES:
+ *     The interface lock must be held when called
+ */
+{
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PADDRESS_ENTRY Current;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
+
+    /* Search the list and remove every ADE we find */
+    CurrentEntry = IF->ADEListHead.Flink;
+    while (CurrentEntry != &IF->ADEListHead) {
+        NextEntry = CurrentEntry->Flink;
+           Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
+        /* Destroy the ADE */
+        DestroyADE(IF, Current);
+        CurrentEntry = NextEntry;
+    }
+}
+
+
+PPREFIX_LIST_ENTRY CreatePLE(
+    PIP_INTERFACE IF,
+    PIP_ADDRESS Prefix,
+    UINT Length)
+/*
+ * FUNCTION: Creates a prefix list entry and binds it to an interface
+ * ARGUMENTS:
+ *     IF     = Pointer to interface
+ *     Prefix = Pointer to prefix
+ *     Length = Length of prefix
+ * RETURNS:
+ *     Pointer to PLE, NULL if there was not enough free resources
+ * NOTES:
+ *     The prefix list entry retains a reference to the interface and
+ *     the provided address.  The caller is responsible for providing
+ *     these references
+ */
+{
+    PPREFIX_LIST_ENTRY PLE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Prefix (0x%X)  Length (%d).\n", IF, Prefix, Length));
+
+    /* Allocate space for an PLE and set it up */
+    PLE = PoolAllocateBuffer(sizeof(PREFIX_LIST_ENTRY));
+    if (!PLE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    PLE->RefCount     = 1;
+    PLE->Interface    = IF;
+    PLE->Prefix       = Prefix;
+    PLE->PrefixLength = Length;
+
+    /* Add PLE to the global prefix list */
+    ExInterlockedInsertTailList(&PrefixListHead, &PLE->ListEntry, &PrefixListLock);
+
+    return PLE;
+}
+
+
+VOID DestroyPLE(
+    PPREFIX_LIST_ENTRY PLE)
+/*
+ * FUNCTION: Destroys an prefix list entry
+ * ARGUMENTS:
+ *     PLE = Pointer to prefix list entry
+ * NOTES:
+ *     The prefix list lock must be held when called
+ */
+{
+    TI_DbgPrint(DEBUG_IP, ("Called. PLE (0x%X).\n", PLE));
+
+    /* Unlink the prefix list entry from the list */
+    RemoveEntryList(&PLE->ListEntry);
+
+    /* Dereference the address */
+    DereferenceObject(PLE->Prefix);
+
+    /* Dereference the interface */
+    DereferenceObject(PLE->Interface);
+
+#ifdef DBG
+    PLE->RefCount--;
+
+    if (PLE->RefCount != 0) {
+        TI_DbgPrint(MIN_TRACE, ("Prefix list entry at (0x%X) has (%d) references (should be 0).\n", PLE, PLE->RefCount));
+    }
+#endif
+
+    /* And free the PLE */
+    PoolFreeBuffer(PLE);
+}
+
+
+VOID DestroyPLEs(
+    VOID)
+/*
+ * FUNCTION: Destroys all prefix list entries
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PPREFIX_LIST_ENTRY Current;
+
+    TI_DbgPrint(DEBUG_IP, ("Called.\n"));
+
+    KeAcquireSpinLock(&PrefixListLock, &OldIrql);
+
+    /* Search the list and remove every PLE we find */
+    CurrentEntry = PrefixListHead.Flink;
+    while (CurrentEntry != &PrefixListHead) {
+        NextEntry = CurrentEntry->Flink;
+           Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);
+        /* Destroy the PLE */
+        DestroyPLE(Current);
+        CurrentEntry = NextEntry;
+    }
+    KeReleaseSpinLock(&PrefixListLock, OldIrql);
+}
+
+
+PNET_TABLE_ENTRY IPCreateNTE(
+    PIP_INTERFACE IF,
+    PIP_ADDRESS Address,
+    UINT PrefixLength)
+/*
+ * FUNCTION: Creates a net table entry and binds it to an interface
+ * ARGUMENTS:
+ *     IF           = Pointer to interface
+ *     Address      = Pointer to interface address
+ *     PrefixLength = Length of prefix
+ * RETURNS:
+ *     Pointer to NTE, NULL if there was not enough free resources
+ * NOTES:
+ *     The interface lock must be held when called.
+ *     The net table entry retains a reference to the interface and
+ *     the provided address. The caller is responsible for providing
+ *     these references
+ */
+{
+    PNET_TABLE_ENTRY NTE;
+    PADDRESS_ENTRY ADE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  PrefixLength (%d).\n", IF, Address, PrefixLength));
+
+    /* Allocate room for an NTE */
+    NTE = PoolAllocateBuffer(sizeof(NET_TABLE_ENTRY));
+    if (!NTE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    NTE->Interface = IF;
+
+    /* One reference is for beeing alive and one reference is for the ADE */
+    NTE->RefCount = 2;
+
+    NTE->Address = Address;
+    /* One reference is for NTE, one reference is given to the
+       address entry, and one reference is given to the prefix
+       list entry */
+    ReferenceObject(Address);
+    ReferenceObject(Address);
+    ReferenceObject(Address);
+
+    /* Create an address entry and add it to the list */
+    ADE = CreateADE(IF, NTE->Address, ADE_UNICAST, NTE);
+    if (!ADE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        PoolFreeBuffer(NTE);
+        return NULL;
+    }
+
+    /* Create a prefix list entry for unicast address */
+    NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
+    if (!NTE->PLE) {
+        DestroyADE(IF, ADE);
+        PoolFreeBuffer(NTE);
+        return NULL;
+    }
+
+    /* Reference the interface for the prefix list entry */
+    ReferenceObject(IF);
+
+    /* Add NTE to the list on the interface */
+    InsertTailList(&IF->NTEListHead, &NTE->IFListEntry);
+
+    /* Add NTE to the global net table list */
+    ExInterlockedInsertTailList(&NetTableListHead, &NTE->NTListEntry, &NetTableListLock);
+
+    return NTE;
+}
+
+
+VOID DestroyNTE(
+    PIP_INTERFACE IF,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Destroys a net table entry
+ * ARGUMENTS:
+ *     IF  = Pointer to interface
+ *     NTE = Pointer to net table entry
+ * NOTES:
+ *     The net table list lock must be held when called
+ *     The interface lock must be held when called
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  NTE (0x%X).\n", IF, NTE));
+
+    /* Invalidate the prefix list entry for this NTE */
+    KeAcquireSpinLock(&PrefixListLock, &OldIrql);
+    DestroyPLE(NTE->PLE);
+    KeReleaseSpinLock(&PrefixListLock, OldIrql);
+
+    /* Remove NTE from the interface list */
+    RemoveEntryList(&NTE->IFListEntry);
+    /* Remove NTE from the net table list */
+    RemoveEntryList(&NTE->NTListEntry);
+    /* Dereference the objects that are referenced */
+    DereferenceObject(NTE->Address);
+    DereferenceObject(NTE->Interface);
+#ifdef DBG
+    NTE->RefCount--;
+
+    if (NTE->RefCount != 0) {
+        TI_DbgPrint(MIN_TRACE, ("Net table entry at (0x%X) has (%d) references (should be 0).\n", NTE, NTE->RefCount));
+    }
+#endif
+    /* And free the NTE */
+    PoolFreeBuffer(NTE);
+}
+
+
+VOID DestroyNTEs(
+    PIP_INTERFACE IF)
+/*
+ * FUNCTION: Destroys all net table entries on an interface
+ * ARGUMENTS:
+ *     IF  = Pointer to interface
+ * NOTES:
+ *     The net table list lock must be held when called
+ *     The interface lock may be held when called
+ */
+{
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PNET_TABLE_ENTRY Current;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
+
+    /* Search the list and remove every NTE we find */
+    CurrentEntry = IF->NTEListHead.Flink;
+    while (CurrentEntry != &IF->NTEListHead) {
+        NextEntry = CurrentEntry->Flink;
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
+        /* Destroy the NTE */
+        DestroyNTE(IF, Current);
+        CurrentEntry = NextEntry;
+    }
+}
+
+
+PNET_TABLE_ENTRY IPLocateNTEOnInterface(
+    PIP_INTERFACE IF,
+    PIP_ADDRESS Address,
+    PUINT AddressType)
+/*
+ * FUNCTION: Locates an NTE on an interface
+ * ARGUMENTS:
+ *     IF          = Pointer to interface
+ *     Address     = Pointer to IP address
+ *     AddressType = Address of type of IP address
+ * NOTES:
+ *     If found, the NTE is referenced for the caller. The caller is
+ *     responsible for dereferencing after use
+ * RETURNS:
+ *     Pointer to net table entry, NULL if none was found
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PADDRESS_ENTRY Current;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X)  Address (0x%X)  AddressType (0x%X).\n",
+        IF, Address, AddressType));
+
+    KeAcquireSpinLock(&IF->Lock, &OldIrql);
+
+    /* Search the list and return the NTE if found */
+    CurrentEntry = IF->ADEListHead.Flink;
+    while (CurrentEntry != &IF->ADEListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_ENTRY, ListEntry);
+        if (AddrIsEqual(Address, Current->Address)) {
+            ReferenceObject(Current->NTE);
+            *AddressType = Current->Type;
+            KeReleaseSpinLock(&IF->Lock, OldIrql);
+            return Current->NTE;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&IF->Lock, OldIrql);
+
+    return NULL;
+}
+
+
+PNET_TABLE_ENTRY IPLocateNTE(
+    PIP_ADDRESS Address,
+    PUINT AddressType)
+/*
+ * FUNCTION: Locates an NTE for the network Address is on 
+ * ARGUMENTS:
+ *     Address     = Pointer to an address to find associated NTE of
+ *     AddressType = Address of address type
+ * NOTES:
+ *     If found the NTE is referenced for the caller. The caller is
+ *     responsible for dereferencing after use
+ * RETURNS:
+ *     Pointer to NTE if the address was found, NULL if not.
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PNET_TABLE_ENTRY Current;
+    PNET_TABLE_ENTRY NTE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X)  AddressType (0x%X).\n",
+        Address, AddressType));
+    
+    KeAcquireSpinLock(&NetTableListLock, &OldIrql);
+
+    /* Search the list and return the NTE if found */
+    CurrentEntry = NetTableListHead.Flink;
+    while (CurrentEntry != &NetTableListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, NTListEntry);
+        NTE = IPLocateNTEOnInterface(Current->Interface, Address, AddressType);
+        if (NTE) {
+            ReferenceObject(NTE);
+            KeReleaseSpinLock(&NetTableListLock, OldIrql);
+            return NTE;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&NetTableListLock, OldIrql);
+
+    return NULL;
+}
+
+
+PADDRESS_ENTRY IPLocateADE(
+    PIP_ADDRESS Address,
+    UINT AddressType)
+/*
+ * FUNCTION: Locates an ADE for the address
+ * ARGUMENTS:
+ *     Address     = Pointer to an address to find associated ADE of
+ *     AddressType = Type of address
+ * RETURNS:
+ *     Pointer to ADE if the address was found, NULL if not.
+ * NOTES:
+ *     If found the ADE is referenced for the caller. The caller is
+ *     responsible for dereferencing after use
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentIFEntry;
+    PLIST_ENTRY CurrentADEEntry;
+    PIP_INTERFACE CurrentIF;
+    PADDRESS_ENTRY CurrentADE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X)  AddressType (0x%X).\n",
+        Address, AddressType));
+
+    KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+    /* Search the interface list */
+    CurrentIFEntry = InterfaceListHead.Flink;
+    while (CurrentIFEntry != &InterfaceListHead) {
+           CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
+
+        /* Search the address entry list and return the ADE if found */
+        CurrentADEEntry = CurrentIF->ADEListHead.Flink;
+        while (CurrentADEEntry != &CurrentIF->ADEListHead) {
+               CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
+            if ((AddrIsEqual(Address, CurrentADE->Address)) && 
+                (CurrentADE->Type == AddressType)) {
+                ReferenceObject(CurrentADE);
+                KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+                return CurrentADE;
+            }
+            CurrentADEEntry = CurrentADEEntry->Flink;
+        }
+        CurrentIFEntry = CurrentIFEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+    return NULL;
+}
+
+
+PADDRESS_ENTRY IPGetDefaultADE(
+    UINT AddressType)
+/*
+ * FUNCTION: Returns a default address entry
+ * ARGUMENTS:
+ *     AddressType = Type of address
+ * RETURNS:
+ *     Pointer to ADE if found, NULL if not.
+ * NOTES:
+ *     Loopback interface is only considered if it is the only interface.
+ *     If found, the address entry is referenced
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentIFEntry;
+    PLIST_ENTRY CurrentADEEntry;
+    PIP_INTERFACE CurrentIF;
+    PADDRESS_ENTRY CurrentADE;
+#if 0
+    BOOLEAN LoopbackIsRegistered = FALSE;
+#endif
+    TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
+
+    KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+    /* Search the interface list */
+    CurrentIFEntry = InterfaceListHead.Flink;
+    while (CurrentIFEntry != &InterfaceListHead) {
+           CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
+#if 0
+        if (CurrentIF != Loopback) {
+#endif
+            /* Search the address entry list and return the first appropriate ADE found */
+            CurrentADEEntry = CurrentIF->ADEListHead.Flink;
+            while (CurrentADEEntry != &CurrentIF->ADEListHead) {
+                   CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
+                if (CurrentADE->Type == AddressType)
+                    ReferenceObject(CurrentADE);
+                    KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+                    return CurrentADE;
+                }
+                CurrentADEEntry = CurrentADEEntry->Flink;
+#if 0
+        } else
+            LoopbackIsRegistered = TRUE;
+#endif
+        CurrentIFEntry = CurrentIFEntry->Flink;
+    }
+#if 0
+    /* No address was found. Use loopback interface if available */
+    if (LoopbackIsRegistered) {
+        CurrentADEEntry = Loopback->ADEListHead.Flink;
+        while (CurrentADEEntry != &Loopback->ADEListHead) {
+               CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
+            if (CurrentADE->Type == AddressType) {
+                ReferenceObject(CurrentADE);
+                KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+                return CurrentADE;
+            }
+            CurrentADEEntry = CurrentADEEntry->Flink;
+        }
+    }
+#endif
+    KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+    return NULL;
+}
+
+
+VOID IPTimeout(
+    PKDPC Dpc,
+    PVOID DeferredContext,
+    PVOID SystemArgument1,
+    PVOID SystemArgument2)
+/*
+ * FUNCTION: Timeout DPC
+ * ARGUMENTS:
+ *     Dpc             = Pointer to our DPC object
+ *     DeferredContext = Pointer to context information (unused)
+ *     SystemArgument1 = Unused
+ *     SystemArgument2 = Unused
+ * NOTES:
+ *     This routine is dispatched once in a while to do maintainance jobs
+ */
+{
+    /* Check if datagram fragments have taken too long to assemble */
+    IPDatagramReassemblyTimeout();
+
+    /* Clean possible outdated cached neighbor addresses */
+    NBTimeout();
+}
+
+
+VOID IPDispatchProtocol(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: IP protocol dispatcher
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry which the packet was received on
+ *     IPPacket = Pointer to an IP packet that was received
+ * NOTES:
+ *     This routine examines the IP header and passes the packet on to the
+ *     right upper level protocol receive handler
+ */
+{
+    UINT Protocol;
+
+    switch (IPPacket->Type) {
+    case IP_ADDRESS_V4:
+        Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
+        break;
+    case IP_ADDRESS_V6:
+        /* FIXME: IPv6 adresses not supported */
+        TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
+        return;
+    default:
+        Protocol = 0;
+    }
+
+    /* Call the appropriate protocol handler */
+    (*ProtocolTable[Protocol])(NTE, IPPacket);
+}
+
+
+PIP_INTERFACE IPCreateInterface(
+    PLLIP_BIND_INFO BindInfo)
+/*
+ * FUNCTION: Creates an IP interface
+ * ARGUMENTS:
+ *     BindInfo = Pointer to link layer to IP binding information
+ * RETURNS:
+ *     Pointer to IP_INTERFACE structure, NULL if there was
+ *     not enough free resources
+ */
+{
+    PIP_INTERFACE IF;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
+
+    IF = PoolAllocateBuffer(sizeof(IP_INTERFACE));
+    if (!IF) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    IF->RefCount      = 1;
+    IF->Context       = BindInfo->Context;
+    IF->HeaderSize    = BindInfo->HeaderSize;
+       if (IF->HeaderSize > MaxLLHeaderSize)
+               MaxLLHeaderSize = IF->HeaderSize;
+
+    IF->MinFrameSize  = BindInfo->MinFrameSize;
+       if (IF->MinFrameSize > MinLLFrameSize)
+               MinLLFrameSize = IF->MinFrameSize;
+
+    IF->MTU           = BindInfo->MTU;
+    IF->Address       = BindInfo->Address;
+    IF->AddressLength = BindInfo->AddressLength;
+    IF->Transmit      = BindInfo->Transmit;
+
+    InitializeListHead(&IF->ADEListHead);
+    InitializeListHead(&IF->NTEListHead);
+
+    KeInitializeSpinLock(&IF->Lock);
+
+    return IF;
+}
+
+
+VOID IPDestroyInterface(
+    PIP_INTERFACE IF)
+/*
+ * FUNCTION: Destroys an IP interface
+ * ARGUMENTS:
+ *     IF = Pointer to interface to destroy
+ */
+{
+    KIRQL OldIrql1;
+    KIRQL OldIrql2;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
+
+    KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
+    KeAcquireSpinLock(&IF->Lock, &OldIrql2);
+    DestroyADEs(IF);
+    DestroyNTEs(IF);
+    KeReleaseSpinLock(&IF->Lock, OldIrql2);
+    KeReleaseSpinLock(&NetTableListLock, OldIrql1);
+
+#ifdef DBG
+    IF->RefCount--;
+
+    if (IF->RefCount != 0) {
+        TI_DbgPrint(MIN_TRACE, ("Interface at (0x%X) has (%d) references (should be 0).\n", IF, IF->RefCount));
+    }
+#endif
+    PoolFreeBuffer(IF);
+}
+
+
+BOOLEAN IPRegisterInterface(
+    PIP_INTERFACE IF)
+/*
+ * FUNCTION: Registers an IP interface with IP layer
+ * ARGUMENTS:
+ *     IF = Pointer to interface to register
+ * RETURNS;
+ *     TRUE if interface was successfully registered, FALSE if not
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PNET_TABLE_ENTRY Current;
+    PROUTE_CACHE_NODE RCN;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
+
+    KeAcquireSpinLock(&IF->Lock, &OldIrql);
+
+    /* Add routes to all NTEs on this interface */
+    CurrentEntry = IF->NTEListHead.Flink;
+    while (CurrentEntry != &IF->NTEListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
+
+        /* Add a permanent neighbor for this NTE */
+        ReferenceObject(Current->Address);
+        NCE = NBAddNeighbor(IF, Current->Address, IF->Address,
+            IF->AddressLength, NUD_PERMANENT);
+        if (!NCE) {
+            TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
+            DereferenceObject(Current->Address);
+            KeReleaseSpinLock(&IF->Lock, OldIrql);
+            return FALSE;
+        }
+        RCN = RouteAddRouteToDestination(Current->Address, Current, IF, NCE);
+        if (!RCN) {
+            TI_DbgPrint(MIN_TRACE, ("Could not create RCN.\n"));
+            DereferenceObject(Current->Address);
+            KeReleaseSpinLock(&IF->Lock, OldIrql);
+            return FALSE;
+        }
+        /* Don't need this any more since the route cache references the NCE */
+        DereferenceObject(NCE);
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    /* Add interface to the global interface list */
+    ExInterlockedInsertTailList(&InterfaceListHead, &IF->ListEntry, &InterfaceListLock);
+
+    KeReleaseSpinLock(&IF->Lock, OldIrql);
+
+    return TRUE;
+}
+
+
+VOID IPUnregisterInterface(
+    PIP_INTERFACE IF)
+/*
+ * FUNCTION: Unregisters an IP interface with IP layer
+ * ARGUMENTS:
+ *     IF = Pointer to interface to unregister
+ */
+{
+    KIRQL OldIrql1;
+    KIRQL OldIrql2;
+    KIRQL OldIrql3;
+    PLIST_ENTRY CurrentEntry;
+    PNET_TABLE_ENTRY Current;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
+
+    KeAcquireSpinLock(&NetTableListLock, &OldIrql1);
+    KeAcquireSpinLock(&IF->Lock, &OldIrql2);
+
+    /* Remove routes to all NTEs on this interface */
+    CurrentEntry = IF->NTEListHead.Flink;
+    while (CurrentEntry != &IF->NTEListHead) {
+        Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
+
+        /* Remove NTE from global net table list */
+        RemoveEntryList(&Current->NTListEntry);
+
+        /* Remove all references from route cache to NTE */
+        RouteInvalidateNTE(Current);
+
+        /* Remove permanent NCE, but first we have to find it */
+        NCE = NBLocateNeighbor(Current->Address);
+        if (NCE) {
+            DereferenceObject(NCE);
+            NBRemoveNeighbor(NCE);
+        }
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeAcquireSpinLock(&InterfaceListLock, &OldIrql3);
+    /* Ouch...three spinlocks acquired! Fortunately
+       we don't unregister interfaces very often */
+    RemoveEntryList(&IF->ListEntry);
+    KeReleaseSpinLock(&InterfaceListLock, OldIrql3);
+
+    KeReleaseSpinLock(&IF->Lock, OldIrql2);
+    KeReleaseSpinLock(&NetTableListLock, OldIrql1);
+}
+
+
+VOID IPRegisterProtocol(
+    UINT ProtocolNumber,
+    IP_PROTOCOL_HANDLER Handler)
+/*
+ * FUNCTION: Registers a handler for an IP protocol number
+ * ARGUMENTS:
+ *     ProtocolNumber = Internet Protocol number for which to register handler
+ *     Handler        = Pointer to handler to be called when a packet is received
+ * NOTES:
+ *     To unregister a protocol handler, call this function with Handler = NULL
+ */
+{
+#ifdef DBG
+    if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE)
+        TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
+#endif
+
+    ProtocolTable[ProtocolNumber] = Handler;
+}
+
+
+VOID DefaultProtocolHandler(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Default handler for Internet protocols
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry which the packet was received on
+ *     IPPacket = Pointer to an IP packet that was received
+ */
+{
+    TI_DbgPrint(MID_TRACE, ("Packet of unknown Internet protocol discarded.\n"));
+}
+
+
+NTSTATUS IPStartup(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Initializes the IP subsystem
+ * ARGUMENTS:
+ *     DriverObject = Pointer to a driver object for this driver
+ *     RegistryPath = Our registry node for configuration parameters
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    UINT i;
+    LARGE_INTEGER DueTime;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+       MaxLLHeaderSize = 0;
+    MinLLFrameSize  = 0;
+
+    /* Start routing subsystem */
+    RouterStartup();
+
+    /* Start route cache subsystem */
+    RouteStartup();
+
+    /* Start neighbor cache subsystem */
+    NBStartup();
+
+    /* Fill the protocol dispatch table with pointers
+       to the default protocol handler */
+    for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
+        IPRegisterProtocol(i, DefaultProtocolHandler);
+
+    /* Register network level protocol receive handlers */
+    IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
+
+    /* Initialize NTE list and protecting lock */
+    InitializeListHead(&NetTableListHead);
+    KeInitializeSpinLock(&NetTableListLock);
+
+    /* Initialize reassembly list and protecting lock */
+    InitializeListHead(&ReassemblyListHead);
+    KeInitializeSpinLock(&ReassemblyListLock);
+
+    /* Initialize the prefix list and protecting lock */
+    InitializeListHead(&PrefixListHead);
+    KeInitializeSpinLock(&PrefixListLock);
+
+    /* Initialize our periodic timer and its associated DPC object. When the
+       timer expires, the IPTimeout deferred procedure call (DPC) is queued */
+    KeInitializeDpc(&IPTimeoutDpc, IPTimeout, NULL);
+    KeInitializeTimer(&IPTimer);
+
+    /* Start the periodic timer with an initial and periodic
+       relative expiration time of IP_TIMEOUT milliseconds */
+    DueTime.QuadPart = -(LONGLONG)IP_TIMEOUT * 10000;
+    KeSetTimerEx(&IPTimer, DueTime, IP_TIMEOUT, &IPTimeoutDpc);
+
+    IPInitialized = TRUE;
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS IPShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the IP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    if (!IPInitialized)
+        return STATUS_SUCCESS;
+
+    /* Cancel timer */
+    KeCancelTimer(&IPTimer);
+
+    /* Shutdown neighbor cache subsystem */
+    NBShutdown();
+
+    /* Shutdown route cache subsystem */
+    RouteShutdown();
+
+    /* Shutdown routing subsystem */
+    RouterShutdown();
+
+    IPFreeReassemblyList();
+
+    /* Clear prefix list */
+    DestroyPLEs();
+
+    IPInitialized = FALSE;
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
index 2e17cb4..3cd103a 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/neighbor.c
+ * PURPOSE:     Neighbor address cache
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <neighbor.h>
+#include <routines.h>
+#include <neighbor.h>
+#include <transmit.h>
+#include <address.h>
+#include <route.h>
+#include <pool.h>
+#include <arp.h>
+#include <ip.h>
+
+
+NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];
+
+
+VOID NCETimeout(
+    PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Neighbor cache entry timeout handler
+ * NOTES:
+ *     The neighbor cache lock must be held
+ */
+{
+    PNDIS_PACKET NdisPacket, Next;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));
+
+    TI_DbgPrint(DEBUG_NCACHE, ("NCE->State is (0x%X).\n", NCE->State));
+
+    switch (NCE->State) {
+    case NUD_INCOMPLETE:
+        /* Retransmission timer expired */
+        if (NCE->EventCount++ > MAX_MULTICAST_SOLICIT) {
+            /* We have retransmitted too many times */
+
+            /* Calling IPSendComplete with cache lock held is not
+               a great thing to do. We don't get here very often
+               so maybe it's not that big a problem */
+
+            /* Flush packet queue */
+            NdisPacket = NCE->WaitQueue;
+            while (NdisPacket) {
+                Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;
+                IPSendComplete((PVOID)NCE->Interface, NdisPacket,
+                    NDIS_STATUS_REQUEST_ABORTED);
+                NdisPacket = Next;
+            }
+            NCE->WaitQueue = NULL;
+
+            NCE->EventCount = 0;
+
+            /* Remove route cache entries with references to this NCE.
+               Remember that neighbor cache lock is taken before
+               route cache lock */
+            RouteInvalidateNCE(NCE);
+        } else
+            /* Retransmit request */
+            NBSendSolicit(NCE);
+        break;
+
+    case NUD_DELAY:
+        /* FIXME: Delayed state */
+        TI_DbgPrint(DEBUG_NCACHE, ("NCE delay state.\n"));
+        break;
+
+    case NUD_PROBE:
+        /* FIXME: Probe state */
+        TI_DbgPrint(DEBUG_NCACHE, ("NCE probe state.\n"));
+        break;
+
+    default:
+        /* Should not happen since other states don't use the event timer */
+        TI_DbgPrint(MIN_TRACE, ("Invalid NCE state (%d).\n", NCE->State));
+        break;
+    }
+}
+
+
+VOID NBTimeout(
+    VOID)
+/*
+ * FUNCTION: Neighbor address cache timeout handler
+ * NOTES:
+ *     This routine is called by IPTimeout to remove outdated cache
+ *     entries.
+ */
+{
+    UINT i;
+    KIRQL OldIrql;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    for (i = 0; i <= NB_HASHMASK; i++) {
+        KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
+
+        for (NCE = NeighborCache[i].Cache;
+            NCE != NULL; NCE = NCE->Next) {
+            /* Check if event timer is running */
+            if (NCE->EventTimer != 0)  {
+                if (--NCE->EventTimer == 0) {
+                    /* Call timeout handler for NCE */
+                    NCETimeout(NCE);
+                }
+            }
+        }
+
+        KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);
+    }
+}
+
+
+VOID NBStartup(
+    VOID)
+/*
+ * FUNCTION: Starts the neighbor cache
+ */
+{
+       UINT i;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called.\n"));
+
+    for (i = 0; i <= NB_HASHMASK; i++) {
+        NeighborCache[i].Cache = NULL;
+        KeInitializeSpinLock(&NeighborCache[i].Lock);
+    }
+}
+
+
+VOID NBShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the neighbor cache
+ */
+{
+       UINT i;
+    KIRQL OldIrql;
+    PNDIS_PACKET NdisPacket, Next;
+    PNEIGHBOR_CACHE_ENTRY CurNCE, NextNCE;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called.\n"));
+
+    /* Remove possible entries from the cache */
+    for (i = 0; i <= NB_HASHMASK; i++) {
+        KeAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
+
+        CurNCE = NeighborCache[i].Cache;
+        while (CurNCE) {
+            NextNCE = CurNCE->Next;
+
+            /* Remove all references from route cache */
+            RouteInvalidateNCE(CurNCE);
+
+            /* Flush wait queue */
+            NdisPacket = CurNCE->WaitQueue;
+            while (NdisPacket) {
+                Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;
+                FreeNdisPacket(NdisPacket);
+                NdisPacket = Next;
+            }
+
+#if DBG
+            if (CurNCE->RefCount != 1) {
+                TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 1).\n", CurNCE, CurNCE->RefCount));
+            }
+#endif
+
+            /* Remove reference for being alive */
+            DereferenceObject(CurNCE);
+
+            CurNCE = NextNCE;
+        }
+        NeighborCache[i].Cache = NULL;
+
+        KeReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+VOID NBSendSolicit(
+    PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Sends a neighbor solicitation message
+ * ARGUMENTS:
+ *     NCE = Pointer to NCE of neighbor to solicit
+ * NOTES:
+ *     May be called with lock held on NCE's table
+ */
+{
+    PLIST_ENTRY CurrentEntry;
+    PNET_TABLE_ENTRY NTE;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));
+
+    if (NCE->State == NUD_INCOMPLETE) {
+        /* This is the first solicitation of this neighbor. Broadcast
+           a request for the neighbor */
+
+        /* FIXME: Choose first NTE. We might want to give an NTE as argument */
+        CurrentEntry = NCE->Interface->NTEListHead.Flink;
+        if (!IsListEmpty(CurrentEntry)) {
+            NTE = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
+            ARPTransmit(NCE->Address, NTE);
+        } else {
+            TI_DbgPrint(MIN_TRACE, ("Interface at 0x%X has zero NTE.\n", NCE->Interface));
+        }
+    } else {
+        /* FIXME: Unicast solicitation since we have a cached address */
+        TI_DbgPrint(MIN_TRACE, ("Uninplemented unicast solicitation.\n"));
+    }
+}
+
+
+PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(
+    PIP_INTERFACE Interface,
+    PIP_ADDRESS Address,
+    PVOID LinkAddress,
+    UINT LinkAddressLength,
+    UCHAR State)
+/*
+ * FUNCTION: Adds a neighbor to the neighbor cache
+ * ARGUMENTS:
+ *     Interface         = Pointer to interface
+ *     Address           = Pointer to IP address
+ *     LinkAddress       = Pointer to link address (may be NULL)
+ *     LinkAddressLength = Length of link address
+ *     State             = State of NCE
+ * RETURNS:
+ *     Pointer to NCE, NULL there is not enough free resources
+ * NOTES:
+ *     The NCE if referenced for the caller if created. The NCE retains
+ *     a reference to the IP address if it is created, the caller is
+ *     responsible for providing this reference
+ */
+{
+    ULONG HashValue;
+    KIRQL OldIrql;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. Interface (0x%X)  Address (0x%X)  "
+        "LinkAddress (0x%X)  LinkAddressLength (%d)  State (0x%X)\n",
+        Interface, Address, LinkAddress, LinkAddressLength, State));
+
+    NCE = PoolAllocateBuffer(sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength);
+    if (!NCE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    /* Reference once for beeing alive and once for the caller */
+    NCE->RefCount  = 2;
+    NCE->Interface = Interface;
+    NCE->Address   = Address;
+    NCE->LinkAddressLength = LinkAddressLength;
+    NCE->LinkAddress       = (PVOID)((ULONG_PTR)NCE + sizeof(NEIGHBOR_CACHE_ENTRY));
+    if (LinkAddress)
+        RtlCopyMemory(NCE->LinkAddress, LinkAddress, LinkAddressLength);
+    NCE->State      = State;
+    NCE->EventTimer = 0; /* Not in use */
+    NCE->WaitQueue  = NULL;
+
+    HashValue  = *(PULONG)&Address->Address;
+    HashValue ^= HashValue >> 16;
+    HashValue ^= HashValue >> 8;
+    HashValue ^= HashValue >> 4;
+    HashValue &= NB_HASHMASK;
+
+    NCE->Table = &NeighborCache[HashValue];
+
+    KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
+
+    NCE->Next = NeighborCache[HashValue].Cache;
+    NeighborCache[HashValue].Cache = NCE;
+
+    KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+
+    return NCE;
+}
+
+
+VOID NBUpdateNeighbor(
+    PNEIGHBOR_CACHE_ENTRY NCE,
+    PVOID LinkAddress,
+    UCHAR State)
+/*
+ * FUNCTION: Update link address information in NCE
+ * ARGUMENTS:
+ *     NCE         = Pointer to NCE to update
+ *     LinkAddress = Pointer to link address
+ *     State       = State of NCE
+ * NOTES:
+ *     The link address and state is updated. Any waiting packets are sent
+ */
+{
+    KIRQL OldIrql;
+    PNDIS_PACKET Current;
+    PNDIS_PACKET Next;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X)  LinkAddress (0x%X)  State (0x%X).\n", NCE, LinkAddress, State));
+
+    KeAcquireSpinLock(&NCE->Table->Lock, &OldIrql);
+
+    RtlCopyMemory(NCE->LinkAddress, LinkAddress, NCE->LinkAddressLength);
+    NCE->State     = State;
+    Current        = NCE->WaitQueue;
+    NCE->WaitQueue = NULL;
+
+    KeReleaseSpinLock(&NCE->Table->Lock, OldIrql);
+#if 1
+    /* Send any waiting packets */
+    while (Current) {
+        /* Our link to the next packet is broken by the
+           datalink layer code so we must save it here */
+        Next = (PNDIS_PACKET)PC(Current)->DLComplete;
+        IPSendFragment(Current, NCE);
+        Current = Next;
+    }
+#endif
+}
+
+
+PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(
+    PIP_ADDRESS Address)
+/*
+ * FUNCTION: Locates a neighbor in the neighbor cache
+ * ARGUMENTS:
+ *     Address = Pointer to IP address
+ * RETURNS:
+ *     Pointer to NCE, NULL if not found
+ * NOTES:
+ *     If the NCE is found, it is referenced. The caller is
+ *     responsible for dereferencing it again after use
+ */
+{
+    UINT HashValue;
+    KIRQL OldIrql;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. Address (0x%X).\n", Address));
+
+    HashValue  = *(PULONG)&Address->Address;
+    HashValue ^= HashValue >> 16;
+    HashValue ^= HashValue >> 8;
+    HashValue ^= HashValue >> 4;
+    HashValue &= NB_HASHMASK;
+
+    KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
+
+    NCE = NeighborCache[HashValue].Cache;
+
+    while ((NCE) && (!AddrIsEqual(Address, NCE->Address)))
+        NCE = NCE->Next;
+
+    if (NCE)
+        ReferenceObject(NCE);
+
+    KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return NCE;
+}
+
+
+PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor(
+    PIP_INTERFACE Interface,
+    PIP_ADDRESS Address)
+/*
+ * FUNCTION: Tries to find a neighbor and if unsuccesful, creates a new NCE
+ * ARGUMENTS:
+ *     Interface = Pointer to interface to use (if NCE is not found)
+ *     Address   = Pointer to IP address
+ * RETURNS:
+ *     Pointer to NCE, NULL if there is not enough free resources
+ * NOTES:
+ *     The NCE is referenced if found or created. The caller is
+ *     responsible for dereferencing it again after use
+ */
+{
+    PNEIGHBOR_CACHE_ENTRY NCE;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. Interface (0x%X)  Address (0x%X).\n", Interface, Address));
+
+    NCE = NBLocateNeighbor(Address);
+    if (!NCE) {
+        ReferenceObject(Address);
+        NCE = NBAddNeighbor(Interface, Address, NULL, 
+            Interface->AddressLength, NUD_INCOMPLETE);
+        NCE->EventTimer = 1;
+        NCE->EventCount = 0;
+    }
+
+    return NCE;
+}
+
+
+BOOLEAN NBQueuePacket(
+    PNEIGHBOR_CACHE_ENTRY NCE,
+    PNDIS_PACKET NdisPacket)
+/*
+ * FUNCTION: Queues a packet on an NCE for later transmission
+ * ARGUMENTS:
+ *     NCE        = Pointer to NCE to queue packet on
+ *     NdisPacket = Pointer to NDIS packet to queue
+ * RETURNS:
+ *     TRUE if the packet was successfully queued, FALSE if not
+ */
+{
+    KIRQL OldIrql;
+    PKSPIN_LOCK Lock;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X)  NdisPacket (0x%X).\n", NCE, NdisPacket));
+
+    /* FIXME: Should we limit the number of queued packets? */
+
+    Lock = &NCE->Table->Lock;
+
+    KeAcquireSpinLock(Lock, &OldIrql);
+
+    /* Use data link level completion handler pointer to link
+       queued packets together */
+    PC(NdisPacket)->DLComplete = (PACKET_COMPLETION_ROUTINE)NCE->WaitQueue;
+    NCE->WaitQueue = NdisPacket;
+
+    KeReleaseSpinLock(Lock, OldIrql);
+
+    return TRUE;
+}
+
+
+VOID NBRemoveNeighbor(
+    PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Removes a neighbor from the neighbor cache
+ * ARGUMENTS:
+ *     NCE = Pointer to NCE to remove from cache
+ * NOTES:
+ *     The NCE must be in a safe state
+ */
+{
+    ULONG HashValue;
+    KIRQL OldIrql;
+    PNEIGHBOR_CACHE_ENTRY *PrevNCE;
+    PNEIGHBOR_CACHE_ENTRY CurNCE;
+    PNDIS_PACKET NdisPacket, Next;
+
+    TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));
+
+       HashValue  = *(PULONG)(&NCE->Address->Address);
+    HashValue ^= HashValue >> 16;
+       HashValue ^= HashValue >> 8;
+       HashValue ^= HashValue >> 4;
+       HashValue &= NB_HASHMASK;
+
+    KeAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
+
+    /* Search the list and remove the NCE from the list if found */
+    for (PrevNCE = &NeighborCache[HashValue].Cache;
+        (CurNCE  = *PrevNCE) != NULL;
+        PrevNCE  = &CurNCE->Next) {
+        if (CurNCE == NCE) {
+            /* Found it, now unlink it from the list */
+            *PrevNCE = CurNCE->Next;
+
+            /* Purge wait queue */
+            NdisPacket = CurNCE->WaitQueue;
+            while (NdisPacket) {
+                Next = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;
+                FreeNdisPacket(NdisPacket);
+                NdisPacket = Next;
+            }
+
+            /* Remove all references from route cache */
+            RouteInvalidateNCE(CurNCE);
+
+            /* Remove reference to the address */
+            DereferenceObject(CurNCE->Address);
+
+#if DBG
+            CurNCE->RefCount--;
+
+            if (CurNCE->RefCount != 0) {
+                TI_DbgPrint(DEBUG_REFCOUNT, ("NCE at (0x%X) has (%d) references (should be 0).\n", CurNCE, CurNCE->RefCount));
+            }
+#endif
+            PoolFreeBuffer(CurNCE);
+            
+            KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+
+            return;
+        }
+    }
+
+    KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+}
+
+/* EOF */
index 679a899..01ee7ac 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/receive.c
+ * PURPOSE:     Internet Protocol receive routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * NOTES:       The IP datagram reassembly algorithm is taken from
+ *              from RFC 815
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <receive.h>
+#include <routines.h>
+#include <checksum.h>
+#include <transmit.h>
+#include <address.h>
+#include <pool.h>
+#include <route.h>
+
+
+LIST_ENTRY ReassemblyListHead;
+KSPIN_LOCK ReassemblyListLock;
+
+
+PIPDATAGRAM_HOLE CreateHoleDescriptor(
+    ULONG First,
+    ULONG Last)
+/*
+ * FUNCTION: Returns a pointer to a IP datagram hole descriptor
+ * ARGUMENTS:
+ *     First = Offset of first octet of the hole
+ *     Last  = Offset of last octet of the hole
+ * RETURNS:
+ *     Pointer to descriptor, NULL if there was not enough free
+ *     resources
+ */
+{
+    PIPDATAGRAM_HOLE Hole;
+
+    TI_DbgPrint(DEBUG_IP, ("Called. First (%d)  Last (%d).\n", First, Last));
+
+    Hole = PoolAllocateBuffer(sizeof(IPDATAGRAM_HOLE));
+    if (!Hole) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    Hole->First = First;
+    Hole->Last  = Last;
+
+    TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));
+
+    return Hole;
+}
+
+
+VOID FreeIPDR(
+    PIPDATAGRAM_REASSEMBLY IPDR)
+/*
+ * FUNCTION: Frees an IP datagram reassembly structure
+ * ARGUMENTS:
+ *     IPDR = Pointer to IP datagram reassembly structure
+ */
+{
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PIPDATAGRAM_HOLE CurrentH;
+    PIP_FRAGMENT CurrentF;
+
+    TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));
+
+    /* Free all descriptors */
+    CurrentEntry = IPDR->HoleListHead.Flink;
+    while (CurrentEntry != &IPDR->HoleListHead) {
+        NextEntry = CurrentEntry->Flink;
+           CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+        /* Unlink it from the list */
+        RemoveEntryList(CurrentEntry);
+           
+        TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));
+
+        /* And free the hole descriptor */
+        PoolFreeBuffer(CurrentH);
+
+        CurrentEntry = NextEntry;
+    }
+
+    /* Free all fragments */
+    CurrentEntry = IPDR->FragmentListHead.Flink;
+    while (CurrentEntry != &IPDR->FragmentListHead) {
+        NextEntry = CurrentEntry->Flink;
+           CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
+        /* Unlink it from the list */
+        RemoveEntryList(CurrentEntry);
+
+        TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data));
+
+        /* Free the fragment data buffer */
+        ExFreePool(CurrentF->Data);
+
+        TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
+
+        /* And free the fragment descriptor */
+        PoolFreeBuffer(CurrentF);
+        CurrentEntry = NextEntry;
+    }
+
+    /* Free resources for the header, if it exists */
+    if (IPDR->IPv4Header) {
+        TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header));
+        ExFreePool(IPDR->IPv4Header);
+    }
+
+    TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
+
+    PoolFreeBuffer(IPDR);
+}
+
+
+VOID RemoveIPDR(
+    PIPDATAGRAM_REASSEMBLY IPDR)
+/*
+ * FUNCTION: Removes an IP datagram reassembly structure from the global list
+ * ARGUMENTS:
+ *     IPDR = Pointer to IP datagram reassembly structure
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
+
+    KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+    RemoveEntryList(&IPDR->ListEntry);
+    KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+}
+
+
+PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Returns a pointer to an IP datagram reassembly structure
+ * ARGUMENTS:
+ *     IPPacket = Pointer to IP packet
+ * NOTES:
+ *     A datagram is identified by four paramters, which are
+ *     Source and destination address, protocol number and
+ *     identification number
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PIPDATAGRAM_REASSEMBLY Current;
+    PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
+
+    TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
+
+    KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+
+    /* FIXME: Assume IPv4 */
+
+    CurrentEntry = ReassemblyListHead.Flink;
+    while (CurrentEntry != &ReassemblyListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
+        if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
+            (Header->Id == Current->Id) &&
+            (Header->Protocol == Current->Protocol) &&
+            (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
+            KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+
+            return Current;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+
+    return NULL;
+}
+
+
+PIP_PACKET ReassembleDatagram(
+    PIPDATAGRAM_REASSEMBLY IPDR)
+/*
+ * FUNCTION: Reassembles an IP datagram
+ * ARGUMENTS:
+ *     IPDR = Pointer to IP datagram reassembly structure
+ * NOTES:
+ *     This routine concatenates fragments into a complete IP datagram.
+ *     The lock is held when this routine is called
+ * RETURNS:
+ *     Pointer to IP packet, NULL if there was not enough free resources
+ */
+{
+    PIP_PACKET IPPacket;
+    PLIST_ENTRY CurrentEntry;
+    PIP_FRAGMENT Current;
+    PVOID Data;
+
+    TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
+
+    IPPacket = PoolAllocateBuffer(sizeof(IP_PACKET));
+    if (!IPPacket) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+       /* FIXME: Assume IPv4 */
+
+       IPPacket->Type       = IP_ADDRESS_V4;
+    IPPacket->RefCount   = 1;
+    IPPacket->TotalSize  = IPDR->HeaderSize + IPDR->DataSize;
+    IPPacket->HeaderSize = IPDR->HeaderSize;
+    IPPacket->Position   = IPDR->HeaderSize;
+
+    RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
+    RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
+
+    /* Allocate space for full IP datagram */
+    IPPacket->Header = ExAllocatePool(NonPagedPool, IPPacket->TotalSize);
+    if (!IPPacket->Header) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        PoolFreeBuffer(IPPacket);
+        return NULL;
+    }
+
+    /* Copy the header into the buffer */
+    RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);
+
+       Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
+    IPPacket->Data = Data;
+
+    /* Copy data from all fragments into buffer */
+    CurrentEntry = IPDR->FragmentListHead.Flink;
+    while (CurrentEntry != &IPDR->FragmentListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
+
+        TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",
+            Current->Size, Data, Current->Offset));
+        /* Copy fragment data to the destination buffer at the correct offset */
+        RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset),
+                      Current->Data,
+                      Current->Size);
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    return IPPacket;
+}
+
+
+__inline VOID Cleanup(
+    PKSPIN_LOCK Lock,
+    KIRQL OldIrql,
+    PIPDATAGRAM_REASSEMBLY IPDR,
+    PVOID Buffer OPTIONAL)
+/*
+ * FUNCTION: Performs cleaning operations on errors
+ * ARGUMENTS:
+ *     Lock     = Pointer to spin lock to be released
+ *     OldIrql  = Value of IRQL when spin lock was acquired
+ *     IPDR     = Pointer to IP datagram reassembly structure to free
+ *     Buffer   = Optional pointer to a buffer to free
+ */
+{
+    TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+
+    KeReleaseSpinLock(Lock, OldIrql);
+    RemoveIPDR(IPDR);
+    FreeIPDR(IPDR);
+    if (Buffer)
+        PoolFreeBuffer(Buffer);
+}
+
+
+VOID ProcessFragment(
+    PIP_INTERFACE IF,
+    PIP_PACKET IPPacket,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Processes an IP datagram or fragment
+ * ARGUMENTS:
+ *     IF       = Pointer to IP interface packet was receive on
+ *     IPPacket = Pointer to IP packet
+ *     NTE      = Pointer to NTE packet was received on
+ * NOTES:
+ *     This routine reassembles fragments and, if a whole datagram can
+ *     be assembled, passes the datagram on to the IP protocol dispatcher
+ */
+{
+    KIRQL OldIrql;
+    PIPDATAGRAM_REASSEMBLY IPDR;
+    PLIST_ENTRY CurrentEntry;
+    PIPDATAGRAM_HOLE Hole, NewHole;
+    USHORT FragFirst;
+    USHORT FragLast;
+    BOOLEAN MoreFragments;
+    PIPv4_HEADER IPv4Header;
+    PIP_PACKET Datagram;
+    PIP_FRAGMENT Fragment;
+
+    /* FIXME: Assume IPv4 */
+
+    IPv4Header = (PIPv4_HEADER)IPPacket->Header;
+
+    /* Check if we already have an reassembly structure for this datagram */
+    IPDR = GetReassemblyInfo(IPPacket);
+    if (IPDR) {
+        TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
+        /* We have a reassembly structure */
+        KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
+        CurrentEntry = IPDR->HoleListHead.Flink;
+        Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+    } else {
+        TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
+
+        /* We don't have a reassembly structure, create one */
+        IPDR = PoolAllocateBuffer(sizeof(IPDATAGRAM_REASSEMBLY));
+        if (!IPDR) {
+            /* We don't have the resources to process this packet, discard it */
+            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+            return;
+        }
+
+        /* Create a descriptor spanning from zero to infinity.
+           Actually, we use a value slightly greater than the
+           maximum number of octets an IP datagram can contain */
+        Hole = CreateHoleDescriptor(0, 65536);
+        if (!Hole) {
+            /* We don't have the resources to process this packet, discard it */
+            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+            PoolFreeBuffer(IPDR);
+            return;
+        }
+        AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
+        AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
+        IPDR->Id         = IPv4Header->Id;
+        IPDR->Protocol   = IPv4Header->Protocol;
+        IPDR->IPv4Header = NULL;
+        InitializeListHead(&IPDR->FragmentListHead);
+        InitializeListHead(&IPDR->HoleListHead);
+        InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
+        CurrentEntry = IPDR->HoleListHead.Flink;
+
+        KeInitializeSpinLock(&IPDR->Lock);
+
+        KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
+
+        /* Update the reassembly list */
+        ExInterlockedInsertTailList(&ReassemblyListHead,
+                                    &IPDR->ListEntry,
+                                    &ReassemblyListLock);
+    }
+
+    FragFirst     = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
+    FragLast      = FragFirst + WN2H(IPv4Header->TotalLength);
+    MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
+
+    for (;;) {
+        if (CurrentEntry == &IPDR->HoleListHead)
+            /* No more entries */
+            break;
+
+        TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
+            FragFirst, FragLast, Hole->First, Hole->Last));
+
+        if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
+            TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
+            /* The fragment does not overlap with the hole, try next
+               descriptor in the list */
+
+            CurrentEntry = CurrentEntry->Flink;
+            if (CurrentEntry != &IPDR->HoleListHead)
+                Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+            continue;
+        }
+
+        /* The fragment overlap with the hole, unlink the descriptor */
+        RemoveEntryList(CurrentEntry);
+
+        if (FragFirst > Hole->First) {
+            NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
+            if (!NewHole) {
+                /* We don't have the resources to process this packet, discard it */
+                Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);
+                return;
+            }
+
+            /* Put the new descriptor in the list */
+            InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
+        }
+
+        if ((FragLast < Hole->Last) && (MoreFragments)) {
+            /* We can reuse the descriptor for the new hole */
+                       Hole->First = FragLast + 1;
+
+                       /* Put the new hole descriptor in the list */
+            InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
+        } else
+            PoolFreeBuffer(Hole);
+
+        /* If this is the first fragment, save the IP header */
+        if (FragFirst == 0) {
+            IPDR->IPv4Header = ExAllocatePool(NonPagedPool, IPPacket->HeaderSize);
+            if (!IPDR->IPv4Header) {
+                /* We don't have the resources to process this packet, discard it */
+                Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
+                return;
+            }
+
+            TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
+                "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize));
+
+            RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
+            IPDR->HeaderSize = IPPacket->HeaderSize;
+        }
+
+        /* Create a buffer, copy the data into it and put it
+           in the fragment list */
+
+        Fragment = PoolAllocateBuffer(sizeof(IP_FRAGMENT));
+        if (!Fragment) {
+            /* We don't have the resources to process this packet, discard it */
+            Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
+            return;
+        }
+
+        TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
+
+        Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
+        Fragment->Data = ExAllocatePool(NonPagedPool, Fragment->Size);
+        if (!Fragment->Data) {
+            /* We don't have the resources to process this packet, discard it */
+            Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);
+            return;
+        }
+
+        TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X)  Size (%d).\n",
+            Fragment->Data, Fragment->Size));
+
+        /* Copy datagram data into fragment buffer */
+        CopyPacketToBuffer(Fragment->Data,
+                           IPPacket->NdisPacket,
+                           IPPacket->Position,
+                           Fragment->Size);
+        Fragment->Offset = FragFirst;
+
+        /* If this is the last fragment, compute and save the datagram data size */
+        if (!MoreFragments)
+            IPDR->DataSize = FragFirst + Fragment->Size;
+
+        /* Put the fragment in the list */
+        InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
+               break;
+    }
+
+    TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
+
+    if (IsListEmpty(&IPDR->HoleListHead)) {
+        /* Hole list is empty which means a complete datagram can be assembled.
+           Assemble the datagram and pass it to an upper layer protocol */
+
+        TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
+
+        Datagram = ReassembleDatagram(IPDR);
+               KeReleaseSpinLock(&IPDR->Lock, OldIrql);
+
+        RemoveIPDR(IPDR);
+        FreeIPDR(IPDR);
+
+        if (!Datagram) {
+            /* Not enough free resources, discard the packet */
+            TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+            return;
+        }
+
+        /* Give the packet to the protocol dispatcher */
+        IPDispatchProtocol(NTE, Datagram);
+
+        /* We're done with this datagram */
+        ExFreePool(Datagram->Header);
+        PoolFreeBuffer(Datagram);
+    } else
+        KeReleaseSpinLock(&IPDR->Lock, OldIrql);
+}
+
+
+VOID IPFreeReassemblyList(
+    VOID)
+/*
+ * FUNCTION: Frees all IP datagram reassembly structures in the list
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PIPDATAGRAM_REASSEMBLY Current;
+
+    KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+
+    CurrentEntry = ReassemblyListHead.Flink;
+    while (CurrentEntry != &ReassemblyListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
+        /* Unlink it from the list */
+        RemoveEntryList(CurrentEntry);
+           
+        /* And free the descriptor */
+        FreeIPDR(Current);
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+}
+
+
+VOID IPDatagramReassemblyTimeout(
+    VOID)
+/*
+ * FUNCTION: IP datagram reassembly timeout handler
+ * NOTES:
+ *     This routine is called by IPTimeout to free any resources used
+ *     to hold IP fragments that are being reassembled to form a
+ *     complete IP datagram
+ */
+{
+}
+
+
+VOID IPv4Receive(
+    PVOID Context,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives an IPv4 datagram (or fragment)
+ * ARGUMENTS:
+ *     Context  = Pointer to context information (IP_INTERFACE)
+ *     IPPacket = Pointer to IP packet
+ */
+{
+//    PNEIGHBOR_CACHE_ENTRY NCE;
+    PNET_TABLE_ENTRY NTE;
+    UINT AddressType;
+
+    TI_DbgPrint(MAX_TRACE, ("Received IPv4 datagram.\n"));
+
+    IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2;
+
+    if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {
+        TI_DbgPrint(MIN_TRACE, ("Datagram received with incorrect header size (%d).\n",
+            IPPacket->HeaderSize));
+        /* Discard packet */
+        return;
+    }
+
+    /* Checksum IPv4 header */
+    if (!CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {
+        TI_DbgPrint(MIN_TRACE, ("Datagram received with bad checksum. Checksum field (0x%X)\n",
+            WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));
+        /* Discard packet */
+        return;
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("TotalSize (datalink) is (%d).\n", IPPacket->TotalSize));
+
+    IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
+
+    TI_DbgPrint(MAX_TRACE, ("TotalSize (IPv4) is (%d).\n", IPPacket->TotalSize));
+
+       AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);
+       AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);
+
+    IPPacket->Position = IPPacket->HeaderSize;
+    IPPacket->Data     = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize);
+
+    /* FIXME: Possibly forward packets with multicast addresses */
+
+    /* FIXME: Should we allow packets to be received on the wrong interface? */
+#if 0
+    NTE = IPLocateNTE(&IPPacket->DstAddr, &AddressType);
+#else
+    NTE = IPLocateNTEOnInterface((PIP_INTERFACE)Context, &IPPacket->DstAddr, &AddressType);
+#endif
+    if (NTE) {
+        /* This packet is destined for us */
+        ProcessFragment((PIP_INTERFACE)Context, IPPacket, NTE);
+        /* Done with this NTE */
+        DereferenceObject(NTE);
+    } else {
+        /* This packet is not destined for us. If we are a router,
+           try to find a route and forward the packet */
+
+        /* FIXME: Check if acting as a router */
+#if 0
+        NCE = RouteFindRouter(&IPPacket->DstAddr, NULL);
+        if (NCE) {
+            /* FIXME: Possibly fragment datagram */
+            /* Forward the packet */
+            IPSendFragment(IPPacket, NCE);
+        } else {
+            TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
+                IPPacket->DstAddr.Address.IPv4Address));
+
+            /* FIXME: Send ICMP error code */
+        }
+#endif
+    }
+}
+
+
+VOID IPReceive(
+    PVOID Context,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives an IP datagram (or fragment)
+ * ARGUMENTS:
+ *     Context  = Pointer to context information (IP_INTERFACE)
+ *     IPPacket = Pointer to IP packet
+ */
+{
+    UINT Version;
+
+    /* Check that IP header has a supported version */
+    Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);
+    switch (Version) {
+    case 4:
+        IPPacket->Type = IP_ADDRESS_V4;
+        IPv4Receive(Context, IPPacket);
+        break;
+    case 6:
+        IPPacket->Type = IP_ADDRESS_V6;
+        TI_DbgPrint(MIN_TRACE, ("Datagram of type IPv6 discarded.\n"));
+        return;
+    default:
+        TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
+        return;
+    }
+}
+
+/* EOF */
index f113b0b..89020f5 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/route.c
+ * PURPOSE:     Route cache
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * NOTES:       The route cache is implemented as a binary search
+ *              tree to obtain fast searches
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <route.h>
+#include <router.h>
+
+
+/* This RCN is shared by all external nodes. It complicates things,
+   but the memory.requirements are reduced by approximately 50%.
+   The RCN is protected by the route cache spin lock */
+PROUTE_CACHE_NODE ExternalRCN;
+PROUTE_CACHE_NODE RouteCache;
+KSPIN_LOCK RouteCacheLock;
+
+
+#if DBG
+VOID PrintTree(
+    PROUTE_CACHE_NODE Node)
+/*
+ * FUNCTION: Prints all nodes on tree
+ * ARGUMENTS:
+ *     Node = Pointer to root node of tree
+ * NOTES:
+ *     This function must be called with the route cache lock held.
+ */
+{
+    if (IsInternalRCN(Node)) {
+        /* Traverse left subtree */
+        PrintTree(Node->Left);
+
+        /* Traverse right subtree */
+        PrintTree(Node->Right);
+
+        /* Finally check the node itself */
+        TI_DbgPrint(MIN_TRACE, ("(Internal) Self,Parent,Left,Right,Data = (%08X, %08X, %08X, %08X, %08X).\n",
+            Node, Node->Parent, Node->Left, Node->Right, (ULONG_PTR)Node->Destination.Address.IPv4Address));
+    } else
+        TI_DbgPrint(MIN_TRACE, ("(External) Self,Parent,Left,Right = (%08X, %08X, %08X, %08X).\n",
+            Node, Node->Parent, Node->Left, Node->Right));
+}
+#endif
+
+
+VOID RemoveAboveExternal(VOID)
+/*
+ * FUNCTION: Removes the parent node of the selected external node from the route cache tree
+ * NOTES:
+ *     This function must be called with the route cache lock held.
+ *     ExternalRCN->Parent must be initialized
+ */
+{
+    PROUTE_CACHE_NODE Parent;
+    PROUTE_CACHE_NODE Sibling;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));
+
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n"));
+    PrintTree(RouteCache);
+#endif
+
+    Parent = ExternalRCN->Parent;
+    /* Find sibling of external node */
+    if (ExternalRCN == Parent->Left)
+        Sibling = Parent->Right;
+    else
+        Sibling = Parent->Left;
+
+    /* Replace parent node with sibling of external node */
+    if (Parent != RouteCache) {
+        if (Parent->Parent->Left == Parent)
+            Parent->Parent->Left = Sibling;
+        else
+            Parent->Parent->Right = Sibling;
+        /* Give sibling a new parent */
+        Sibling->Parent = Parent->Parent;
+    } else {
+        /* This is the root we're removing */
+        RouteCache      = Sibling;
+        Sibling->Parent = NULL;
+    }
+
+    DereferenceObject(Parent);
+
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n"));
+    PrintTree(RouteCache);
+#endif
+}
+
+
+PROUTE_CACHE_NODE SearchRouteCache(
+    PIP_ADDRESS Destination,
+    PROUTE_CACHE_NODE Node)
+/*
+ * FUNCTION: Searches route cache for a RCN for a destination address
+ * ARGUMENTS:
+ *     Destination = Pointer to destination address (key)
+ *     Node        = Pointer to start route cache node
+ * NOTES:
+ *     This function must be called with the route cache lock held
+ * RETURNS:
+ *     Pointer to internal node if a matching node was found, or
+ *     external node where it should be if none was found
+ */
+{
+    INT Value;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)  Node (0x%X)\n", Destination, Node));
+
+    /* Is this an external node? */
+    if (IsExternalRCN(Node))
+        return Node;
+
+    /* Is it this node we are looking for? */
+    Value = AddrCompare(Destination, &Node->Destination);
+    if (Value == 0)
+        return Node;
+
+    /* Traverse down the left subtree if the key is smaller than
+       the key of the node, otherwise traverse the right subtree */
+    if (Value < 0) {
+        Node->Left->Parent = Node;
+        ExternalRCN->Left  = (PROUTE_CACHE_NODE)&Node->Left;
+        return SearchRouteCache(Destination, Node->Left);
+    } else {
+        Node->Right->Parent = Node;
+        ExternalRCN->Left   = (PROUTE_CACHE_NODE)&Node->Right;
+        return SearchRouteCache(Destination, Node->Right);
+    }
+}
+
+
+PROUTE_CACHE_NODE ExpandExternalRCN(VOID)
+/*
+ * FUNCTION: Expands an external route cache node
+ * NOTES:
+ *     This function must be called with the route cache lock held.
+ *     We cheat a little here to save memory. We don't actually allocate memory
+ *     for external nodes. We wait until they're turned into internal nodes.
+ *     ExternalRCN->Parent must be initialized
+ *     ExternalRCN->Left must be a pointer to the correct child link of it's parent
+ * RETURNS:
+ *     Pointer to new internal node if the external node was expanded, NULL if not
+ */
+{
+    PROUTE_CACHE_NODE RCN;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));
+
+    RCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE));
+    if (!RCN) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    if (ExternalRCN->Left)
+        /* Register RCN as a child with it's parent */
+        *(PROUTE_CACHE_NODE*)ExternalRCN->Left = RCN;
+
+    RCN->Parent = ExternalRCN->Parent;
+    RCN->Left   = ExternalRCN;
+    RCN->Right  = ExternalRCN;
+
+    return RCN;
+}
+
+#if 0
+VOID SwapRCN(
+    PROUTE_CACHE_NODE *Node1,
+    PROUTE_CACHE_NODE *Node2)
+/*
+ * FUNCTION: Swaps two nodes
+ * ARGUMENTS:
+ *     Node1 = Address of pointer to first node
+ *     Node2 = Address of pointer to second node
+ */
+{
+    PROUTE_CACHE_NODE Temp;
+
+    Temp  = *Node2;
+    *Node2 = *Node1;
+    *Node1 = Temp;
+}
+#endif
+
+/*
+ * FUNCTION: Removes a route to a destination
+ * ARGUMENTS:
+ *     RCN = Pointer to route cache node to remove
+ * NOTES:
+ *     Internal version. Route cache lock must be held
+ */
+VOID RemoveRouteToDestination(
+    PROUTE_CACHE_NODE RCN)
+{
+    PROUTE_CACHE_NODE RemNode, Parent, SwapNode;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN));
+
+    if (IsExternalRCN(RCN->Left)) {
+        /* Left node is external */
+        RemNode         = RCN->Left;
+        RemNode->Parent = RCN;
+    } else if (IsExternalRCN(RCN->Right)) {
+        /* Right node is external */
+        RemNode         = RCN->Right;
+        RemNode->Parent = RCN;
+    } else {
+        /* The node has internal children */
+#if 0
+        /* Normally we would replace
+           the item of RCN with the item of the leftmost external
+           node on the right subtree of RCN. This we cannot do here
+           because there may be references directly to that node.
+           Instead we swap pointer values (parent, left and right)
+           of the two nodes */
+#endif
+        RemNode = RCN->Right;
+        do {
+            Parent  = RemNode;
+            RemNode = RemNode->Left;
+        } while (IsInternalRCN(RemNode));
+        RemNode->Parent = Parent;
+
+        SwapNode = RemNode->Parent;
+#if 0
+        if (RCN != RouteCache) {
+            /* Set SwapNode to be child of RCN's parent instead of RCN */
+            Parent = RCN->Parent;
+            if (RCN == Parent->Left)
+                Parent->Left = SwapNode;
+            else
+                Parent->Right = SwapNode;
+        } else
+            /* SwapNode is the new cache root */
+            RouteCache = SwapNode;
+
+        /* Set RCN to be child of SwapNode's parent instead of SwapNode */
+        Parent = SwapNode->Parent;
+        if (SwapNode == Parent->Left)
+            Parent->Left = RCN;
+        else
+            Parent->Right = RCN;
+
+        /* Swap parents */
+        SwapRCN(&SwapNode->Parent, &RCN->Parent);
+        /* Swap children */
+        SwapRCN(&SwapNode->Left, &RCN->Left);
+        SwapRCN(&SwapNode->Right, &RCN->Right);
+#endif
+    }
+    
+    /* Dereference NTE and NCE */
+    DereferenceObject(RCN->NTE);
+    DereferenceObject(RCN->NCE);
+
+    ExternalRCN->Parent = RemNode->Parent;
+
+    RemoveAboveExternal();
+}
+
+
+VOID InvalidateNTEOnSubtree(
+    PNET_TABLE_ENTRY NTE,
+    PROUTE_CACHE_NODE Node)
+/*
+ * FUNCTION: Removes all RCNs with references to an NTE on a subtree
+ * ARGUMENNTS:
+ *     NTE  = Pointer to NTE to invalidate
+ *     Node = Pointer to RCN to start removing nodes at
+ * NOTES:
+ *     This function must be called with the route cache lock held.
+ */
+{
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X)  Node (0x%X).\n", NTE, Node));
+
+    if (IsInternalRCN(Node)) {
+        /* Traverse left subtree */
+        InvalidateNTEOnSubtree(NTE, Node->Left);
+
+        /* Traverse right subtree */
+        InvalidateNTEOnSubtree(NTE, Node->Right);
+
+        /* Finally check the node itself */
+        if (Node->NTE == NTE)
+            RemoveRouteToDestination(Node);
+    }
+}
+
+
+VOID InvalidateNCEOnSubtree(
+    PNEIGHBOR_CACHE_ENTRY NCE,
+    PROUTE_CACHE_NODE Node)
+/*
+ * FUNCTION: Removes all RCNs with references to an NCE on a subtree
+ * ARGUMENNTS:
+ *     NCE  = Pointer to NCE to invalidate
+ *     Node = Pointer to RCN to start removing nodes at
+ * NOTES:
+ *     This function must be called with the route cache lock held
+ */
+{
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X)  Node (0x%X).\n", NCE, Node));
+
+    if (IsInternalRCN(Node)) {
+        /* Traverse left subtree */
+        InvalidateNCEOnSubtree(NCE, Node->Left);
+
+        /* Traverse right subtree */
+        InvalidateNCEOnSubtree(NCE, Node->Right);
+
+        /* Finally check the node itself */
+        if (Node->NCE == NCE)
+            RemoveRouteToDestination(Node);
+    }
+}
+
+
+VOID RemoveSubtree(
+    PROUTE_CACHE_NODE Node)
+/*
+ * FUNCTION: Removes a subtree from the tree using recursion
+ * ARGUMENNTS:
+ *     Node = Pointer to RCN to start removing nodes at
+ * NOTES:
+ *     This function must be called with the route cache lock held
+ */
+{
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Node (0x%X).\n", Node));
+
+    if (IsInternalRCN(Node)) {
+        /* Traverse left subtree */
+        RemoveSubtree(Node->Left);
+
+        /* Traverse right subtree */
+        RemoveSubtree(Node->Right);
+
+        /* Finally remove the node itself */
+
+        /* It's an internal node, so dereference NTE and NCE */
+        DereferenceObject(Node->NTE);
+        DereferenceObject(Node->NCE);
+
+#if DBG
+        if (Node->RefCount != 1)
+            TI_DbgPrint(MIN_TRACE, ("RCN at (0x%X) has (%d) references (should be 1).\n", Node, Node->RefCount));
+#endif
+
+        /* Remove reference for being alive */
+        DereferenceObject(Node);
+    }
+}
+
+
+NTSTATUS RouteStartup(
+    VOID)
+/*
+ * FUNCTION: Initializes the routing subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));
+
+    /* Initialize the pseudo external route cache node */
+    ExternalRCN = PoolAllocateBuffer(sizeof(ROUTE_CACHE_NODE));
+    if (!ExternalRCN) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    ExternalRCN->Parent = NULL;
+    ExternalRCN->Left   = NULL;
+    ExternalRCN->Right  = NULL;
+
+    /* Initialize the route cache root */
+    RouteCache = ExternalRCN;
+
+    KeInitializeSpinLock(&RouteCacheLock);
+
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n"));
+    PrintTree(RouteCache);
+#endif
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS RouteShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the routing subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));
+
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n"));
+    PrintTree(RouteCache);
+#endif
+    /* Clear route cache */
+    RemoveSubtree(RouteCache);
+
+    PoolFreeBuffer(ExternalRCN);
+
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+
+    return STATUS_SUCCESS;
+}
+
+
+UINT RouteGetRouteToDestination(
+    PIP_ADDRESS Destination,
+    PNET_TABLE_ENTRY NTE,
+    PROUTE_CACHE_NODE *RCN)
+/*
+ * FUNCTION: Locates an RCN describing a route to a destination address
+ * ARGUMENTS:
+ *     Destination = Pointer to destination address to find route to
+ *     NTE         = Pointer to NTE describing net to send on
+ *                   (NULL means routing module choose NTE to send on)
+ *     RCN         = Address of pointer to an RCN
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     The RCN is referenced for the caller. The caller is responsible
+ *     for dereferencing it after use
+ */
+{
+    KIRQL OldIrql;
+    PROUTE_CACHE_NODE RCN2;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+    PIP_INTERFACE Interface;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)  NTE (0x%X).\n", Destination, NTE));
+
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
+
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n"));
+    PrintTree(RouteCache);
+#endif
+
+    ExternalRCN->Left = NULL;
+    RCN2 = SearchRouteCache(Destination, RouteCache);
+    if (IsExternalRCN(RCN2)) {
+        /* No route was found in the cache */
+
+        /* Check if the destination is on-link */
+        Interface = RouterFindOnLinkInterface(Destination, NTE);
+        if (Interface) {
+            if (!NTE) {
+                NTE = RouterFindBestNTE(Interface, Destination);
+                if (!NTE) {
+                    /* We cannot get to the specified destination. Return error */
+                    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+                    return IP_NO_ROUTE_TO_DESTINATION;
+                }
+            } else
+                ReferenceObject(NTE);
+
+            /* The destination address is on-link. Check our neighbor cache */
+            NCE = NBFindOrCreateNeighbor(Interface, Destination);
+            if (!NCE) {
+                DereferenceObject(NTE);
+                KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+                return IP_NO_RESOURCES;
+            }
+        } else {
+            /* Destination is not on any subnets we're on. Find a router to use */
+            NCE = RouterGetRoute(Destination, NTE);
+            if (!NCE) {
+                /* We cannot get to the specified destination. Return error */
+                KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+                return IP_NO_ROUTE_TO_DESTINATION;
+            }
+        }
+
+        /* Add the new route to the route cache */
+        if (RCN2 == RouteCache) {
+            RCN2       = ExpandExternalRCN();
+            RouteCache = RCN2;
+        } else
+            RCN2 = ExpandExternalRCN();
+        if (!RCN2) {
+            DereferenceObject(NTE);
+            DereferenceObject(NCE);
+            KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+            return IP_NO_RESOURCES;
+        }
+
+        RCN2->RefCount    = 1;
+        RCN2->State       = RCN_STATE_COMPUTED;
+        RCN2->NTE         = NTE;
+        RtlCopyMemory(&RCN2->Destination, Destination, sizeof(IP_ADDRESS));
+        RCN2->PathMTU     = NCE->Interface->MTU;
+        RCN2->NCE         = NCE;
+
+        /* The route cache node references the NTE and the NCE. The
+           NTE was referenced before and NCE is already referenced by
+           RouteGetRoute() or NBFindOrCreateNeighbor() so we don't
+           reference them here */
+    }
+
+    /* Reference the RCN for the user */
+    ReferenceObject(RCN2);
+
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree (after).\n"));
+    PrintTree(RouteCache);
+#endif
+
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+
+    *RCN = RCN2;
+
+    return IP_SUCCESS;
+}
+
+
+PROUTE_CACHE_NODE RouteAddRouteToDestination(
+    PIP_ADDRESS Destination,
+    PNET_TABLE_ENTRY NTE,
+    PIP_INTERFACE IF,
+    PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Adds a (permanent) route to a destination
+ * ARGUMENTS:
+ *     Destination = Pointer to destination address
+ *     NTE         = Pointer to net table entry
+ *     IF          = Pointer to interface to use
+ *     NCE         = Pointer to first hop to destination
+ * RETURNS:
+ *     Pointer to RCN if the route was added, NULL if not.
+ *     There can be at most one RCN per destination address / interface pair
+ */
+{
+    KIRQL OldIrql;
+    PROUTE_CACHE_NODE RCN;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)  NTE (0x%X)  IF (0x%X)  NCE (0x%X).\n", Destination, NTE, IF, NCE));
+
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
+
+    /* Locate an external RCN we can expand */
+    RCN               = RouteCache;
+    ExternalRCN->Left = NULL;
+    for (;;) {
+        RCN = SearchRouteCache(Destination, RCN);
+        if (IsInternalRCN(RCN)) {
+            ExternalRCN->Left = (PROUTE_CACHE_NODE)&RCN->Right;
+            /* This is an internal node, continue the search to the right */
+            RCN = RCN->Right;
+        } else
+            /* This is an external node, we've found an empty spot */
+            break;
+    }
+
+    /* Expand the external node */
+    if (RCN == RouteCache) {
+        RCN        = ExpandExternalRCN();
+        RouteCache = RCN;
+    } else
+        RCN = ExpandExternalRCN();
+    if (!RCN) {
+        KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+        return NULL;
+    }
+
+    /* Initialize the newly created internal node */
+
+    /* Reference once for beeing alive */
+    RCN->RefCount    = 1;
+    RCN->State       = RCN_STATE_PERMANENT;
+    RCN->NTE         = NTE;
+    RtlCopyMemory(&RCN->Destination, Destination, sizeof(IP_ADDRESS));
+    RCN->PathMTU     = IF->MTU;
+    RCN->NCE         = NCE;
+
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+
+    /* The route cache node references the NTE and the NCE */
+    ReferenceObject(NTE);
+    if (NCE)
+        ReferenceObject(NCE);
+
+#if 0
+    TI_DbgPrint(MIN_TRACE, ("Displaying tree.\n"));
+    PrintTree(RouteCache);
+#endif
+
+    return RCN;
+}
+
+
+VOID RouteRemoveRouteToDestination(
+    PROUTE_CACHE_NODE RCN)
+/*
+ * FUNCTION: Removes a route to a destination
+ * ARGUMENTS:
+ *     RCN = Pointer to route cache node to remove
+ */
+{
+    KIRQL OldIrql;
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. RCN (0x%X).\n", RCN));
+
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
+
+    RemoveRouteToDestination(RCN);
+
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+}
+
+
+VOID RouteInvalidateNTE(
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Removes all RCNs with references to an NTE
+ * ARGUMENTS:
+ *     NTE = Pointer to net table entry to invalidate
+ */
+{
+    KIRQL OldIrql;
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NTE (0x%X).\n", NTE));
+
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
+    InvalidateNTEOnSubtree(NTE, RouteCache);
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+}
+
+
+VOID RouteInvalidateNCE(
+    PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Removes all RCNs with references to an NCE
+ * ARGUMENTS:
+ *     NCE = Pointer to neighbor cache entry to invalidate
+ */
+{
+    KIRQL OldIrql;
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. NCE (0x%X).\n", NCE));
+
+    KeAcquireSpinLock(&RouteCacheLock, &OldIrql);
+    InvalidateNCEOnSubtree(NCE, RouteCache);
+    KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+}
+
+/* EOF */
index 1791dc4..90da679 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/router.c
+ * PURPOSE:     IP routing subsystem
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <address.h>
+#include <router.h>
+#include <pool.h>
+
+
+LIST_ENTRY FIBListHead;
+KSPIN_LOCK FIBLock;
+
+
+VOID DestroyFIBE(
+    PFIB_ENTRY FIBE)
+/*
+ * FUNCTION: Destroys an forward information base entry
+ * ARGUMENTS:
+ *     FIBE = Pointer to FIB entry
+ * NOTES:
+ *     The forward information base lock must be held when called
+ */
+{
+    /* Unlink the FIB entry from the list */
+    RemoveEntryList(&FIBE->ListEntry);
+
+    /* Dereference the referenced objects */
+    DereferenceObject(FIBE->NetworkAddress);
+    DereferenceObject(FIBE->Netmask);
+    DereferenceObject(FIBE->Router);
+    DereferenceObject(FIBE->NTE);
+
+#ifdef DBG
+    FIBE->RefCount--;
+
+    if (FIBE->RefCount != 0) {
+        TI_DbgPrint(MIN_TRACE, ("FIB entry at (0x%X) has (%d) references (Should be 0).\n", FIBE, FIBE->RefCount));
+    }
+#endif
+
+    /* And free the FIB entry */
+    PoolFreeBuffer(FIBE);
+}
+
+
+VOID DestroyFIBEs(
+    VOID)
+/*
+ * FUNCTION: Destroys all forward information base entries
+ * NOTES:
+ *     The forward information base lock must be held when called
+ */
+{
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PFIB_ENTRY Current;
+
+    /* Search the list and remove every FIB entry we find */
+    CurrentEntry = FIBListHead.Flink;
+    while (CurrentEntry != &FIBListHead) {
+        NextEntry = CurrentEntry->Flink;
+           Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
+        /* Destroy the FIB entry */
+        DestroyFIBE(Current);
+        CurrentEntry = NextEntry;
+    }
+}
+
+
+UINT CommonPrefixLength(
+    PIP_ADDRESS Address1,
+    PIP_ADDRESS Address2)
+/*
+ * FUNCTION: Computes the length of the longest prefix common to two addresses
+ * ARGUMENTS:
+ *     Address1 = Pointer to first address
+ *     Address2 = Pointer to second address
+ * NOTES:
+ *     The two addresses must be of the same type
+ * RETURNS:
+ *     Length of longest common prefix
+ */
+{
+    PUCHAR Addr1, Addr2;
+    UINT Size;
+    UINT i, j;
+    UINT Bitmask;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Address1 (0x%X)  Address2 (0x%X).\n", Address1, Address2));
+
+    if (Address1->Type == IP_ADDRESS_V4)
+        Size = sizeof(IPv4_RAW_ADDRESS);
+    else
+        Size = sizeof(IPv6_RAW_ADDRESS);
+
+    Addr1 = (PUCHAR)&Address1->Address;
+    Addr2 = (PUCHAR)&Address2->Address;
+
+    /* Find first non-matching byte */
+    for (i = 0; ; i++) {
+        if (i == Size)
+            return 8 * i; /* The two addresses are equal */
+
+        if (Addr1[i] != Addr2[i])
+            break;
+    }
+
+    /* Find first non-matching bit */
+    Bitmask = 0x80;
+    for (j = 0; ; j++) {
+        if ((Addr1[i] & Bitmask) != (Addr2[i] & Bitmask))
+            break;
+        Bitmask >>= 1;
+    }
+
+    return 8 * i + j;
+}
+
+
+BOOLEAN HasPrefix(
+    PIP_ADDRESS Address,
+    PIP_ADDRESS Prefix,
+    UINT Length)
+/*
+ * FUNCTION: Determines wether an address has an given prefix
+ * ARGUMENTS:
+ *     Address = Pointer to address to use
+ *     Prefix  = Pointer to prefix to check for
+ *     Length  = Length of prefix
+ * RETURNS:
+ *     TRUE if the address has the prefix, FALSE if not
+ * NOTES:
+ *     The two addresses must be of the same type
+ */
+{
+    PUCHAR pAddress = (PUCHAR)&Address->Address;
+    PUCHAR pPrefix  = (PUCHAR)&Prefix->Address;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X)  Prefix (0x%X)  Length (%d).\n", Address, Prefix, Length));
+
+    /* Check that initial integral bytes match */
+    while (Length > 8) {
+        if (*pAddress++ != *pPrefix++)
+            return FALSE;
+        Length -= 8;
+    } 
+
+    /* Check any remaining bits */
+    if ((Length > 0) && ((*pAddress >> (8 - Length)) != (*pPrefix >> (8 - Length))))
+        return FALSE;
+
+    return TRUE;
+}
+
+
+PNET_TABLE_ENTRY RouterFindBestNTE(
+    PIP_INTERFACE Interface,
+    PIP_ADDRESS Destination)
+/*
+ * FUNCTION: Checks all on-link prefixes to find out if an address is on-link
+ * ARGUMENTS:
+ *     Interface   = Pointer to interface to use
+ *     Destination = Pointer to destination address
+ * NOTES:
+ *     If found the NTE if referenced
+ * RETURNS:
+ *     Pointer to NTE if found, NULL if not
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PNET_TABLE_ENTRY Current;
+    UINT Length, BestLength  = 0;
+    PNET_TABLE_ENTRY BestNTE = NULL;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Interface (0x%X)  Destination (0x%X).\n", Interface, Destination));
+
+    KeAcquireSpinLock(&Interface->Lock, &OldIrql);
+
+    CurrentEntry = Interface->NTEListHead.Flink;
+    while (CurrentEntry != &Interface->NTEListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
+
+        Length = CommonPrefixLength(Destination, Current->Address);
+        if (BestNTE) {
+            if (Length > BestLength) {
+                /* This seems to be a better NTE */
+                DereferenceObject(BestNTE);
+                ReferenceObject(Current);
+                BestNTE    = Current;
+                BestLength = Length;
+            }
+        } else {
+            /* First suitable NTE found, save it */
+            ReferenceObject(Current);
+            BestNTE    = Current;
+            BestLength = Length;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&Interface->Lock, OldIrql);
+
+    return BestNTE;
+}
+
+
+PIP_INTERFACE RouterFindOnLinkInterface(
+    PIP_ADDRESS Address,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Checks all on-link prefixes to find out if an address is on-link
+ * ARGUMENTS:
+ *     Address = Pointer to address to check
+ *     NTE     = Pointer to NTE to check (NULL = check all interfaces)
+ * RETURNS:
+ *     Pointer to interface if address is on-link, NULL if not
+ */
+{
+    PLIST_ENTRY CurrentEntry;
+    PPREFIX_LIST_ENTRY Current;
+
+    TI_DbgPrint(DEBUG_RCACHE, ("Called. Address (0x%X)  NTE (0x%X).\n", Address, NTE));
+
+    CurrentEntry = PrefixListHead.Flink;
+    while (CurrentEntry != &PrefixListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, PREFIX_LIST_ENTRY, ListEntry);
+
+        if (HasPrefix(Address, Current->Prefix, Current->PrefixLength) &&
+            ((!NTE) || (NTE->Interface == Current->Interface)))
+            return Current->Interface;
+
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    return NULL;
+}
+
+
+PFIB_ENTRY RouterAddRoute(
+    PIP_ADDRESS NetworkAddress,
+    PIP_ADDRESS Netmask,
+    PNET_TABLE_ENTRY NTE,
+    PNEIGHBOR_CACHE_ENTRY Router,
+    UINT Metric)
+/*
+ * FUNCTION: Adds a route to the Forward Information Base (FIB)
+ * ARGUMENTS:
+ *     NetworkAddress = Pointer to address of network
+ *     Netmask        = Pointer to netmask of network
+ *     NTE            = Pointer to NTE to use
+ *     Router         = Pointer to NCE of router to use
+ *     Metric         = Cost of this route
+ * RETURNS:
+ *     Pointer to FIB entry if the route was added, NULL if not
+ * NOTES:
+ *     The FIB entry references the NetworkAddress, Netmask, NTE and
+ *     the NCE of the router. The caller is responsible for providing
+ *     these references
+ */
+{
+    PFIB_ENTRY FIBE;
+
+    TI_DbgPrint(DEBUG_ROUTER, ("Called. NetworkAddress (0x%X)  Netmask (0x%X)  NTE (0x%X)  "
+        "Router (0x%X)  Metric (%d).\n", NetworkAddress, Netmask, NTE, Router, Metric));
+
+    FIBE = PoolAllocateBuffer(sizeof(FIB_ENTRY));
+    if (!FIBE) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    FIBE->NetworkAddress = NetworkAddress;
+    FIBE->Netmask        = Netmask;
+    FIBE->NTE            = NTE;
+    FIBE->Router         = Router;
+    FIBE->Metric         = Metric;
+
+    /* Add FIB to the forward information base */
+    ExInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock);
+
+    return FIBE;
+}
+
+
+PNEIGHBOR_CACHE_ENTRY RouterGetRoute(
+    PIP_ADDRESS Destination,
+    PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Finds a router to use to get to Destination
+ * ARGUMENTS:
+ *     Destination = Pointer to destination address (NULL means don't care)
+ *     NTE         = Pointer to NTE describing net to send on
+ *                   (NULL means don't care)
+ * RETURNS:
+ *     Pointer to NCE for router, NULL if none was found
+ * NOTES:
+ *     If found the NCE is referenced
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PFIB_ENTRY Current;
+    UCHAR State, BestState = 0;
+    UINT Length, BestLength = 0;
+    PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL;
+
+    TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X)  NTE (0x%X).\n", Destination, NTE));
+
+    KeAcquireSpinLock(&FIBLock, &OldIrql);
+
+    CurrentEntry = FIBListHead.Flink;
+    while (CurrentEntry != &FIBListHead) {
+        NextEntry = CurrentEntry->Flink;
+           Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
+
+        NCE   = Current->Router;
+        State = NCE->State;
+
+        if ((!NTE) || (NTE->Interface == NCE->Interface)) {
+            if (Destination)
+                Length = CommonPrefixLength(Destination, NCE->Address);
+            else
+                Length = 0;
+
+            if (BestNCE) {
+                if ((State  > BestState)  || 
+                    ((State == BestState) &&
+                    (Length > BestLength))) {
+                    /* This seems to be a better router */
+                    DereferenceObject(BestNCE);
+                    ReferenceObject(NCE);
+                    BestNCE    = NCE;
+                    BestLength = Length;
+                    BestState  = State;
+                }
+            } else {
+                /* First suitable router found, save it */
+                ReferenceObject(NCE);
+                BestNCE    = NCE;
+                BestLength = Length;
+                BestState  = State;
+            }
+        }
+        CurrentEntry = NextEntry;
+    }
+
+    KeReleaseSpinLock(&FIBLock, OldIrql);
+
+    return BestNCE;
+}
+
+
+VOID RouterRemoveRoute(
+    PFIB_ENTRY FIBE)
+/*
+ * FUNCTION: Removes a route from the Forward Information Base (FIB)
+ * ARGUMENTS:
+ *     FIBE = Pointer to FIB entry describing route
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE));
+
+    KeAcquireSpinLock(&FIBLock, &OldIrql);
+    DestroyFIBE(FIBE);
+    KeReleaseSpinLock(&FIBLock, OldIrql);
+}
+
+
+PFIB_ENTRY RouterCreateRouteIPv4(
+    IPv4_RAW_ADDRESS NetworkAddress,
+    IPv4_RAW_ADDRESS Netmask,
+    IPv4_RAW_ADDRESS RouterAddress,
+    PNET_TABLE_ENTRY NTE,
+    UINT Metric)
+/*
+ * FUNCTION: Creates a route with IPv4 addresses as parameters
+ * ARGUMENTS:
+ *     NetworkAddress = Address of network
+ *     Netmask        = Netmask of network
+ *     RouterAddress  = Address of router to use
+ *     NTE            = Pointer to NTE to use
+ *     Metric         = Cost of this route
+ * RETURNS:
+ *     Pointer to FIB entry if the route was created, NULL if not.
+ *     The FIB entry references the NTE. The caller is responsible
+ *     for providing this reference
+ */
+{
+    PIP_ADDRESS pNetworkAddress;
+    PIP_ADDRESS pNetmask;
+    PIP_ADDRESS pRouterAddress;
+    PNEIGHBOR_CACHE_ENTRY NCE;
+    PFIB_ENTRY FIBE;
+
+    pNetworkAddress = AddrBuildIPv4(NetworkAddress);
+    if (!NetworkAddress) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return NULL;
+    }
+
+    pNetmask = AddrBuildIPv4(Netmask);
+    if (!Netmask) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        DereferenceObject(pNetworkAddress);
+        return NULL;
+    }
+
+    pRouterAddress = AddrBuildIPv4(RouterAddress);
+    if (!RouterAddress) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        DereferenceObject(pNetworkAddress);
+        DereferenceObject(pNetmask);
+        return NULL;
+    }
+
+    /* The NCE references RouterAddress. The NCE is referenced for us */
+    NCE = NBAddNeighbor(NTE->Interface,
+                        pRouterAddress,
+                        NULL,
+                        NTE->Interface->AddressLength,
+                        NUD_PROBE);
+    if (!NCE) {
+        /* Not enough free resources */
+        DereferenceObject(pNetworkAddress);
+        DereferenceObject(pNetmask);
+        DereferenceObject(pRouterAddress);
+        return NULL;
+    }
+
+    ReferenceObject(pNetworkAddress);
+    ReferenceObject(pNetmask);
+    FIBE = RouterAddRoute(pNetworkAddress, pNetmask, NTE, NCE, 1);
+    if (!FIBE) {
+        /* Not enough free resources */
+        NBRemoveNeighbor(NCE);
+        PoolFreeBuffer(pNetworkAddress);
+        PoolFreeBuffer(pNetmask);
+        PoolFreeBuffer(pRouterAddress);
+    }
+
+    return FIBE;
+}
+
+
+NTSTATUS RouterStartup(
+    VOID)
+/*
+ * FUNCTION: Initializes the routing subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_ROUTER, ("Called.\n"));
+
+    /* Initialize the Forward Information Base */
+    InitializeListHead(&FIBListHead);
+    KeInitializeSpinLock(&FIBLock);
+
+#if 0
+    /* TEST: Create a test route */
+    /* Network is 10.0.0.0  */
+    /* Netmask is 255.0.0.0 */
+    /* Router is 10.0.0.1   */
+    RouterCreateRouteIPv4(0x0000000A, 0x000000FF, 0x0100000A, NTE?, 1);
+#endif
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS RouterShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the routing subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_ROUTER, ("Called.\n"));
+
+    /* Clear Forward Information Base */
+    KeAcquireSpinLock(&FIBLock, &OldIrql);
+    DestroyFIBEs();
+    KeReleaseSpinLock(&FIBLock, OldIrql);
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
index cb3c4f5..3bcdf29 100644 (file)
-/*\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
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        network/transmit.c
+ * PURPOSE:     Internet Protocol transmit routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <transmit.h>
+#include <routines.h>
+#include <checksum.h>
+#include <pool.h>
+#include <arp.h>
+#include <lan.h>
+
+
+BOOLEAN PrepareNextFragment(
+    PIPFRAGMENT_CONTEXT IFC)
+/*
+ * FUNCTION: Prepares the next fragment of an IP datagram for transmission
+ * ARGUMENTS:
+ *     IFC = Pointer to IP fragment context
+ * RETURNS:
+ *     TRUE if a fragment was prepared for transmission, FALSE if
+ *     there are no more fragments to send
+ */
+{
+    UINT MaxData;
+    UINT DataSize;
+    PIPv4_HEADER Header;
+    BOOLEAN MoreFragments;
+    USHORT FragOfs;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    if (IFC->BytesLeft != 0) {
+
+        TI_DbgPrint(MAX_TRACE, ("Preparing 1 fragment.\n"));
+
+        MaxData  = IFC->PathMTU - IFC->HeaderSize;
+        /* Make fragment a multiplum of 64bit */
+        MaxData -= MaxData % 8;
+        if (IFC->BytesLeft > MaxData) {
+            DataSize      = MaxData;
+            MoreFragments = TRUE;
+        } else {
+            DataSize      = IFC->BytesLeft;
+            MoreFragments = FALSE;
+        }
+
+        RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize);
+
+        FragOfs = (USHORT)IFC->Position; // Swap?
+        if (MoreFragments)
+            FragOfs |= IPv4_MF_MASK;
+        else
+            FragOfs &= ~IPv4_MF_MASK;
+
+        Header = IFC->Header;
+        Header->FlagsFragOfs = FragOfs;
+
+        /* FIXME: Handle options */
+
+        /* Calculate checksum of IP header */
+        Header->Checksum = 0;
+        Header->Checksum = (USHORT)IPv4Checksum(Header, IFC->HeaderSize, 0);
+
+        /* Update pointers */
+        (ULONG_PTR)IFC->DatagramData += DataSize;
+        IFC->Position  += DataSize;
+        IFC->BytesLeft -= DataSize;
+
+        return TRUE;
+    } else {
+        TI_DbgPrint(MAX_TRACE, ("No more fragments.\n"));
+        return FALSE;
+    }
+}
+
+
+NTSTATUS SendFragments(
+    PIP_PACKET IPPacket,
+    PNEIGHBOR_CACHE_ENTRY NCE,
+    UINT PathMTU)
+/*
+ * FUNCTION: Fragments and sends the first fragment of an IP datagram
+ * ARGUMENTS:
+ *     IPPacket  = Pointer to an IP packet
+ *     NCE       = Pointer to NCE for first hop to destination
+ *     PathMTU   = Size of Maximum Transmission Unit of path
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     IP datagram is larger than PathMTU when this is called
+ */
+{
+    PIPFRAGMENT_CONTEXT IFC;
+    NDIS_STATUS NdisStatus;
+    PVOID Data;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    IFC = PoolAllocateBuffer(sizeof(IPFRAGMENT_CONTEXT));
+    if (!IFC)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    /* We allocate a buffer for a PathMTU sized packet and reuse
+       it for all fragments */
+    Data = ExAllocatePool(NonPagedPool, MaxLLHeaderSize + PathMTU);
+    if (!IFC->Header) {
+        PoolFreeBuffer(IFC);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Allocate NDIS packet */
+    NdisAllocatePacket(&NdisStatus, &IFC->NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        ExFreePool(Data);
+        PoolFreeBuffer(IFC);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Allocate NDIS buffer */
+    NdisAllocateBuffer(&NdisStatus, &IFC->NdisBuffer,
+        GlobalBufferPool, Data, MaxLLHeaderSize + PathMTU);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        NdisFreePacket(IFC->NdisPacket);
+        ExFreePool(Data);
+        PoolFreeBuffer(IFC);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Link NDIS buffer into packet */
+    NdisChainBufferAtFront(IFC->NdisPacket, IFC->NdisBuffer);
+
+    IFC->Header       = (PVOID)((ULONG_PTR)Data + MaxLLHeaderSize);
+    IFC->Datagram     = IPPacket->NdisPacket;
+    IFC->DatagramData = IPPacket->Header;
+    IFC->HeaderSize   = IPPacket->HeaderSize;
+    IFC->PathMTU      = PathMTU;
+    IFC->NCE          = NCE;
+    IFC->Position     = 0;
+    IFC->BytesLeft    = IPPacket->TotalSize - IPPacket->HeaderSize;
+    IFC->Data         = (PVOID)((ULONG_PTR)IFC->Header + IPPacket->HeaderSize);
+
+    PC(IFC->NdisPacket)->DLComplete = IPSendComplete;
+    /* Set upper layer completion function to NULL to indicate that
+       this packet is an IP datagram fragment and thus we should
+       check for more fragments to send. If this is NULL the
+       Context field is a pointer to an IPFRAGMENT_CONTEXT structure */
+    PC(IFC->NdisPacket)->Complete = NULL;
+    PC(IFC->NdisPacket)->Context  = IFC;
+
+    /* Copy IP datagram header to fragment buffer */
+    RtlCopyMemory(IFC->Header, IPPacket->Header, IPPacket->HeaderSize);
+
+    /* Prepare next fragment for transmission and send it */
+
+    PrepareNextFragment(IFC);
+
+    IPSendFragment(IFC->NdisPacket, NCE);
+
+    return STATUS_SUCCESS;
+}
+
+
+VOID IPSendComplete(
+    PVOID Context,
+    PNDIS_PACKET NdisPacket,
+    NDIS_STATUS NdisStatus)
+/*
+ * FUNCTION: IP datagram fragment send completion handler
+ * ARGUMENTS:
+ *     Context    = Pointer to context information (IP_INTERFACE)
+ *     Packet     = Pointer to NDIS packet that was sent
+ *     NdisStatus = NDIS status of operation
+ * NOTES:
+ *    This routine is called when an IP datagram fragment has been sent
+ */
+{
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* FIXME: Stop sending fragments and cleanup datagram buffers if
+       there was an error */
+
+    if (PC(NdisPacket)->Complete)
+        /* This datagram was only one fragment long so call completion handler now */
+        (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus);
+    else {
+        /* This was one of many fragments of an IP datagram. Prepare
+           next fragment and send it or if there are no more fragments,
+           call upper layer completion routine */
+
+        PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)PC(NdisPacket)->Context;
+
+        if (PrepareNextFragment(IFC)) {
+            /* A fragment was prepared for transmission, so send it */
+            IPSendFragment(IFC->NdisPacket, IFC->NCE);
+        } else {
+            TI_DbgPrint(MAX_TRACE, ("Calling completion handler.\n"));
+
+            /* There are no more fragments to transmit, so call completion handler */
+            NdisPacket = IFC->Datagram;
+            FreeNdisPacket(IFC->NdisPacket);
+            PoolFreeBuffer(IFC);
+            (*PC(NdisPacket)->Complete)(PC(NdisPacket)->Context, NdisPacket, NdisStatus);
+        }
+    }
+}
+
+
+NTSTATUS IPSendFragment(
+    PNDIS_PACKET NdisPacket,
+    PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Sends an IP datagram fragment to a neighbor
+ * ARGUMENTS:
+ *     NdisPacket = Pointer to an NDIS packet containing fragment
+ *     NCE        = Pointer to NCE for first hop to destination
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     Lowest level IP send routine
+ */
+{
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State));
+
+    switch (NCE->State) {
+    case NUD_PERMANENT:
+        /* Neighbor is always valid */
+        break;
+
+    case NUD_REACHABLE:
+        /* Neighbor is reachable */
+        
+        /* FIXME: Set reachable timer */
+
+        break;
+
+    case NUD_STALE:
+        /* Enter delay state and send packet */
+
+        /* FIXME: Enter delay state */
+
+        break;
+
+    case NUD_DELAY:
+    case NUD_PROBE:
+        /* In these states we send the packet and hope the neighbor
+           hasn't changed hardware address */
+        break;
+
+    case NUD_INCOMPLETE:
+        TI_DbgPrint(MAX_TRACE, ("Queueing packet.\n"));
+
+        /* We don't know the hardware address of the first hop to
+           the destination. Queue the packet on the NCE and return */
+        NBQueuePacket(NCE, NdisPacket);
+
+        return STATUS_SUCCESS;
+    default:
+        /* Should not happen */
+        TI_DbgPrint(MIN_TRACE, ("Unknown NCE state.\n"));
+
+        return STATUS_SUCCESS;
+    }
+
+    PC(NdisPacket)->DLComplete = IPSendComplete;
+    (*NCE->Interface->Transmit)(NCE->Interface->Context, NdisPacket,
+        MaxLLHeaderSize, NCE->LinkAddress, LAN_PROTO_IPv4);
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS IPSendDatagram(
+    PIP_PACKET IPPacket,
+    PROUTE_CACHE_NODE RCN)
+/*
+ * FUNCTION: Sends an IP datagram to a remote address
+ * ARGUMENTS:
+ *     IPPacket = Pointer to an IP packet
+ *     RCN      = Pointer to route cache node
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     This is the highest level IP send routine. It possibly breaks the packet
+ *     into two or more fragments before passing it on to the next lower level
+ *     send routine (IPSendFragment)
+ */
+{
+    PNEIGHBOR_CACHE_ENTRY NCE;
+    UINT PathMTU;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    NCE = RCN->NCE;
+
+#if DBG
+    if (!NCE) {
+        TI_DbgPrint(MIN_TRACE, ("No NCE to use.\n"));
+        FreeNdisPacket(IPPacket->NdisPacket);
+        return STATUS_SUCCESS;
+    }
+#endif
+
+    /* Fetch path MTU now, because it may change */
+    PathMTU = RCN->PathMTU;
+    if (IPPacket->TotalSize > PathMTU) {
+        return SendFragments(IPPacket, NCE, PathMTU);
+    } else {
+        /* Calculate checksum of IP header */
+        ((PIPv4_HEADER)IPPacket->Header)->Checksum = 0;
+
+        ((PIPv4_HEADER)IPPacket->Header)->Checksum = (USHORT)
+            IPv4Checksum(IPPacket->Header, IPPacket->HeaderSize, 0);
+
+        TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n", WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength)));
+
+        return IPSendFragment(IPPacket->NdisPacket, NCE);
+    }
+}
+
+/* EOF */
index a4f061e..b87c9df 100644 (file)
@@ -1,19 +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
+Build instructions for TCP/IP protocol driver
+---------------------------------------------
+
+Building with Visual C++ and Windows NT DDK:
+
+Variables:
+%BASEDIR%     = path to NT4 DDK (e.g. c:\ntddk)
+%DDKBUILDENV% = DDK build environment (free or checked)
+
+DDK environment variables must be set! (run setenv.bat)
+
+    - Create the directory objects/i386/%DDKBUILDENV%
+    - Run "build" to build the driver
+
+
+Building with Mingw32 and ReactOS include files:
+
+    - Build NDIS.SYS (i.e. "make ndis")
+    - Run "make tcpip" FROM THE ReactOS ROOT DIRECTORY to build the driver
index 43b9506..cec8466 100644 (file)
@@ -1,32 +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
+; TCPIP.SYS - TCP/IP protocol driver
+
+LIBRARY tcpip.sys
+
+EXPORTS
+;FreeIprBuff
+;GetIFAndLink
+IPAddInterface@20
+;IPAllocBuff
+IPDelInterface@4
+;IPDelayedNdisReEnumerateBindings
+;IPDeregisterARP
+;IPDisableSniffer
+;IPEnableSniffer
+;IPFreeBuff
+;IPGetAddrType
+;IPGetBestInterface
+;IPGetInfo
+;IPInjectPkt
+;IPProxyNdisRequest
+;IPRegisterARP
+;IPRegisterProtocol
+;IPSetIPSecStatus
+;IPTransmit
+LookupRoute@8
+;LookupRouteInformation
+;SendICMPErr
+;SetIPSecPtr
+;UnSetIPSecPtr
+;UnSetIPSecSendPtr
+
+; EOF
index 08f8b9b..56e0c62 100644 (file)
@@ -1,32 +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
+; TCPIP.SYS - TCP/IP protocol driver
+
+LIBRARY tcpip.sys
+
+EXPORTS
+;FreeIprBuff
+;GetIFAndLink
+IPAddInterface=IPAddInterface@20
+;IPAllocBuff
+IPDelInterface=IPDelInterface@4
+;IPDelayedNdisReEnumerateBindings
+;IPDeregisterARP
+;IPDisableSniffer
+;IPEnableSniffer
+;IPFreeBuff
+;IPGetAddrType
+;IPGetBestInterface
+;IPGetInfo
+;IPInjectPkt
+;IPProxyNdisRequest
+;IPRegisterARP
+;IPRegisterProtocol
+;IPSetIPSecStatus
+;IPTransmit
+LookupRoute=LookupRoute@8
+;LookupRouteInformation
+;SendICMPErr
+;SetIPSecPtr
+;UnSetIPSecPtr
+;UnSetIPSecSendPtr
+
+; EOF
index 484b00d..6f31df8 100644 (file)
@@ -1,38 +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
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",         RES_STR_COMPANY_NAME
+            VALUE "FileDescription",  "TCP/IP protocol driver\0"
+            VALUE "FileVersion",         "0.0.0\0"
+            VALUE "InternalName",        "tcpip\0"
+            VALUE "LegalCopyright",      RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalFilename", "tcpip.sys\0"
+            VALUE "ProductName",         RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",      RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
index 6241e53..c5fbdc3 100644 (file)
-/*\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_REQUEST Request,\r
-    TDIObjectID *ID,\r
-    PVOID Buffer,\r
-    UINT BufferSize)\r
-/*\r
- * FUNCTION: Sets extended information\r
- * ARGUMENTS:\r
- *     Request    = Pointer to TDI request structure for the request\r
- *     ID         = Pointer to TDI object ID\r
- *     Buffer     = Pointer to buffer with data to use\r
- *     BufferSize = Size of Buffer\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    /* FIXME: Set extended information */\r
-\r
-    return TDI_INVALID_REQUEST;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/info.c
+ * PURPOSE:     TDI query and set information routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/07-2000 Created
+ */
+#include <tcpip.h>
+#include <routines.h>
+#include <info.h>
+
+
+TDI_STATUS IPTdiQueryInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PNDIS_BUFFER Buffer,
+    PUINT BufferSize,
+    PVOID Context)
+/*
+ * FUNCTION: Returns extended information about network layer
+ * ARGUMENTS:
+ *     Request    = Pointer to TDI request structure for the request
+ *     ID         = TDI object ID
+ *     Buffer     = Pointer to buffer with data to use. 
+ *     BufferSize = Pointer to buffer with size of Buffer. On return
+ *                  this is filled with number of bytes returned
+ *     Context    = Pointer to context buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    IPADDR_ENTRY IpAddress;
+    IPSNMP_INFO SnmpInfo;
+    PADDRESS_ENTRY ADE;
+    PIP_INTERFACE IF;
+    ULONG Temp;
+    UINT Count;
+    ULONG Entity;
+    KIRQL OldIrql;
+    UINT BufSize = *BufferSize;
+
+    /* Make return parameters consistent every time */
+    *BufferSize = 0;
+
+    Entity = ID->toi_entity.tei_entity;
+    if (Entity != CL_NL_ENTITY) {
+        /* We can't handle this entity */
+        return TDI_INVALID_PARAMETER;
+    }
+
+    if (ID->toi_entity.tei_instance != TL_INSTANCE)
+        /* We only support a single instance */
+        return TDI_INVALID_REQUEST;
+    if (ID->toi_class == INFO_CLASS_GENERIC) {
+        if (ID->toi_type == INFO_TYPE_PROVIDER && 
+            ID->toi_id == ENTITY_TYPE_ID) {
+
+            if (BufSize < sizeof(ULONG))
+                return TDI_BUFFER_TOO_SMALL;
+            Temp = CL_NL_IP;
+
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG));
+
+            return TDI_SUCCESS;
+        }
+        return TDI_INVALID_PARAMETER;
+    }
+
+    if (ID->toi_class == INFO_CLASS_PROTOCOL) {
+        if (ID->toi_type != INFO_TYPE_PROVIDER)
+            return TDI_INVALID_PARAMETER;
+
+        switch (ID->toi_id) {
+        case IP_MIB_ADDRTABLE_ENTRY_ID:
+            Temp = 0;
+
+            KeAcquireSpinLock(&InterfaceLock, &OldIrql);
+/*
+    /* Search the interface list */
+    CurrentIFEntry = InterfaceListHead.Flink;
+    while (CurrentIFEntry != &InterfaceListHead) {
+           CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
+        if (CurrentIF != Loopback) {
+            /* Search the address entry list and return the first appropriate ADE found */
+            CurrentADEEntry = CurrentIF->ADEListHead.Flink;
+            while (CurrentADEEntry != &CurrentIF->ADEListHead) {
+                   CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
+                if (CurrentADE->Type == AddressType)
+                    ReferenceAddress(CurrentADE->Address);
+                    KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+                    return CurrentADE;
+                }
+                CurrentADEEntry = CurrentADEEntry->Flink;
+        } else
+            LoopbackIsRegistered = TRUE;
+        CurrentIFEntry = CurrentIFEntry->Flink;
+    }
+
+
+            */
+            for (IF = InterfaceList; IF != NULL; IF = IF->Next) {
+                if (Temp + sizeof(IPADDR_ENTRY) > BufSize) {
+                    KeReleaseSpinLock(&InterfaceLock, OldIrql);
+                    return TDI_BUFFER_TOO_SMALL;
+                }
+
+                IpAddress.Addr      = 0;
+                IpAddress.BcastAddr = 0;
+                IpAddress.Mask      = 0;
+                /* Locate the diffrent addresses and put them the right place */
+                for (ADE = IF->ADE; ADE != NULL; ADE = ADE->Next) {
+                    switch (ADE->Type) {
+                    case ADE_UNICAST  : IpAddress.Addr      = ADE->Address->Address.IPv4Address;
+                    case ADE_MULTICAST: IpAddress.BcastAddr = ADE->Address->Address.IPv4Address;
+                    case ADE_ADDRMASK : IpAddress.Mask      = ADE->Address->Address.IPv4Address;
+                    }
+                }
+                /* Pack the address information into IPADDR_ENTRY structure */
+                IpAddress.Index     = 0;
+                IpAddress.ReasmSize = 0;
+                IpAddress.Context   = 0;
+                IpAddress.Pad       = 0;
+
+                Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY));
+
+                Temp += sizeof(IPADDR_ENTRY);
+            }
+            KeReleaseSpinLock(&InterfaceLock, OldIrql);
+            return TDI_SUCCESS;
+
+        case IP_MIB_STATS_ID:
+            if (BufSize < sizeof(IPSNMP_INFO))
+                return TDI_BUFFER_TOO_SMALL;
+
+            RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO));
+
+            /* Count number of addresses */
+            Count = 0;
+            KeAcquireSpinLock(&InterfaceLock, &OldIrql);
+            for (IF = InterfaceList; IF != NULL; IF = IF->Next)
+                Count++;
+            KeReleaseSpinLock(&InterfaceLock, OldIrql);
+
+            SnmpInfo.NumAddr = Count;
+
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO));
+
+            return TDI_SUCCESS;
+
+        default:
+            /* We can't handle this ID */
+            return TDI_INVALID_PARAMETER;
+        }
+    }
+
+    return TDI_INVALID_PARAMETER;
+}
+
+
+TDI_STATUS InfoTdiQueryInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PNDIS_BUFFER Buffer,
+    PUINT BufferSize,
+    PVOID Context)
+/*
+ * FUNCTION: Returns extended information
+ * ARGUMENTS:
+ *     Request    = Pointer to TDI request structure for the request
+ *     ID         = TDI object ID
+ *     Buffer     = Pointer to buffer with data to use
+ *     BufferSize = Pointer to buffer with size of Buffer. On return
+ *                  this is filled with number of bytes returned
+ *     Context    = Pointer to context buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PADDRESS_FILE AddrFile;
+    PADDRESS_ENTRY ADE;
+    ADDRESS_INFO Info;
+    KIRQL OldIrql;
+    UINT Entity;
+    UINT Count;
+    UINT Size;
+    ULONG Temp;
+    UINT Offset = 0;
+    UINT BufSize = *BufferSize;
+
+    /* Check wether it is a query for a list of entities */
+    Entity = ID->toi_entity.tei_entity;
+    if (Entity == GENERIC_ENTITY) {
+        if (ID->toi_class  != INFO_CLASS_GENERIC ||
+            ID->toi_type != INFO_TYPE_PROVIDER ||
+            ID->toi_id != ENTITY_LIST_ID)
+            return TDI_INVALID_PARAMETER;
+
+        *BufferSize = 0;
+
+        Size = EntityCount * sizeof(TDIEntityID);
+        if (BufSize < Size)
+            /* The buffer is too small to contain requested data */
+            return TDI_BUFFER_TOO_SMALL;
+
+        /* Return entity list */
+        Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size);
+
+        *BufferSize = Size;
+
+        return TDI_SUCCESS;
+    }
+
+    if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) {
+        /* We can't handle this entity, pass it on */
+        return IPTdiQueryInformationEx(
+            Request, ID, Buffer, BufferSize, Context);
+    }
+
+    /* Make return parameters consistent every time */
+    *BufferSize = 0;
+
+    if (ID->toi_entity.tei_instance != TL_INSTANCE)
+        /* We only support a single instance */
+        return TDI_INVALID_REQUEST;
+
+    if (ID->toi_class == INFO_CLASS_GENERIC) {
+
+        if (ID->toi_type != INFO_TYPE_PROVIDER ||
+            ID->toi_id != ENTITY_TYPE_ID)
+            return TDI_INVALID_PARAMETER;
+
+        if (BufSize < sizeof(ULONG))
+            return TDI_BUFFER_TOO_SMALL;
+
+        if (Entity == CL_TL_ENTITY)
+            Temp = CL_TL_UDP;
+        else if (Entity == CO_TL_ENTITY)
+            Temp = CO_TL_TCP;
+        else
+            return TDI_INVALID_PARAMETER;
+
+        Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG));
+
+        return TDI_SUCCESS;
+    }
+
+    if (ID->toi_class == INFO_CLASS_PROTOCOL) {
+
+        if (ID->toi_type != INFO_TYPE_PROVIDER)
+            return TDI_INVALID_PARAMETER;
+
+        switch (ID->toi_id) {
+        case UDP_MIB_STAT_ID:
+            if (Entity != CL_TL_ENTITY)
+                return TDI_INVALID_PARAMETER;
+
+            if (BufSize < sizeof(UDPStats))
+                return TDI_BUFFER_TOO_SMALL;
+
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS));
+
+            return TDI_SUCCESS;
+
+        case UDP_MIB_TABLE_ID:
+            if (Entity != CL_TL_ENTITY)
+                return TDI_INVALID_PARAMETER;
+
+            Offset = 0;
+
+            KeAcquireSpinLock(&AddressFileLock, &OldIrql);
+
+            for (AddrFile = AddressFileList;
+                AddrFile->Next != NULL;
+                AddrFile = AddrFile->Next) {
+
+                if (Offset + sizeof(ADDRESS_INFO) > BufSize) {
+                    KeReleaseSpinLock(&AddressFileLock, OldIrql);
+                    *BufferSize = Offset;
+                    return TDI_BUFFER_OVERFLOW;
+                }
+
+                for (ADE = AddrFile->ADE; ADE != NULL; ADE = ADE->Next) {
+                    /* We only care about IPv4 unicast address */
+                    if ((ADE->Type == ADE_UNICAST) &&
+                        (ADE->Address->Type == IP_ADDRESS_V4))
+                        Info.LocalAddress = ADE->Address->Address.IPv4Address;
+                }
+
+                Info.LocalPort = AddrFile->Port;
+
+                Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO));
+
+                Offset += Count;
+            }
+
+            KeReleaseSpinLock(&AddressFileLock, OldIrql);
+
+            *BufferSize = Offset;
+
+            return STATUS_SUCCESS;
+
+        default:
+            /* We can't handle this ID */
+            return TDI_INVALID_PARAMETER;
+        }
+    }
+
+    return TDI_INVALID_PARAMETER;
+}
+
+
+TDI_STATUS InfoTdiSetInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PVOID Buffer,
+    UINT BufferSize)
+/*
+ * FUNCTION: Sets extended information
+ * ARGUMENTS:
+ *     Request    = Pointer to TDI request structure for the request
+ *     ID         = Pointer to TDI object ID
+ *     Buffer     = Pointer to buffer with data to use
+ *     BufferSize = Size of Buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    /* FIXME: Set extended information */
+
+    return TDI_INVALID_REQUEST;
+}
+
+/* EOF */
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index e39f49a..6e20291 100644 (file)
@@ -1,28 +1,28 @@
-TARGETNAME=tcpip\r
-TARGETPATH=..\objects\r
-TARGETTYPE=EXPORT_DRIVER\r
-\r
-TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \\r
-           $(DDK_LIB_PATH)\ndis.lib \\r
-           ..\objects\*\free\datagram.lib \\r
-           ..\objects\*\free\datalink.lib \\r
-           ..\objects\*\free\network.lib \\r
-           ..\objects\*\free\rawip.lib \\r
-           ..\objects\*\free\tcp.lib \\r
-           ..\objects\*\free\udp.lib\r
-\r
-INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net\r
-\r
-\r
-SOURCES= address.c \\r
-         checksum.c \\r
-            dispatch.c \\r
-         fileobjs.c \\r
-         info.c \\r
-         main.c \\r
-         pool.c \\r
-         routines.c \\r
-         RESOURCE.RC\r
-\r
-MSC_WARNING_LEVEL=/W3 /WX\r
-\r
+TARGETNAME=tcpip
+TARGETPATH=..\objects
+TARGETTYPE=EXPORT_DRIVER
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib \
+           ..\objects\*\free\datagram.lib \
+           ..\objects\*\free\datalink.lib \
+           ..\objects\*\free\network.lib \
+           ..\objects\*\free\rawip.lib \
+           ..\objects\*\free\tcp.lib \
+           ..\objects\*\free\udp.lib
+
+INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net
+
+
+SOURCES= address.c \
+         checksum.c \
+            dispatch.c \
+         fileobjs.c \
+         info.c \
+         main.c \
+         pool.c \
+         routines.c \
+         RESOURCE.RC
+
+MSC_WARNING_LEVEL=/W3 /WX
+
index eba0e2c..1c80aec 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/address.c\r
- * PURPOSE:     Routines for handling addresses\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 <pool.h>\r
-#include <ip.h>\r
-\r
-\r
-BOOLEAN AddrIsUnspecified(\r
-    PIP_ADDRESS Address)\r
-/*\r
- * FUNCTION: Return wether IP address is an unspecified address\r
- * ARGUMENTS:\r
- *     Address  = Pointer to an IP address structure\r
- * RETURNS:\r
- *     TRUE if the IP address is an unspecified address, FALSE if not\r
- */\r
-{\r
-    switch (Address->Type) {\r
-        case IP_ADDRESS_V4:\r
-            return (Address->Address.IPv4Address == 0);\r
-\r
-        case IP_ADDRESS_V6:\r
-        /* FIXME: IPv6 is not supported */\r
-        default:\r
-            return FALSE;\r
-    }\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Extract IP address from TDI address structure\r
- * ARGUMENTS:\r
- *     AddrList = Pointer to transport address list to extract from\r
- *     Address  = Address of a pointer to where an IP address is stored\r
- *     Port     = Pointer to where port number is stored\r
- *     Cache    = Address of pointer to a cached address (updated on return)\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS AddrGetAddress(\r
-    PTRANSPORT_ADDRESS AddrList,\r
-    PIP_ADDRESS *Address,\r
-    PUSHORT Port,\r
-    PIP_ADDRESS *Cache)\r
-{\r
-    PTA_ADDRESS CurAddr;\r
-    INT i;\r
-\r
-    /* We can only use IP addresses. Search the list until we find one */\r
-    CurAddr = AddrList->Address;\r
-\r
-    for (i = 0; i < AddrList->TAAddressCount; i++) {\r
-        switch (CurAddr->AddressType) {\r
-        case TDI_ADDRESS_TYPE_IP:\r
-            if (CurAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {\r
-                /* This is an IPv4 address */\r
-                PIP_ADDRESS IPAddress;\r
-                PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;\r
-\r
-                *Port = ValidAddr->sin_port;\r
-\r
-                if (*Cache) {\r
-                    if (((*Cache)->Type == IP_ADDRESS_V4) &&\r
-                        ((*Cache)->Address.IPv4Address == ValidAddr->in_addr)) {\r
-                        *Address = *Cache;\r
-                        return STATUS_SUCCESS;\r
-                    } else {\r
-                        /* Release the cached address as we cannot use it this time */\r
-                        DereferenceObject(*Cache);\r
-                        *Cache = NULL;\r
-                    }\r
-                }\r
-\r
-                IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS));\r
-                if (IPAddress) {\r
-                    AddrInitIPv4(IPAddress, ValidAddr->in_addr);\r
-                    *Address = IPAddress;\r
-\r
-                    /* Update address cache */\r
-                    *Cache = IPAddress;\r
-                    ReferenceObject(*Cache);\r
-                    return STATUS_SUCCESS;\r
-                } else\r
-                    return STATUS_INSUFFICIENT_RESOURCES;\r
-            } else\r
-                return STATUS_INVALID_ADDRESS;\r
-        default:\r
-            /* This is an unsupported address type.\r
-               Skip it and go to the next in the list */\r
-            CurAddr = (PTA_ADDRESS)((ULONG_PTR)CurAddr->Address + CurAddr->AddressLength);\r
-        }\r
-    }\r
-\r
-    return STATUS_INVALID_ADDRESS;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Returns wether two addresses are equal\r
- * ARGUMENTS:\r
- *     Address1 = Pointer to first address\r
- *     Address2 = Pointer to last address\r
- * RETURNS:\r
- *     TRUE if Address1 = Address2, FALSE if not\r
- */\r
-BOOLEAN AddrIsEqual(\r
-    PIP_ADDRESS Address1,\r
-    PIP_ADDRESS Address2)\r
-{\r
-    if (Address1->Type != Address2->Type)\r
-        return FALSE;\r
-\r
-    switch (Address1->Type) {\r
-        case IP_ADDRESS_V4:\r
-            return (Address1->Address.IPv4Address == Address2->Address.IPv4Address);\r
-\r
-        case IP_ADDRESS_V6:\r
-            return (RtlCompareMemory(&Address1->Address, &Address2->Address,\r
-                sizeof(IPv6_RAW_ADDRESS)) == sizeof(IPv6_RAW_ADDRESS));\r
-            break;\r
-    }\r
-\r
-    return FALSE;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Returns wether Address1 is less than Address2\r
- * ARGUMENTS:\r
- *     Address1 = Pointer to first address\r
- *     Address2 = Pointer to last address\r
- * RETURNS:\r
- *     -1 if Address1 < Address2, 1 if Address1 > Address2,\r
- *     or 0 if they are equal\r
- */\r
-INT AddrCompare(\r
-    PIP_ADDRESS Address1,\r
-    PIP_ADDRESS Address2)\r
-{\r
-    switch (Address1->Type) {\r
-        case IP_ADDRESS_V4: {\r
-            ULONG Addr1, Addr2;\r
-            if (Address2->Type == IP_ADDRESS_V4) {\r
-                Addr1 = DN2H(Address1->Address.IPv4Address);\r
-                Addr2 = DN2H(Address2->Address.IPv4Address);\r
-                if (Addr1 < Addr2)\r
-                    return -1;\r
-                else\r
-                    if (Addr1 == Addr2)\r
-                        return 0;\r
-                    else\r
-                        return 1;\r
-            } else\r
-                /* FIXME: Support IPv6 */\r
-                return -1;\r
-\r
-        case IP_ADDRESS_V6:\r
-            /* FIXME: Support IPv6 */\r
-        break;\r
-        }\r
-    }\r
-\r
-    return FALSE;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Returns wether two addresses are equal with IPv4 as input\r
- * ARGUMENTS:\r
- *     Address1 = Pointer to first address\r
- *     Address2 = Pointer to last address\r
- * RETURNS:\r
- *     TRUE if Address1 = Address2, FALSE if not\r
- */\r
-BOOLEAN AddrIsEqualIPv4(\r
-    PIP_ADDRESS Address1,\r
-    IPv4_RAW_ADDRESS Address2)\r
-{\r
-    if (Address1->Type == IP_ADDRESS_V4)\r
-        return (Address1->Address.IPv4Address == Address2);\r
-\r
-    return FALSE;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Build an IPv4 style address\r
- * ARGUMENTS:\r
- *     Address = Raw IPv4 address\r
- * RETURNS:\r
- *     Pointer to IP address structure, NULL if there was not enough free\r
- *     non-paged memory\r
- */\r
-PIP_ADDRESS AddrBuildIPv4(\r
-    IPv4_RAW_ADDRESS Address)\r
-{\r
-    PIP_ADDRESS IPAddress;\r
-\r
-    IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS));\r
-    if (IPAddress) {\r
-        IPAddress->RefCount            = 1;\r
-        IPAddress->Type                = IP_ADDRESS_V4;\r
-        IPAddress->Address.IPv4Address = Address;\r
-    }\r
-\r
-    return IPAddress;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Locates and returns an address entry using IPv4 adress as argument\r
- * ARGUMENTS:\r
- *     Address = Raw IPv4 address\r
- * RETURNS:\r
- *     Pointer to address entry if found, NULL if not found\r
- * NOTES:\r
- *     Only unicast addresses are considered.\r
- *     If found, the address is referenced\r
- */\r
-PADDRESS_ENTRY AddrLocateADEv4(\r
-    IPv4_RAW_ADDRESS Address)\r
-{\r
-    IP_ADDRESS Addr;\r
-\r
-    AddrInitIPv4(&Addr, Address);\r
-\r
-    return IPLocateADE(&Addr, ADE_UNICAST);\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Searches through address file entries to find the first match\r
- * ARGUMENTS:\r
- *     Address       = IP address\r
- *     Port          = Port number\r
- *     Protocol      = Protocol number\r
- *     SearchContext = Pointer to search context\r
- * RETURNS:\r
- *     Pointer to address file, NULL if none was found\r
- */\r
-PADDRESS_FILE AddrSearchFirst(\r
-    PIP_ADDRESS Address,\r
-    USHORT Port,\r
-    USHORT Protocol,\r
-    PAF_SEARCH SearchContext)\r
-{\r
-    SearchContext->Address  = Address;\r
-    SearchContext->Port     = Port;\r
-    SearchContext->Next     = AddressFileListHead.Flink;\r
-    SearchContext->Protocol = Protocol;\r
-\r
-    return AddrSearchNext(SearchContext);\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Searches through address file entries to find next match\r
- * ARGUMENTS:\r
- *     SearchContext = Pointer to search context\r
- * RETURNS:\r
- *     Pointer to address file, NULL if none was found\r
- */\r
-PADDRESS_FILE AddrSearchNext(\r
-    PAF_SEARCH SearchContext)\r
-{\r
-    PLIST_ENTRY CurrentEntry;\r
-    PIP_ADDRESS IPAddress;\r
-    KIRQL OldIrql;\r
-    PADDRESS_FILE Current = NULL;\r
-    BOOLEAN Found = FALSE;\r
-\r
-    if (IsListEmpty(SearchContext->Next))\r
-        return NULL;\r
-\r
-    CurrentEntry = SearchContext->Next;\r
-\r
-    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);\r
-\r
-    while (CurrentEntry != &AddressFileListHead) {\r
-           Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);\r
-\r
-        /* See if this address matches the search criteria */\r
-        IPAddress = Current->ADE->Address;\r
-        if (((Current->Port    == SearchContext->Port) &&\r
-            (Current->Protocol == SearchContext->Protocol) &&\r
-            (AddrIsEqual(IPAddress, SearchContext->Address))) ||\r
-            (AddrIsUnspecified(IPAddress))) {\r
-            /* We've found a match */\r
-            Found = TRUE;\r
-            break;\r
-        }\r
-        CurrentEntry = CurrentEntry->Flink;\r
-    }\r
-\r
-    KeReleaseSpinLock(&AddressFileListLock, OldIrql);\r
-\r
-    if (Found) {\r
-        SearchContext->Next = CurrentEntry->Flink;\r
-        return Current;\r
-    } else\r
-        return NULL;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/address.c
+ * PURPOSE:     Routines for handling addresses
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <address.h>
+#include <pool.h>
+#include <ip.h>
+
+
+BOOLEAN AddrIsUnspecified(
+    PIP_ADDRESS Address)
+/*
+ * FUNCTION: Return wether IP address is an unspecified address
+ * ARGUMENTS:
+ *     Address  = Pointer to an IP address structure
+ * RETURNS:
+ *     TRUE if the IP address is an unspecified address, FALSE if not
+ */
+{
+    switch (Address->Type) {
+        case IP_ADDRESS_V4:
+            return (Address->Address.IPv4Address == 0);
+
+        case IP_ADDRESS_V6:
+        /* FIXME: IPv6 is not supported */
+        default:
+            return FALSE;
+    }
+}
+
+
+/*
+ * FUNCTION: Extract IP address from TDI address structure
+ * ARGUMENTS:
+ *     AddrList = Pointer to transport address list to extract from
+ *     Address  = Address of a pointer to where an IP address is stored
+ *     Port     = Pointer to where port number is stored
+ *     Cache    = Address of pointer to a cached address (updated on return)
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS AddrGetAddress(
+    PTRANSPORT_ADDRESS AddrList,
+    PIP_ADDRESS *Address,
+    PUSHORT Port,
+    PIP_ADDRESS *Cache)
+{
+    PTA_ADDRESS CurAddr;
+    INT i;
+
+    /* We can only use IP addresses. Search the list until we find one */
+    CurAddr = AddrList->Address;
+
+    for (i = 0; i < AddrList->TAAddressCount; i++) {
+        switch (CurAddr->AddressType) {
+        case TDI_ADDRESS_TYPE_IP:
+            if (CurAddr->AddressLength >= TDI_ADDRESS_LENGTH_IP) {
+                /* This is an IPv4 address */
+                PIP_ADDRESS IPAddress;
+                PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;
+
+                *Port = ValidAddr->sin_port;
+
+                if (*Cache) {
+                    if (((*Cache)->Type == IP_ADDRESS_V4) &&
+                        ((*Cache)->Address.IPv4Address == ValidAddr->in_addr)) {
+                        *Address = *Cache;
+                        return STATUS_SUCCESS;
+                    } else {
+                        /* Release the cached address as we cannot use it this time */
+                        DereferenceObject(*Cache);
+                        *Cache = NULL;
+                    }
+                }
+
+                IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS));
+                if (IPAddress) {
+                    AddrInitIPv4(IPAddress, ValidAddr->in_addr);
+                    *Address = IPAddress;
+
+                    /* Update address cache */
+                    *Cache = IPAddress;
+                    ReferenceObject(*Cache);
+                    return STATUS_SUCCESS;
+                } else
+                    return STATUS_INSUFFICIENT_RESOURCES;
+            } else
+                return STATUS_INVALID_ADDRESS;
+        default:
+            /* This is an unsupported address type.
+               Skip it and go to the next in the list */
+            CurAddr = (PTA_ADDRESS)((ULONG_PTR)CurAddr->Address + CurAddr->AddressLength);
+        }
+    }
+
+    return STATUS_INVALID_ADDRESS;
+}
+
+
+/*
+ * FUNCTION: Returns wether two addresses are equal
+ * ARGUMENTS:
+ *     Address1 = Pointer to first address
+ *     Address2 = Pointer to last address
+ * RETURNS:
+ *     TRUE if Address1 = Address2, FALSE if not
+ */
+BOOLEAN AddrIsEqual(
+    PIP_ADDRESS Address1,
+    PIP_ADDRESS Address2)
+{
+    if (Address1->Type != Address2->Type)
+        return FALSE;
+
+    switch (Address1->Type) {
+        case IP_ADDRESS_V4:
+            return (Address1->Address.IPv4Address == Address2->Address.IPv4Address);
+
+        case IP_ADDRESS_V6:
+            return (RtlCompareMemory(&Address1->Address, &Address2->Address,
+                sizeof(IPv6_RAW_ADDRESS)) == sizeof(IPv6_RAW_ADDRESS));
+            break;
+    }
+
+    return FALSE;
+}
+
+
+/*
+ * FUNCTION: Returns wether Address1 is less than Address2
+ * ARGUMENTS:
+ *     Address1 = Pointer to first address
+ *     Address2 = Pointer to last address
+ * RETURNS:
+ *     -1 if Address1 < Address2, 1 if Address1 > Address2,
+ *     or 0 if they are equal
+ */
+INT AddrCompare(
+    PIP_ADDRESS Address1,
+    PIP_ADDRESS Address2)
+{
+    switch (Address1->Type) {
+        case IP_ADDRESS_V4: {
+            ULONG Addr1, Addr2;
+            if (Address2->Type == IP_ADDRESS_V4) {
+                Addr1 = DN2H(Address1->Address.IPv4Address);
+                Addr2 = DN2H(Address2->Address.IPv4Address);
+                if (Addr1 < Addr2)
+                    return -1;
+                else
+                    if (Addr1 == Addr2)
+                        return 0;
+                    else
+                        return 1;
+            } else
+                /* FIXME: Support IPv6 */
+                return -1;
+
+        case IP_ADDRESS_V6:
+            /* FIXME: Support IPv6 */
+        break;
+        }
+    }
+
+    return FALSE;
+}
+
+
+/*
+ * FUNCTION: Returns wether two addresses are equal with IPv4 as input
+ * ARGUMENTS:
+ *     Address1 = Pointer to first address
+ *     Address2 = Pointer to last address
+ * RETURNS:
+ *     TRUE if Address1 = Address2, FALSE if not
+ */
+BOOLEAN AddrIsEqualIPv4(
+    PIP_ADDRESS Address1,
+    IPv4_RAW_ADDRESS Address2)
+{
+    if (Address1->Type == IP_ADDRESS_V4)
+        return (Address1->Address.IPv4Address == Address2);
+
+    return FALSE;
+}
+
+
+/*
+ * FUNCTION: Build an IPv4 style address
+ * ARGUMENTS:
+ *     Address = Raw IPv4 address
+ * RETURNS:
+ *     Pointer to IP address structure, NULL if there was not enough free
+ *     non-paged memory
+ */
+PIP_ADDRESS AddrBuildIPv4(
+    IPv4_RAW_ADDRESS Address)
+{
+    PIP_ADDRESS IPAddress;
+
+    IPAddress = PoolAllocateBuffer(sizeof(IP_ADDRESS));
+    if (IPAddress) {
+        IPAddress->RefCount            = 1;
+        IPAddress->Type                = IP_ADDRESS_V4;
+        IPAddress->Address.IPv4Address = Address;
+    }
+
+    return IPAddress;
+}
+
+
+/*
+ * FUNCTION: Locates and returns an address entry using IPv4 adress as argument
+ * ARGUMENTS:
+ *     Address = Raw IPv4 address
+ * RETURNS:
+ *     Pointer to address entry if found, NULL if not found
+ * NOTES:
+ *     Only unicast addresses are considered.
+ *     If found, the address is referenced
+ */
+PADDRESS_ENTRY AddrLocateADEv4(
+    IPv4_RAW_ADDRESS Address)
+{
+    IP_ADDRESS Addr;
+
+    AddrInitIPv4(&Addr, Address);
+
+    return IPLocateADE(&Addr, ADE_UNICAST);
+}
+
+
+/*
+ * FUNCTION: Searches through address file entries to find the first match
+ * ARGUMENTS:
+ *     Address       = IP address
+ *     Port          = Port number
+ *     Protocol      = Protocol number
+ *     SearchContext = Pointer to search context
+ * RETURNS:
+ *     Pointer to address file, NULL if none was found
+ */
+PADDRESS_FILE AddrSearchFirst(
+    PIP_ADDRESS Address,
+    USHORT Port,
+    USHORT Protocol,
+    PAF_SEARCH SearchContext)
+{
+    SearchContext->Address  = Address;
+    SearchContext->Port     = Port;
+    SearchContext->Next     = AddressFileListHead.Flink;
+    SearchContext->Protocol = Protocol;
+
+    return AddrSearchNext(SearchContext);
+}
+
+
+/*
+ * FUNCTION: Searches through address file entries to find next match
+ * ARGUMENTS:
+ *     SearchContext = Pointer to search context
+ * RETURNS:
+ *     Pointer to address file, NULL if none was found
+ */
+PADDRESS_FILE AddrSearchNext(
+    PAF_SEARCH SearchContext)
+{
+    PLIST_ENTRY CurrentEntry;
+    PIP_ADDRESS IPAddress;
+    KIRQL OldIrql;
+    PADDRESS_FILE Current = NULL;
+    BOOLEAN Found = FALSE;
+
+    if (IsListEmpty(SearchContext->Next))
+        return NULL;
+
+    CurrentEntry = SearchContext->Next;
+
+    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+
+    while (CurrentEntry != &AddressFileListHead) {
+           Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
+
+        /* See if this address matches the search criteria */
+        IPAddress = Current->ADE->Address;
+        if (((Current->Port    == SearchContext->Port) &&
+            (Current->Protocol == SearchContext->Protocol) &&
+            (AddrIsEqual(IPAddress, SearchContext->Address))) ||
+            (AddrIsUnspecified(IPAddress))) {
+            /* We've found a match */
+            Found = TRUE;
+            break;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+    if (Found) {
+        SearchContext->Next = CurrentEntry->Flink;
+        return Current;
+    } else
+        return NULL;
+}
+
+/* EOF */
index b43b29a..72c08e8 100644 (file)
@@ -1,50 +1,50 @@
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/checksum.c\r
- * PURPOSE:     Checksum routines\r
- * NOTES:       The checksum routine is from RFC 1071\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- *   CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <checksum.h>\r
-\r
-\r
-ULONG ChecksumCompute(\r
-    PVOID Data,\r
-    UINT Count,\r
-    ULONG Seed)\r
-/*\r
- * FUNCTION: Calculate checksum of a buffer\r
- * ARGUMENTS:\r
- *     Data  = Pointer to buffer with data\r
- *     Count = Number of bytes in buffer\r
- *     Seed  = Previously calculated checksum (if any)\r
- * RETURNS:\r
- *     Checksum of buffer\r
- */\r
-{\r
-    /* FIXME: This should be done in assembler */\r
-\r
-    register ULONG Sum = Seed;\r
-\r
-    while (Count > 1) {\r
-        Sum             += *(PUSHORT)Data;\r
-        Count           -= 2;\r
-        (ULONG_PTR)Data += 2;\r
-    }\r
-\r
-    /* Add left-over byte, if any */\r
-    if (Count > 0)\r
-        Sum += *(PUCHAR)Data;\r
-\r
-    /* Fold 32-bit sum to 16 bits */\r
-    while (Sum >> 16)\r
-        Sum = (Sum & 0xFFFF) + (Sum >> 16);\r
-\r
-    return ~Sum;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/checksum.c
+ * PURPOSE:     Checksum routines
+ * NOTES:       The checksum routine is from RFC 1071
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <checksum.h>
+
+
+ULONG ChecksumCompute(
+    PVOID Data,
+    UINT Count,
+    ULONG Seed)
+/*
+ * FUNCTION: Calculate checksum of a buffer
+ * ARGUMENTS:
+ *     Data  = Pointer to buffer with data
+ *     Count = Number of bytes in buffer
+ *     Seed  = Previously calculated checksum (if any)
+ * RETURNS:
+ *     Checksum of buffer
+ */
+{
+    /* FIXME: This should be done in assembler */
+
+    register ULONG Sum = Seed;
+
+    while (Count > 1) {
+        Sum             += *(PUSHORT)Data;
+        Count           -= 2;
+        (ULONG_PTR)Data += 2;
+    }
+
+    /* Add left-over byte, if any */
+    if (Count > 0)
+        Sum += *(PUCHAR)Data;
+
+    /* Fold 32-bit sum to 16 bits */
+    while (Sum >> 16)
+        Sum = (Sum & 0xFFFF) + (Sum >> 16);
+
+    return ~Sum;
+}
+
+/* EOF */
index 5d91ff3..600d88f 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/dispatch.h\r
- * PURPOSE:     TDI dispatch 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 <dispatch.h>\r
-#include <routines.h>\r
-#include <datagram.h>\r
-#include <info.h>\r
-\r
-\r
-NTSTATUS DispPrepareIrpForCancel(\r
-    PTRANSPORT_CONTEXT Context,\r
-    PIRP Irp,\r
-    PDRIVER_CANCEL CancelRoutine)\r
-/*\r
- * FUNCTION: Prepare an IRP for cancellation\r
- * ARGUMENTS:\r
- *     Context       = Pointer to context information\r
- *     Irp           = Pointer to an I/O request packet\r
- *     CancelRoutine = Routine to be called when I/O request is cancelled\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    IoAcquireCancelSpinLock(&OldIrql);\r
-\r
-    if (!Irp->Cancel) {\r
-        IoMarkIrpPending(Irp);\r
-        IoSetCancelRoutine(Irp, CancelRoutine);\r
-        Context->RefCount++;\r
-        IoReleaseCancelSpinLock(OldIrql);\r
-\r
-        TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp));\r
-\r
-        return STATUS_SUCCESS;\r
-    }\r
-\r
-    /* IRP has already been cancelled */\r
\r
-    IoReleaseCancelSpinLock(OldIrql);\r
-\r
-    Irp->IoStatus.Status      = STATUS_CANCELLED;\r
-    Irp->IoStatus.Information = 0;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));\r
-\r
-    IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n"));\r
-\r
-    return STATUS_CANCELLED;\r
-}\r
-\r
-\r
-VOID DispCancelComplete(\r
-    PVOID Context)\r
-/*\r
- * FUNCTION: Completes a cancel request\r
- * ARGUMENTS:\r
- *     Context = Pointer to context information (FILE_OBJECT)\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-    PFILE_OBJECT FileObject;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    \r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    FileObject  = (PFILE_OBJECT)Context;\r
-    TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;\r
-    \r
-    IoAcquireCancelSpinLock(&OldIrql);\r
-\r
-    /* Remove the reference placed on the endpoint by the cancel routine.\r
-       The cancelled IRP will be completed by the completion routine for\r
-       the request */\r
-    TranContext->RefCount--;\r
-\r
-    if (TranContext->RefCount == 0) {\r
-        TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n"));\r
-        /* Set the cleanup event */\r
-        KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount));\r
-\r
-    IoReleaseCancelSpinLock(OldIrql);\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));\r
-}\r
-\r
-\r
-VOID DispCancelRequest(\r
-    PDEVICE_OBJECT Device,\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: Cancels an IRP\r
- * ARGUMENTS:\r
- *     Device = Pointer to device object\r
- *     Irp    = Pointer to an I/O request packet\r
- */\r
-{\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    PFILE_OBJECT FileObject;\r
-    UCHAR MinorFunction;\r
-    NTSTATUS Status = STATUS_SUCCESS;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    IrpSp         = IoGetCurrentIrpStackLocation(Irp);\r
-    FileObject    = IrpSp->FileObject;\r
-    TranContext   = (PTRANSPORT_CONTEXT)FileObject->FsContext;\r
-    MinorFunction = IrpSp->MinorFunction;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X)  MinorFunction (0x%X)  IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));\r
-\r
-#ifdef DBG\r
-    if (!Irp->Cancel)\r
-        TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));\r
-#endif\r
-\r
-    /* Increase reference count to prevent accidential closure\r
-       of the object while inside the cancel routine */\r
-    TranContext->RefCount++;\r
-\r
-    IoReleaseCancelSpinLock(Irp->CancelIrql);\r
-\r
-    /* Try canceling the request */\r
-    switch(MinorFunction) {\r
-    case TDI_SEND:\r
-\r
-    case TDI_RECEIVE:\r
-        /* FIXME: Close connection */\r
-        break;\r
-\r
-    case TDI_SEND_DATAGRAM:\r
-        if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {\r
-            TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));\r
-            break;\r
-        }\r
-\r
-        DGCancelSendRequest(TranContext->Handle.AddressHandle, Irp);\r
-        break;\r
-\r
-    case TDI_RECEIVE_DATAGRAM:\r
-        if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {\r
-            TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));\r
-            break;\r
-        }\r
-\r
-        DGCancelReceiveRequest(TranContext->Handle.AddressHandle, Irp);\r
-        break;\r
-\r
-    default:\r
-        TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction));\r
-        break;\r
-    }\r
-\r
-    if (Status != STATUS_PENDING)\r
-        DispCancelComplete(FileObject);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-VOID DispDataRequestComplete(\r
-    PVOID Context,\r
-    NTSTATUS Status,\r
-    ULONG Count)\r
-/*\r
- * FUNCTION: Completes a send/receive IRP\r
- * ARGUMENTS:\r
- *     Context = Pointer to context information (IRP)\r
- *     Status  = Status of the request\r
- *     Count   = Number of bytes sent or received\r
- */\r
-{\r
-    PIRP Irp;\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    KIRQL OldIrql;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    Irp         = (PIRP)Context;\r
-    IrpSp       = IoGetCurrentIrpStackLocation(Irp);\r
-    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;\r
-\r
-    IoAcquireCancelSpinLock(&OldIrql);\r
-\r
-    IoSetCancelRoutine(Irp, NULL);\r
-    TranContext->RefCount--;\r
-    TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount));\r
-    if (TranContext->RefCount == 0) {\r
-        TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n"));\r
-\r
-        KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);\r
-    }\r
-\r
-    if (Irp->Cancel || TranContext->CancelIrps) {\r
-        /* The IRP has been cancelled */\r
-\r
-        TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n"));\r
-\r
-        Status = STATUS_CANCELLED;\r
-        Count  = 0;\r
-    }\r
-\r
-    IoReleaseCancelSpinLock(OldIrql);\r
-\r
-    Irp->IoStatus.Status      = Status;\r
-    Irp->IoStatus.Information = Count;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));\r
-\r
-    IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);\r
-}\r
-\r
-\r
-NTSTATUS DispTdiAccept(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_ACCEPT handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiAssociateAddress(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_ASSOCIATE_ADDRESS handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiConnect(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_CONNECT handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiDisassociateAddress(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_DISASSOCIATE_ADDRESS handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiDisconnect(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_DISCONNECT handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiListen(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_LISTEN handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiQueryInformation(\r
-    PDEVICE_OBJECT DeviceObject,\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_QUERY_INFORMATION handler\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to device object structure\r
- *     Irp          = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiReceive(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_RECEIVE handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiReceiveDatagram(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_RECEIVE_DATAGRAM handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    TDI_REQUEST Request;\r
-    NTSTATUS Status;\r
-    ULONG BytesReceived;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    IrpSp     = IoGetCurrentIrpStackLocation(Irp);\r
-    DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);\r
-\r
-    TranContext = IrpSp->FileObject->FsContext;\r
-    /* Initialize a receive request */\r
-    Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;\r
-    Request.RequestNotifyObject  = DispDataRequestComplete;\r
-    Request.RequestContext       = Irp;\r
-    Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest);\r
-    if (NT_SUCCESS(Status)) {\r
-        Status = UDPReceiveDatagram(&Request,\r
-            DgramInfo->ReceiveDatagramInformation,\r
-            (PNDIS_BUFFER)Irp->MdlAddress,\r
-            DgramInfo->ReceiveLength,\r
-            DgramInfo->ReceiveFlags,\r
-            DgramInfo->ReturnDatagramInformation,\r
-            &BytesReceived);\r
-        if (Status != STATUS_PENDING) {\r
-            DispDataRequestComplete(Irp, Status, BytesReceived);\r
-            /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */\r
-            Status = STATUS_PENDING;\r
-        }\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiSend(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_SEND handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiSendDatagram(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_SEND_DATAGRAM handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PIO_STACK_LOCATION IrpSp;\r
-    TDI_REQUEST Request;\r
-    PTDI_REQUEST_KERNEL_SENDDG DgramInfo;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    NTSTATUS Status;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    IrpSp     = IoGetCurrentIrpStackLocation(Irp);\r
-    DgramInfo = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters);\r
-    \r
-    TranContext                  = IrpSp->FileObject->FsContext;\r
-    /* Initialize a send request */\r
-    Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;\r
-    Request.RequestNotifyObject  = DispDataRequestComplete;\r
-    Request.RequestContext       = Irp;\r
-\r
-    Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest);\r
-    if (NT_SUCCESS(Status)) {\r
-\r
-        /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress \r
-           must be of type PTDI_ADDRESS_IP */\r
-\r
-        Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(\r
-            &Request, DgramInfo->SendDatagramInformation,\r
-            (PNDIS_BUFFER)Irp->MdlAddress, DgramInfo->SendLength);\r
-        if (Status != STATUS_PENDING) {\r
-            DispDataRequestComplete(Irp, Status, 0);\r
-            /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */\r
-            Status = STATUS_PENDING;\r
-        }\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiSetEventHandler(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_SET_EVENT_HANDER handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to a I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-#ifdef _MSC_VER\r
-    PTDI_REQUEST_KERNEL_SET_EVENT Parameters;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PADDRESS_FILE AddrFile;\r
-    NTSTATUS Status;\r
-    KIRQL OldIrql;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-    /* Get associated address file object. Quit if none exists */\r
-    TranContext = IrpSp->FileObject->FsContext;\r
-    if (!TranContext) {\r
-        TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n"));\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;\r
-    if (!AddrFile) {\r
-        TI_DbgPrint(MIN_TRACE, ("No address file object.\n"));\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;\r
-    Status     = STATUS_SUCCESS;\r
-    \r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    /* Set the event handler. if an event handler is associated with\r
-       a specific event, it's flag (RegisteredXxxHandler) is TRUE.\r
-       If an event handler is not used it's flag is FALSE */\r
-    switch (Parameters->EventType) {\r
-    case TDI_EVENT_CONNECT:\r
-        if (!Parameters->EventHandler) {\r
-            AddrFile->ConnectionHandler =\r
-                (PTDI_IND_CONNECT)TdiDefaultConnectHandler;\r
-            AddrFile->ConnectionHandlerContext    = NULL;\r
-            AddrFile->RegisteredConnectionHandler = FALSE;\r
-        } else {\r
-            AddrFile->ConnectionHandler =\r
-                (PTDI_IND_CONNECT)Parameters->EventHandler;\r
-            AddrFile->ConnectionHandlerContext    = Parameters->EventContext;\r
-            AddrFile->RegisteredConnectionHandler = TRUE;\r
-        }\r
-        break;\r
-\r
-    case TDI_EVENT_DISCONNECT:\r
-        if (!Parameters->EventHandler) {\r
-            AddrFile->DisconnectHandler =\r
-                (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler;\r
-            AddrFile->DisconnectHandlerContext    = NULL;\r
-            AddrFile->RegisteredDisconnectHandler = FALSE;\r
-        } else {\r
-            AddrFile->DisconnectHandler =\r
-                (PTDI_IND_DISCONNECT)Parameters->EventHandler;\r
-            AddrFile->DisconnectHandlerContext    = Parameters->EventContext;\r
-            AddrFile->RegisteredDisconnectHandler = TRUE;\r
-        }\r
-        break;\r
-\r
-    case TDI_EVENT_RECEIVE:\r
-        if (Parameters->EventHandler == NULL) {\r
-            AddrFile->ReceiveHandler =\r
-                (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler;\r
-            AddrFile->ReceiveHandlerContext    = NULL;\r
-            AddrFile->RegisteredReceiveHandler = FALSE;\r
-        } else {\r
-            AddrFile->ReceiveHandler =\r
-                (PTDI_IND_RECEIVE)Parameters->EventHandler;\r
-            AddrFile->ReceiveHandlerContext    = Parameters->EventContext;\r
-            AddrFile->RegisteredReceiveHandler = TRUE;\r
-        }\r
-        break;\r
-\r
-    case TDI_EVENT_RECEIVE_EXPEDITED:\r
-        if (Parameters->EventHandler == NULL) {\r
-            AddrFile->ExpeditedReceiveHandler =\r
-                (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler;\r
-            AddrFile->ExpeditedReceiveHandlerContext    = NULL;\r
-            AddrFile->RegisteredExpeditedReceiveHandler = FALSE;\r
-        } else {\r
-            AddrFile->ExpeditedReceiveHandler =\r
-                (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler;\r
-            AddrFile->ExpeditedReceiveHandlerContext    = Parameters->EventContext;\r
-            AddrFile->RegisteredExpeditedReceiveHandler = TRUE;\r
-        }\r
-        break;\r
-\r
-    case TDI_EVENT_RECEIVE_DATAGRAM:\r
-        if (Parameters->EventHandler == NULL) {\r
-            AddrFile->ReceiveDatagramHandler =\r
-                (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;\r
-            AddrFile->ReceiveDatagramHandlerContext    = NULL;\r
-            AddrFile->RegisteredReceiveDatagramHandler = FALSE;\r
-        } else {\r
-            AddrFile->ReceiveDatagramHandler =\r
-                (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;\r
-            AddrFile->ReceiveDatagramHandlerContext    = Parameters->EventContext;\r
-            AddrFile->RegisteredReceiveDatagramHandler = TRUE;\r
-        }\r
-        break;\r
-\r
-    case TDI_EVENT_ERROR:\r
-        if (Parameters->EventHandler == NULL) {\r
-            AddrFile->ErrorHandler =\r
-                (PTDI_IND_ERROR)TdiDefaultErrorHandler;\r
-            AddrFile->ErrorHandlerContext    = NULL;\r
-            AddrFile->RegisteredErrorHandler = FALSE;\r
-        } else {\r
-            AddrFile->ErrorHandler =\r
-                (PTDI_IND_ERROR)Parameters->EventHandler;\r
-            AddrFile->ErrorHandlerContext    = Parameters->EventContext;\r
-            AddrFile->RegisteredErrorHandler = TRUE;\r
-        }\r
-        break;\r
-\r
-    default:\r
-        Status = STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    return Status;\r
-#else\r
-    return STATUS_NOT_IMPLEMENTED;\r
-#endif\r
-}\r
-\r
-\r
-NTSTATUS DispTdiSetInformation(\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: TDI_SET_INFORMATION handler\r
- * ARGUMENTS:\r
- *     Irp = Pointer to an I/O request packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-       return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-VOID DispTdiQueryInformationExComplete(\r
-    PVOID Context,\r
-    ULONG Status,\r
-    UINT ByteCount)\r
-/*\r
- * FUNCTION: Completes a TDI QueryInformationEx request\r
- * ARGUMENTS:\r
- *     Context   = Pointer to the IRP for the request\r
- *     Status    = TDI status of the request\r
- *     ByteCount = Number of bytes returned in output buffer\r
- */\r
-{\r
-    PTI_QUERY_CONTEXT QueryContext;\r
-    UINT Count = 0;\r
-\r
-    QueryContext = (PTI_QUERY_CONTEXT)Context;\r
-    if (NT_SUCCESS(Status)) {\r
-        Count = CopyBufferToBufferChain(\r
-            QueryContext->InputMdl,\r
-            FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),\r
-            (PUCHAR)&QueryContext->QueryInfo.Context,\r
-            CONTEXT_SIZE);\r
-    }\r
-\r
-    MmUnlockPages(QueryContext->InputMdl);\r
-    IoFreeMdl(QueryContext->InputMdl);\r
-    MmUnlockPages(QueryContext->OutputMdl);\r
-    IoFreeMdl(QueryContext->OutputMdl);\r
-\r
-    QueryContext->Irp->IoStatus.Information = Count;\r
-    QueryContext->Irp->IoStatus.Status      = Status;\r
-\r
-    ExFreePool(QueryContext);\r
-}\r
-\r
-\r
-NTSTATUS DispTdiQueryInformationEx(\r
-    PIRP Irp,\r
-    PIO_STACK_LOCATION IrpSp)\r
-/*\r
- * FUNCTION: TDI QueryInformationEx handler\r
- * ARGUMENTS:\r
- *     Irp   = Pointer to I/O request packet\r
- *     IrpSp = Pointer to current stack location of Irp\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    PTI_QUERY_CONTEXT QueryContext;\r
-    PVOID OutputBuffer;\r
-    TDI_REQUEST Request;\r
-    UINT Size;\r
-    UINT InputBufferLength;\r
-    UINT OutputBufferLength;\r
-    BOOLEAN InputMdlLocked  = FALSE;\r
-    BOOLEAN OutputMdlLocked = FALSE;\r
-    PMDL InputMdl           = NULL;\r
-    PMDL OutputMdl          = NULL;\r
-    NTSTATUS Status         = STATUS_SUCCESS;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;\r
-\r
-    switch ((ULONG)IrpSp->FileObject->FsContext2) {\r
-    case TDI_TRANSPORT_ADDRESS_FILE:\r
-        Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;\r
-        break;\r
-\r
-    case TDI_CONNECTION_FILE:\r
-        Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;\r
-        break;\r
-\r
-    case TDI_CONTROL_CHANNEL_FILE:\r
-        Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;\r
-        break;\r
-\r
-    default:\r
-        TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    InputBufferLength  = IrpSp->Parameters.DeviceIoControl.InputBufferLength;\r
-    OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;\r
-\r
-    /* Validate parameters */\r
-    if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&\r
-        (OutputBufferLength != 0)) {\r
-\r
-        InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)\r
-            IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;\r
-        OutputBuffer = Irp->UserBuffer;\r
-\r
-        QueryContext = ExAllocatePool(NonPagedPool, sizeof(TI_QUERY_CONTEXT));\r
-        if (QueryContext) {\r
-#ifdef _MSC_VER\r
-            try {\r
-#endif\r
-                InputMdl = IoAllocateMdl(InputBuffer,\r
-                    sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),\r
-                    FALSE, TRUE, NULL);\r
-\r
-                OutputMdl = IoAllocateMdl(OutputBuffer,\r
-                    OutputBufferLength, FALSE, TRUE, NULL);\r
-\r
-                if (InputMdl && OutputMdl) {\r
-\r
-                    MmProbeAndLockPages(InputMdl, Irp->RequestorMode,\r
-                        IoModifyAccess);\r
-\r
-                    InputMdlLocked = TRUE;\r
-\r
-                    MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,\r
-                        IoWriteAccess);\r
-\r
-                    OutputMdlLocked = TRUE;\r
-\r
-                    RtlCopyMemory(&QueryContext->QueryInfo,\r
-                        InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));\r
-\r
-                } else\r
-                    Status = STATUS_INSUFFICIENT_RESOURCES;\r
-#ifdef _MSC_VER\r
-            } except(EXCEPTION_EXECUTE_HANDLER) {\r
-                Status = GetExceptionCode();\r
-            }\r
-#endif\r
-            if (NT_SUCCESS(Status)) {\r
-                Size = MmGetMdlByteCount(OutputMdl);\r
-\r
-                QueryContext->Irp       = Irp;\r
-                QueryContext->InputMdl  = InputMdl;\r
-                QueryContext->OutputMdl = OutputMdl;\r
-\r
-                Request.RequestNotifyObject = DispTdiQueryInformationExComplete;\r
-                Request.RequestContext      = QueryContext;\r
-                Status = InfoTdiQueryInformationEx(&Request,\r
-                    &QueryContext->QueryInfo.ID, OutputMdl,\r
-                    &Size, &QueryContext->QueryInfo.Context);\r
-                DispTdiQueryInformationExComplete(QueryContext, Status, Size);\r
-\r
-                TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));\r
-\r
-                return Status;\r
-            }\r
-\r
-            /* An error occurred if we get here */\r
-\r
-            if (InputMdl) {\r
-                if (InputMdlLocked)\r
-                    MmUnlockPages(InputMdl);\r
-                IoFreeMdl(InputMdl);\r
-            }\r
-\r
-            if (OutputMdl) {\r
-                if (OutputMdlLocked)\r
-                    MmUnlockPages(OutputMdl);\r
-                IoFreeMdl(OutputMdl);\r
-            }\r
-\r
-            ExFreePool(QueryContext);\r
-        } else\r
-            Status = STATUS_INSUFFICIENT_RESOURCES;\r
-    } else\r
-        Status = STATUS_INVALID_PARAMETER;\r
-\r
-    TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-NTSTATUS DispTdiSetInformationEx(\r
-    PIRP Irp,\r
-    PIO_STACK_LOCATION IrpSp)\r
-/*\r
- * FUNCTION: TDI SetInformationEx handler\r
- * ARGUMENTS:\r
- *     Irp   = Pointer to I/O request packet\r
- *     IrpSp = Pointer to current stack location of Irp\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    PTCP_REQUEST_SET_INFORMATION_EX Info;\r
-    TDI_REQUEST Request;\r
-    TDI_STATUS Status;\r
-    KIRQL OldIrql;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));\r
-\r
-    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;\r
-    Info        = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;\r
-\r
-    switch ((ULONG)IrpSp->FileObject->FsContext2) {\r
-    case TDI_TRANSPORT_ADDRESS_FILE:\r
-        Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;\r
-        break;\r
-\r
-    case TDI_CONNECTION_FILE:\r
-        Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;\r
-        break;\r
-\r
-    case TDI_CONTROL_CHANNEL_FILE:\r
-        Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;\r
-        break;\r
-\r
-    default:\r
-        Irp->IoStatus.Status      = STATUS_INVALID_PARAMETER;\r
-        Irp->IoStatus.Information = 0;\r
-\r
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));\r
-\r
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);\r
-\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    Status = DispPrepareIrpForCancel(TranContext, Irp, NULL);\r
-    if (NT_SUCCESS(Status)) {\r
-        Request.RequestNotifyObject = DispDataRequestComplete;\r
-        Request.RequestContext      = Irp;\r
-\r
-        Status = InfoTdiSetInformationEx(&Request, &Info->ID,\r
-            &Info->Buffer, Info->BufferSize);\r
-\r
-        if (Status != STATUS_PENDING) {\r
-            IoAcquireCancelSpinLock(&OldIrql);\r
-            IoSetCancelRoutine(Irp, NULL);\r
-            IoReleaseCancelSpinLock(OldIrql);\r
-        }\r
-    }\r
-\r
-    return Status;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/dispatch.h
+ * PURPOSE:     TDI dispatch routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <dispatch.h>
+#include <routines.h>
+#include <datagram.h>
+#include <info.h>
+
+
+NTSTATUS DispPrepareIrpForCancel(
+    PTRANSPORT_CONTEXT Context,
+    PIRP Irp,
+    PDRIVER_CANCEL CancelRoutine)
+/*
+ * FUNCTION: Prepare an IRP for cancellation
+ * ARGUMENTS:
+ *     Context       = Pointer to context information
+ *     Irp           = Pointer to an I/O request packet
+ *     CancelRoutine = Routine to be called when I/O request is cancelled
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    if (!Irp->Cancel) {
+        IoMarkIrpPending(Irp);
+        IoSetCancelRoutine(Irp, CancelRoutine);
+        Context->RefCount++;
+        IoReleaseCancelSpinLock(OldIrql);
+
+        TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP at 0x%X can now be cancelled).\n", Irp));
+
+        return STATUS_SUCCESS;
+    }
+
+    /* IRP has already been cancelled */
+    IoReleaseCancelSpinLock(OldIrql);
+
+    Irp->IoStatus.Status      = STATUS_CANCELLED;
+    Irp->IoStatus.Information = 0;
+
+    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+    IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving (IRP was already cancelled).\n"));
+
+    return STATUS_CANCELLED;
+}
+
+
+VOID DispCancelComplete(
+    PVOID Context)
+/*
+ * FUNCTION: Completes a cancel request
+ * ARGUMENTS:
+ *     Context = Pointer to context information (FILE_OBJECT)
+ */
+{
+    KIRQL OldIrql;
+    PFILE_OBJECT FileObject;
+    PTRANSPORT_CONTEXT TranContext;
+    
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    FileObject  = (PFILE_OBJECT)Context;
+    TranContext = (PTRANSPORT_CONTEXT)FileObject->FsContext;
+    
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    /* Remove the reference placed on the endpoint by the cancel routine.
+       The cancelled IRP will be completed by the completion routine for
+       the request */
+    TranContext->RefCount--;
+
+    if (TranContext->RefCount == 0) {
+        TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n"));
+        /* Set the cleanup event */
+        KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
+    }
+
+    TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount));
+
+    IoReleaseCancelSpinLock(OldIrql);
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
+}
+
+
+VOID DispCancelRequest(
+    PDEVICE_OBJECT Device,
+    PIRP Irp)
+/*
+ * FUNCTION: Cancels an IRP
+ * ARGUMENTS:
+ *     Device = Pointer to device object
+ *     Irp    = Pointer to an I/O request packet
+ */
+{
+    PIO_STACK_LOCATION IrpSp;
+    PTRANSPORT_CONTEXT TranContext;
+    PFILE_OBJECT FileObject;
+    UCHAR MinorFunction;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    IrpSp         = IoGetCurrentIrpStackLocation(Irp);
+    FileObject    = IrpSp->FileObject;
+    TranContext   = (PTRANSPORT_CONTEXT)FileObject->FsContext;
+    MinorFunction = IrpSp->MinorFunction;
+
+    TI_DbgPrint(DEBUG_IRP, ("IRP at (0x%X)  MinorFunction (0x%X)  IrpSp (0x%X).\n", Irp, MinorFunction, IrpSp));
+
+#ifdef DBG
+    if (!Irp->Cancel)
+        TI_DbgPrint(MIN_TRACE, ("Irp->Cancel is FALSE, should be TRUE.\n"));
+#endif
+
+    /* Increase reference count to prevent accidential closure
+       of the object while inside the cancel routine */
+    TranContext->RefCount++;
+
+    IoReleaseCancelSpinLock(Irp->CancelIrql);
+
+    /* Try canceling the request */
+    switch(MinorFunction) {
+    case TDI_SEND:
+
+    case TDI_RECEIVE:
+        /* FIXME: Close connection */
+        break;
+
+    case TDI_SEND_DATAGRAM:
+        if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+            TI_DbgPrint(MIN_TRACE, ("TDI_SEND_DATAGRAM, but no address file.\n"));
+            break;
+        }
+
+        DGCancelSendRequest(TranContext->Handle.AddressHandle, Irp);
+        break;
+
+    case TDI_RECEIVE_DATAGRAM:
+        if (FileObject->FsContext2 != (PVOID)TDI_TRANSPORT_ADDRESS_FILE) {
+            TI_DbgPrint(MIN_TRACE, ("TDI_RECEIVE_DATAGRAM, but no address file.\n"));
+            break;
+        }
+
+        DGCancelReceiveRequest(TranContext->Handle.AddressHandle, Irp);
+        break;
+
+    default:
+        TI_DbgPrint(MIN_TRACE, ("Unknown IRP. MinorFunction (0x%X).\n", MinorFunction));
+        break;
+    }
+
+    if (Status != STATUS_PENDING)
+        DispCancelComplete(FileObject);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+VOID DispDataRequestComplete(
+    PVOID Context,
+    NTSTATUS Status,
+    ULONG Count)
+/*
+ * FUNCTION: Completes a send/receive IRP
+ * ARGUMENTS:
+ *     Context = Pointer to context information (IRP)
+ *     Status  = Status of the request
+ *     Count   = Number of bytes sent or received
+ */
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IrpSp;
+    PTRANSPORT_CONTEXT TranContext;
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    Irp         = (PIRP)Context;
+    IrpSp       = IoGetCurrentIrpStackLocation(Irp);
+    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    IoSetCancelRoutine(Irp, NULL);
+    TranContext->RefCount--;
+    TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount (%d).\n", TranContext->RefCount));
+    if (TranContext->RefCount == 0) {
+        TI_DbgPrint(DEBUG_IRP, ("Setting TranContext->CleanupEvent to signaled.\n"));
+
+        KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
+    }
+
+    if (Irp->Cancel || TranContext->CancelIrps) {
+        /* The IRP has been cancelled */
+
+        TI_DbgPrint(DEBUG_IRP, ("IRP is cancelled.\n"));
+
+        Status = STATUS_CANCELLED;
+        Count  = 0;
+    }
+
+    IoReleaseCancelSpinLock(OldIrql);
+
+    Irp->IoStatus.Status      = Status;
+    Irp->IoStatus.Information = Count;
+
+    TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+    IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+}
+
+
+NTSTATUS DispTdiAccept(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_ACCEPT handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiAssociateAddress(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_ASSOCIATE_ADDRESS handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiConnect(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_CONNECT handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiDisassociateAddress(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_DISASSOCIATE_ADDRESS handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiDisconnect(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_DISCONNECT handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiListen(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_LISTEN handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiQueryInformation(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_QUERY_INFORMATION handler
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to device object structure
+ *     Irp          = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiReceive(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_RECEIVE handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiReceiveDatagram(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_RECEIVE_DATAGRAM handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIO_STACK_LOCATION IrpSp;
+    PTDI_REQUEST_KERNEL_RECEIVEDG DgramInfo;
+    PTRANSPORT_CONTEXT TranContext;
+    TDI_REQUEST Request;
+    NTSTATUS Status;
+    ULONG BytesReceived;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    IrpSp     = IoGetCurrentIrpStackLocation(Irp);
+    DgramInfo = (PTDI_REQUEST_KERNEL_RECEIVEDG)&(IrpSp->Parameters);
+
+    TranContext = IrpSp->FileObject->FsContext;
+    /* Initialize a receive request */
+    Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+    Request.RequestNotifyObject  = DispDataRequestComplete;
+    Request.RequestContext       = Irp;
+    Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest);
+    if (NT_SUCCESS(Status)) {
+        Status = UDPReceiveDatagram(&Request,
+            DgramInfo->ReceiveDatagramInformation,
+            (PNDIS_BUFFER)Irp->MdlAddress,
+            DgramInfo->ReceiveLength,
+            DgramInfo->ReceiveFlags,
+            DgramInfo->ReturnDatagramInformation,
+            &BytesReceived);
+        if (Status != STATUS_PENDING) {
+            DispDataRequestComplete(Irp, Status, BytesReceived);
+            /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */
+            Status = STATUS_PENDING;
+        }
+    }
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+    return Status;
+}
+
+
+NTSTATUS DispTdiSend(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_SEND handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+NTSTATUS DispTdiSendDatagram(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_SEND_DATAGRAM handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIO_STACK_LOCATION IrpSp;
+    TDI_REQUEST Request;
+    PTDI_REQUEST_KERNEL_SENDDG DgramInfo;
+    PTRANSPORT_CONTEXT TranContext;
+    NTSTATUS Status;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    IrpSp     = IoGetCurrentIrpStackLocation(Irp);
+    DgramInfo = (PTDI_REQUEST_KERNEL_SENDDG)&(IrpSp->Parameters);
+    
+    TranContext                  = IrpSp->FileObject->FsContext;
+    /* Initialize a send request */
+    Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+    Request.RequestNotifyObject  = DispDataRequestComplete;
+    Request.RequestContext       = Irp;
+
+    Status = DispPrepareIrpForCancel(IrpSp->FileObject->FsContext, Irp, (PDRIVER_CANCEL)DispCancelRequest);
+    if (NT_SUCCESS(Status)) {
+
+        /* FIXME: DgramInfo->SendDatagramInformation->RemoteAddress 
+           must be of type PTDI_ADDRESS_IP */
+
+        Status = (*((PADDRESS_FILE)Request.Handle.AddressHandle)->Send)(
+            &Request, DgramInfo->SendDatagramInformation,
+            (PNDIS_BUFFER)Irp->MdlAddress, DgramInfo->SendLength);
+        if (Status != STATUS_PENDING) {
+            DispDataRequestComplete(Irp, Status, 0);
+            /* Return STATUS_PENDING because DispPrepareIrpForCancel marks Irp as pending */
+            Status = STATUS_PENDING;
+        }
+    }
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving.\n"));
+
+    return Status;
+}
+
+
+NTSTATUS DispTdiSetEventHandler(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_SET_EVENT_HANDER handler
+ * ARGUMENTS:
+ *     Irp = Pointer to a I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+#ifdef _MSC_VER
+    PTDI_REQUEST_KERNEL_SET_EVENT Parameters;
+    PTRANSPORT_CONTEXT TranContext;
+    PIO_STACK_LOCATION IrpSp;
+    PADDRESS_FILE AddrFile;
+    NTSTATUS Status;
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    /* Get associated address file object. Quit if none exists */
+    TranContext = IrpSp->FileObject->FsContext;
+    if (!TranContext) {
+        TI_DbgPrint(MIN_TRACE, ("Bad transport context.\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    AddrFile = (PADDRESS_FILE)TranContext->Handle.AddressHandle;
+    if (!AddrFile) {
+        TI_DbgPrint(MIN_TRACE, ("No address file object.\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Parameters = (PTDI_REQUEST_KERNEL_SET_EVENT)&IrpSp->Parameters;
+    Status     = STATUS_SUCCESS;
+    
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    /* Set the event handler. if an event handler is associated with
+       a specific event, it's flag (RegisteredXxxHandler) is TRUE.
+       If an event handler is not used it's flag is FALSE */
+    switch (Parameters->EventType) {
+    case TDI_EVENT_CONNECT:
+        if (!Parameters->EventHandler) {
+            AddrFile->ConnectionHandler =
+                (PTDI_IND_CONNECT)TdiDefaultConnectHandler;
+            AddrFile->ConnectionHandlerContext    = NULL;
+            AddrFile->RegisteredConnectionHandler = FALSE;
+        } else {
+            AddrFile->ConnectionHandler =
+                (PTDI_IND_CONNECT)Parameters->EventHandler;
+            AddrFile->ConnectionHandlerContext    = Parameters->EventContext;
+            AddrFile->RegisteredConnectionHandler = TRUE;
+        }
+        break;
+
+    case TDI_EVENT_DISCONNECT:
+        if (!Parameters->EventHandler) {
+            AddrFile->DisconnectHandler =
+                (PTDI_IND_DISCONNECT)TdiDefaultDisconnectHandler;
+            AddrFile->DisconnectHandlerContext    = NULL;
+            AddrFile->RegisteredDisconnectHandler = FALSE;
+        } else {
+            AddrFile->DisconnectHandler =
+                (PTDI_IND_DISCONNECT)Parameters->EventHandler;
+            AddrFile->DisconnectHandlerContext    = Parameters->EventContext;
+            AddrFile->RegisteredDisconnectHandler = TRUE;
+        }
+        break;
+
+    case TDI_EVENT_RECEIVE:
+        if (Parameters->EventHandler == NULL) {
+            AddrFile->ReceiveHandler =
+                (PTDI_IND_RECEIVE)TdiDefaultReceiveHandler;
+            AddrFile->ReceiveHandlerContext    = NULL;
+            AddrFile->RegisteredReceiveHandler = FALSE;
+        } else {
+            AddrFile->ReceiveHandler =
+                (PTDI_IND_RECEIVE)Parameters->EventHandler;
+            AddrFile->ReceiveHandlerContext    = Parameters->EventContext;
+            AddrFile->RegisteredReceiveHandler = TRUE;
+        }
+        break;
+
+    case TDI_EVENT_RECEIVE_EXPEDITED:
+        if (Parameters->EventHandler == NULL) {
+            AddrFile->ExpeditedReceiveHandler =
+                (PTDI_IND_RECEIVE_EXPEDITED)TdiDefaultRcvExpeditedHandler;
+            AddrFile->ExpeditedReceiveHandlerContext    = NULL;
+            AddrFile->RegisteredExpeditedReceiveHandler = FALSE;
+        } else {
+            AddrFile->ExpeditedReceiveHandler =
+                (PTDI_IND_RECEIVE_EXPEDITED)Parameters->EventHandler;
+            AddrFile->ExpeditedReceiveHandlerContext    = Parameters->EventContext;
+            AddrFile->RegisteredExpeditedReceiveHandler = TRUE;
+        }
+        break;
+
+    case TDI_EVENT_RECEIVE_DATAGRAM:
+        if (Parameters->EventHandler == NULL) {
+            AddrFile->ReceiveDatagramHandler =
+                (PTDI_IND_RECEIVE_DATAGRAM)TdiDefaultRcvDatagramHandler;
+            AddrFile->ReceiveDatagramHandlerContext    = NULL;
+            AddrFile->RegisteredReceiveDatagramHandler = FALSE;
+        } else {
+            AddrFile->ReceiveDatagramHandler =
+                (PTDI_IND_RECEIVE_DATAGRAM)Parameters->EventHandler;
+            AddrFile->ReceiveDatagramHandlerContext    = Parameters->EventContext;
+            AddrFile->RegisteredReceiveDatagramHandler = TRUE;
+        }
+        break;
+
+    case TDI_EVENT_ERROR:
+        if (Parameters->EventHandler == NULL) {
+            AddrFile->ErrorHandler =
+                (PTDI_IND_ERROR)TdiDefaultErrorHandler;
+            AddrFile->ErrorHandlerContext    = NULL;
+            AddrFile->RegisteredErrorHandler = FALSE;
+        } else {
+            AddrFile->ErrorHandler =
+                (PTDI_IND_ERROR)Parameters->EventHandler;
+            AddrFile->ErrorHandlerContext    = Parameters->EventContext;
+            AddrFile->RegisteredErrorHandler = TRUE;
+        }
+        break;
+
+    default:
+        Status = STATUS_INVALID_PARAMETER;
+    }
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    return Status;
+#else
+    return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+
+NTSTATUS DispTdiSetInformation(
+    PIRP Irp)
+/*
+ * FUNCTION: TDI_SET_INFORMATION handler
+ * ARGUMENTS:
+ *     Irp = Pointer to an I/O request packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+       return STATUS_NOT_IMPLEMENTED;
+}
+
+
+VOID DispTdiQueryInformationExComplete(
+    PVOID Context,
+    ULONG Status,
+    UINT ByteCount)
+/*
+ * FUNCTION: Completes a TDI QueryInformationEx request
+ * ARGUMENTS:
+ *     Context   = Pointer to the IRP for the request
+ *     Status    = TDI status of the request
+ *     ByteCount = Number of bytes returned in output buffer
+ */
+{
+    PTI_QUERY_CONTEXT QueryContext;
+    UINT Count = 0;
+
+    QueryContext = (PTI_QUERY_CONTEXT)Context;
+    if (NT_SUCCESS(Status)) {
+        Count = CopyBufferToBufferChain(
+            QueryContext->InputMdl,
+            FIELD_OFFSET(TCP_REQUEST_QUERY_INFORMATION_EX, Context),
+            (PUCHAR)&QueryContext->QueryInfo.Context,
+            CONTEXT_SIZE);
+    }
+
+    MmUnlockPages(QueryContext->InputMdl);
+    IoFreeMdl(QueryContext->InputMdl);
+    MmUnlockPages(QueryContext->OutputMdl);
+    IoFreeMdl(QueryContext->OutputMdl);
+
+    QueryContext->Irp->IoStatus.Information = Count;
+    QueryContext->Irp->IoStatus.Status      = Status;
+
+    ExFreePool(QueryContext);
+}
+
+
+NTSTATUS DispTdiQueryInformationEx(
+    PIRP Irp,
+    PIO_STACK_LOCATION IrpSp)
+/*
+ * FUNCTION: TDI QueryInformationEx handler
+ * ARGUMENTS:
+ *     Irp   = Pointer to I/O request packet
+ *     IrpSp = Pointer to current stack location of Irp
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PTCP_REQUEST_QUERY_INFORMATION_EX InputBuffer;
+    PTRANSPORT_CONTEXT TranContext;
+    PTI_QUERY_CONTEXT QueryContext;
+    PVOID OutputBuffer;
+    TDI_REQUEST Request;
+    UINT Size;
+    UINT InputBufferLength;
+    UINT OutputBufferLength;
+    BOOLEAN InputMdlLocked  = FALSE;
+    BOOLEAN OutputMdlLocked = FALSE;
+    PMDL InputMdl           = NULL;
+    PMDL OutputMdl          = NULL;
+    NTSTATUS Status         = STATUS_SUCCESS;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+
+    switch ((ULONG)IrpSp->FileObject->FsContext2) {
+    case TDI_TRANSPORT_ADDRESS_FILE:
+        Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+        break;
+
+    case TDI_CONNECTION_FILE:
+        Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
+        break;
+
+    case TDI_CONTROL_CHANNEL_FILE:
+        Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
+        break;
+
+    default:
+        TI_DbgPrint(MIN_TRACE, ("Invalid transport context\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    InputBufferLength  = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
+    OutputBufferLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
+
+    /* Validate parameters */
+    if ((InputBufferLength == sizeof(TCP_REQUEST_QUERY_INFORMATION_EX)) &&
+        (OutputBufferLength != 0)) {
+
+        InputBuffer = (PTCP_REQUEST_QUERY_INFORMATION_EX)
+            IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
+        OutputBuffer = Irp->UserBuffer;
+
+        QueryContext = ExAllocatePool(NonPagedPool, sizeof(TI_QUERY_CONTEXT));
+        if (QueryContext) {
+#ifdef _MSC_VER
+            try {
+#endif
+                InputMdl = IoAllocateMdl(InputBuffer,
+                    sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),
+                    FALSE, TRUE, NULL);
+
+                OutputMdl = IoAllocateMdl(OutputBuffer,
+                    OutputBufferLength, FALSE, TRUE, NULL);
+
+                if (InputMdl && OutputMdl) {
+
+                    MmProbeAndLockPages(InputMdl, Irp->RequestorMode,
+                        IoModifyAccess);
+
+                    InputMdlLocked = TRUE;
+
+                    MmProbeAndLockPages(OutputMdl, Irp->RequestorMode,
+                        IoWriteAccess);
+
+                    OutputMdlLocked = TRUE;
+
+                    RtlCopyMemory(&QueryContext->QueryInfo,
+                        InputBuffer, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
+
+                } else
+                    Status = STATUS_INSUFFICIENT_RESOURCES;
+#ifdef _MSC_VER
+            } except(EXCEPTION_EXECUTE_HANDLER) {
+                Status = GetExceptionCode();
+            }
+#endif
+            if (NT_SUCCESS(Status)) {
+                Size = MmGetMdlByteCount(OutputMdl);
+
+                QueryContext->Irp       = Irp;
+                QueryContext->InputMdl  = InputMdl;
+                QueryContext->OutputMdl = OutputMdl;
+
+                Request.RequestNotifyObject = DispTdiQueryInformationExComplete;
+                Request.RequestContext      = QueryContext;
+                Status = InfoTdiQueryInformationEx(&Request,
+                    &QueryContext->QueryInfo.ID, OutputMdl,
+                    &Size, &QueryContext->QueryInfo.Context);
+                DispTdiQueryInformationExComplete(QueryContext, Status, Size);
+
+                TI_DbgPrint(MAX_TRACE, ("Leaving. Status = (0x%X)\n", Status));
+
+                return Status;
+            }
+
+            /* An error occurred if we get here */
+
+            if (InputMdl) {
+                if (InputMdlLocked)
+                    MmUnlockPages(InputMdl);
+                IoFreeMdl(InputMdl);
+            }
+
+            if (OutputMdl) {
+                if (OutputMdlLocked)
+                    MmUnlockPages(OutputMdl);
+                IoFreeMdl(OutputMdl);
+            }
+
+            ExFreePool(QueryContext);
+        } else
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+    } else
+        Status = STATUS_INVALID_PARAMETER;
+
+    TI_DbgPrint(MIN_TRACE, ("Leaving. Status = (0x%X)\n", Status));
+
+    return Status;
+}
+
+
+NTSTATUS DispTdiSetInformationEx(
+    PIRP Irp,
+    PIO_STACK_LOCATION IrpSp)
+/*
+ * FUNCTION: TDI SetInformationEx handler
+ * ARGUMENTS:
+ *     Irp   = Pointer to I/O request packet
+ *     IrpSp = Pointer to current stack location of Irp
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PTRANSPORT_CONTEXT TranContext;
+    PTCP_REQUEST_SET_INFORMATION_EX Info;
+    TDI_REQUEST Request;
+    TDI_STATUS Status;
+    KIRQL OldIrql;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
+
+    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+    Info        = (PTCP_REQUEST_SET_INFORMATION_EX)Irp->AssociatedIrp.SystemBuffer;
+
+    switch ((ULONG)IrpSp->FileObject->FsContext2) {
+    case TDI_TRANSPORT_ADDRESS_FILE:
+        Request.Handle.AddressHandle = TranContext->Handle.AddressHandle;
+        break;
+
+    case TDI_CONNECTION_FILE:
+        Request.Handle.ConnectionContext = TranContext->Handle.ConnectionContext;
+        break;
+
+    case TDI_CONTROL_CHANNEL_FILE:
+        Request.Handle.ControlChannel = TranContext->Handle.ControlChannel;
+        break;
+
+    default:
+        Irp->IoStatus.Status      = STATUS_INVALID_PARAMETER;
+        Irp->IoStatus.Information = 0;
+
+        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    Status = DispPrepareIrpForCancel(TranContext, Irp, NULL);
+    if (NT_SUCCESS(Status)) {
+        Request.RequestNotifyObject = DispDataRequestComplete;
+        Request.RequestContext      = Irp;
+
+        Status = InfoTdiSetInformationEx(&Request, &Info->ID,
+            &Info->Buffer, Info->BufferSize);
+
+        if (Status != STATUS_PENDING) {
+            IoAcquireCancelSpinLock(&OldIrql);
+            IoSetCancelRoutine(Irp, NULL);
+            IoReleaseCancelSpinLock(OldIrql);
+        }
+    }
+
+    return Status;
+}
+
+/* EOF */
index 29bb42f..0b24fa5 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/fileobjs.c\r
- * PURPOSE:     Routines for handling file objects\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- *   CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <datagram.h>\r
-#include <address.h>\r
-#include <pool.h>\r
-#include <rawip.h>\r
-#include <udp.h>\r
-#include <ip.h>\r
-#include <fileobjs.h>\r
-\r
-LIST_ENTRY AddressFileListHead;\r
-KSPIN_LOCK AddressFileListLock;\r
-\r
-\r
-/*\r
- * FUNCTION: Deletes an address file object\r
- * ARGUMENTS:\r
- *     AddrFile = Pointer to address file object to delete\r
- */\r
-VOID DeleteAddress(\r
-    PADDRESS_FILE AddrFile)\r
-{\r
-    KIRQL OldIrql;\r
-    PLIST_ENTRY CurrentEntry;\r
-    PLIST_ENTRY NextEntry;\r
-    PDATAGRAM_SEND_REQUEST SendRequest;\r
-    PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    /* Remove address file from the global list */\r
-    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);\r
-    RemoveEntryList(&AddrFile->ListEntry);\r
-    KeReleaseSpinLock(&AddressFileListLock, OldIrql);\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    /* FIXME: Kill TCP connections on this address file object */\r
-\r
-    /* Return pending requests with error */\r
-\r
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));\r
-\r
-    /* Go through pending receive request list and cancel them all */\r
-    CurrentEntry = AddrFile->ReceiveQueue.Flink;\r
-    while (CurrentEntry != &AddrFile->ReceiveQueue) {\r
-        NextEntry = CurrentEntry->Flink;\r
-        ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);\r
-        /* Abort the request and free its resources */\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-        (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);\r
-        PoolFreeBuffer(ReceiveRequest);\r
-        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-        CurrentEntry = NextEntry;\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));\r
-\r
-    /* Go through pending send request list and cancel them all */\r
-    CurrentEntry = AddrFile->TransmitQueue.Flink;\r
-    while (CurrentEntry != &AddrFile->TransmitQueue) {\r
-        NextEntry = CurrentEntry->Flink;\r
-        SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);\r
-        /* Abort the request and free its resources */\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-        (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);\r
-        PoolFreeBuffer(SendRequest);\r
-        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-        CurrentEntry = NextEntry;\r
-    }\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    /* Dereference address entry */\r
-    DereferenceObject(AddrFile->ADE);\r
-\r
-    /* Dereference address cache */\r
-    if (AddrFile->AddrCache)\r
-        DereferenceObject(AddrFile->AddrCache);\r
-\r
-#ifdef DBG\r
-    /* Remove reference provided at creation time */\r
-    AddrFile->RefCount--;\r
-\r
-    if (AddrFile->RefCount != 0)\r
-        TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount));\r
-#endif\r
-    \r
-    PoolFreeBuffer(AddrFile);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-VOID RequestWorker(\r
-    PVOID Context)\r
-/*\r
- * FUNCTION: Worker routine for processing address file object requests\r
- * ARGUMENTS:\r
- *     Context = Pointer to context information (ADDRESS_FILE)\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-    PLIST_ENTRY CurrentEntry;\r
-    PADDRESS_FILE AddrFile = Context;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    /* Check it the address file should be deleted */\r
-    if (AF_IS_PENDING(AddrFile, AFF_DELETE)) {\r
-        DATAGRAM_COMPLETION_ROUTINE RtnComplete;\r
-        PVOID RtnContext;\r
-\r
-        RtnComplete = AddrFile->Complete;\r
-        RtnContext  = AddrFile->Context;\r
-\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-        DeleteAddress(AddrFile);\r
-\r
-        (*RtnComplete)(RtnContext, TDI_SUCCESS, 0);\r
-\r
-        TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n"));\r
-\r
-        return;\r
-    }\r
-\r
-    /* Check if there is a pending send request */\r
-    if (AF_IS_PENDING(AddrFile, AFF_SEND)) {\r
-        if (!IsListEmpty(&AddrFile->TransmitQueue)) {\r
-            PDATAGRAM_SEND_REQUEST SendRequest;\r
-\r
-            CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);\r
-            SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);\r
-\r
-            AF_CLR_BUSY(AddrFile);\r
-\r
-            ReferenceObject(AddrFile);\r
-\r
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-            /* The send routine processes the send requests in\r
-               the transmit queue on the address file. When the\r
-               queue is empty the pending send flag is cleared.\r
-               The routine may return with the pending send flag\r
-               set. This can happen if there was not enough free\r
-               resources available to complete all send requests */\r
-            DGSend(AddrFile, SendRequest);\r
-\r
-            KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-            DereferenceObject(AddrFile);\r
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-            TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n"));\r
-\r
-            return;\r
-        } else\r
-            /* There was a pending send, but no send request.\r
-               Print a debug message and continue */\r
-            TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n"));\r
-    }\r
-\r
-    AF_CLR_BUSY(AddrFile);\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Open an address file object\r
- * ARGUMENTS:\r
- *     Request  = Pointer to TDI request structure for this request\r
- *     Address  = Pointer to address to be opened\r
- *     Protocol = Protocol on which to open the address\r
- *     Options  = Pointer to option buffer\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS FileOpenAddress(\r
-    PTDI_REQUEST Request,\r
-    PTA_ADDRESS_IP Address,\r
-    USHORT Protocol,\r
-    PVOID Options)\r
-{\r
-    PADDRESS_FILE AddrFile;\r
-    IPv4_RAW_ADDRESS IPv4Address;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    AddrFile = PoolAllocateBuffer(sizeof(ADDRESS_FILE));\r
-    if (!AddrFile) {\r
-        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));\r
-\r
-    RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));\r
-\r
-    /* Make sure address is a local unicast address or 0 */\r
-\r
-    /* Locate address entry. If specified address is 0, a random address is chosen */\r
-\r
-    IPv4Address = Address->Address[0].Address[0].in_addr;\r
-    if (IPv4Address == 0)\r
-        AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);\r
-    else\r
-        AddrFile->ADE = AddrLocateADEv4(IPv4Address);\r
-\r
-    if (!AddrFile->ADE) {\r
-        PoolFreeBuffer(AddrFile);\r
-        TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_ADDRFILE, ("Opening address (0x%X) for communication.\n",\r
-        DN2H(AddrFile->ADE->Address->Address.IPv4Address)));\r
-\r
-    /* Protocol specific handling */\r
-    switch (Protocol) {\r
-    case IPPROTO_TCP:\r
-        /* FIXME: TCP */\r
-        TI_DbgPrint(MIN_TRACE, ("TCP is not supported.\n"));\r
-        DereferenceObject(AddrFile->ADE);\r
-        PoolFreeBuffer(AddrFile);\r
-        return STATUS_INVALID_PARAMETER;\r
-    case IPPROTO_UDP:\r
-        /* FIXME: If specified port is 0, a port is chosen dynamically */\r
-        AddrFile->Port = Address->Address[0].Address[0].sin_port;\r
-        AddrFile->Send = UDPSendDatagram;\r
-        break;\r
-    default:\r
-        /* Use raw IP for all other protocols */\r
-        AddrFile->Send = RawIPSendDatagram;\r
-        break;\r
-    }\r
-\r
-    /* Set protocol */\r
-    AddrFile->Protocol = Protocol;\r
-    \r
-    /* Initialize receive and transmit queues */\r
-    InitializeListHead(&AddrFile->ReceiveQueue);\r
-    InitializeListHead(&AddrFile->TransmitQueue);\r
-\r
-    /* Initialize work queue item. We use this for pending requests */\r
-    ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);\r
-\r
-    /* Initialize spin lock that protects the address file object */\r
-    KeInitializeSpinLock(&AddrFile->Lock);\r
-\r
-    /* Reference the object */\r
-    AddrFile->RefCount = 1;\r
-\r
-    /* Set valid flag so the address can be used */\r
-    AF_SET_VALID(AddrFile);\r
-\r
-    /* Return address file object */\r
-    Request->Handle.AddressHandle = AddrFile;\r
-\r
-    /* Add address file to global list */\r
-    ExInterlockedInsertTailList(&AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Closes an address file object\r
- * ARGUMENTS:\r
- *     Request = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS FileCloseAddress(\r
-    PTDI_REQUEST Request)\r
-{\r
-    KIRQL OldIrql;\r
-    PADDRESS_FILE AddrFile;\r
-    NTSTATUS Status = STATUS_SUCCESS;\r
-\r
-    TI_DbgPrint(MID_TRACE, ("Called.\n"));\r
-\r
-    AddrFile = Request->Handle.AddressHandle;\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) {\r
-        /* Set address file object exclusive to us */\r
-        AF_SET_BUSY(AddrFile);\r
-        AF_CLR_VALID(AddrFile);\r
-\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-        DeleteAddress(AddrFile);\r
-    } else {\r
-        if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {\r
-            AddrFile->Complete = Request->RequestNotifyObject;\r
-            AddrFile->Context  = Request->RequestContext;\r
-\r
-            /* Shedule address file for deletion */\r
-            AF_SET_PENDING(AddrFile, AFF_DELETE);\r
-            AF_CLR_VALID(AddrFile);\r
-\r
-            if (!AF_IS_BUSY(AddrFile)) {\r
-                /* Worker function is not running, so shedule it to run */\r
-                AF_SET_BUSY(AddrFile);\r
-                KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-                ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue);\r
-            } else\r
-                KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-            TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));\r
-\r
-            return STATUS_PENDING;\r
-        } else\r
-            Status = STATUS_ADDRESS_CLOSED;\r
-\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-    }\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Opens a connection file object\r
- * ARGUMENTS:\r
- *     Request  = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS FileOpenConnection(\r
-    PTDI_REQUEST Request)\r
-{\r
-    return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Closes an connection file object\r
- * ARGUMENTS:\r
- *     Request  = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS FileCloseConnection(\r
-    PTDI_REQUEST Request)\r
-{\r
-    return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Opens a control channel file object\r
- * ARGUMENTS:\r
- *     Request  = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS FileOpenControlChannel(\r
-    PTDI_REQUEST Request)\r
-{\r
-    return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Closes a control channel file object\r
- * ARGUMENTS:\r
- *     Request  = Pointer to TDI request structure for this request\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-NTSTATUS FileCloseControlChannel(\r
-    PTDI_REQUEST Request)\r
-{\r
-    return STATUS_NOT_IMPLEMENTED;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/fileobjs.c
+ * PURPOSE:     Routines for handling file objects
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <datagram.h>
+#include <address.h>
+#include <pool.h>
+#include <rawip.h>
+#include <udp.h>
+#include <ip.h>
+#include <fileobjs.h>
+
+LIST_ENTRY AddressFileListHead;
+KSPIN_LOCK AddressFileListLock;
+
+
+/*
+ * FUNCTION: Deletes an address file object
+ * ARGUMENTS:
+ *     AddrFile = Pointer to address file object to delete
+ */
+VOID DeleteAddress(
+    PADDRESS_FILE AddrFile)
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PLIST_ENTRY NextEntry;
+    PDATAGRAM_SEND_REQUEST SendRequest;
+    PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    /* Remove address file from the global list */
+    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+    RemoveEntryList(&AddrFile->ListEntry);
+    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    /* FIXME: Kill TCP connections on this address file object */
+
+    /* Return pending requests with error */
+
+    TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting receive requests on AddrFile at (0x%X).\n", AddrFile));
+
+    /* Go through pending receive request list and cancel them all */
+    CurrentEntry = AddrFile->ReceiveQueue.Flink;
+    while (CurrentEntry != &AddrFile->ReceiveQueue) {
+        NextEntry = CurrentEntry->Flink;
+        ReceiveRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
+        /* Abort the request and free its resources */
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+        (*ReceiveRequest->Complete)(ReceiveRequest->Context, STATUS_ADDRESS_CLOSED, 0);
+        PoolFreeBuffer(ReceiveRequest);
+        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+        CurrentEntry = NextEntry;
+    }
+
+    TI_DbgPrint(DEBUG_ADDRFILE, ("Aborting send requests on address file at (0x%X).\n", AddrFile));
+
+    /* Go through pending send request list and cancel them all */
+    CurrentEntry = AddrFile->TransmitQueue.Flink;
+    while (CurrentEntry != &AddrFile->TransmitQueue) {
+        NextEntry = CurrentEntry->Flink;
+        SendRequest = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+        /* Abort the request and free its resources */
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+        (*SendRequest->Complete)(SendRequest->Context, STATUS_ADDRESS_CLOSED, 0);
+        PoolFreeBuffer(SendRequest);
+        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+        CurrentEntry = NextEntry;
+    }
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    /* Dereference address entry */
+    DereferenceObject(AddrFile->ADE);
+
+    /* Dereference address cache */
+    if (AddrFile->AddrCache)
+        DereferenceObject(AddrFile->AddrCache);
+
+#ifdef DBG
+    /* Remove reference provided at creation time */
+    AddrFile->RefCount--;
+
+    if (AddrFile->RefCount != 0)
+        TI_DbgPrint(DEBUG_REFCOUNT, ("AddrFile->RefCount is (%d) (should be 0).\n", AddrFile->RefCount));
+#endif
+    
+    PoolFreeBuffer(AddrFile);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+VOID RequestWorker(
+    PVOID Context)
+/*
+ * FUNCTION: Worker routine for processing address file object requests
+ * ARGUMENTS:
+ *     Context = Pointer to context information (ADDRESS_FILE)
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PADDRESS_FILE AddrFile = Context;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    /* Check it the address file should be deleted */
+    if (AF_IS_PENDING(AddrFile, AFF_DELETE)) {
+        DATAGRAM_COMPLETION_ROUTINE RtnComplete;
+        PVOID RtnContext;
+
+        RtnComplete = AddrFile->Complete;
+        RtnContext  = AddrFile->Context;
+
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+        DeleteAddress(AddrFile);
+
+        (*RtnComplete)(RtnContext, TDI_SUCCESS, 0);
+
+        TI_DbgPrint(MAX_TRACE, ("Leaving (delete).\n"));
+
+        return;
+    }
+
+    /* Check if there is a pending send request */
+    if (AF_IS_PENDING(AddrFile, AFF_SEND)) {
+        if (!IsListEmpty(&AddrFile->TransmitQueue)) {
+            PDATAGRAM_SEND_REQUEST SendRequest;
+
+            CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
+            SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+
+            AF_CLR_BUSY(AddrFile);
+
+            ReferenceObject(AddrFile);
+
+            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+            /* The send routine processes the send requests in
+               the transmit queue on the address file. When the
+               queue is empty the pending send flag is cleared.
+               The routine may return with the pending send flag
+               set. This can happen if there was not enough free
+               resources available to complete all send requests */
+            DGSend(AddrFile, SendRequest);
+
+            KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+            DereferenceObject(AddrFile);
+            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+            TI_DbgPrint(MAX_TRACE, ("Leaving (send request).\n"));
+
+            return;
+        } else
+            /* There was a pending send, but no send request.
+               Print a debug message and continue */
+            TI_DbgPrint(MIN_TRACE, ("Pending send, but no send request.\n"));
+    }
+
+    AF_CLR_BUSY(AddrFile);
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+/*
+ * FUNCTION: Open an address file object
+ * ARGUMENTS:
+ *     Request  = Pointer to TDI request structure for this request
+ *     Address  = Pointer to address to be opened
+ *     Protocol = Protocol on which to open the address
+ *     Options  = Pointer to option buffer
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS FileOpenAddress(
+    PTDI_REQUEST Request,
+    PTA_ADDRESS_IP Address,
+    USHORT Protocol,
+    PVOID Options)
+{
+    PADDRESS_FILE AddrFile;
+    IPv4_RAW_ADDRESS IPv4Address;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    AddrFile = PoolAllocateBuffer(sizeof(ADDRESS_FILE));
+    if (!AddrFile) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    TI_DbgPrint(DEBUG_ADDRFILE, ("Address file object allocated at (0x%X).\n", AddrFile));
+
+    RtlZeroMemory(AddrFile, sizeof(ADDRESS_FILE));
+
+    /* Make sure address is a local unicast address or 0 */
+
+    /* Locate address entry. If specified address is 0, a random address is chosen */
+
+    IPv4Address = Address->Address[0].Address[0].in_addr;
+    if (IPv4Address == 0)
+        AddrFile->ADE = IPGetDefaultADE(ADE_UNICAST);
+    else
+        AddrFile->ADE = AddrLocateADEv4(IPv4Address);
+
+    if (!AddrFile->ADE) {
+        PoolFreeBuffer(AddrFile);
+        TI_DbgPrint(MIN_TRACE, ("Non-local address given (0x%X).\n", DN2H(IPv4Address)));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    TI_DbgPrint(DEBUG_ADDRFILE, ("Opening address (0x%X) for communication.\n",
+        DN2H(AddrFile->ADE->Address->Address.IPv4Address)));
+
+    /* Protocol specific handling */
+    switch (Protocol) {
+    case IPPROTO_TCP:
+        /* FIXME: TCP */
+        TI_DbgPrint(MIN_TRACE, ("TCP is not supported.\n"));
+        DereferenceObject(AddrFile->ADE);
+        PoolFreeBuffer(AddrFile);
+        return STATUS_INVALID_PARAMETER;
+    case IPPROTO_UDP:
+        /* FIXME: If specified port is 0, a port is chosen dynamically */
+        AddrFile->Port = Address->Address[0].Address[0].sin_port;
+        AddrFile->Send = UDPSendDatagram;
+        break;
+    default:
+        /* Use raw IP for all other protocols */
+        AddrFile->Send = RawIPSendDatagram;
+        break;
+    }
+
+    /* Set protocol */
+    AddrFile->Protocol = Protocol;
+    
+    /* Initialize receive and transmit queues */
+    InitializeListHead(&AddrFile->ReceiveQueue);
+    InitializeListHead(&AddrFile->TransmitQueue);
+
+    /* Initialize work queue item. We use this for pending requests */
+    ExInitializeWorkItem(&AddrFile->WorkItem, RequestWorker, AddrFile);
+
+    /* Initialize spin lock that protects the address file object */
+    KeInitializeSpinLock(&AddrFile->Lock);
+
+    /* Reference the object */
+    AddrFile->RefCount = 1;
+
+    /* Set valid flag so the address can be used */
+    AF_SET_VALID(AddrFile);
+
+    /* Return address file object */
+    Request->Handle.AddressHandle = AddrFile;
+
+    /* Add address file to global list */
+    ExInterlockedInsertTailList(&AddressFileListHead, &AddrFile->ListEntry, &AddressFileListLock);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return STATUS_SUCCESS;
+}
+
+
+/*
+ * FUNCTION: Closes an address file object
+ * ARGUMENTS:
+ *     Request = Pointer to TDI request structure for this request
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS FileCloseAddress(
+    PTDI_REQUEST Request)
+{
+    KIRQL OldIrql;
+    PADDRESS_FILE AddrFile;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+    AddrFile = Request->Handle.AddressHandle;
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    if ((!AF_IS_BUSY(AddrFile)) && (AddrFile->RefCount == 1)) {
+        /* Set address file object exclusive to us */
+        AF_SET_BUSY(AddrFile);
+        AF_CLR_VALID(AddrFile);
+
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+        DeleteAddress(AddrFile);
+    } else {
+        if (!AF_IS_PENDING(AddrFile, AFF_DELETE)) {
+            AddrFile->Complete = Request->RequestNotifyObject;
+            AddrFile->Context  = Request->RequestContext;
+
+            /* Shedule address file for deletion */
+            AF_SET_PENDING(AddrFile, AFF_DELETE);
+            AF_CLR_VALID(AddrFile);
+
+            if (!AF_IS_BUSY(AddrFile)) {
+                /* Worker function is not running, so shedule it to run */
+                AF_SET_BUSY(AddrFile);
+                KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+                ExQueueWorkItem(&AddrFile->WorkItem, CriticalWorkQueue);
+            } else
+                KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+            TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+
+            return STATUS_PENDING;
+        } else
+            Status = STATUS_ADDRESS_CLOSED;
+
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return Status;
+}
+
+
+/*
+ * FUNCTION: Opens a connection file object
+ * ARGUMENTS:
+ *     Request  = Pointer to TDI request structure for this request
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS FileOpenConnection(
+    PTDI_REQUEST Request)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+
+/*
+ * FUNCTION: Closes an connection file object
+ * ARGUMENTS:
+ *     Request  = Pointer to TDI request structure for this request
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS FileCloseConnection(
+    PTDI_REQUEST Request)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+
+/*
+ * FUNCTION: Opens a control channel file object
+ * ARGUMENTS:
+ *     Request  = Pointer to TDI request structure for this request
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS FileOpenControlChannel(
+    PTDI_REQUEST Request)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+
+/*
+ * FUNCTION: Closes a control channel file object
+ * ARGUMENTS:
+ *     Request  = Pointer to TDI request structure for this request
+ * RETURNS:
+ *     Status of operation
+ */
+NTSTATUS FileCloseControlChannel(
+    PTDI_REQUEST Request)
+{
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+/* EOF */
index fc8f07d..b24c4f7 100644 (file)
-/*\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/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <info.h>\r
-#include <routines.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
-    PLIST_ENTRY CurrentIFEntry;\r
-    PLIST_ENTRY CurrentADEEntry;\r
-    PIP_INTERFACE CurrentIF;\r
-    PADDRESS_ENTRY CurrentADE;\r
-    IPADDR_ENTRY IpAddress;\r
-    IPSNMP_INFO SnmpInfo;\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(&InterfaceListLock, &OldIrql);\r
-\r
-            CurrentIFEntry = InterfaceListHead.Flink;\r
-            while (CurrentIFEntry != &InterfaceListHead) {\r
-                   CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);\r
-\r
-                if (Temp + sizeof(IPADDR_ENTRY) > BufSize) {\r
-                    KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
-                    return TDI_BUFFER_TOO_SMALL;\r
-                }\r
-\r
-                IpAddress.Addr      = 0;\r
-                IpAddress.BcastAddr = 0;\r
-                IpAddress.Mask      = 0;\r
-\r
-                /* Locate the diffrent addresses and put them the right place */\r
-                CurrentADEEntry = CurrentIF->ADEListHead.Flink;\r
-                while (CurrentADEEntry != &CurrentIF->ADEListHead) {\r
-                       CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);\r
-\r
-                    switch (CurrentADE->Type) {\r
-                    case ADE_UNICAST:\r
-                        IpAddress.Addr = CurrentADE->Address->Address.IPv4Address;\r
-                        break;\r
-                    case ADE_MULTICAST:\r
-                        IpAddress.BcastAddr = CurrentADE->Address->Address.IPv4Address;\r
-                        break;\r
-                    case ADE_ADDRMASK:\r
-                        IpAddress.Mask = CurrentADE->Address->Address.IPv4Address;\r
-                        break;\r
-                    default:\r
-                        /* Should not happen */\r
-                        TI_DbgPrint(MIN_TRACE, ("Unknown address entry type (0x%X)\n", CurrentADE->Type));\r
-                        break;\r
-                    }\r
-                    CurrentADEEntry = CurrentADEEntry->Flink;\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
-                CurrentIFEntry = CurrentIFEntry->Flink;\r
-            }\r
-\r
-            KeReleaseSpinLock(&InterfaceListLock, OldIrql);\r
-\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(&InterfaceListLock, &OldIrql);\r
-\r
-            CurrentIFEntry = InterfaceListHead.Flink;\r
-            while (CurrentIFEntry != &InterfaceListHead) {\r
-                   CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);\r
-                Count++;\r
-                CurrentIFEntry = CurrentIFEntry->Flink;\r
-            }\r
-\r
-            KeReleaseSpinLock(&InterfaceListLock, 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
-    PLIST_ENTRY CurrentADFEntry;\r
-    PADDRESS_FILE CurrentADF;\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(&AddressFileListLock, &OldIrql);\r
-\r
-            CurrentADFEntry = AddressFileListHead.Flink;\r
-            while (CurrentADFEntry != &AddressFileListHead) {\r
-                   CurrentADF = CONTAINING_RECORD(CurrentADFEntry, ADDRESS_FILE, ListEntry);\r
-\r
-                if (Offset + sizeof(ADDRESS_INFO) > BufSize) {\r
-                    KeReleaseSpinLock(&AddressFileListLock, OldIrql);\r
-                    *BufferSize = Offset;\r
-                    return TDI_BUFFER_OVERFLOW;\r
-                }\r
-\r
-                Info.LocalAddress = CurrentADF->ADE->Address->Address.IPv4Address;\r
-                Info.LocalPort    = CurrentADF->Port;\r
-\r
-                Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO));\r
-\r
-                Offset += Count;\r
-\r
-                CurrentADFEntry = CurrentADFEntry->Flink;\r
-            }\r
-\r
-            KeReleaseSpinLock(&AddressFileListLock, 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_REQUEST Request,\r
-    TDIObjectID *ID,\r
-    PVOID Buffer,\r
-    UINT BufferSize)\r
-/*\r
- * FUNCTION: Sets extended information\r
- * ARGUMENTS:\r
- *     Request    = Pointer to TDI request structure for the request\r
- *     ID         = Pointer to TDI object ID\r
- *     Buffer     = Pointer to buffer with data to use\r
- *     BufferSize = Size of Buffer\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    /* FIXME: Set extended information */\r
-\r
-    return TDI_INVALID_REQUEST;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/info.c
+ * PURPOSE:     TDI query and set information routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <info.h>
+#include <routines.h>
+
+
+TDI_STATUS IPTdiQueryInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PNDIS_BUFFER Buffer,
+    PUINT BufferSize,
+    PVOID Context)
+/*
+ * FUNCTION: Returns extended information about network layer
+ * ARGUMENTS:
+ *     Request    = Pointer to TDI request structure for the request
+ *     ID         = TDI object ID
+ *     Buffer     = Pointer to buffer with data to use. 
+ *     BufferSize = Pointer to buffer with size of Buffer. On return
+ *                  this is filled with number of bytes returned
+ *     Context    = Pointer to context buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PLIST_ENTRY CurrentIFEntry;
+    PLIST_ENTRY CurrentADEEntry;
+    PIP_INTERFACE CurrentIF;
+    PADDRESS_ENTRY CurrentADE;
+    IPADDR_ENTRY IpAddress;
+    IPSNMP_INFO SnmpInfo;
+    ULONG Temp;
+    UINT Count;
+    ULONG Entity;
+    KIRQL OldIrql;
+    UINT BufSize = *BufferSize;
+
+    /* Make return parameters consistent every time */
+    *BufferSize = 0;
+
+    Entity = ID->toi_entity.tei_entity;
+    if (Entity != CL_NL_ENTITY) {
+        /* We can't handle this entity */
+        return TDI_INVALID_PARAMETER;
+    }
+
+    if (ID->toi_entity.tei_instance != TL_INSTANCE)
+        /* We only support a single instance */
+        return TDI_INVALID_REQUEST;
+    if (ID->toi_class == INFO_CLASS_GENERIC) {
+        if (ID->toi_type == INFO_TYPE_PROVIDER && 
+            ID->toi_id == ENTITY_TYPE_ID) {
+
+            if (BufSize < sizeof(ULONG))
+                return TDI_BUFFER_TOO_SMALL;
+            Temp = CL_NL_IP;
+
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG));
+
+            return TDI_SUCCESS;
+        }
+        return TDI_INVALID_PARAMETER;
+    }
+
+    if (ID->toi_class == INFO_CLASS_PROTOCOL) {
+        if (ID->toi_type != INFO_TYPE_PROVIDER)
+            return TDI_INVALID_PARAMETER;
+
+        switch (ID->toi_id) {
+        case IP_MIB_ADDRTABLE_ENTRY_ID:
+            Temp = 0;
+
+            KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+            CurrentIFEntry = InterfaceListHead.Flink;
+            while (CurrentIFEntry != &InterfaceListHead) {
+                   CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
+
+                if (Temp + sizeof(IPADDR_ENTRY) > BufSize) {
+                    KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+                    return TDI_BUFFER_TOO_SMALL;
+                }
+
+                IpAddress.Addr      = 0;
+                IpAddress.BcastAddr = 0;
+                IpAddress.Mask      = 0;
+
+                /* Locate the diffrent addresses and put them the right place */
+                CurrentADEEntry = CurrentIF->ADEListHead.Flink;
+                while (CurrentADEEntry != &CurrentIF->ADEListHead) {
+                       CurrentADE = CONTAINING_RECORD(CurrentADEEntry, ADDRESS_ENTRY, ListEntry);
+
+                    switch (CurrentADE->Type) {
+                    case ADE_UNICAST:
+                        IpAddress.Addr = CurrentADE->Address->Address.IPv4Address;
+                        break;
+                    case ADE_MULTICAST:
+                        IpAddress.BcastAddr = CurrentADE->Address->Address.IPv4Address;
+                        break;
+                    case ADE_ADDRMASK:
+                        IpAddress.Mask = CurrentADE->Address->Address.IPv4Address;
+                        break;
+                    default:
+                        /* Should not happen */
+                        TI_DbgPrint(MIN_TRACE, ("Unknown address entry type (0x%X)\n", CurrentADE->Type));
+                        break;
+                    }
+                    CurrentADEEntry = CurrentADEEntry->Flink;
+                }
+                /* Pack the address information into IPADDR_ENTRY structure */
+                IpAddress.Index     = 0;
+                IpAddress.ReasmSize = 0;
+                IpAddress.Context   = 0;
+                IpAddress.Pad       = 0;
+
+                Count = CopyBufferToBufferChain(Buffer, Temp, (PUCHAR)&IpAddress, sizeof(IPADDR_ENTRY));
+
+                Temp += sizeof(IPADDR_ENTRY);
+
+                CurrentIFEntry = CurrentIFEntry->Flink;
+            }
+
+            KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+            return TDI_SUCCESS;
+
+        case IP_MIB_STATS_ID:
+            if (BufSize < sizeof(IPSNMP_INFO))
+                return TDI_BUFFER_TOO_SMALL;
+
+            RtlZeroMemory(&SnmpInfo, sizeof(IPSNMP_INFO));
+
+            /* Count number of addresses */
+            Count = 0;
+            KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+            CurrentIFEntry = InterfaceListHead.Flink;
+            while (CurrentIFEntry != &InterfaceListHead) {
+                   CurrentIF = CONTAINING_RECORD(CurrentIFEntry, IP_INTERFACE, ListEntry);
+                Count++;
+                CurrentIFEntry = CurrentIFEntry->Flink;
+            }
+
+            KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+            SnmpInfo.NumAddr = Count;
+
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&SnmpInfo, sizeof(IPSNMP_INFO));
+
+            return TDI_SUCCESS;
+
+        default:
+            /* We can't handle this ID */
+            return TDI_INVALID_PARAMETER;
+        }
+    }
+
+    return TDI_INVALID_PARAMETER;
+}
+
+
+TDI_STATUS InfoTdiQueryInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PNDIS_BUFFER Buffer,
+    PUINT BufferSize,
+    PVOID Context)
+/*
+ * FUNCTION: Returns extended information
+ * ARGUMENTS:
+ *     Request    = Pointer to TDI request structure for the request
+ *     ID         = TDI object ID
+ *     Buffer     = Pointer to buffer with data to use
+ *     BufferSize = Pointer to buffer with size of Buffer. On return
+ *                  this is filled with number of bytes returned
+ *     Context    = Pointer to context buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PLIST_ENTRY CurrentADFEntry;
+    PADDRESS_FILE CurrentADF;
+    ADDRESS_INFO Info;
+    KIRQL OldIrql;
+    UINT Entity;
+    UINT Count;
+    UINT Size;
+    ULONG Temp;
+    UINT Offset = 0;
+    UINT BufSize = *BufferSize;
+
+    /* Check wether it is a query for a list of entities */
+    Entity = ID->toi_entity.tei_entity;
+    if (Entity == GENERIC_ENTITY) {
+        if (ID->toi_class  != INFO_CLASS_GENERIC ||
+            ID->toi_type != INFO_TYPE_PROVIDER ||
+            ID->toi_id != ENTITY_LIST_ID)
+            return TDI_INVALID_PARAMETER;
+
+        *BufferSize = 0;
+
+        Size = EntityCount * sizeof(TDIEntityID);
+        if (BufSize < Size)
+            /* The buffer is too small to contain requested data */
+            return TDI_BUFFER_TOO_SMALL;
+
+        /* Return entity list */
+        Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)EntityList, Size);
+
+        *BufferSize = Size;
+
+        return TDI_SUCCESS;
+    }
+
+    if ((Entity != CL_TL_ENTITY) && (Entity != CO_TL_ENTITY)) {
+        /* We can't handle this entity, pass it on */
+        return IPTdiQueryInformationEx(
+            Request, ID, Buffer, BufferSize, Context);
+    }
+
+    /* Make return parameters consistent every time */
+    *BufferSize = 0;
+
+    if (ID->toi_entity.tei_instance != TL_INSTANCE)
+        /* We only support a single instance */
+        return TDI_INVALID_REQUEST;
+
+    if (ID->toi_class == INFO_CLASS_GENERIC) {
+
+        if (ID->toi_type != INFO_TYPE_PROVIDER ||
+            ID->toi_id != ENTITY_TYPE_ID)
+            return TDI_INVALID_PARAMETER;
+
+        if (BufSize < sizeof(ULONG))
+            return TDI_BUFFER_TOO_SMALL;
+
+        if (Entity == CL_TL_ENTITY)
+            Temp = CL_TL_UDP;
+        else if (Entity == CO_TL_ENTITY)
+            Temp = CO_TL_TCP;
+        else
+            return TDI_INVALID_PARAMETER;
+
+        Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&Temp, sizeof(ULONG));
+
+        return TDI_SUCCESS;
+    }
+
+    if (ID->toi_class == INFO_CLASS_PROTOCOL) {
+
+        if (ID->toi_type != INFO_TYPE_PROVIDER)
+            return TDI_INVALID_PARAMETER;
+
+        switch (ID->toi_id) {
+        case UDP_MIB_STAT_ID:
+            if (Entity != CL_TL_ENTITY)
+                return TDI_INVALID_PARAMETER;
+
+            if (BufSize < sizeof(UDPStats))
+                return TDI_BUFFER_TOO_SMALL;
+
+            Count = CopyBufferToBufferChain(Buffer, 0, (PUCHAR)&UDPStats, sizeof(UDP_STATISTICS));
+
+            return TDI_SUCCESS;
+
+        case UDP_MIB_TABLE_ID:
+            if (Entity != CL_TL_ENTITY)
+                return TDI_INVALID_PARAMETER;
+
+            Offset = 0;
+
+            KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+
+            CurrentADFEntry = AddressFileListHead.Flink;
+            while (CurrentADFEntry != &AddressFileListHead) {
+                   CurrentADF = CONTAINING_RECORD(CurrentADFEntry, ADDRESS_FILE, ListEntry);
+
+                if (Offset + sizeof(ADDRESS_INFO) > BufSize) {
+                    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+                    *BufferSize = Offset;
+                    return TDI_BUFFER_OVERFLOW;
+                }
+
+                Info.LocalAddress = CurrentADF->ADE->Address->Address.IPv4Address;
+                Info.LocalPort    = CurrentADF->Port;
+
+                Count = CopyBufferToBufferChain(Buffer, Offset, (PUCHAR)&Info, sizeof(ADDRESS_INFO));
+
+                Offset += Count;
+
+                CurrentADFEntry = CurrentADFEntry->Flink;
+            }
+
+            KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+
+            *BufferSize = Offset;
+
+            return STATUS_SUCCESS;
+
+        default:
+            /* We can't handle this ID */
+            return TDI_INVALID_PARAMETER;
+        }
+    }
+
+    return TDI_INVALID_PARAMETER;
+}
+
+
+TDI_STATUS InfoTdiSetInformationEx(
+    PTDI_REQUEST Request,
+    TDIObjectID *ID,
+    PVOID Buffer,
+    UINT BufferSize)
+/*
+ * FUNCTION: Sets extended information
+ * ARGUMENTS:
+ *     Request    = Pointer to TDI request structure for the request
+ *     ID         = Pointer to TDI object ID
+ *     Buffer     = Pointer to buffer with data to use
+ *     BufferSize = Size of Buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    /* FIXME: Set extended information */
+
+    return TDI_INVALID_REQUEST;
+}
+
+/* EOF */
index 3162b91..0dab08f 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/main.c\r
- * PURPOSE:     Driver entry point\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- *   CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <dispatch.h>\r
-#include <fileobjs.h>\r
-#include <datagram.h>\r
-#include <loopback.h>\r
-#include <rawip.h>\r
-#include <udp.h>\r
-#include <tcp.h>\r
-\r
-\r
-#ifdef DBG\r
-/* See debug.h for debug/trace constants */\r
-DWORD DebugTraceLevel = MIN_TRACE;\r
-#endif /* DBG */\r
-\r
-PDEVICE_OBJECT TCPDeviceObject   = NULL;\r
-PDEVICE_OBJECT UDPDeviceObject   = NULL;\r
-PDEVICE_OBJECT IPDeviceObject    = NULL;\r
-PDEVICE_OBJECT RawIPDeviceObject = NULL;\r
-NDIS_HANDLE GlobalPacketPool     = NULL;\r
-NDIS_HANDLE GlobalBufferPool     = NULL;\r
-TDIEntityID *EntityList          = NULL;\r
-ULONG EntityCount                = 0;\r
-UDP_STATISTICS UDPStats;\r
-\r
-\r
-VOID TiWriteErrorLog(\r
-    PDRIVER_OBJECT DriverContext,\r
-    NTSTATUS ErrorCode,\r
-    ULONG UniqueErrorValue,\r
-    NTSTATUS FinalStatus,\r
-    PWSTR String,\r
-    ULONG DumpDataCount,\r
-    PULONG DumpData)\r
-/*\r
- * FUNCTION: Writes an error log entry\r
- * ARGUMENTS:\r
- *     DriverContext    = Pointer to the driver or device object\r
- *     ErrorCode        = An error code to put in the log entry\r
- *     UniqueErrorValue = UniqueErrorValue in the error log packet\r
- *     FinalStatus      = FinalStatus in the error log packet\r
- *     String           = If not NULL, a pointer to a string to put in log entry\r
- *     DumpDataCount    = Number of ULONGs of dump data\r
- *     DumpData         = Pointer to dump data for the log entry\r
- */\r
-{\r
-#ifdef _MSC_VER\r
-    PIO_ERROR_LOG_PACKET LogEntry;\r
-    UCHAR EntrySize;\r
-    ULONG StringSize;\r
-    PUCHAR pString;\r
-    static WCHAR DriverName[] = L"TCP/IP";\r
-\r
-    EntrySize = sizeof(IO_ERROR_LOG_PACKET) + \r
-        (DumpDataCount * sizeof(ULONG)) + sizeof(DriverName);\r
-\r
-    if (String) {\r
-        StringSize = (wcslen(String) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);\r
-        EntrySize += (UCHAR)StringSize;\r
-    }\r
-\r
-    LogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(\r
-               DriverContext, EntrySize);\r
-\r
-    if (LogEntry) {\r
-        LogEntry->MajorFunctionCode = -1;\r
-        LogEntry->RetryCount        = -1;\r
-        LogEntry->DumpDataSize      = (USHORT)(DumpDataCount * sizeof(ULONG));\r
-        LogEntry->NumberOfStrings   = (String == NULL) ? 1 : 2;\r
-        LogEntry->StringOffset      = sizeof(IO_ERROR_LOG_PACKET) + (DumpDataCount-1) * sizeof(ULONG);\r
-        LogEntry->EventCategory     = 0;\r
-        LogEntry->ErrorCode         = ErrorCode;\r
-        LogEntry->UniqueErrorValue  = UniqueErrorValue;\r
-        LogEntry->FinalStatus       = FinalStatus;\r
-        LogEntry->SequenceNumber    = -1;\r
-        LogEntry->IoControlCode     = 0;\r
-\r
-        if (DumpDataCount)\r
-            RtlCopyMemory(LogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));\r
-\r
-        pString = ((PUCHAR)LogEntry) + LogEntry->StringOffset;\r
-        RtlCopyMemory(pString, DriverName, sizeof(DriverName));\r
-        pString += sizeof(DriverName);\r
-\r
-        if (String)\r
-            RtlCopyMemory(pString, String, StringSize);\r
-\r
-        IoWriteErrorLogEntry(LogEntry);\r
-    }\r
-#endif\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Creates a file object\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to a device object for this driver\r
- *     Irp          = Pointer to a I/O request packet\r
- * RETURNS:\r
- *     Status of the operation\r
- */\r
-NTSTATUS TiCreateFileObject(\r
-    PDEVICE_OBJECT DeviceObject,\r
-    PIRP Irp)\r
-{\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PFILE_FULL_EA_INFORMATION EaInfo;\r
-    PTA_ADDRESS_IP Address;\r
-    PTRANSPORT_CONTEXT Context;\r
-    TDI_REQUEST Request;\r
-    NTSTATUS Status;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));\r
-\r
-    EaInfo = Irp->AssociatedIrp.SystemBuffer;\r
-\r
-    /* Parameter check */\r
-    if (!EaInfo) {\r
-        TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n"));\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-    \r
-    /* Allocate resources here. We release them again if something failed */\r
-    Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT));\r
-    if (!Context) {\r
-        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    Context->RefCount   = 1;\r
-    Context->CancelIrps = FALSE;\r
-    KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE);\r
-\r
-    IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-    IrpSp->FileObject->FsContext = Context;\r
-    Request.RequestContext       = Irp;\r
-\r
-    /* Branch to the right handler */\r
-    if ((EaInfo->EaNameLength==TDI_TRANSPORT_ADDRESS_LENGTH) && \r
-        (RtlCompareMemory(&EaInfo->EaName, TdiTransportAddress,\r
-         TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) {\r
-        /* This is a request to open an address */\r
-\r
-        /* Parameter checks */\r
-        Address = (PTA_ADDRESS_IP)(EaInfo->EaName + EaInfo->EaNameLength + 1);\r
-        if ((EaInfo->EaValueLength < sizeof(TA_ADDRESS_IP)) ||\r
-            (Address->TAAddressCount != 1) ||\r
-            (Address->Address[0].AddressLength < sizeof(TDI_ADDRESS_IP)) ||\r
-            (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) {\r
-            TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));\r
-            ExFreePool(Context);\r
-            return STATUS_INVALID_PARAMETER;\r
-        }\r
-\r
-        /* Open address file object */\r
-        /* FIXME: Protocol depends on device object */\r
-        Status = FileOpenAddress(&Request, Address, IPPROTO_UDP, NULL);\r
-        if (NT_SUCCESS(Status)) {\r
-            IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;\r
-            Context->Handle.AddressHandle = Request.Handle.AddressHandle;\r
-        }\r
-    } else {\r
-        TI_DbgPrint(MIN_TRACE, ("Connection point, and control connections are not supported.\n"));\r
-        /* FIXME: Open a connection endpoint, or control connection */\r
-        Status = STATUS_NOT_IMPLEMENTED;\r
-    }\r
-\r
-    if (!NT_SUCCESS(Status))\r
-        ExFreePool(Context);\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-VOID TiCleanupFileObjectComplete(\r
-    PVOID Context,\r
-    NTSTATUS Status)\r
-/*\r
- * FUNCTION: Completes an object cleanup IRP I/O request\r
- * ARGUMENTS:\r
- *     Context = Pointer to the IRP for this request\r
- *     Status  = Final status of the operation\r
- */\r
-{\r
-    PIRP Irp;\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PTRANSPORT_CONTEXT TranContext;\r
-    KIRQL OldIrql;\r
-\r
-    Irp         = (PIRP)Context;\r
-    IrpSp       = IoGetCurrentIrpStackLocation(Irp);\r
-    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;\r
-\r
-    Irp->IoStatus.Status = Status;\r
-    \r
-    IoAcquireCancelSpinLock(&OldIrql);\r
-\r
-    /* Remove the initial reference provided at object creation time */\r
-    TranContext->RefCount--;\r
-\r
-#ifdef DBG\r
-    if (TranContext->RefCount != 0)\r
-        TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount is %i, should be 0.\n", TranContext->RefCount));\r
-#endif\r
-\r
-    KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);\r
-\r
-    IoReleaseCancelSpinLock(OldIrql);\r
-}\r
-\r
-\r
-/*\r
- * FUNCTION: Releases resources used by a file object\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to a device object for this driver\r
- *     Irp          = Pointer to a I/O request packet\r
- * RETURNS:\r
- *     Status of the operation\r
- * NOTES:\r
- *     This function does not pend\r
- */\r
-NTSTATUS TiCleanupFileObject(\r
-    PDEVICE_OBJECT DeviceObject,\r
-    PIRP Irp)\r
-{\r
-    PIO_STACK_LOCATION IrpSp;\r
-    PTRANSPORT_CONTEXT Context;\r
-    TDI_REQUEST Request;\r
-    NTSTATUS Status;\r
-    KIRQL OldIrql;\r
-\r
-    IrpSp   = IoGetCurrentIrpStackLocation(Irp);\r
-    Context = IrpSp->FileObject->FsContext;    \r
-    if (!Context) {\r
-        TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    IoAcquireCancelSpinLock(&OldIrql);\r
-\r
-    Context->CancelIrps = TRUE;\r
-    KeResetEvent(&Context->CleanupEvent);\r
-\r
-    IoReleaseCancelSpinLock(OldIrql);\r
-\r
-    Request.RequestNotifyObject = TiCleanupFileObjectComplete;\r
-    Request.RequestContext      = Irp;\r
-\r
-    switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {\r
-    case TDI_TRANSPORT_ADDRESS_FILE:\r
-        Request.Handle.AddressHandle = Context->Handle.AddressHandle;\r
-        Status = FileCloseAddress(&Request);\r
-        break;\r
-\r
-    case TDI_CONNECTION_FILE:\r
-        Request.Handle.ConnectionContext = Context->Handle.ConnectionContext;\r
-        Status = FileCloseConnection(&Request);\r
-        break;\r
-\r
-    case TDI_CONTROL_CHANNEL_FILE:\r
-        Request.Handle.ControlChannel = Context->Handle.ControlChannel;\r
-        Status = FileCloseControlChannel(&Request);\r
-        break;\r
-\r
-    default:\r
-        /* This should never happen */\r
-\r
-        TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n"));\r
-\r
-        IoAcquireCancelSpinLock(&OldIrql);\r
-        Context->CancelIrps = FALSE;\r
-        IoReleaseCancelSpinLock(OldIrql);\r
-\r
-        return STATUS_INVALID_PARAMETER;\r
-    }\r
-\r
-    if (Status != STATUS_PENDING)\r
-       TiCleanupFileObjectComplete(Irp, Status);\r
-    \r
-    KeWaitForSingleObject(&Context->CleanupEvent,\r
-        UserRequest, KernelMode, FALSE, NULL);\r
-    \r
-    return Irp->IoStatus.Status;\r
-}\r
-\r
-\r
-NTSTATUS TiDispatchOpenClose(\r
-    PDEVICE_OBJECT DeviceObject,\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: Main dispath routine\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to a device object for this driver\r
- *     Irp          = Pointer to a I/O request packet\r
- * RETURNS:\r
- *     Status of the operation\r
- */\r
-{\r
-    PIO_STACK_LOCATION IrpSp;\r
-    NTSTATUS Status;\r
-    PTRANSPORT_CONTEXT Context;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));\r
-\r
-    IoMarkIrpPending(Irp);\r
-    Irp->IoStatus.Status      = STATUS_PENDING;\r
-    Irp->IoStatus.Information = 0;\r
-\r
-    IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-    switch (IrpSp->MajorFunction) {\r
-    /* Open an address file, connection endpoint, or control connection */\r
-    case IRP_MJ_CREATE:\r
-        Status = TiCreateFileObject(DeviceObject, Irp);\r
-        break;\r
-\r
-    /* Close an address file, connection endpoint, or control connection */\r
-    case IRP_MJ_CLOSE:\r
-        Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;\r
-        if (Context)\r
-            ExFreePool(Context);\r
-        Status = STATUS_SUCCESS;\r
-        break;\r
-\r
-    /* Release resources bound to an address file, connection endpoint, \r
-       or control connection */\r
-    case IRP_MJ_CLEANUP:\r
-        Status = TiCleanupFileObject(DeviceObject, Irp);\r
-        break;\r
-\r
-       default:\r
-        Status = STATUS_INVALID_DEVICE_REQUEST;\r
-    }\r
-\r
-    if (Status != STATUS_PENDING) {\r
-        IrpSp->Control &= ~SL_PENDING_RETURNED;\r
-        Irp->IoStatus.Status = Status;\r
-\r
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));\r
-\r
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-NTSTATUS TiDispatchInternal(\r
-    PDEVICE_OBJECT DeviceObject,\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: Internal IOCTL dispatch routine\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to a device object for this driver\r
- *     Irp          = Pointer to a I/O request packet\r
- * RETURNS:\r
- *     Status of the operation\r
- */\r
-{\r
-       NTSTATUS Status;\r
-    PIO_STACK_LOCATION IrpSp;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));\r
-\r
-       IrpSp = IoGetCurrentIrpStackLocation(Irp);\r
-\r
-    Irp->IoStatus.Status      = STATUS_SUCCESS;\r
-    Irp->IoStatus.Information = 0;\r
-\r
-    switch (IrpSp->MinorFunction) {\r
-    case TDI_RECEIVE:\r
-        Status = DispTdiReceive(Irp);\r
-        break;\r
-\r
-    case TDI_RECEIVE_DATAGRAM:\r
-        Status = DispTdiReceiveDatagram(Irp);\r
-        break;\r
-\r
-    case TDI_SEND:\r
-        Status = DispTdiSend(Irp);\r
-        break;\r
-\r
-    case TDI_SEND_DATAGRAM:\r
-        Status = DispTdiSendDatagram(Irp);\r
-        break;\r
-\r
-    case TDI_ACCEPT:\r
-        Status = DispTdiAccept(Irp);\r
-        break;\r
-\r
-    case TDI_LISTEN:\r
-        Status = DispTdiListen(Irp);\r
-        break;\r
-\r
-    case TDI_CONNECT:\r
-        Status = DispTdiConnect(Irp);\r
-        break;\r
-\r
-    case TDI_DISCONNECT:\r
-        Status = DispTdiDisconnect(Irp);\r
-        break;\r
-\r
-    case TDI_ASSOCIATE_ADDRESS:\r
-        Status = DispTdiAssociateAddress(Irp);\r
-        break;\r
-\r
-    case TDI_DISASSOCIATE_ADDRESS:\r
-        Status = DispTdiDisassociateAddress(Irp);\r
-        break;\r
-\r
-    case TDI_QUERY_INFORMATION:\r
-        Status = DispTdiQueryInformation(DeviceObject, Irp);\r
-        break;\r
-\r
-    case TDI_SET_INFORMATION:\r
-        Status = DispTdiSetInformation(Irp);\r
-        break;\r
-\r
-    case TDI_SET_EVENT_HANDLER:\r
-        Status = DispTdiSetEventHandler(Irp);\r
-        break;\r
-\r
-    case TDI_ACTION:\r
-        Status = STATUS_SUCCESS;\r
-        break;\r
-\r
-    /* An unsupported IOCTL code was submitted */\r
-    default:\r
-        Status = STATUS_INVALID_DEVICE_REQUEST;\r
-    }\r
-\r
-    if (Status != STATUS_PENDING) {\r
-        Irp->IoStatus.Status = Status;\r
-\r
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));\r
-\r
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));\r
-\r
-       return Status;\r
-}\r
-\r
-\r
-NTSTATUS TiDispatch(\r
-    PDEVICE_OBJECT DeviceObject,\r
-    PIRP Irp)\r
-/*\r
- * FUNCTION: Dispath routine for IRP_MJ_DEVICE_CONTROL requests\r
- * ARGUMENTS:\r
- *     DeviceObject = Pointer to a device object for this driver\r
- *     Irp          = Pointer to a I/O request packet\r
- * RETURNS:\r
- *     Status of the operation\r
- */\r
-{\r
-    NTSTATUS Status;\r
-    PIO_STACK_LOCATION IrpSp;\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp));\r
-\r
-    Irp->IoStatus.Information = 0;\r
-\r
-    IrpSp  = IoGetCurrentIrpStackLocation(Irp);\r
-#ifdef _MSC_VER\r
-    Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);\r
-    if (NT_SUCCESS(Status)) {\r
-        TiDispatchInternal(DeviceObject, Irp);\r
-        Status = STATUS_PENDING;\r
-    } else {\r
-#else\r
-    if (TRUE) {\r
-#endif\r
-        /* See if this request is TCP/IP specific */\r
-        switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {\r
-        case IOCTL_TCP_QUERY_INFORMATION_EX:\r
-            Status = DispTdiQueryInformationEx(Irp, IrpSp);\r
-            break;\r
-\r
-        case IOCTL_TCP_SET_INFORMATION_EX:\r
-            Status = DispTdiSetInformationEx(Irp, IrpSp);\r
-            break;\r
-\r
-        default:\r
-            TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",\r
-                IrpSp->Parameters.DeviceIoControl.IoControlCode));\r
-            Status = STATUS_NOT_IMPLEMENTED;\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (Status != STATUS_PENDING) {\r
-        Irp->IoStatus.Status = Status;\r
-\r
-        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));\r
-\r
-        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);\r
-    }\r
-\r
-    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-VOID TiUnload(\r
-    PDRIVER_OBJECT DriverObject)\r
-/*\r
- * FUNCTION: Unloads the driver\r
- * ARGUMENTS:\r
- *     DriverObject = Pointer to driver object created by the system\r
- */\r
-{\r
-#ifdef BDG\r
-    KIRQL OldIrql;\r
-\r
-    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);\r
-    if (!IsListEmpty(AddressFileList)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n"));\r
-    }\r
-    KeReleaseSpinLock(&AddressFileListLock, OldIrql);\r
-#endif\r
-\r
-    /* Unregister loopback adapter */\r
-    LoopUnregisterAdapter(NULL);\r
-\r
-    /* Unregister protocol with NDIS */\r
-#ifdef _MSC_VER\r
-    LANUnregisterProtocol();\r
-#endif\r
-\r
-    /* Shutdown transport level protocol subsystems */\r
-    TCPShutdown();\r
-    UDPShutdown();\r
-    RawIPShutdown();\r
-    DGShutdown();\r
-\r
-    /* Shutdown network level protocol subsystem */\r
-    IPShutdown();\r
-\r
-    /* Free NDIS buffer descriptors */\r
-    if (GlobalBufferPool)\r
-        NdisFreeBufferPool(GlobalBufferPool);\r
-\r
-    /* Free NDIS packet descriptors */\r
-    if (GlobalPacketPool)\r
-        NdisFreePacketPool(GlobalPacketPool);\r
-\r
-    /* Release all device objects */\r
-\r
-    if (TCPDeviceObject)\r
-        IoDeleteDevice(TCPDeviceObject);\r
-\r
-    if (UDPDeviceObject)\r
-        IoDeleteDevice(UDPDeviceObject);\r
-\r
-    if (RawIPDeviceObject)\r
-        IoDeleteDevice(RawIPDeviceObject);\r
-\r
-    if (IPDeviceObject)\r
-        IoDeleteDevice(IPDeviceObject);\r
-\r
-    if (EntityList)\r
-        ExFreePool(EntityList);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-NTSTATUS\r
-#ifndef _MSC_VER\r
-STDCALL\r
-#endif\r
-DriverEntry(\r
-    PDRIVER_OBJECT DriverObject,\r
-    PUNICODE_STRING RegistryPath)\r
-/*\r
- * FUNCTION: Main driver entry point\r
- * ARGUMENTS:\r
- *     DriverObject = Pointer to a driver object for this driver\r
- *     RegistryPath = Registry node for configuration parameters\r
- * RETURNS:\r
- *     Status of driver initialization\r
- */\r
-{\r
-    NTSTATUS Status;\r
-    UNICODE_STRING strDeviceName;\r
-    STRING strNdisDeviceName;\r
-    NDIS_STATUS NdisStatus;\r
-#ifdef _MSC_VER\r
-    PLAN_ADAPTER Adapter;\r
-    NDIS_STRING DeviceName;\r
-#endif\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    /* Create IP device object */\r
-    RtlInitUnicodeString(&strDeviceName, DD_IP_DEVICE_NAME);\r
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,\r
-        FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject);\r
-    if (!NT_SUCCESS(Status)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status));\r
-        return Status;\r
-    }\r
-\r
-    /* Create RawIP device object */\r
-    RtlInitUnicodeString(&strDeviceName, DD_RAWIP_DEVICE_NAME);\r
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,\r
-        FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject);\r
-    if (!NT_SUCCESS(Status)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status));\r
-        TiUnload(DriverObject);\r
-        return Status;\r
-    }\r
-\r
-    /* Create UDP device object */\r
-    RtlInitUnicodeString(&strDeviceName, DD_UDP_DEVICE_NAME);\r
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,\r
-        FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject);\r
-    if (!NT_SUCCESS(Status)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status));\r
-        TiUnload(DriverObject);\r
-        return Status;\r
-    }\r
-\r
-    /* Create TCP device object */\r
-    RtlInitUnicodeString(&strDeviceName, DD_TCP_DEVICE_NAME);\r
-    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,\r
-        FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject);\r
-    if (!NT_SUCCESS(Status)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status));\r
-        TiUnload(DriverObject);\r
-        return Status;\r
-    }\r
-\r
-    /* Allocate NDIS packet descriptors */\r
-    NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT));\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        TiUnload(DriverObject);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    /* Allocate NDIS buffer descriptors */\r
-    NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100);\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        TiUnload(DriverObject);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    /* Initialize address file list and protecting spin lock */\r
-    InitializeListHead(&AddressFileListHead);\r
-    KeInitializeSpinLock(&AddressFileListLock);\r
-\r
-    /* Initialize interface list and protecting spin lock */\r
-    InitializeListHead(&InterfaceListHead);\r
-    KeInitializeSpinLock(&InterfaceListLock);\r
-\r
-    /* Initialize network level protocol subsystem */\r
-    IPStartup(DriverObject, RegistryPath);\r
-\r
-    /* Initialize transport level protocol subsystems */\r
-    DGStartup();\r
-    RawIPStartup();\r
-    UDPStartup();\r
-    TCPStartup();\r
-\r
-    /* Register protocol with NDIS */\r
-    RtlInitString(&strNdisDeviceName, IP_DEVICE_NAME);\r
-    Status = LANRegisterProtocol(&strNdisDeviceName);\r
-    if (!NT_SUCCESS(Status)) {\r
-               TiWriteErrorLog(\r
-            DriverObject,\r
-            EVENT_TRANSPORT_REGISTER_FAILED,\r
-            TI_ERROR_DRIVERENTRY,\r
-            Status,\r
-            NULL,\r
-            0,\r
-            NULL);\r
-        TiUnload(DriverObject);\r
-        return Status;\r
-    }\r
-\r
-    /* Open loopback adapter */\r
-    if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) {\r
-        TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status));\r
-        TiUnload(DriverObject);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-#if 1\r
-#ifdef _MSC_VER\r
-    /* Open underlying adapter(s) we are bound to */\r
-\r
-    /* FIXME: Get binding information from registry */\r
-\r
-    /* Put your own NDIS adapter device name here */\r
-\r
-#if 0\r
-    /* NT4 */\r
-    NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1");\r
-#else\r
-    /* NT5 */\r
-    NdisInitUnicodeString(&DeviceName,\r
-        L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}");\r
-#endif\r
-\r
-    NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter);\r
-    if (!NT_SUCCESS(NdisStatus)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Failed to intialize adapter. Status (0x%X).\n", Status));\r
-               TiWriteErrorLog(\r
-            DriverObject,\r
-            EVENT_TRANSPORT_ADAPTER_NOT_FOUND,\r
-            TI_ERROR_DRIVERENTRY,\r
-            NdisStatus,\r
-            NULL,\r
-            0,\r
-            NULL);\r
-        TiUnload(DriverObject);\r
-        return STATUS_DEVICE_DOES_NOT_EXIST;\r
-    }\r
-#endif\r
-#endif\r
-    /* Setup network layer and transport layer entities */\r
-    EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2);\r
-    if (!NT_SUCCESS(Status)) {\r
-        TiUnload(DriverObject);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    EntityList[0].tei_entity   = CL_NL_ENTITY;\r
-    EntityList[0].tei_instance = 0;\r
-    EntityList[1].tei_entity   = CL_TL_ENTITY;\r
-    EntityList[1].tei_instance = 0;\r
-    EntityCount = 2;\r
-\r
-    /* Use direct I/O */\r
-    IPDeviceObject->Flags    |= DO_DIRECT_IO;\r
-    RawIPDeviceObject->Flags |= DO_DIRECT_IO;\r
-    UDPDeviceObject->Flags   |= DO_DIRECT_IO;\r
-    TCPDeviceObject->Flags   |= DO_DIRECT_IO;\r
-\r
-    /* Initialize the driver object with this driver's entry points */\r
-    DriverObject->MajorFunction[IRP_MJ_CREATE]  = TiDispatchOpenClose;\r
-    DriverObject->MajorFunction[IRP_MJ_CLOSE]   = TiDispatchOpenClose;\r
-    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose;\r
-    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal;\r
-    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch;\r
-\r
-    DriverObject->DriverUnload = (PDRIVER_UNLOAD)TiUnload;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-VOID\r
-#ifndef _MSC_VER\r
-STDCALL\r
-#endif\r
-IPAddInterface(\r
-       DWORD   Unknown0,\r
-       DWORD   Unknown1,\r
-       DWORD   Unknown2,\r
-       DWORD   Unknown3,\r
-       DWORD   Unknown4)\r
-{\r
-    UNIMPLEMENTED\r
-}\r
-\r
-\r
-VOID\r
-#ifndef _MSC_VER\r
-STDCALL\r
-#endif\r
-IPDelInterface(\r
-       DWORD   Unknown0)\r
-{\r
-    UNIMPLEMENTED\r
-}\r
-\r
-\r
-VOID\r
-#ifndef _MSC_VER\r
-STDCALL\r
-#endif\r
-LookupRoute(\r
-       DWORD   Unknown0,\r
-       DWORD   Unknown1)\r
-{\r
-    UNIMPLEMENTED\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/main.c
+ * PURPOSE:     Driver entry point
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <dispatch.h>
+#include <fileobjs.h>
+#include <datagram.h>
+#include <loopback.h>
+#include <rawip.h>
+#include <udp.h>
+#include <tcp.h>
+
+
+#ifdef DBG
+/* See debug.h for debug/trace constants */
+DWORD DebugTraceLevel = MIN_TRACE;
+#endif /* DBG */
+
+PDEVICE_OBJECT TCPDeviceObject   = NULL;
+PDEVICE_OBJECT UDPDeviceObject   = NULL;
+PDEVICE_OBJECT IPDeviceObject    = NULL;
+PDEVICE_OBJECT RawIPDeviceObject = NULL;
+NDIS_HANDLE GlobalPacketPool     = NULL;
+NDIS_HANDLE GlobalBufferPool     = NULL;
+TDIEntityID *EntityList          = NULL;
+ULONG EntityCount                = 0;
+UDP_STATISTICS UDPStats;
+
+
+VOID TiWriteErrorLog(
+    PDRIVER_OBJECT DriverContext,
+    NTSTATUS ErrorCode,
+    ULONG UniqueErrorValue,
+    NTSTATUS FinalStatus,
+    PWSTR String,
+    ULONG DumpDataCount,
+    PULONG DumpData)
+/*
+ * FUNCTION: Writes an error log entry
+ * ARGUMENTS:
+ *     DriverContext    = Pointer to the driver or device object
+ *     ErrorCode        = An error code to put in the log entry
+ *     UniqueErrorValue = UniqueErrorValue in the error log packet
+ *     FinalStatus      = FinalStatus in the error log packet
+ *     String           = If not NULL, a pointer to a string to put in log entry
+ *     DumpDataCount    = Number of ULONGs of dump data
+ *     DumpData         = Pointer to dump data for the log entry
+ */
+{
+#ifdef _MSC_VER
+    PIO_ERROR_LOG_PACKET LogEntry;
+    UCHAR EntrySize;
+    ULONG StringSize;
+    PUCHAR pString;
+    static WCHAR DriverName[] = L"TCP/IP";
+
+    EntrySize = sizeof(IO_ERROR_LOG_PACKET) + 
+        (DumpDataCount * sizeof(ULONG)) + sizeof(DriverName);
+
+    if (String) {
+        StringSize = (wcslen(String) * sizeof(WCHAR)) + sizeof(UNICODE_NULL);
+        EntrySize += (UCHAR)StringSize;
+    }
+
+    LogEntry = (PIO_ERROR_LOG_PACKET)IoAllocateErrorLogEntry(
+               DriverContext, EntrySize);
+
+    if (LogEntry) {
+        LogEntry->MajorFunctionCode = -1;
+        LogEntry->RetryCount        = -1;
+        LogEntry->DumpDataSize      = (USHORT)(DumpDataCount * sizeof(ULONG));
+        LogEntry->NumberOfStrings   = (String == NULL) ? 1 : 2;
+        LogEntry->StringOffset      = sizeof(IO_ERROR_LOG_PACKET) + (DumpDataCount-1) * sizeof(ULONG);
+        LogEntry->EventCategory     = 0;
+        LogEntry->ErrorCode         = ErrorCode;
+        LogEntry->UniqueErrorValue  = UniqueErrorValue;
+        LogEntry->FinalStatus       = FinalStatus;
+        LogEntry->SequenceNumber    = -1;
+        LogEntry->IoControlCode     = 0;
+
+        if (DumpDataCount)
+            RtlCopyMemory(LogEntry->DumpData, DumpData, DumpDataCount * sizeof(ULONG));
+
+        pString = ((PUCHAR)LogEntry) + LogEntry->StringOffset;
+        RtlCopyMemory(pString, DriverName, sizeof(DriverName));
+        pString += sizeof(DriverName);
+
+        if (String)
+            RtlCopyMemory(pString, String, StringSize);
+
+        IoWriteErrorLogEntry(LogEntry);
+    }
+#endif
+}
+
+
+/*
+ * FUNCTION: Creates a file object
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to a device object for this driver
+ *     Irp          = Pointer to a I/O request packet
+ * RETURNS:
+ *     Status of the operation
+ */
+NTSTATUS TiCreateFileObject(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    PIO_STACK_LOCATION IrpSp;
+    PFILE_FULL_EA_INFORMATION EaInfo;
+    PTA_ADDRESS_IP Address;
+    PTRANSPORT_CONTEXT Context;
+    TDI_REQUEST Request;
+    NTSTATUS Status;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
+
+    EaInfo = Irp->AssociatedIrp.SystemBuffer;
+
+    /* Parameter check */
+    if (!EaInfo) {
+        TI_DbgPrint(MIN_TRACE, ("No EA information in IRP.\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+    
+    /* Allocate resources here. We release them again if something failed */
+    Context = ExAllocatePool(NonPagedPool, sizeof(TRANSPORT_CONTEXT));
+    if (!Context) {
+        TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Context->RefCount   = 1;
+    Context->CancelIrps = FALSE;
+    KeInitializeEvent(&Context->CleanupEvent, NotificationEvent, FALSE);
+
+    IrpSp = IoGetCurrentIrpStackLocation(Irp);
+    IrpSp->FileObject->FsContext = Context;
+    Request.RequestContext       = Irp;
+
+    /* Branch to the right handler */
+    if ((EaInfo->EaNameLength==TDI_TRANSPORT_ADDRESS_LENGTH) && 
+        (RtlCompareMemory(&EaInfo->EaName, TdiTransportAddress,
+         TDI_TRANSPORT_ADDRESS_LENGTH) == TDI_TRANSPORT_ADDRESS_LENGTH)) {
+        /* This is a request to open an address */
+
+        /* Parameter checks */
+        Address = (PTA_ADDRESS_IP)(EaInfo->EaName + EaInfo->EaNameLength + 1);
+        if ((EaInfo->EaValueLength < sizeof(TA_ADDRESS_IP)) ||
+            (Address->TAAddressCount != 1) ||
+            (Address->Address[0].AddressLength < sizeof(TDI_ADDRESS_IP)) ||
+            (Address->Address[0].AddressType != TDI_ADDRESS_TYPE_IP)) {
+            TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
+            ExFreePool(Context);
+            return STATUS_INVALID_PARAMETER;
+        }
+
+        /* Open address file object */
+        /* FIXME: Protocol depends on device object */
+        Status = FileOpenAddress(&Request, Address, IPPROTO_UDP, NULL);
+        if (NT_SUCCESS(Status)) {
+            IrpSp->FileObject->FsContext2 = (PVOID)TDI_TRANSPORT_ADDRESS_FILE;
+            Context->Handle.AddressHandle = Request.Handle.AddressHandle;
+        }
+    } else {
+        TI_DbgPrint(MIN_TRACE, ("Connection point, and control connections are not supported.\n"));
+        /* FIXME: Open a connection endpoint, or control connection */
+        Status = STATUS_NOT_IMPLEMENTED;
+    }
+
+    if (!NT_SUCCESS(Status))
+        ExFreePool(Context);
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+
+    return Status;
+}
+
+
+VOID TiCleanupFileObjectComplete(
+    PVOID Context,
+    NTSTATUS Status)
+/*
+ * FUNCTION: Completes an object cleanup IRP I/O request
+ * ARGUMENTS:
+ *     Context = Pointer to the IRP for this request
+ *     Status  = Final status of the operation
+ */
+{
+    PIRP Irp;
+    PIO_STACK_LOCATION IrpSp;
+    PTRANSPORT_CONTEXT TranContext;
+    KIRQL OldIrql;
+
+    Irp         = (PIRP)Context;
+    IrpSp       = IoGetCurrentIrpStackLocation(Irp);
+    TranContext = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+
+    Irp->IoStatus.Status = Status;
+    
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    /* Remove the initial reference provided at object creation time */
+    TranContext->RefCount--;
+
+#ifdef DBG
+    if (TranContext->RefCount != 0)
+        TI_DbgPrint(DEBUG_REFCOUNT, ("TranContext->RefCount is %i, should be 0.\n", TranContext->RefCount));
+#endif
+
+    KeSetEvent(&TranContext->CleanupEvent, 0, FALSE);
+
+    IoReleaseCancelSpinLock(OldIrql);
+}
+
+
+/*
+ * FUNCTION: Releases resources used by a file object
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to a device object for this driver
+ *     Irp          = Pointer to a I/O request packet
+ * RETURNS:
+ *     Status of the operation
+ * NOTES:
+ *     This function does not pend
+ */
+NTSTATUS TiCleanupFileObject(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+{
+    PIO_STACK_LOCATION IrpSp;
+    PTRANSPORT_CONTEXT Context;
+    TDI_REQUEST Request;
+    NTSTATUS Status;
+    KIRQL OldIrql;
+
+    IrpSp   = IoGetCurrentIrpStackLocation(Irp);
+    Context = IrpSp->FileObject->FsContext;    
+    if (!Context) {
+        TI_DbgPrint(MIN_TRACE, ("Parameters are invalid.\n"));
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    IoAcquireCancelSpinLock(&OldIrql);
+
+    Context->CancelIrps = TRUE;
+    KeResetEvent(&Context->CleanupEvent);
+
+    IoReleaseCancelSpinLock(OldIrql);
+
+    Request.RequestNotifyObject = TiCleanupFileObjectComplete;
+    Request.RequestContext      = Irp;
+
+    switch ((ULONG_PTR)IrpSp->FileObject->FsContext2) {
+    case TDI_TRANSPORT_ADDRESS_FILE:
+        Request.Handle.AddressHandle = Context->Handle.AddressHandle;
+        Status = FileCloseAddress(&Request);
+        break;
+
+    case TDI_CONNECTION_FILE:
+        Request.Handle.ConnectionContext = Context->Handle.ConnectionContext;
+        Status = FileCloseConnection(&Request);
+        break;
+
+    case TDI_CONTROL_CHANNEL_FILE:
+        Request.Handle.ControlChannel = Context->Handle.ControlChannel;
+        Status = FileCloseControlChannel(&Request);
+        break;
+
+    default:
+        /* This should never happen */
+
+        TI_DbgPrint(MIN_TRACE, ("Unknown transport context.\n"));
+
+        IoAcquireCancelSpinLock(&OldIrql);
+        Context->CancelIrps = FALSE;
+        IoReleaseCancelSpinLock(OldIrql);
+
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    if (Status != STATUS_PENDING)
+       TiCleanupFileObjectComplete(Irp, Status);
+    
+    KeWaitForSingleObject(&Context->CleanupEvent,
+        UserRequest, KernelMode, FALSE, NULL);
+    
+    return Irp->IoStatus.Status;
+}
+
+
+NTSTATUS TiDispatchOpenClose(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+/*
+ * FUNCTION: Main dispath routine
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to a device object for this driver
+ *     Irp          = Pointer to a I/O request packet
+ * RETURNS:
+ *     Status of the operation
+ */
+{
+    PIO_STACK_LOCATION IrpSp;
+    NTSTATUS Status;
+    PTRANSPORT_CONTEXT Context;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
+
+    IoMarkIrpPending(Irp);
+    Irp->IoStatus.Status      = STATUS_PENDING;
+    Irp->IoStatus.Information = 0;
+
+    IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    switch (IrpSp->MajorFunction) {
+    /* Open an address file, connection endpoint, or control connection */
+    case IRP_MJ_CREATE:
+        Status = TiCreateFileObject(DeviceObject, Irp);
+        break;
+
+    /* Close an address file, connection endpoint, or control connection */
+    case IRP_MJ_CLOSE:
+        Context = (PTRANSPORT_CONTEXT)IrpSp->FileObject->FsContext;
+        if (Context)
+            ExFreePool(Context);
+        Status = STATUS_SUCCESS;
+        break;
+
+    /* Release resources bound to an address file, connection endpoint, 
+       or control connection */
+    case IRP_MJ_CLEANUP:
+        Status = TiCleanupFileObject(DeviceObject, Irp);
+        break;
+
+       default:
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    if (Status != STATUS_PENDING) {
+        IrpSp->Control &= ~SL_PENDING_RETURNED;
+        Irp->IoStatus.Status = Status;
+
+        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+    }
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status is (0x%X)\n", Status));
+
+    return Status;
+}
+
+
+NTSTATUS TiDispatchInternal(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+/*
+ * FUNCTION: Internal IOCTL dispatch routine
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to a device object for this driver
+ *     Irp          = Pointer to a I/O request packet
+ * RETURNS:
+ *     Status of the operation
+ */
+{
+       NTSTATUS Status;
+    PIO_STACK_LOCATION IrpSp;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called. DeviceObject is at (0x%X), IRP is at (0x%X).\n", DeviceObject, Irp));
+
+       IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+    Irp->IoStatus.Status      = STATUS_SUCCESS;
+    Irp->IoStatus.Information = 0;
+
+    switch (IrpSp->MinorFunction) {
+    case TDI_RECEIVE:
+        Status = DispTdiReceive(Irp);
+        break;
+
+    case TDI_RECEIVE_DATAGRAM:
+        Status = DispTdiReceiveDatagram(Irp);
+        break;
+
+    case TDI_SEND:
+        Status = DispTdiSend(Irp);
+        break;
+
+    case TDI_SEND_DATAGRAM:
+        Status = DispTdiSendDatagram(Irp);
+        break;
+
+    case TDI_ACCEPT:
+        Status = DispTdiAccept(Irp);
+        break;
+
+    case TDI_LISTEN:
+        Status = DispTdiListen(Irp);
+        break;
+
+    case TDI_CONNECT:
+        Status = DispTdiConnect(Irp);
+        break;
+
+    case TDI_DISCONNECT:
+        Status = DispTdiDisconnect(Irp);
+        break;
+
+    case TDI_ASSOCIATE_ADDRESS:
+        Status = DispTdiAssociateAddress(Irp);
+        break;
+
+    case TDI_DISASSOCIATE_ADDRESS:
+        Status = DispTdiDisassociateAddress(Irp);
+        break;
+
+    case TDI_QUERY_INFORMATION:
+        Status = DispTdiQueryInformation(DeviceObject, Irp);
+        break;
+
+    case TDI_SET_INFORMATION:
+        Status = DispTdiSetInformation(Irp);
+        break;
+
+    case TDI_SET_EVENT_HANDLER:
+        Status = DispTdiSetEventHandler(Irp);
+        break;
+
+    case TDI_ACTION:
+        Status = STATUS_SUCCESS;
+        break;
+
+    /* An unsupported IOCTL code was submitted */
+    default:
+        Status = STATUS_INVALID_DEVICE_REQUEST;
+    }
+
+    if (Status != STATUS_PENDING) {
+        Irp->IoStatus.Status = Status;
+
+        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+    }
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+
+       return Status;
+}
+
+
+NTSTATUS TiDispatch(
+    PDEVICE_OBJECT DeviceObject,
+    PIRP Irp)
+/*
+ * FUNCTION: Dispath routine for IRP_MJ_DEVICE_CONTROL requests
+ * ARGUMENTS:
+ *     DeviceObject = Pointer to a device object for this driver
+ *     Irp          = Pointer to a I/O request packet
+ * RETURNS:
+ *     Status of the operation
+ */
+{
+    NTSTATUS Status;
+    PIO_STACK_LOCATION IrpSp;
+
+    TI_DbgPrint(DEBUG_IRP, ("Called. IRP is at (0x%X).\n", Irp));
+
+    Irp->IoStatus.Information = 0;
+
+    IrpSp  = IoGetCurrentIrpStackLocation(Irp);
+#ifdef _MSC_VER
+    Status = TdiMapUserRequest(DeviceObject, Irp, IrpSp);
+    if (NT_SUCCESS(Status)) {
+        TiDispatchInternal(DeviceObject, Irp);
+        Status = STATUS_PENDING;
+    } else {
+#else
+    if (TRUE) {
+#endif
+        /* See if this request is TCP/IP specific */
+        switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
+        case IOCTL_TCP_QUERY_INFORMATION_EX:
+            Status = DispTdiQueryInformationEx(Irp, IrpSp);
+            break;
+
+        case IOCTL_TCP_SET_INFORMATION_EX:
+            Status = DispTdiSetInformationEx(Irp, IrpSp);
+            break;
+
+        default:
+            TI_DbgPrint(MIN_TRACE, ("Unknown IOCTL 0x%X\n",
+                IrpSp->Parameters.DeviceIoControl.IoControlCode));
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+        }
+    }
+
+    if (Status != STATUS_PENDING) {
+        Irp->IoStatus.Status = Status;
+
+        TI_DbgPrint(DEBUG_IRP, ("Completing IRP at (0x%X).\n", Irp));
+
+        IoCompleteRequest(Irp, IO_NETWORK_INCREMENT);
+    }
+
+    TI_DbgPrint(DEBUG_IRP, ("Leaving. Status = (0x%X).\n", Status));
+
+    return Status;
+}
+
+
+VOID TiUnload(
+    PDRIVER_OBJECT DriverObject)
+/*
+ * FUNCTION: Unloads the driver
+ * ARGUMENTS:
+ *     DriverObject = Pointer to driver object created by the system
+ */
+{
+#ifdef BDG
+    KIRQL OldIrql;
+
+    KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
+    if (!IsListEmpty(AddressFileList)) {
+        TI_DbgPrint(MIN_TRACE, ("Open address file objects exists.\n"));
+    }
+    KeReleaseSpinLock(&AddressFileListLock, OldIrql);
+#endif
+
+    /* Unregister loopback adapter */
+    LoopUnregisterAdapter(NULL);
+
+    /* Unregister protocol with NDIS */
+#ifdef _MSC_VER
+    LANUnregisterProtocol();
+#endif
+
+    /* Shutdown transport level protocol subsystems */
+    TCPShutdown();
+    UDPShutdown();
+    RawIPShutdown();
+    DGShutdown();
+
+    /* Shutdown network level protocol subsystem */
+    IPShutdown();
+
+    /* Free NDIS buffer descriptors */
+    if (GlobalBufferPool)
+        NdisFreeBufferPool(GlobalBufferPool);
+
+    /* Free NDIS packet descriptors */
+    if (GlobalPacketPool)
+        NdisFreePacketPool(GlobalPacketPool);
+
+    /* Release all device objects */
+
+    if (TCPDeviceObject)
+        IoDeleteDevice(TCPDeviceObject);
+
+    if (UDPDeviceObject)
+        IoDeleteDevice(UDPDeviceObject);
+
+    if (RawIPDeviceObject)
+        IoDeleteDevice(RawIPDeviceObject);
+
+    if (IPDeviceObject)
+        IoDeleteDevice(IPDeviceObject);
+
+    if (EntityList)
+        ExFreePool(EntityList);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+NTSTATUS
+#ifndef _MSC_VER
+STDCALL
+#endif
+DriverEntry(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Main driver entry point
+ * ARGUMENTS:
+ *     DriverObject = Pointer to a driver object for this driver
+ *     RegistryPath = Registry node for configuration parameters
+ * RETURNS:
+ *     Status of driver initialization
+ */
+{
+    NTSTATUS Status;
+    UNICODE_STRING strDeviceName;
+    STRING strNdisDeviceName;
+    NDIS_STATUS NdisStatus;
+#ifdef _MSC_VER
+    PLAN_ADAPTER Adapter;
+    NDIS_STRING DeviceName;
+#endif
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Create IP device object */
+    RtlInitUnicodeString(&strDeviceName, DD_IP_DEVICE_NAME);
+    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
+        FILE_DEVICE_NETWORK, 0, FALSE, &IPDeviceObject);
+    if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to create IP device object. Status (0x%X).\n", Status));
+        return Status;
+    }
+
+    /* Create RawIP device object */
+    RtlInitUnicodeString(&strDeviceName, DD_RAWIP_DEVICE_NAME);
+    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
+        FILE_DEVICE_NETWORK, 0, FALSE, &RawIPDeviceObject);
+    if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to create RawIP device object. Status (0x%X).\n", Status));
+        TiUnload(DriverObject);
+        return Status;
+    }
+
+    /* Create UDP device object */
+    RtlInitUnicodeString(&strDeviceName, DD_UDP_DEVICE_NAME);
+    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
+        FILE_DEVICE_NETWORK, 0, FALSE, &UDPDeviceObject);
+    if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to create UDP device object. Status (0x%X).\n", Status));
+        TiUnload(DriverObject);
+        return Status;
+    }
+
+    /* Create TCP device object */
+    RtlInitUnicodeString(&strDeviceName, DD_TCP_DEVICE_NAME);
+    Status = IoCreateDevice(DriverObject, 0, &strDeviceName,
+        FILE_DEVICE_NETWORK, 0, FALSE, &TCPDeviceObject);
+    if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to create TCP device object. Status (0x%X).\n", Status));
+        TiUnload(DriverObject);
+        return Status;
+    }
+
+    /* Allocate NDIS packet descriptors */
+    NdisAllocatePacketPool(&NdisStatus, &GlobalPacketPool, 100, sizeof(PACKET_CONTEXT));
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TiUnload(DriverObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Allocate NDIS buffer descriptors */
+    NdisAllocateBufferPool(&NdisStatus, &GlobalBufferPool, 100);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TiUnload(DriverObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Initialize address file list and protecting spin lock */
+    InitializeListHead(&AddressFileListHead);
+    KeInitializeSpinLock(&AddressFileListLock);
+
+    /* Initialize interface list and protecting spin lock */
+    InitializeListHead(&InterfaceListHead);
+    KeInitializeSpinLock(&InterfaceListLock);
+
+    /* Initialize network level protocol subsystem */
+    IPStartup(DriverObject, RegistryPath);
+
+    /* Initialize transport level protocol subsystems */
+    DGStartup();
+    RawIPStartup();
+    UDPStartup();
+    TCPStartup();
+
+    /* Register protocol with NDIS */
+    RtlInitString(&strNdisDeviceName, IP_DEVICE_NAME);
+    Status = LANRegisterProtocol(&strNdisDeviceName);
+    if (!NT_SUCCESS(Status)) {
+               TiWriteErrorLog(
+            DriverObject,
+            EVENT_TRANSPORT_REGISTER_FAILED,
+            TI_ERROR_DRIVERENTRY,
+            Status,
+            NULL,
+            0,
+            NULL);
+        TiUnload(DriverObject);
+        return Status;
+    }
+
+    /* Open loopback adapter */
+    if (!NT_SUCCESS(LoopRegisterAdapter(NULL, NULL))) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to create loopback adapter. Status (0x%X).\n", Status));
+        TiUnload(DriverObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+#if 1
+#ifdef _MSC_VER
+    /* Open underlying adapter(s) we are bound to */
+
+    /* FIXME: Get binding information from registry */
+
+    /* Put your own NDIS adapter device name here */
+
+#if 0
+    /* NT4 */
+    NdisInitUnicodeString(&DeviceName, L"\\Device\\El90x1");
+#else
+    /* NT5 */
+    NdisInitUnicodeString(&DeviceName,
+        L"\\Device\\{56388B49-67BB-4419-A3F4-28DF190B9149}");
+#endif
+
+    NdisStatus = LANRegisterAdapter(&DeviceName, &Adapter);
+    if (!NT_SUCCESS(NdisStatus)) {
+        TI_DbgPrint(MIN_TRACE, ("Failed to intialize adapter. Status (0x%X).\n", Status));
+               TiWriteErrorLog(
+            DriverObject,
+            EVENT_TRANSPORT_ADAPTER_NOT_FOUND,
+            TI_ERROR_DRIVERENTRY,
+            NdisStatus,
+            NULL,
+            0,
+            NULL);
+        TiUnload(DriverObject);
+        return STATUS_DEVICE_DOES_NOT_EXIST;
+    }
+#endif
+#endif
+    /* Setup network layer and transport layer entities */
+    EntityList = ExAllocatePool(NonPagedPool, sizeof(TDIEntityID) * 2);
+    if (!NT_SUCCESS(Status)) {
+        TiUnload(DriverObject);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    EntityList[0].tei_entity   = CL_NL_ENTITY;
+    EntityList[0].tei_instance = 0;
+    EntityList[1].tei_entity   = CL_TL_ENTITY;
+    EntityList[1].tei_instance = 0;
+    EntityCount = 2;
+
+    /* Use direct I/O */
+    IPDeviceObject->Flags    |= DO_DIRECT_IO;
+    RawIPDeviceObject->Flags |= DO_DIRECT_IO;
+    UDPDeviceObject->Flags   |= DO_DIRECT_IO;
+    TCPDeviceObject->Flags   |= DO_DIRECT_IO;
+
+    /* Initialize the driver object with this driver's entry points */
+    DriverObject->MajorFunction[IRP_MJ_CREATE]  = TiDispatchOpenClose;
+    DriverObject->MajorFunction[IRP_MJ_CLOSE]   = TiDispatchOpenClose;
+    DriverObject->MajorFunction[IRP_MJ_CLEANUP] = TiDispatchOpenClose;
+    DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = TiDispatchInternal;
+    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = TiDispatch;
+
+    DriverObject->DriverUnload = (PDRIVER_UNLOAD)TiUnload;
+
+    return STATUS_SUCCESS;
+}
+
+
+VOID
+#ifndef _MSC_VER
+STDCALL
+#endif
+IPAddInterface(
+       DWORD   Unknown0,
+       DWORD   Unknown1,
+       DWORD   Unknown2,
+       DWORD   Unknown3,
+       DWORD   Unknown4)
+{
+    UNIMPLEMENTED
+}
+
+
+VOID
+#ifndef _MSC_VER
+STDCALL
+#endif
+IPDelInterface(
+       DWORD   Unknown0)
+{
+    UNIMPLEMENTED
+}
+
+
+VOID
+#ifndef _MSC_VER
+STDCALL
+#endif
+LookupRoute(
+       DWORD   Unknown0,
+       DWORD   Unknown1)
+{
+    UNIMPLEMENTED
+}
+
+/* EOF */
index da73352..ca67822 100644 (file)
@@ -1,50 +1,50 @@
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/pool.c\r
- * PURPOSE:     Routines for controling pools\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- *   CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <pool.h>\r
-\r
-\r
-PVOID PoolAllocateBuffer(\r
-    ULONG Size)\r
-/*\r
- * FUNCTION: Returns a buffer from the free buffer pool\r
- * RETURNS:\r
- *     Pointer to buffer, NULL if there was not enough\r
- *     free resources\r
- */\r
-{\r
-    PVOID Buffer;\r
-\r
-    /* FIXME: Get buffer from a free buffer pool with enough room */\r
-\r
-    Buffer = ExAllocatePool(NonPagedPool, Size);\r
-\r
-    TI_DbgPrint(DEBUG_MEMORY, ("Allocated (%i) bytes at (0x%X).\n", Size, Buffer));\r
-\r
-    return Buffer;\r
-}\r
-\r
-\r
-VOID PoolFreeBuffer(\r
-    PVOID Buffer)\r
-/*\r
- * FUNCTION: Returns a buffer to the free buffer pool\r
- * ARGUMENTS:\r
- *     Buffer = Buffer to return to free buffer pool\r
- */\r
-{\r
-    /* FIXME: Put buffer in free buffer pool */\r
-\r
-    TI_DbgPrint(DEBUG_MEMORY, ("Freeing buffer at (0x%X).\n", Buffer));\r
-\r
-    ExFreePool(Buffer);\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/pool.c
+ * PURPOSE:     Routines for controling pools
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <pool.h>
+
+
+PVOID PoolAllocateBuffer(
+    ULONG Size)
+/*
+ * FUNCTION: Returns a buffer from the free buffer pool
+ * RETURNS:
+ *     Pointer to buffer, NULL if there was not enough
+ *     free resources
+ */
+{
+    PVOID Buffer;
+
+    /* FIXME: Get buffer from a free buffer pool with enough room */
+
+    Buffer = ExAllocatePool(NonPagedPool, Size);
+
+    TI_DbgPrint(DEBUG_MEMORY, ("Allocated (%i) bytes at (0x%X).\n", Size, Buffer));
+
+    return Buffer;
+}
+
+
+VOID PoolFreeBuffer(
+    PVOID Buffer)
+/*
+ * FUNCTION: Returns a buffer to the free buffer pool
+ * ARGUMENTS:
+ *     Buffer = Buffer to return to free buffer pool
+ */
+{
+    /* FIXME: Put buffer in free buffer pool */
+
+    TI_DbgPrint(DEBUG_MEMORY, ("Freeing buffer at (0x%X).\n", Buffer));
+
+    ExFreePool(Buffer);
+}
+
+/* EOF */
index 0c634d2..a5c8ca5 100644 (file)
@@ -1,10 +1,10 @@
-#include <windows.h>\r
-#include <ntverp.h>\r
-\r
-#define        VER_FILETYPE                VFT_DRV\r
-#define        VER_FILESUBTYPE             VFT2_DRV_NETWORK\r
-#define VER_FILEDESCRIPTION_STR     "TCP/IP protocol driver"\r
-#define VER_INTERNALNAME_STR        "TCPIP.SYS"\r
-#define VER_ORIGINALFILENAME_STR    "TCPIP.SYS"\r
-\r
-#include "common.ver"\r
+#include <windows.h>
+#include <ntverp.h>
+
+#define        VER_FILETYPE                VFT_DRV
+#define        VER_FILESUBTYPE             VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR     "TCP/IP protocol driver"
+#define VER_INTERNALNAME_STR        "TCPIP.SYS"
+#define VER_ORIGINALFILENAME_STR    "TCPIP.SYS"
+
+#include "common.ver"
index 223e76b..9f48df7 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        tcpip/routines.c\r
- * PURPOSE:     Common 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 <routines.h>\r
-#include <pool.h>\r
-\r
-\r
-UINT RandomNumber = 0x12345678;\r
-\r
-\r
-UINT Random(\r
-    VOID)\r
-/*\r
- * FUNCTION: Returns a pseudo random number\r
- * RETURNS:\r
- *     Pseudo random number\r
- */\r
-{\r
-    RandomNumber ^= 0x78563412;\r
-\r
-    return RandomNumber;\r
-}\r
-\r
-\r
-__inline INT SkipToOffset(\r
-    PNDIS_BUFFER Buffer,\r
-    UINT Offset,\r
-    PUCHAR *Data,\r
-    PUINT Size)\r
-/*\r
- * FUNCTION: Skip Offset bytes into a buffer chain\r
- * ARGUMENTS:\r
- *     Buffer = Pointer to NDIS buffer\r
- *     Offset = Number of bytes to skip\r
- *     Data   = Address of a pointer that on return will contain the\r
- *              address of the offset in the buffer\r
- *     Size   = Address of a pointer that on return will contain the\r
- *              size of the destination buffer\r
- * RETURNS:\r
- *     Offset into buffer, -1 if buffer chain was smaller than Offset bytes\r
- * NOTES:\r
- *     Buffer may be NULL\r
- */\r
-{\r
-    for (;;) {\r
-\r
-        if (!Buffer)\r
-            return -1;\r
-\r
-        NdisQueryBuffer(Buffer, Data, Size);\r
-\r
-        if (Offset < *Size) {\r
-            ((ULONG_PTR)*Data) += Offset;\r
-            *Size              -= Offset;\r
-            break;\r
-        }\r
-\r
-        Offset -= *Size;\r
-\r
-        NdisGetNextBuffer(Buffer, &Buffer);\r
-    }\r
-\r
-    return Offset;\r
-}\r
-\r
-\r
-UINT CopyBufferToBufferChain(\r
-    PNDIS_BUFFER DstBuffer,\r
-    UINT DstOffset,\r
-    PUCHAR SrcData,\r
-    UINT Length)\r
-/*\r
- * FUNCTION: Copies data from a buffer to an NDIS buffer chain\r
- * ARGUMENTS:\r
- *     DstBuffer = Pointer to destination NDIS buffer \r
- *     DstOffset = Destination start offset\r
- *     SrcData   = Pointer to source buffer\r
- *     Length    = Number of bytes to copy\r
- * RETURNS:\r
- *     Number of bytes copied to destination buffer\r
- * NOTES:\r
- *     The number of bytes copied may be limited by the destination\r
- *     buffer size\r
- */\r
-{\r
-    UINT BytesCopied, BytesToCopy, DstSize;\r
-    PUCHAR DstData;\r
-\r
-    TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcData (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcData, Length));\r
-\r
-    /* Skip DstOffset bytes in the destination buffer chain */\r
-    if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)\r
-        return 0;\r
-\r
-    /* Start copying the data */\r
-    BytesCopied = 0;\r
-    for (;;) {\r
-        BytesToCopy = MIN(DstSize, Length);\r
-\r
-        RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);\r
-        BytesCopied        += BytesToCopy;\r
-        (ULONG_PTR)SrcData += BytesToCopy;\r
-\r
-        Length -= BytesToCopy;\r
-        if (Length == 0)\r
-            break;\r
-\r
-        DstSize -= BytesToCopy;\r
-        if (DstSize == 0) {\r
-            /* No more bytes in desination buffer. Proceed to\r
-               the next buffer in the destination buffer chain */\r
-            NdisGetNextBuffer(DstBuffer, &DstBuffer);\r
-            if (!DstBuffer)\r
-                break;\r
-\r
-            NdisQueryBuffer(DstBuffer, &DstData, &DstSize);\r
-        }\r
-    }\r
-\r
-    return BytesCopied;\r
-}\r
-\r
-\r
-UINT CopyBufferChainToBuffer(\r
-    PUCHAR DstData,\r
-    PNDIS_BUFFER SrcBuffer,\r
-    UINT SrcOffset,\r
-    UINT Length)\r
-/*\r
- * FUNCTION: Copies data from an NDIS buffer chain to a buffer\r
- * ARGUMENTS:\r
- *     DstData   = Pointer to destination buffer\r
- *     SrcBuffer = Pointer to source NDIS buffer\r
- *     SrcOffset = Source start offset\r
- *     Length    = Number of bytes to copy\r
- * RETURNS:\r
- *     Number of bytes copied to destination buffer\r
- * NOTES:\r
- *     The number of bytes copied may be limited by the source\r
- *     buffer size\r
- */\r
-{\r
-    UINT BytesCopied, BytesToCopy, SrcSize;\r
-    PUCHAR SrcData;\r
-\r
-    TI_DbgPrint(DEBUG_BUFFER, ("DstData 0x%X  SrcBuffer 0x%X  SrcOffset 0x%X  Length %d\n",DstData,SrcBuffer, SrcOffset, Length));\r
-    \r
-    /* Skip SrcOffset bytes in the source buffer chain */\r
-    if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)\r
-        return 0;\r
-\r
-    /* Start copying the data */\r
-    BytesCopied = 0;\r
-    for (;;) {\r
-        BytesToCopy = MIN(SrcSize, Length);\r
-\r
-        TI_DbgPrint(DEBUG_BUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));\r
-\r
-        RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);\r
-        BytesCopied        += BytesToCopy;\r
-        (ULONG_PTR)DstData += BytesToCopy;\r
-\r
-        Length -= BytesToCopy;\r
-        if (Length == 0)\r
-            break;\r
-\r
-        SrcSize -= BytesToCopy;\r
-        if (SrcSize == 0) {\r
-            /* No more bytes in source buffer. Proceed to\r
-               the next buffer in the source buffer chain */\r
-            NdisGetNextBuffer(SrcBuffer, &SrcBuffer);\r
-            if (!SrcBuffer)\r
-                break;\r
-\r
-            NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);\r
-        }\r
-    }\r
-\r
-    return BytesCopied;\r
-}\r
-\r
-\r
-UINT CopyPacketToBuffer(\r
-    PUCHAR DstData,\r
-    PNDIS_PACKET SrcPacket,\r
-    UINT SrcOffset,\r
-    UINT Length)\r
-/*\r
- * FUNCTION: Copies data from an NDIS packet to a buffer\r
- * ARGUMENTS:\r
- *     DstData   = Pointer to destination buffer\r
- *     SrcPacket = Pointer to source NDIS packet\r
- *     SrcOffset = Source start offset\r
- *     Length    = Number of bytes to copy\r
- * RETURNS:\r
- *     Number of bytes copied to destination buffer\r
- * NOTES:\r
- *     The number of bytes copied may be limited by the source\r
- *     buffer size\r
- */\r
-{\r
-    PNDIS_BUFFER FirstBuffer;\r
-    PVOID Address;\r
-    UINT FirstLength;\r
-    UINT TotalLength;\r
-\r
-    TI_DbgPrint(DEBUG_BUFFER, ("DstData (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstData, SrcPacket, SrcOffset, Length));\r
-\r
-    NdisGetFirstBufferFromPacket(SrcPacket,\r
-                                 &FirstBuffer,\r
-                                 &Address,\r
-                                 &FirstLength,\r
-                                 &TotalLength);\r
-\r
-    return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length);\r
-}\r
-\r
-\r
-UINT CopyPacketToBufferChain(\r
-    PNDIS_BUFFER DstBuffer,\r
-    UINT DstOffset,\r
-    PNDIS_PACKET SrcPacket,\r
-    UINT SrcOffset,\r
-    UINT Length)\r
-/*\r
- * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain\r
- * ARGUMENTS:\r
- *     DstBuffer = Pointer to destination NDIS buffer\r
- *     DstOffset = Destination start offset\r
- *     SrcPacket = Pointer to source NDIS packet\r
- *     SrcOffset = Source start offset\r
- *     Length    = Number of bytes to copy\r
- * RETURNS:\r
- *     Number of bytes copied to destination buffer\r
- * NOTES:\r
- *     The number of bytes copied may be limited by the source and\r
- *     destination buffer sizes\r
- */\r
-{\r
-    PNDIS_BUFFER SrcBuffer;\r
-    PUCHAR DstData, SrcData;\r
-    UINT DstSize, SrcSize;\r
-    UINT Count, Total;\r
-\r
-    TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length));\r
-\r
-    /* Skip DstOffset bytes in the destination buffer chain */\r
-    NdisQueryBuffer(DstBuffer, &DstData, &DstSize);\r
-    if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)\r
-        return 0;\r
-\r
-    /* Skip SrcOffset bytes in the source packet */\r
-    NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, &SrcData, &SrcSize, &Total);\r
-    if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)\r
-        return 0;\r
-\r
-    /* Copy the data */\r
-    for (Total = 0;;) {\r
-        /* Find out how many bytes we can copy at one time */\r
-        if (Length < SrcSize)\r
-            Count = Length;\r
-        else\r
-            Count = SrcSize;\r
-        if (DstSize < Count)\r
-            Count = DstSize;\r
-\r
-        RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count);\r
-\r
-        Total  += Count;\r
-        Length -= Count;\r
-        if (Length == 0)\r
-            break;\r
-\r
-        DstSize -= Count;\r
-        if (DstSize == 0) {\r
-            /* No more bytes in destination buffer. Proceed to\r
-               the next buffer in the destination buffer chain */\r
-            NdisGetNextBuffer(DstBuffer, &DstBuffer);\r
-            if (!DstBuffer)\r
-                break;\r
-\r
-            NdisQueryBuffer(DstBuffer, &DstData, &DstSize);\r
-        }\r
-\r
-        SrcSize -= Count;\r
-        if (SrcSize == 0) {\r
-            /* No more bytes in source buffer. Proceed to\r
-               the next buffer in the source buffer chain */\r
-            NdisGetNextBuffer(SrcBuffer, &SrcBuffer);\r
-            if (!SrcBuffer)\r
-                break;\r
-\r
-            NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);\r
-        }\r
-    }\r
-\r
-    return Total;\r
-}\r
-\r
-\r
-VOID FreeNdisPacket(\r
-    PNDIS_PACKET Packet)\r
-/*\r
- * FUNCTION: Frees an NDIS packet\r
- * ARGUMENTS:\r
- *     Packet = Pointer to NDIS packet to be freed\r
- */\r
-{\r
-    PNDIS_BUFFER Buffer, NextBuffer;\r
-\r
-    TI_DbgPrint(DEBUG_BUFFER, ("Packet (0x%X)\n", Packet));\r
-\r
-    /* Free all the buffers in the packet first */\r
-    NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);\r
-    for (; Buffer != NULL; Buffer = NextBuffer) {\r
-        PVOID Data;\r
-        UINT Length;\r
-\r
-        NdisGetNextBuffer(Buffer, &NextBuffer);\r
-        NdisQueryBuffer(Buffer, &Data, &Length);\r
-        NdisFreeBuffer(Buffer);\r
-        ExFreePool(Data);\r
-    }\r
-\r
-    /* Finally free the NDIS packet discriptor */\r
-    NdisFreePacket(Packet);\r
-}\r
-\r
-\r
-PVOID AdjustPacket(\r
-    PNDIS_PACKET Packet,\r
-    UINT Available,\r
-    UINT Needed)\r
-/*\r
- * FUNCTION: Adjusts the amount of unused space at the beginning of the packet\r
- * ARGUMENTS:\r
- *     Packet    = Pointer to packet\r
- *     Available = Number of bytes available at start of first buffer\r
- *     Needed    = Number of bytes needed for the header\r
- * RETURNS:\r
- *     Pointer to start of packet\r
- */\r
-{\r
-    PNDIS_BUFFER NdisBuffer;\r
-    INT Adjust;\r
-\r
-    TI_DbgPrint(DEBUG_BUFFER, ("Available = %d, Needed = %d.\n", Available, Needed));\r
-\r
-    Adjust = Available - Needed;\r
-\r
-    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);\r
-\r
-    /* If Adjust is zero there is no need to adjust this packet as\r
-       there is no additional space at start the of first buffer */\r
-    if (Adjust != 0) {\r
-#if 0\r
-        (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust;\r
-        (ULONG_PTR)(NdisBuffer->StartVa)        += Adjust;\r
-        NdisBuffer->ByteCount                   -= Adjust;\r
-#else\r
-        (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust;\r
-        NdisBuffer->ByteOffset                  += Adjust;\r
-        NdisBuffer->ByteCount                   -= Adjust;\r
-#endif\r
-    }\r
-\r
-    return NdisBuffer->MappedSystemVa;\r
-}\r
-\r
-\r
-UINT ResizePacket(\r
-    PNDIS_PACKET Packet,\r
-    UINT Size)\r
-/*\r
- * FUNCTION: Resizes an NDIS packet\r
- * ARGUMENTS:\r
- *     Packet = Pointer to packet\r
- *     Size   = Number of bytes in first buffer\r
- * RETURNS:\r
- *     Previous size of first buffer\r
- */\r
-{\r
-    PNDIS_BUFFER NdisBuffer;\r
-    UINT OldSize;\r
-\r
-    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);\r
-\r
-    OldSize = NdisBuffer->ByteCount;\r
-\r
-    if (Size != OldSize)\r
-        NdisBuffer->ByteCount = Size;\r
-\r
-    return OldSize;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        tcpip/routines.c
+ * PURPOSE:     Common routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <routines.h>
+#include <pool.h>
+
+
+UINT RandomNumber = 0x12345678;
+
+
+UINT Random(
+    VOID)
+/*
+ * FUNCTION: Returns a pseudo random number
+ * RETURNS:
+ *     Pseudo random number
+ */
+{
+    RandomNumber ^= 0x78563412;
+
+    return RandomNumber;
+}
+
+
+__inline INT SkipToOffset(
+    PNDIS_BUFFER Buffer,
+    UINT Offset,
+    PUCHAR *Data,
+    PUINT Size)
+/*
+ * FUNCTION: Skip Offset bytes into a buffer chain
+ * ARGUMENTS:
+ *     Buffer = Pointer to NDIS buffer
+ *     Offset = Number of bytes to skip
+ *     Data   = Address of a pointer that on return will contain the
+ *              address of the offset in the buffer
+ *     Size   = Address of a pointer that on return will contain the
+ *              size of the destination buffer
+ * RETURNS:
+ *     Offset into buffer, -1 if buffer chain was smaller than Offset bytes
+ * NOTES:
+ *     Buffer may be NULL
+ */
+{
+    for (;;) {
+
+        if (!Buffer)
+            return -1;
+
+        NdisQueryBuffer(Buffer, Data, Size);
+
+        if (Offset < *Size) {
+            ((ULONG_PTR)*Data) += Offset;
+            *Size              -= Offset;
+            break;
+        }
+
+        Offset -= *Size;
+
+        NdisGetNextBuffer(Buffer, &Buffer);
+    }
+
+    return Offset;
+}
+
+
+UINT CopyBufferToBufferChain(
+    PNDIS_BUFFER DstBuffer,
+    UINT DstOffset,
+    PUCHAR SrcData,
+    UINT Length)
+/*
+ * FUNCTION: Copies data from a buffer to an NDIS buffer chain
+ * ARGUMENTS:
+ *     DstBuffer = Pointer to destination NDIS buffer 
+ *     DstOffset = Destination start offset
+ *     SrcData   = Pointer to source buffer
+ *     Length    = Number of bytes to copy
+ * RETURNS:
+ *     Number of bytes copied to destination buffer
+ * NOTES:
+ *     The number of bytes copied may be limited by the destination
+ *     buffer size
+ */
+{
+    UINT BytesCopied, BytesToCopy, DstSize;
+    PUCHAR DstData;
+
+    TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcData (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcData, Length));
+
+    /* Skip DstOffset bytes in the destination buffer chain */
+    if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
+        return 0;
+
+    /* Start copying the data */
+    BytesCopied = 0;
+    for (;;) {
+        BytesToCopy = MIN(DstSize, Length);
+
+        RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
+        BytesCopied        += BytesToCopy;
+        (ULONG_PTR)SrcData += BytesToCopy;
+
+        Length -= BytesToCopy;
+        if (Length == 0)
+            break;
+
+        DstSize -= BytesToCopy;
+        if (DstSize == 0) {
+            /* No more bytes in desination buffer. Proceed to
+               the next buffer in the destination buffer chain */
+            NdisGetNextBuffer(DstBuffer, &DstBuffer);
+            if (!DstBuffer)
+                break;
+
+            NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
+        }
+    }
+
+    return BytesCopied;
+}
+
+
+UINT CopyBufferChainToBuffer(
+    PUCHAR DstData,
+    PNDIS_BUFFER SrcBuffer,
+    UINT SrcOffset,
+    UINT Length)
+/*
+ * FUNCTION: Copies data from an NDIS buffer chain to a buffer
+ * ARGUMENTS:
+ *     DstData   = Pointer to destination buffer
+ *     SrcBuffer = Pointer to source NDIS buffer
+ *     SrcOffset = Source start offset
+ *     Length    = Number of bytes to copy
+ * RETURNS:
+ *     Number of bytes copied to destination buffer
+ * NOTES:
+ *     The number of bytes copied may be limited by the source
+ *     buffer size
+ */
+{
+    UINT BytesCopied, BytesToCopy, SrcSize;
+    PUCHAR SrcData;
+
+    TI_DbgPrint(DEBUG_BUFFER, ("DstData 0x%X  SrcBuffer 0x%X  SrcOffset 0x%X  Length %d\n",DstData,SrcBuffer, SrcOffset, Length));
+    
+    /* Skip SrcOffset bytes in the source buffer chain */
+    if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
+        return 0;
+
+    /* Start copying the data */
+    BytesCopied = 0;
+    for (;;) {
+        BytesToCopy = MIN(SrcSize, Length);
+
+        TI_DbgPrint(DEBUG_BUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));
+
+        RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
+        BytesCopied        += BytesToCopy;
+        (ULONG_PTR)DstData += BytesToCopy;
+
+        Length -= BytesToCopy;
+        if (Length == 0)
+            break;
+
+        SrcSize -= BytesToCopy;
+        if (SrcSize == 0) {
+            /* No more bytes in source buffer. Proceed to
+               the next buffer in the source buffer chain */
+            NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
+            if (!SrcBuffer)
+                break;
+
+            NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
+        }
+    }
+
+    return BytesCopied;
+}
+
+
+UINT CopyPacketToBuffer(
+    PUCHAR DstData,
+    PNDIS_PACKET SrcPacket,
+    UINT SrcOffset,
+    UINT Length)
+/*
+ * FUNCTION: Copies data from an NDIS packet to a buffer
+ * ARGUMENTS:
+ *     DstData   = Pointer to destination buffer
+ *     SrcPacket = Pointer to source NDIS packet
+ *     SrcOffset = Source start offset
+ *     Length    = Number of bytes to copy
+ * RETURNS:
+ *     Number of bytes copied to destination buffer
+ * NOTES:
+ *     The number of bytes copied may be limited by the source
+ *     buffer size
+ */
+{
+    PNDIS_BUFFER FirstBuffer;
+    PVOID Address;
+    UINT FirstLength;
+    UINT TotalLength;
+
+    TI_DbgPrint(DEBUG_BUFFER, ("DstData (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstData, SrcPacket, SrcOffset, Length));
+
+    NdisGetFirstBufferFromPacket(SrcPacket,
+                                 &FirstBuffer,
+                                 &Address,
+                                 &FirstLength,
+                                 &TotalLength);
+
+    return CopyBufferChainToBuffer(DstData, FirstBuffer, SrcOffset, Length);
+}
+
+
+UINT CopyPacketToBufferChain(
+    PNDIS_BUFFER DstBuffer,
+    UINT DstOffset,
+    PNDIS_PACKET SrcPacket,
+    UINT SrcOffset,
+    UINT Length)
+/*
+ * FUNCTION: Copies data from an NDIS packet to an NDIS buffer chain
+ * ARGUMENTS:
+ *     DstBuffer = Pointer to destination NDIS buffer
+ *     DstOffset = Destination start offset
+ *     SrcPacket = Pointer to source NDIS packet
+ *     SrcOffset = Source start offset
+ *     Length    = Number of bytes to copy
+ * RETURNS:
+ *     Number of bytes copied to destination buffer
+ * NOTES:
+ *     The number of bytes copied may be limited by the source and
+ *     destination buffer sizes
+ */
+{
+    PNDIS_BUFFER SrcBuffer;
+    PUCHAR DstData, SrcData;
+    UINT DstSize, SrcSize;
+    UINT Count, Total;
+
+    TI_DbgPrint(DEBUG_BUFFER, ("DstBuffer (0x%X)  DstOffset (0x%X)  SrcPacket (0x%X)  SrcOffset (0x%X)  Length (%d)\n", DstBuffer, DstOffset, SrcPacket, SrcOffset, Length));
+
+    /* Skip DstOffset bytes in the destination buffer chain */
+    NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
+    if (SkipToOffset(DstBuffer, DstOffset, &DstData, &DstSize) == -1)
+        return 0;
+
+    /* Skip SrcOffset bytes in the source packet */
+    NdisGetFirstBufferFromPacket(SrcPacket, &SrcBuffer, &SrcData, &SrcSize, &Total);
+    if (SkipToOffset(SrcBuffer, SrcOffset, &SrcData, &SrcSize) == -1)
+        return 0;
+
+    /* Copy the data */
+    for (Total = 0;;) {
+        /* Find out how many bytes we can copy at one time */
+        if (Length < SrcSize)
+            Count = Length;
+        else
+            Count = SrcSize;
+        if (DstSize < Count)
+            Count = DstSize;
+
+        RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, Count);
+
+        Total  += Count;
+        Length -= Count;
+        if (Length == 0)
+            break;
+
+        DstSize -= Count;
+        if (DstSize == 0) {
+            /* No more bytes in destination buffer. Proceed to
+               the next buffer in the destination buffer chain */
+            NdisGetNextBuffer(DstBuffer, &DstBuffer);
+            if (!DstBuffer)
+                break;
+
+            NdisQueryBuffer(DstBuffer, &DstData, &DstSize);
+        }
+
+        SrcSize -= Count;
+        if (SrcSize == 0) {
+            /* No more bytes in source buffer. Proceed to
+               the next buffer in the source buffer chain */
+            NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
+            if (!SrcBuffer)
+                break;
+
+            NdisQueryBuffer(SrcBuffer, &SrcData, &SrcSize);
+        }
+    }
+
+    return Total;
+}
+
+
+VOID FreeNdisPacket(
+    PNDIS_PACKET Packet)
+/*
+ * FUNCTION: Frees an NDIS packet
+ * ARGUMENTS:
+ *     Packet = Pointer to NDIS packet to be freed
+ */
+{
+    PNDIS_BUFFER Buffer, NextBuffer;
+
+    TI_DbgPrint(DEBUG_BUFFER, ("Packet (0x%X)\n", Packet));
+
+    /* Free all the buffers in the packet first */
+    NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
+    for (; Buffer != NULL; Buffer = NextBuffer) {
+        PVOID Data;
+        UINT Length;
+
+        NdisGetNextBuffer(Buffer, &NextBuffer);
+        NdisQueryBuffer(Buffer, &Data, &Length);
+        NdisFreeBuffer(Buffer);
+        ExFreePool(Data);
+    }
+
+    /* Finally free the NDIS packet discriptor */
+    NdisFreePacket(Packet);
+}
+
+
+PVOID AdjustPacket(
+    PNDIS_PACKET Packet,
+    UINT Available,
+    UINT Needed)
+/*
+ * FUNCTION: Adjusts the amount of unused space at the beginning of the packet
+ * ARGUMENTS:
+ *     Packet    = Pointer to packet
+ *     Available = Number of bytes available at start of first buffer
+ *     Needed    = Number of bytes needed for the header
+ * RETURNS:
+ *     Pointer to start of packet
+ */
+{
+    PNDIS_BUFFER NdisBuffer;
+    INT Adjust;
+
+    TI_DbgPrint(DEBUG_BUFFER, ("Available = %d, Needed = %d.\n", Available, Needed));
+
+    Adjust = Available - Needed;
+
+    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
+
+    /* If Adjust is zero there is no need to adjust this packet as
+       there is no additional space at start the of first buffer */
+    if (Adjust != 0) {
+#if 0
+        (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust;
+        (ULONG_PTR)(NdisBuffer->StartVa)        += Adjust;
+        NdisBuffer->ByteCount                   -= Adjust;
+#else
+        (ULONG_PTR)(NdisBuffer->MappedSystemVa) += Adjust;
+        NdisBuffer->ByteOffset                  += Adjust;
+        NdisBuffer->ByteCount                   -= Adjust;
+#endif
+    }
+
+    return NdisBuffer->MappedSystemVa;
+}
+
+
+UINT ResizePacket(
+    PNDIS_PACKET Packet,
+    UINT Size)
+/*
+ * FUNCTION: Resizes an NDIS packet
+ * ARGUMENTS:
+ *     Packet = Pointer to packet
+ *     Size   = Number of bytes in first buffer
+ * RETURNS:
+ *     Previous size of first buffer
+ */
+{
+    PNDIS_BUFFER NdisBuffer;
+    UINT OldSize;
+
+    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
+
+    OldSize = NdisBuffer->ByteCount;
+
+    if (Size != OldSize)
+        NdisBuffer->ByteCount = Size;
+
+    return OldSize;
+}
+
+/* EOF */
diff --git a/reactos/drivers/net/tcpip/tcpip/tcpip.def b/reactos/drivers/net/tcpip/tcpip/tcpip.def
new file mode 100644 (file)
index 0000000..136ec91
--- /dev/null
@@ -0,0 +1,32 @@
+; TCPIP.SYS - TCP/IP protocol driver
+
+LIBRARY tcpip.sys
+
+EXPORTS
+;FreeIprBuff
+;GetIFAndLink
+IPAddInterface
+;IPAllocBuff
+IPDelInterface
+;IPDelayedNdisReEnumerateBindings
+;IPDeregisterARP
+;IPDisableSniffer
+;IPEnableSniffer
+;IPFreeBuff
+;IPGetAddrType
+;IPGetBestInterface
+;IPGetInfo
+;IPInjectPkt
+;IPProxyNdisRequest
+;IPRegisterARP
+;IPRegisterProtocol
+;IPSetIPSecStatus
+;IPTransmit
+LookupRoute
+;LookupRouteInformation
+;SendICMPErr
+;SetIPSecPtr
+;UnSetIPSecPtr
+;UnSetIPSecSendPtr
+
+; EOF
index 901d426..4ff3f7f 100644 (file)
@@ -1,5 +1,5 @@
-DIRS= datagram \\r
-      rawip \\r
-      tcp \\r
-      udp\r
-\r
+DIRS= datagram \
+      rawip \
+      tcp \
+      udp
+
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index aef69b1..50cbe51 100644 (file)
@@ -1,13 +1,13 @@
-TARGETNAME=datagram\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
-SOURCES= datagram.c\r
-\r
-MSC_WARNING_LEVEL=/W3 /WX\r
-\r
+TARGETNAME=datagram
+TARGETPATH=..\..\objects
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
+
+SOURCES= datagram.c
+
+MSC_WARNING_LEVEL=/W3 /WX
+
index 9f792fe..ac9d48e 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        transport/datagram/datagram.c\r
- * PURPOSE:     Routines for sending and receiving datagrams\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- *   CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-#include <datagram.h>\r
-#include <routines.h>\r
-#include <transmit.h>\r
-#include <address.h>\r
-#include <route.h>\r
-#include <pool.h>\r
-\r
-\r
-/* Pending request queue */\r
-LIST_ENTRY DGPendingListHead;\r
-KSPIN_LOCK DGPendingListLock;\r
-/* Work queue item for pending requests */\r
-WORK_QUEUE_ITEM DGWorkItem;\r
-\r
-\r
-VOID DatagramWorker(\r
-    PVOID Context)\r
-/*\r
- * FUNCTION: Handles pending requests\r
- * ARGUMENTS:\r
- *     Context = Pointer to context information (unused)\r
- * NOTES:\r
- *     This routine is called after the driver has run out of resources.\r
- *     It processes send requests or shedules them to be processed\r
- */\r
-{\r
-    PLIST_ENTRY CurrentADFEntry;\r
-    PLIST_ENTRY CurrentSREntry;\r
-    PADDRESS_FILE CurrentADF;\r
-    PDATAGRAM_SEND_REQUEST CurrentSR;\r
-    KIRQL OldIrql1;\r
-    KIRQL OldIrql2;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    KeAcquireSpinLock(&DGPendingListLock, &OldIrql1);\r
-\r
-    CurrentADFEntry = DGPendingListHead.Flink;\r
-    while (CurrentADFEntry != &DGPendingListHead) {\r
-        RemoveEntryList(CurrentADFEntry);\r
-        CurrentADF = CONTAINING_RECORD(CurrentADFEntry,\r
-                                       ADDRESS_FILE,\r
-                                       ListEntry);\r
-\r
-        KeAcquireSpinLock(&CurrentADF->Lock, &OldIrql2);\r
-\r
-        if (AF_IS_BUSY(CurrentADF)) {\r
-            /* The send worker function is already running so we just\r
-               set the pending send flag on the address file object */\r
-\r
-            AF_SET_PENDING(CurrentADF, AFF_SEND);\r
-            KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);\r
-        } else {\r
-            if (!IsListEmpty(&CurrentADF->TransmitQueue)) {\r
-                /* The transmit queue is not empty. Dequeue a send\r
-                   request and process it */\r
-\r
-                CurrentSREntry = RemoveHeadList(&CurrentADF->TransmitQueue);\r
-                CurrentSR      = CONTAINING_RECORD(CurrentADFEntry,\r
-                                                   DATAGRAM_SEND_REQUEST,\r
-                                                   ListEntry);\r
-\r
-                KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);\r
-\r
-                DGSend(CurrentADF, CurrentSR);\r
-            } else\r
-                KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);\r
-        }\r
-        CurrentADFEntry = CurrentADFEntry->Flink;\r
-    }\r
-\r
-    KeReleaseSpinLock(&DGPendingListLock, OldIrql1);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-VOID SendDatagramComplete(\r
-    PVOID Context,\r
-    PNDIS_PACKET Packet,\r
-    NDIS_STATUS NdisStatus)\r
-/*\r
- * FUNCTION: Datagram transmit completion handler\r
- * ARGUMENTS:\r
- *     Context    = Pointer to context infomation (DATAGRAM_SEND_REQUEST)\r
- *     Packet     = Pointer to NDIS packet\r
- *     NdisStatus = Status of transmit operation\r
- * NOTES:\r
- *     This routine is called by IP when a datagram send completes.\r
- *     We shedule the out-of-resource worker function if there\r
- *     are pending address files in the queue\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-    ULONG BytesSent;\r
-    PVOID CompleteContext;\r
-    PNDIS_BUFFER NdisBuffer;\r
-    PDATAGRAM_SEND_REQUEST SendRequest;\r
-    DATAGRAM_COMPLETION_ROUTINE Complete;\r
-    BOOLEAN QueueWorkItem;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    SendRequest     = (PDATAGRAM_SEND_REQUEST)Context;\r
-    Complete        = SendRequest->Complete;\r
-    CompleteContext = SendRequest->Context;\r
-    BytesSent       = SendRequest->BufferSize;\r
-\r
-    /* Remove data buffer before releasing memory for packet buffers */\r
-    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);\r
-    NdisUnchainBufferAtBack(Packet, &NdisBuffer);\r
-    FreeNdisPacket(Packet);\r
-    DereferenceObject(SendRequest->RemoteAddress);\r
-    PoolFreeBuffer(SendRequest);\r
-\r
-    /* If there are pending send requests, shedule worker function */\r
-    KeAcquireSpinLock(&DGPendingListLock, &OldIrql);\r
-    QueueWorkItem = (!IsListEmpty(&DGPendingListHead));\r
-    KeReleaseSpinLock(&DGPendingListLock, OldIrql);\r
-    if (QueueWorkItem)\r
-        ExQueueWorkItem(&DGWorkItem, CriticalWorkQueue);\r
-\r
-    /* Call completion routine for send request */\r
-    (*Complete)(CompleteContext, NdisStatus, BytesSent);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-VOID DGSend(\r
-    PVOID Context,\r
-    PDATAGRAM_SEND_REQUEST SendRequest)\r
-/*\r
- * FUNCTION: Sends a datagram to IP layer\r
- * ARGUMENTS:\r
- *     Context     = Pointer to context information (ADDRESS_FILE)\r
- *     SendRequest = Pointer to send request\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-    NTSTATUS Status;\r
-    USHORT LocalPort;\r
-    PIP_PACKET IPPacket;\r
-    PROUTE_CACHE_NODE RCN;\r
-    PLIST_ENTRY CurrentEntry;\r
-    PADDRESS_FILE AddrFile = Context;\r
-    PADDRESS_ENTRY ADE;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    /* Get the information we need from the address file\r
-       now so we minimize the time we hold the spin lock */\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-    LocalPort = AddrFile->Port;\r
-    ADE       = AddrFile->ADE;\r
-    ReferenceObject(ADE);\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    /* Loop until there are no more send requests in the\r
-       transmit queue or until we run out of resources */\r
-    for (;;) {\r
-        Status = SendRequest->Build(SendRequest, ADE->Address, LocalPort, &IPPacket);\r
-        if (!NT_SUCCESS(Status)) {\r
-            KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-            /* An error occurred, enqueue the send request again and return */\r
-            InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry);\r
-            DereferenceObject(ADE);\r
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-            TI_DbgPrint(MIN_TRACE, ("Leaving (insufficient resources).\n"));\r
-            return;\r
-        }\r
-\r
-        /* Get a route to the destination address */\r
-        if (RouteGetRouteToDestination(SendRequest->RemoteAddress, ADE->NTE, &RCN) == IP_SUCCESS) {\r
-            /* Set completion routine and send the packet */\r
-            PC(IPPacket->NdisPacket)->Complete = SendDatagramComplete;\r
-            PC(IPPacket->NdisPacket)->Context  = SendRequest;\r
-            if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS)\r
-                SendDatagramComplete(SendRequest,\r
-                                     IPPacket->NdisPacket,\r
-                                     NDIS_STATUS_REQUEST_ABORTED);\r
-            /* We're done with the RCN */\r
-            DereferenceObject(RCN);\r
-        } else {\r
-            /* No route to destination */\r
-            /* FIXME: Which error code should we use here? */\r
-            TI_DbgPrint(MIN_TRACE, ("No route to destination address (0x%X).\n",\r
-                SendRequest->RemoteAddress->Address.IPv4Address));\r
-            SendDatagramComplete(SendRequest,\r
-                                 IPPacket->NdisPacket,\r
-                                 NDIS_STATUS_REQUEST_ABORTED);\r
-        }\r
-\r
-        PoolFreeBuffer(IPPacket);\r
-\r
-        /* Check transmit queue for more to send */\r
-\r
-        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-        if (!IsListEmpty(&AddrFile->TransmitQueue)) {\r
-            /* Transmit queue is not empty, process one more request */\r
-            CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);\r
-            SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);\r
-\r
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-        } else {\r
-            /* Transmit queue is empty */\r
-            AF_CLR_PENDING(AddrFile, AFF_SEND);\r
-            DereferenceObject(ADE);\r
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-            TI_DbgPrint(MAX_TRACE, ("Leaving (empty queue).\n"));\r
-            return;\r
-        }\r
-    }\r
-}\r
-\r
-\r
-VOID DGCancelSendRequest(\r
-    PADDRESS_FILE AddrFile,\r
-    PVOID Context)\r
-/*\r
- * FUNCTION: Cancels a datagram send request\r
- * ARGUMENTS:\r
- *     AddrFile = Pointer to address file of the request\r
- *     Context  = Pointer to context information for completion handler\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-    PLIST_ENTRY CurrentEntry;\r
-    PDATAGRAM_SEND_REQUEST Current = NULL;\r
-    BOOLEAN Found = FALSE;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    /* Search the request list for the specified request and remove it */\r
-    CurrentEntry = AddrFile->TransmitQueue.Flink;\r
-    while ((CurrentEntry != &AddrFile->TransmitQueue) && (!Found)) {\r
-           Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);\r
-        if (Context == Current->Context) {\r
-            /* We've found the request, now remove it from the queue */\r
-            RemoveEntryList(CurrentEntry);\r
-            AddrFile->RefCount--;\r
-            Found = TRUE;\r
-            break;\r
-        }\r
-        CurrentEntry = CurrentEntry->Flink;\r
-    }\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    if (Found) {\r
-        /* Complete the request and free its resources */\r
-        (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0);\r
-        PoolFreeBuffer(Current->RemoteAddress);\r
-        PoolFreeBuffer(Current);\r
-    } else {\r
-        TI_DbgPrint(MID_TRACE, ("Cannot find send request.\n"));\r
-    }\r
-}\r
-\r
-\r
-VOID DGCancelReceiveRequest(\r
-    PADDRESS_FILE AddrFile,\r
-    PVOID Context)\r
-/*\r
- * FUNCTION: Cancels a datagram receive request\r
- * ARGUMENTS:\r
- *     AddrFile = Pointer to address file of the request\r
- *     Context  = Pointer to context information for completion handler\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-    PLIST_ENTRY CurrentEntry;\r
-    PDATAGRAM_RECEIVE_REQUEST Current = NULL;\r
-    BOOLEAN Found = FALSE;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    /* Search the request list for the specified request and remove it */\r
-    CurrentEntry = AddrFile->ReceiveQueue.Flink;\r
-    while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {\r
-           Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);\r
-        if (Context == Current->Context) {\r
-            /* We've found the request, now remove it from the queue */\r
-            RemoveEntryList(CurrentEntry);\r
-            AddrFile->RefCount--;\r
-            Found = TRUE;\r
-            break;\r
-        }\r
-        CurrentEntry = CurrentEntry->Flink;\r
-    }\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    if (Found) {\r
-        /* Complete the request and free its resources */\r
-        (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0);\r
-        /* Remote address can be NULL if the caller wants to receive\r
-           packets sent from any address */\r
-        if (Current->RemoteAddress)\r
-            PoolFreeBuffer(Current->RemoteAddress);\r
-        PoolFreeBuffer(Current);\r
-    } else {\r
-        TI_DbgPrint(MID_TRACE, ("Cannot find receive request.\n"));\r
-    }\r
-}\r
-\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
- * FUNCTION: Sends a datagram to a remote address\r
- * ARGUMENTS:\r
- *     Request   = Pointer to TDI request\r
- *     ConnInfo  = Pointer to connection information\r
- *     Buffer    = Pointer to NDIS buffer with data\r
- *     DataSize  = Size in bytes of data to be sent\r
- *     Build     = Pointer to datagram build routine\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PADDRESS_FILE AddrFile;\r
-    KIRQL OldIrql;\r
-    NTSTATUS Status;\r
-    PDATAGRAM_SEND_REQUEST SendRequest = NULL;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    AddrFile = Request->Handle.AddressHandle;\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    if (AF_IS_VALID(AddrFile)) {\r
-        SendRequest = PoolAllocateBuffer(sizeof(DATAGRAM_SEND_REQUEST));\r
-        if (SendRequest) {\r
-            /* Initialize a send request */\r
-            Status = AddrGetAddress(ConnInfo->RemoteAddress,\r
-                &SendRequest->RemoteAddress, &SendRequest->RemotePort,\r
-                &AddrFile->AddrCache);\r
-            if (NT_SUCCESS(Status)) {\r
-                SendRequest->Buffer     = Buffer;\r
-                SendRequest->BufferSize = DataSize;\r
-                SendRequest->Complete   = Request->RequestNotifyObject;\r
-                SendRequest->Context    = Request->RequestContext;\r
-                SendRequest->Build      = Build;\r
-\r
-                if (AF_IS_BUSY(AddrFile)) {\r
-                    /* Queue send request on the transmit queue */\r
-                    InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry);\r
-\r
-                    /* Reference address file and set pending send request flag */\r
-                    AddrFile->RefCount++;\r
-                    AF_SET_PENDING(AddrFile, AFF_SEND);\r
-\r
-                    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-                    TI_DbgPrint(MAX_TRACE, ("Leaving (queued).\n"));\r
-                } else {\r
-                    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-                    /* Send the datagram */\r
-                    DGSend(AddrFile, SendRequest);\r
-\r
-                    TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));\r
-                }\r
-                return STATUS_PENDING;\r
-            }\r
-        } else\r
-            Status = STATUS_INSUFFICIENT_RESOURCES;\r
-    } else\r
-        Status = STATUS_ADDRESS_CLOSED;\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X)\n", Status));\r
-\r
-    return Status;\r
-}\r
-\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
- * FUNCTION: Attempts to receive a datagram from a remote address\r
- * ARGUMENTS:\r
- *     Request       = Pointer to TDI request\r
- *     ConnInfo      = Pointer to connection information\r
- *     Buffer        = Pointer to NDIS buffer chain to store received data\r
- *     ReceiveLength = Maximum size to use of buffer (0 if all can be used)\r
- *     ReceiveFlags  = Receive flags (None, Normal, Peek)\r
- *     ReturnInfo    = Pointer to structure for return information\r
- *     BytesReceive  = Pointer to structure for number of bytes received\r
- * RETURNS:\r
- *     Status of operation\r
- * NOTES:\r
- *     This is the high level interface for receiving datagrams\r
- */\r
-{\r
-    PADDRESS_FILE AddrFile;\r
-    KIRQL OldIrql;\r
-    NTSTATUS Status;\r
-    PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    AddrFile = Request->Handle.AddressHandle;\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    if (AF_IS_VALID(AddrFile)) {\r
-        ReceiveRequest = PoolAllocateBuffer(sizeof(DATAGRAM_RECEIVE_REQUEST));\r
-        if (ReceiveRequest) {\r
-            /* Initialize a receive request */\r
-\r
-            /* Extract the remote address filter from the request (if any) */\r
-            if (((ConnInfo->RemoteAddressLength != 0)) && (ConnInfo->RemoteAddress)) {\r
-                Status = AddrGetAddress(ConnInfo->RemoteAddress,\r
-                    &ReceiveRequest->RemoteAddress,\r
-                    &ReceiveRequest->RemotePort,\r
-                    &AddrFile->AddrCache);\r
-                if (!NT_SUCCESS(Status)) {\r
-                    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-                    PoolFreeBuffer(ReceiveRequest);\r
-                    return Status;\r
-                }\r
-            } else {\r
-                ReceiveRequest->RemotePort    = 0;\r
-                ReceiveRequest->RemoteAddress = NULL;\r
-            }\r
-            ReceiveRequest->ReturnInfo = ReturnInfo;\r
-            ReceiveRequest->Buffer     = Buffer;\r
-            /* If ReceiveLength is 0, the whole buffer is available to us */\r
-            ReceiveRequest->BufferSize = (ReceiveLength == 0) ?\r
-                MmGetMdlByteCount(Buffer) : ReceiveLength;\r
-            ReceiveRequest->Complete   = Request->RequestNotifyObject;\r
-            ReceiveRequest->Context    = Request->RequestContext;\r
-\r
-            /* Queue receive request */\r
-            InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry);\r
-\r
-            /* Reference address file and set pending receive request flag */\r
-            AddrFile->RefCount++;\r
-            AF_SET_PENDING(AddrFile, AFF_RECEIVE);\r
-\r
-            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-            TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));\r
-\r
-            return STATUS_PENDING;\r
-        } else\r
-            Status = STATUS_INSUFFICIENT_RESOURCES;\r
-    } else\r
-        Status = STATUS_INVALID_ADDRESS;\r
-\r
-    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status));\r
-\r
-    return Status;\r
-}\r
-\r
-\r
-NTSTATUS DGStartup(\r
-    VOID)\r
-/*\r
- * FUNCTION: Initializes the datagram subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    InitializeListHead(&DGPendingListHead);\r
-\r
-    KeInitializeSpinLock(&DGPendingListLock);\r
-\r
-    ExInitializeWorkItem(&DGWorkItem, DatagramWorker, NULL);\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS DGShutdown(\r
-    VOID)\r
-/*\r
- * FUNCTION: Shuts down the datagram subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        transport/datagram/datagram.c
+ * PURPOSE:     Routines for sending and receiving datagrams
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <datagram.h>
+#include <routines.h>
+#include <transmit.h>
+#include <address.h>
+#include <route.h>
+#include <pool.h>
+
+
+/* Pending request queue */
+LIST_ENTRY DGPendingListHead;
+KSPIN_LOCK DGPendingListLock;
+/* Work queue item for pending requests */
+WORK_QUEUE_ITEM DGWorkItem;
+
+
+VOID DatagramWorker(
+    PVOID Context)
+/*
+ * FUNCTION: Handles pending requests
+ * ARGUMENTS:
+ *     Context = Pointer to context information (unused)
+ * NOTES:
+ *     This routine is called after the driver has run out of resources.
+ *     It processes send requests or shedules them to be processed
+ */
+{
+    PLIST_ENTRY CurrentADFEntry;
+    PLIST_ENTRY CurrentSREntry;
+    PADDRESS_FILE CurrentADF;
+    PDATAGRAM_SEND_REQUEST CurrentSR;
+    KIRQL OldIrql1;
+    KIRQL OldIrql2;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    KeAcquireSpinLock(&DGPendingListLock, &OldIrql1);
+
+    CurrentADFEntry = DGPendingListHead.Flink;
+    while (CurrentADFEntry != &DGPendingListHead) {
+        RemoveEntryList(CurrentADFEntry);
+        CurrentADF = CONTAINING_RECORD(CurrentADFEntry,
+                                       ADDRESS_FILE,
+                                       ListEntry);
+
+        KeAcquireSpinLock(&CurrentADF->Lock, &OldIrql2);
+
+        if (AF_IS_BUSY(CurrentADF)) {
+            /* The send worker function is already running so we just
+               set the pending send flag on the address file object */
+
+            AF_SET_PENDING(CurrentADF, AFF_SEND);
+            KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);
+        } else {
+            if (!IsListEmpty(&CurrentADF->TransmitQueue)) {
+                /* The transmit queue is not empty. Dequeue a send
+                   request and process it */
+
+                CurrentSREntry = RemoveHeadList(&CurrentADF->TransmitQueue);
+                CurrentSR      = CONTAINING_RECORD(CurrentADFEntry,
+                                                   DATAGRAM_SEND_REQUEST,
+                                                   ListEntry);
+
+                KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);
+
+                DGSend(CurrentADF, CurrentSR);
+            } else
+                KeReleaseSpinLock(&CurrentADF->Lock, OldIrql2);
+        }
+        CurrentADFEntry = CurrentADFEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&DGPendingListLock, OldIrql1);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+VOID SendDatagramComplete(
+    PVOID Context,
+    PNDIS_PACKET Packet,
+    NDIS_STATUS NdisStatus)
+/*
+ * FUNCTION: Datagram transmit completion handler
+ * ARGUMENTS:
+ *     Context    = Pointer to context infomation (DATAGRAM_SEND_REQUEST)
+ *     Packet     = Pointer to NDIS packet
+ *     NdisStatus = Status of transmit operation
+ * NOTES:
+ *     This routine is called by IP when a datagram send completes.
+ *     We shedule the out-of-resource worker function if there
+ *     are pending address files in the queue
+ */
+{
+    KIRQL OldIrql;
+    ULONG BytesSent;
+    PVOID CompleteContext;
+    PNDIS_BUFFER NdisBuffer;
+    PDATAGRAM_SEND_REQUEST SendRequest;
+    DATAGRAM_COMPLETION_ROUTINE Complete;
+    BOOLEAN QueueWorkItem;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    SendRequest     = (PDATAGRAM_SEND_REQUEST)Context;
+    Complete        = SendRequest->Complete;
+    CompleteContext = SendRequest->Context;
+    BytesSent       = SendRequest->BufferSize;
+
+    /* Remove data buffer before releasing memory for packet buffers */
+    NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
+    NdisUnchainBufferAtBack(Packet, &NdisBuffer);
+    FreeNdisPacket(Packet);
+    DereferenceObject(SendRequest->RemoteAddress);
+    PoolFreeBuffer(SendRequest);
+
+    /* If there are pending send requests, shedule worker function */
+    KeAcquireSpinLock(&DGPendingListLock, &OldIrql);
+    QueueWorkItem = (!IsListEmpty(&DGPendingListHead));
+    KeReleaseSpinLock(&DGPendingListLock, OldIrql);
+    if (QueueWorkItem)
+        ExQueueWorkItem(&DGWorkItem, CriticalWorkQueue);
+
+    /* Call completion routine for send request */
+    (*Complete)(CompleteContext, NdisStatus, BytesSent);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+VOID DGSend(
+    PVOID Context,
+    PDATAGRAM_SEND_REQUEST SendRequest)
+/*
+ * FUNCTION: Sends a datagram to IP layer
+ * ARGUMENTS:
+ *     Context     = Pointer to context information (ADDRESS_FILE)
+ *     SendRequest = Pointer to send request
+ */
+{
+    KIRQL OldIrql;
+    NTSTATUS Status;
+    USHORT LocalPort;
+    PIP_PACKET IPPacket;
+    PROUTE_CACHE_NODE RCN;
+    PLIST_ENTRY CurrentEntry;
+    PADDRESS_FILE AddrFile = Context;
+    PADDRESS_ENTRY ADE;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Get the information we need from the address file
+       now so we minimize the time we hold the spin lock */
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+    LocalPort = AddrFile->Port;
+    ADE       = AddrFile->ADE;
+    ReferenceObject(ADE);
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    /* Loop until there are no more send requests in the
+       transmit queue or until we run out of resources */
+    for (;;) {
+        Status = SendRequest->Build(SendRequest, ADE->Address, LocalPort, &IPPacket);
+        if (!NT_SUCCESS(Status)) {
+            KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+            /* An error occurred, enqueue the send request again and return */
+            InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry);
+            DereferenceObject(ADE);
+            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+            TI_DbgPrint(MIN_TRACE, ("Leaving (insufficient resources).\n"));
+            return;
+        }
+
+        /* Get a route to the destination address */
+        if (RouteGetRouteToDestination(SendRequest->RemoteAddress, ADE->NTE, &RCN) == IP_SUCCESS) {
+            /* Set completion routine and send the packet */
+            PC(IPPacket->NdisPacket)->Complete = SendDatagramComplete;
+            PC(IPPacket->NdisPacket)->Context  = SendRequest;
+            if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS)
+                SendDatagramComplete(SendRequest,
+                                     IPPacket->NdisPacket,
+                                     NDIS_STATUS_REQUEST_ABORTED);
+            /* We're done with the RCN */
+            DereferenceObject(RCN);
+        } else {
+            /* No route to destination */
+            /* FIXME: Which error code should we use here? */
+            TI_DbgPrint(MIN_TRACE, ("No route to destination address (0x%X).\n",
+                SendRequest->RemoteAddress->Address.IPv4Address));
+            SendDatagramComplete(SendRequest,
+                                 IPPacket->NdisPacket,
+                                 NDIS_STATUS_REQUEST_ABORTED);
+        }
+
+        PoolFreeBuffer(IPPacket);
+
+        /* Check transmit queue for more to send */
+
+        KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+        if (!IsListEmpty(&AddrFile->TransmitQueue)) {
+            /* Transmit queue is not empty, process one more request */
+            CurrentEntry = RemoveHeadList(&AddrFile->TransmitQueue);
+            SendRequest  = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+
+            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+        } else {
+            /* Transmit queue is empty */
+            AF_CLR_PENDING(AddrFile, AFF_SEND);
+            DereferenceObject(ADE);
+            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+            TI_DbgPrint(MAX_TRACE, ("Leaving (empty queue).\n"));
+            return;
+        }
+    }
+}
+
+
+VOID DGCancelSendRequest(
+    PADDRESS_FILE AddrFile,
+    PVOID Context)
+/*
+ * FUNCTION: Cancels a datagram send request
+ * ARGUMENTS:
+ *     AddrFile = Pointer to address file of the request
+ *     Context  = Pointer to context information for completion handler
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PDATAGRAM_SEND_REQUEST Current = NULL;
+    BOOLEAN Found = FALSE;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    /* Search the request list for the specified request and remove it */
+    CurrentEntry = AddrFile->TransmitQueue.Flink;
+    while ((CurrentEntry != &AddrFile->TransmitQueue) && (!Found)) {
+           Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_SEND_REQUEST, ListEntry);
+        if (Context == Current->Context) {
+            /* We've found the request, now remove it from the queue */
+            RemoveEntryList(CurrentEntry);
+            AddrFile->RefCount--;
+            Found = TRUE;
+            break;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    if (Found) {
+        /* Complete the request and free its resources */
+        (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0);
+        PoolFreeBuffer(Current->RemoteAddress);
+        PoolFreeBuffer(Current);
+    } else {
+        TI_DbgPrint(MID_TRACE, ("Cannot find send request.\n"));
+    }
+}
+
+
+VOID DGCancelReceiveRequest(
+    PADDRESS_FILE AddrFile,
+    PVOID Context)
+/*
+ * FUNCTION: Cancels a datagram receive request
+ * ARGUMENTS:
+ *     AddrFile = Pointer to address file of the request
+ *     Context  = Pointer to context information for completion handler
+ */
+{
+    KIRQL OldIrql;
+    PLIST_ENTRY CurrentEntry;
+    PDATAGRAM_RECEIVE_REQUEST Current = NULL;
+    BOOLEAN Found = FALSE;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    /* Search the request list for the specified request and remove it */
+    CurrentEntry = AddrFile->ReceiveQueue.Flink;
+    while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {
+           Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
+        if (Context == Current->Context) {
+            /* We've found the request, now remove it from the queue */
+            RemoveEntryList(CurrentEntry);
+            AddrFile->RefCount--;
+            Found = TRUE;
+            break;
+        }
+        CurrentEntry = CurrentEntry->Flink;
+    }
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    if (Found) {
+        /* Complete the request and free its resources */
+        (*Current->Complete)(Current->Context, STATUS_CANCELLED, 0);
+        /* Remote address can be NULL if the caller wants to receive
+           packets sent from any address */
+        if (Current->RemoteAddress)
+            PoolFreeBuffer(Current->RemoteAddress);
+        PoolFreeBuffer(Current);
+    } else {
+        TI_DbgPrint(MID_TRACE, ("Cannot find receive request.\n"));
+    }
+}
+
+
+NTSTATUS DGSendDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize,
+    DATAGRAM_BUILD_ROUTINE Build)
+/*
+ * FUNCTION: Sends a datagram to a remote address
+ * ARGUMENTS:
+ *     Request   = Pointer to TDI request
+ *     ConnInfo  = Pointer to connection information
+ *     Buffer    = Pointer to NDIS buffer with data
+ *     DataSize  = Size in bytes of data to be sent
+ *     Build     = Pointer to datagram build routine
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PADDRESS_FILE AddrFile;
+    KIRQL OldIrql;
+    NTSTATUS Status;
+    PDATAGRAM_SEND_REQUEST SendRequest = NULL;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    AddrFile = Request->Handle.AddressHandle;
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    if (AF_IS_VALID(AddrFile)) {
+        SendRequest = PoolAllocateBuffer(sizeof(DATAGRAM_SEND_REQUEST));
+        if (SendRequest) {
+            /* Initialize a send request */
+            Status = AddrGetAddress(ConnInfo->RemoteAddress,
+                &SendRequest->RemoteAddress, &SendRequest->RemotePort,
+                &AddrFile->AddrCache);
+            if (NT_SUCCESS(Status)) {
+                SendRequest->Buffer     = Buffer;
+                SendRequest->BufferSize = DataSize;
+                SendRequest->Complete   = Request->RequestNotifyObject;
+                SendRequest->Context    = Request->RequestContext;
+                SendRequest->Build      = Build;
+
+                if (AF_IS_BUSY(AddrFile)) {
+                    /* Queue send request on the transmit queue */
+                    InsertTailList(&AddrFile->TransmitQueue, &SendRequest->ListEntry);
+
+                    /* Reference address file and set pending send request flag */
+                    AddrFile->RefCount++;
+                    AF_SET_PENDING(AddrFile, AFF_SEND);
+
+                    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+                    TI_DbgPrint(MAX_TRACE, ("Leaving (queued).\n"));
+                } else {
+                    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+                    /* Send the datagram */
+                    DGSend(AddrFile, SendRequest);
+
+                    TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+                }
+                return STATUS_PENDING;
+            }
+        } else
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+    } else
+        Status = STATUS_ADDRESS_CLOSED;
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X)\n", Status));
+
+    return Status;
+}
+
+
+NTSTATUS DGReceiveDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG ReceiveLength,
+    ULONG ReceiveFlags,
+    PTDI_CONNECTION_INFORMATION ReturnInfo,
+    PULONG BytesReceived)
+/*
+ * FUNCTION: Attempts to receive a datagram from a remote address
+ * ARGUMENTS:
+ *     Request       = Pointer to TDI request
+ *     ConnInfo      = Pointer to connection information
+ *     Buffer        = Pointer to NDIS buffer chain to store received data
+ *     ReceiveLength = Maximum size to use of buffer (0 if all can be used)
+ *     ReceiveFlags  = Receive flags (None, Normal, Peek)
+ *     ReturnInfo    = Pointer to structure for return information
+ *     BytesReceive  = Pointer to structure for number of bytes received
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     This is the high level interface for receiving datagrams
+ */
+{
+    PADDRESS_FILE AddrFile;
+    KIRQL OldIrql;
+    NTSTATUS Status;
+    PDATAGRAM_RECEIVE_REQUEST ReceiveRequest;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    AddrFile = Request->Handle.AddressHandle;
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    if (AF_IS_VALID(AddrFile)) {
+        ReceiveRequest = PoolAllocateBuffer(sizeof(DATAGRAM_RECEIVE_REQUEST));
+        if (ReceiveRequest) {
+            /* Initialize a receive request */
+
+            /* Extract the remote address filter from the request (if any) */
+            if (((ConnInfo->RemoteAddressLength != 0)) && (ConnInfo->RemoteAddress)) {
+                Status = AddrGetAddress(ConnInfo->RemoteAddress,
+                    &ReceiveRequest->RemoteAddress,
+                    &ReceiveRequest->RemotePort,
+                    &AddrFile->AddrCache);
+                if (!NT_SUCCESS(Status)) {
+                    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+                    PoolFreeBuffer(ReceiveRequest);
+                    return Status;
+                }
+            } else {
+                ReceiveRequest->RemotePort    = 0;
+                ReceiveRequest->RemoteAddress = NULL;
+            }
+            ReceiveRequest->ReturnInfo = ReturnInfo;
+            ReceiveRequest->Buffer     = Buffer;
+            /* If ReceiveLength is 0, the whole buffer is available to us */
+            ReceiveRequest->BufferSize = (ReceiveLength == 0) ?
+                MmGetMdlByteCount(Buffer) : ReceiveLength;
+            ReceiveRequest->Complete   = Request->RequestNotifyObject;
+            ReceiveRequest->Context    = Request->RequestContext;
+
+            /* Queue receive request */
+            InsertTailList(&AddrFile->ReceiveQueue, &ReceiveRequest->ListEntry);
+
+            /* Reference address file and set pending receive request flag */
+            AddrFile->RefCount++;
+            AF_SET_PENDING(AddrFile, AFF_RECEIVE);
+
+            KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+            TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+
+            return STATUS_PENDING;
+        } else
+            Status = STATUS_INSUFFICIENT_RESOURCES;
+    } else
+        Status = STATUS_INVALID_ADDRESS;
+
+    KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving with errors (0x%X).\n", Status));
+
+    return Status;
+}
+
+
+NTSTATUS DGStartup(
+    VOID)
+/*
+ * FUNCTION: Initializes the datagram subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    InitializeListHead(&DGPendingListHead);
+
+    KeInitializeSpinLock(&DGPendingListLock);
+
+    ExInitializeWorkItem(&DGWorkItem, DatagramWorker, NULL);
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS DGShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the datagram subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    return STATUS_SUCCESS;
+}
+
+
+/* EOF */
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index 1568428..7c92afe 100644 (file)
@@ -1,13 +1,13 @@
-TARGETNAME=rawip\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
-SOURCES= rawip.c\r
-\r
-MSC_WARNING_LEVEL=/W3 /WX\r
-\r
+TARGETNAME=rawip
+TARGETPATH=..\..\objects
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
+
+SOURCES= rawip.c
+
+MSC_WARNING_LEVEL=/W3 /WX
+
index 1aa4a65..bddebe2 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        transport/rawip/rawip.c\r
- * PURPOSE:     Raw IP 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 <datagram.h>\r
-#include <rawip.h>\r
-#include <pool.h>\r
-\r
-\r
-BOOLEAN RawIPInitialized = FALSE;\r
-\r
-\r
-NTSTATUS BuildRawIPPacket(\r
-    PVOID Context,\r
-    PIP_ADDRESS LocalAddress,\r
-    USHORT LocalPort,\r
-    PIP_PACKET *IPPacket)\r
-/*\r
- * FUNCTION: Builds an UDP packet\r
- * ARGUMENTS:\r
- *     Context      = Pointer to context information (DATAGRAM_SEND_REQUEST)\r
- *     LocalAddress = Pointer to our local address (NULL)\r
- *     LocalPort    = The port we send this datagram from (0)\r
- *     IPPacket     = Address of pointer to IP packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PIP_PACKET Packet;\r
-    NDIS_STATUS NdisStatus;\r
-    PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;\r
-\r
-    /* Prepare packet */\r
-    Packet = PoolAllocateBuffer(sizeof(IP_PACKET));\r
-    if (!Packet)\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-\r
-    RtlZeroMemory(Packet, sizeof(IP_PACKET));\r
-    Packet->RefCount   = 1;\r
-    Packet->TotalSize  = SendRequest->BufferSize;\r
-\r
-    /* Allocate NDIS packet */\r
-    NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool);\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        PoolFreeBuffer(Packet);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    /* Chain buffer to packet */\r
-    NdisChainBufferAtFront(Packet->NdisPacket, SendRequest->Buffer);\r
-\r
-    *IPPacket = Packet;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS RawIPSendDatagram(\r
-    PTDI_REQUEST Request,\r
-    PTDI_CONNECTION_INFORMATION ConnInfo,\r
-    PNDIS_BUFFER Buffer,\r
-    ULONG DataSize)\r
-/*\r
- * FUNCTION: Sends a raw IP datagram to a remote address\r
- * ARGUMENTS:\r
- *     Request   = Pointer to TDI request\r
- *     ConnInfo  = Pointer to connection information\r
- *     Buffer    = Pointer to NDIS buffer with data\r
- *     DataSize  = Size in bytes of data to be sent\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    return DGSendDatagram(Request, ConnInfo,\r
-        Buffer, DataSize, BuildRawIPPacket);\r
-}\r
-\r
-\r
-NTSTATUS RawIPStartup(\r
-    VOID)\r
-/*\r
- * FUNCTION: Initializes the Raw IP subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    RawIPInitialized = TRUE;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS RawIPShutdown(\r
-    VOID)\r
-/*\r
- * FUNCTION: Shuts down the Raw IP subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    if (!RawIPInitialized)\r
-        return STATUS_SUCCESS;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        transport/rawip/rawip.c
+ * PURPOSE:     Raw IP routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <datagram.h>
+#include <rawip.h>
+#include <pool.h>
+
+
+BOOLEAN RawIPInitialized = FALSE;
+
+
+NTSTATUS BuildRawIPPacket(
+    PVOID Context,
+    PIP_ADDRESS LocalAddress,
+    USHORT LocalPort,
+    PIP_PACKET *IPPacket)
+/*
+ * FUNCTION: Builds an UDP packet
+ * ARGUMENTS:
+ *     Context      = Pointer to context information (DATAGRAM_SEND_REQUEST)
+ *     LocalAddress = Pointer to our local address (NULL)
+ *     LocalPort    = The port we send this datagram from (0)
+ *     IPPacket     = Address of pointer to IP packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIP_PACKET Packet;
+    NDIS_STATUS NdisStatus;
+    PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;
+
+    /* Prepare packet */
+    Packet = PoolAllocateBuffer(sizeof(IP_PACKET));
+    if (!Packet)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    RtlZeroMemory(Packet, sizeof(IP_PACKET));
+    Packet->RefCount   = 1;
+    Packet->TotalSize  = SendRequest->BufferSize;
+
+    /* Allocate NDIS packet */
+    NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        PoolFreeBuffer(Packet);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Chain buffer to packet */
+    NdisChainBufferAtFront(Packet->NdisPacket, SendRequest->Buffer);
+
+    *IPPacket = Packet;
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS RawIPSendDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize)
+/*
+ * FUNCTION: Sends a raw IP datagram to a remote address
+ * ARGUMENTS:
+ *     Request   = Pointer to TDI request
+ *     ConnInfo  = Pointer to connection information
+ *     Buffer    = Pointer to NDIS buffer with data
+ *     DataSize  = Size in bytes of data to be sent
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    return DGSendDatagram(Request, ConnInfo,
+        Buffer, DataSize, BuildRawIPPacket);
+}
+
+
+NTSTATUS RawIPStartup(
+    VOID)
+/*
+ * FUNCTION: Initializes the Raw IP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    RawIPInitialized = TRUE;
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS RawIPShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the Raw IP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    if (!RawIPInitialized)
+        return STATUS_SUCCESS;
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index 9c3e674..82d019f 100644 (file)
@@ -1,13 +1,13 @@
-TARGETNAME=tcp\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
-SOURCES= tcp.c\r
-\r
-MSC_WARNING_LEVEL=/W3 /WX\r
-\r
+TARGETNAME=tcp
+TARGETPATH=..\..\objects
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
+
+SOURCES= tcp.c
+
+MSC_WARNING_LEVEL=/W3 /WX
+
index 11a6ca2..eec133c 100644 (file)
@@ -1,44 +1,44 @@
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        transport/tcp/tcp.c\r
- * PURPOSE:     Transmission Control Protocol\r
- * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)\r
- * REVISIONS:\r
- *   CSH 01/08-2000 Created\r
- */\r
-#include <tcpip.h>\r
-\r
-\r
-BOOLEAN TCPInitialized = FALSE;\r
-\r
-\r
-NTSTATUS TCPStartup(\r
-    VOID)\r
-/*\r
- * FUNCTION: Initializes the TCP subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    TCPInitialized = TRUE;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS TCPShutdown(\r
-    VOID)\r
-/*\r
- * FUNCTION: Shuts down the TCP subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    if (!TCPInitialized)\r
-        return STATUS_SUCCESS;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        transport/tcp/tcp.c
+ * PURPOSE:     Transmission Control Protocol
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+
+
+BOOLEAN TCPInitialized = FALSE;
+
+
+NTSTATUS TCPStartup(
+    VOID)
+/*
+ * FUNCTION: Initializes the TCP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TCPInitialized = TRUE;
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS TCPShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the TCP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    if (!TCPInitialized)
+        return STATUS_SUCCESS;
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
index 9c985f5..5818975 100644 (file)
@@ -1,7 +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
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
index ed16c82..ebbec23 100644 (file)
@@ -1,12 +1,12 @@
-TARGETNAME=udp\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
-SOURCES= udp.c\r
-\r
-MSC_WARNING_LEVEL=/W3 /WX\r
+TARGETNAME=udp
+TARGETPATH=..\..\objects
+TARGETTYPE=LIBRARY
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
+
+SOURCES= udp.c
+
+MSC_WARNING_LEVEL=/W3 /WX
index da65746..10e931b 100644 (file)
-/*\r
- * COPYRIGHT:   See COPYING in the top level directory\r
- * PROJECT:     ReactOS TCP/IP protocol driver\r
- * FILE:        transport/udp/udp.c\r
- * PURPOSE:     User Datagram 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 <udp.h>\r
-#include <routines.h>\r
-#include <transmit.h>\r
-#include <datagram.h>\r
-#include <checksum.h>\r
-#include <address.h>\r
-#include <pool.h>\r
-\r
-\r
-BOOLEAN UDPInitialized = FALSE;\r
-\r
-\r
-NTSTATUS AddUDPHeaderIPv4(\r
-    PDATAGRAM_SEND_REQUEST SendRequest,\r
-    PIP_ADDRESS LocalAddress,\r
-    USHORT LocalPort,\r
-    PIP_PACKET IPPacket)\r
-/*\r
- * FUNCTION: Adds an IPv4 and UDP header to an IP packet\r
- * ARGUMENTS:\r
- *     SendRequest  = Pointer to send request\r
- *     LocalAddress = Pointer to our local address\r
- *     LocalPort    = The port we send this datagram from\r
- *     IPPacket     = Pointer to IP packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    PIPv4_HEADER IPHeader;\r
-    PUDP_HEADER UDPHeader;\r
-    PVOID Header;\r
-       ULONG BufferSize;\r
-    NDIS_STATUS NdisStatus;\r
-    PNDIS_BUFFER HeaderBuffer;\r
-\r
-       BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(UDP_HEADER);\r
-    Header     = PoolAllocateBuffer(BufferSize);\r
-\r
-    if (!Header) {\r
-        TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n"));\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    /* Allocate NDIS buffer for maximum Link level, IP and UDP header */\r
-    NdisAllocateBuffer(&NdisStatus,\r
-                       &HeaderBuffer,\r
-                       GlobalBufferPool,\r
-                       Header,\r
-                       BufferSize);\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus));\r
-        PoolFreeBuffer(Header);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    /* Chain header at front of NDIS packet */\r
-    NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer);\r
-    \r
-       IPPacket->Header     = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize);\r
-    IPPacket->HeaderSize = 20;\r
-\r
-    /* Build IPv4 header */\r
-    IPHeader = (PIPv4_HEADER)IPPacket->Header;\r
-    /* Version = 4, Length = 5 DWORDs */\r
-    IPHeader->VerIHL = 0x45;\r
-    /* Normal Type-of-Service */\r
-    IPHeader->Tos = 0;\r
-    /* Length of header and data */\r
-    IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);\r
-    /* Identification */\r
-    IPHeader->Id = 0;\r
-    /* One fragment at offset 0 */\r
-    IPHeader->FlagsFragOfs = 0;\r
-    /* Time-to-Live is 128 */\r
-    IPHeader->Ttl = 128;\r
-    /* User Datagram Protocol */\r
-    IPHeader->Protocol = IPPROTO_UDP;\r
-    /* Checksum is 0 (for later calculation of this) */\r
-    IPHeader->Checksum = 0;\r
-    /* Source address */\r
-    IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;\r
-    /* Destination address. FIXME: IPv4 only */\r
-    IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address;\r
-\r
-    /* Build UDP header */\r
-    UDPHeader = (PUDP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER));\r
-    /* Port values are already big-endian values */\r
-    UDPHeader->SourcePort = LocalPort;\r
-    UDPHeader->DestPort   = SendRequest->RemotePort;\r
-    /* FIXME: Calculate UDP checksum and put it in UDP header */\r
-    UDPHeader->Checksum   = 0;\r
-    /* Length of UDP header and data */\r
-    UDPHeader->Length     = WH2N((USHORT)IPPacket->TotalSize - IPPacket->HeaderSize);\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS BuildUDPPacket(\r
-    PVOID Context,\r
-    PIP_ADDRESS LocalAddress,\r
-    USHORT LocalPort,\r
-    PIP_PACKET *IPPacket)\r
-/*\r
- * FUNCTION: Builds an UDP packet\r
- * ARGUMENTS:\r
- *     Context      = Pointer to context information (DATAGRAM_SEND_REQUEST)\r
- *     LocalAddress = Pointer to our local address\r
- *     LocalPort    = The port we send this datagram from\r
- *     IPPacket     = Address of pointer to IP packet\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    NTSTATUS Status;\r
-    PIP_PACKET Packet;\r
-    NDIS_STATUS NdisStatus;\r
-    PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    /* Prepare packet */\r
-    Packet = PoolAllocateBuffer(sizeof(IP_PACKET));\r
-    if (!Packet) {\r
-        TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet.\n"));\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    RtlZeroMemory(Packet, sizeof(IP_PACKET));\r
-    Packet->RefCount   = 1;\r
-    Packet->TotalSize  = sizeof(IPv4_HEADER) +\r
-                         sizeof(UDP_HEADER)  +\r
-                         SendRequest->BufferSize;\r
-\r
-    /* Allocate NDIS packet */\r
-    NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool);\r
-    if (NdisStatus != NDIS_STATUS_SUCCESS) {\r
-        TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS packet. NdisStatus = (0x%X)\n", NdisStatus));\r
-        PoolFreeBuffer(Packet);\r
-        return STATUS_INSUFFICIENT_RESOURCES;\r
-    }\r
-\r
-    switch (SendRequest->RemoteAddress->Type) {\r
-    case IP_ADDRESS_V4:\r
-        Status = AddUDPHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet);\r
-        break;\r
-    case IP_ADDRESS_V6:\r
-        /* FIXME: Support IPv6 */\r
-        TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n"));\r
-    default:\r
-        Status = STATUS_UNSUCCESSFUL;\r
-        break;\r
-    }\r
-    if (!NT_SUCCESS(Status)) {\r
-        TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n", Status));\r
-        NdisFreePacket(Packet->NdisPacket);\r
-        PoolFreeBuffer(Packet);\r
-        return Status;\r
-    }\r
-\r
-    /* Chain data after header */\r
-    NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer);\r
-\r
-    *IPPacket = Packet;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-VOID DeliverUDPData(\r
-    PADDRESS_FILE AddrFile,\r
-    PIP_ADDRESS Address,\r
-    PIP_PACKET IPPacket,\r
-    UINT DataSize)\r
-/*\r
- * FUNCTION: Delivers UDP data to a user\r
- * ARGUMENTS:\r
- *     AddrFile = Address file to deliver data to\r
- *     Address  = Remote address the packet came from\r
- *     IPPacket = Pointer to IP packet to deliver\r
- *     DataSize = Number of bytes in data area\r
- * NOTES:\r
- *     If there is a receive request, then we copy the data to the\r
- *     buffer supplied by the user and complete the receive request.\r
- *     If no suitable receive request exists, then we call the event\r
- *     handler if it exists, otherwise we drop the packet.\r
- */\r
-{\r
-    KIRQL OldIrql;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);\r
-\r
-    if (!IsListEmpty(&AddrFile->ReceiveQueue)) {\r
-        PLIST_ENTRY CurrentEntry;\r
-        PDATAGRAM_RECEIVE_REQUEST Current;\r
-        BOOLEAN Found;\r
-\r
-        /* Search receive request list to find a match */\r
-        Found = FALSE;\r
-        CurrentEntry = AddrFile->ReceiveQueue.Flink;\r
-        while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {\r
-            Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);\r
-            if (!Current->RemoteAddress)\r
-                Found = TRUE;\r
-            else if (AddrIsEqual(Address, Current->RemoteAddress))\r
-                Found = TRUE;\r
-\r
-            if (Found) {\r
-                /* FIXME: Maybe we should check if the buffer of this\r
-                   receive request is large enough and if not, search\r
-                   for another. Also a 'best fit' strategy could be used. */\r
-\r
-                /* Remove the request from the queue */\r
-                RemoveEntryList(&Current->ListEntry);\r
-                AddrFile->RefCount--;\r
-                break;\r
-            }\r
-            CurrentEntry = CurrentEntry->Flink;\r
-        }\r
-\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-        if (Found) {\r
-            /* Copy the data into buffer provided by the user */\r
-            CopyBufferToBufferChain(Current->Buffer,\r
-                                    0,\r
-                                    IPPacket->Data,\r
-                                    DataSize);\r
-\r
-            /* Complete the receive request */\r
-            (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize);\r
-\r
-            /* Finally free the receive request */\r
-            if (Current->RemoteAddress)\r
-                PoolFreeBuffer(Current->RemoteAddress);\r
-            PoolFreeBuffer(Current);\r
-        }\r
-    } else {\r
-        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);\r
-\r
-        /* FIXME: Call event handler */\r
-        TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));\r
-    }\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-NTSTATUS UDPSendDatagram(\r
-    PTDI_REQUEST Request,\r
-    PTDI_CONNECTION_INFORMATION ConnInfo,\r
-    PNDIS_BUFFER Buffer,\r
-    ULONG DataSize)\r
-/*\r
- * FUNCTION: Sends an UDP datagram to a remote address\r
- * ARGUMENTS:\r
- *     Request   = Pointer to TDI request\r
- *     ConnInfo  = Pointer to connection information\r
- *     Buffer    = Pointer to NDIS buffer with data\r
- *     DataSize  = Size in bytes of data to be sent\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    return DGSendDatagram(Request,\r
-                          ConnInfo,\r
-                          Buffer,\r
-                          DataSize,\r
-                          BuildUDPPacket);\r
-}\r
-\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
- * FUNCTION: Attempts to receive an UDP datagram from a remote address\r
- * ARGUMENTS:\r
- *     Request       = Pointer to TDI request\r
- *     ConnInfo      = Pointer to connection information\r
- *     Buffer        = Pointer to NDIS buffer chain to store received data\r
- *     ReceiveLength = Maximum size to use of buffer, 0 if all can be used\r
- *     ReceiveFlags  = Receive flags (None, Normal, Peek)\r
- *     ReturnInfo    = Pointer to structure for return information\r
- *     BytesReceive  = Pointer to structure for number of bytes received\r
- * RETURNS:\r
- *     Status of operation\r
- * NOTES:\r
- *     This is the high level interface for receiving UDP datagrams\r
- */\r
-{\r
-    return DGReceiveDatagram(Request,\r
-                             ConnInfo,\r
-                             Buffer,\r
-                             ReceiveLength,\r
-                             ReceiveFlags,\r
-                             ReturnInfo,\r
-                             BytesReceived);\r
-}\r
-\r
-\r
-VOID UDPReceive(\r
-    PNET_TABLE_ENTRY NTE,\r
-    PIP_PACKET IPPacket)\r
-/*\r
- * FUNCTION: Receives and queues a UDP datagram\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 is the low level interface for receiving UDP datagrams. It strips\r
- *     the UDP header from a packet and delivers the data to anyone that wants it\r
- */\r
-{\r
-    AF_SEARCH SearchContext;\r
-    PIPv4_HEADER IPv4Header;\r
-    PADDRESS_FILE AddrFile;\r
-    PUDP_HEADER UDPHeader;\r
-    PIP_ADDRESS DstAddress;\r
-    UINT DataSize, i;\r
-\r
-    TI_DbgPrint(MAX_TRACE, ("Called.\n"));\r
-\r
-    switch (IPPacket->Type) {\r
-    /* IPv4 packet */\r
-    case IP_ADDRESS_V4:\r
-        IPv4Header = IPPacket->Header;\r
-        DstAddress = &IPPacket->DstAddr;\r
-        break;\r
-\r
-    /* IPv6 packet */\r
-    case IP_ADDRESS_V6:\r
-        TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize));\r
-\r
-        /* FIXME: IPv6 is not supported */\r
-        return;\r
-    }\r
-\r
-    UDPHeader = (PUDP_HEADER)IPPacket->Data;\r
-\r
-    /* FIXME: Calculate and validate UDP checksum */\r
-\r
-    /* Sanity checks */\r
-    i = WH2N(UDPHeader->Length);\r
-    if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) {\r
-        /* Incorrect or damaged packet received, discard it */\r
-        TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n"));\r
-        return;\r
-    }\r
-\r
-    DataSize = i - sizeof(UDP_HEADER);\r
-\r
-    /* Go to UDP data area */\r
-    (ULONG_PTR)IPPacket->Data += sizeof(UDP_HEADER);\r
-\r
-    /* Locate a receive request on destination address file object\r
-       and deliver the packet if one is found. If there is no receive\r
-       request on the address file object, call the associated receive\r
-       handler. If no receive handler is registered, drop the packet */\r
-\r
-    AddrFile = AddrSearchFirst(DstAddress,\r
-                               UDPHeader->DestPort,\r
-                               IPPROTO_UDP,\r
-                               &SearchContext);\r
-    if (AddrFile) {\r
-        do {\r
-            DeliverUDPData(AddrFile,\r
-                           DstAddress,\r
-                           IPPacket,\r
-                           DataSize);\r
-        } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);\r
-    } else {\r
-        /* There are no open address files that will take this datagram */\r
-        /* FIXME: IPv4 only */\r
-        TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",\r
-            DN2H(DstAddress->Address.IPv4Address)));\r
-\r
-        /* FIXME: Send ICMP reply */\r
-    }\r
-    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));\r
-}\r
-\r
-\r
-NTSTATUS UDPStartup(\r
-    VOID)\r
-/*\r
- * FUNCTION: Initializes the UDP subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));\r
-\r
-    /* Register this protocol with IP layer */\r
-    IPRegisterProtocol(IPPROTO_UDP, UDPReceive);\r
-\r
-    UDPInitialized = TRUE;\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-\r
-NTSTATUS UDPShutdown(\r
-    VOID)\r
-/*\r
- * FUNCTION: Shuts down the UDP subsystem\r
- * RETURNS:\r
- *     Status of operation\r
- */\r
-{\r
-    if (!UDPInitialized)\r
-        return STATUS_SUCCESS;\r
-\r
-    /* Deregister this protocol with IP layer */\r
-    IPRegisterProtocol(IPPROTO_UDP, NULL);\r
-\r
-    return STATUS_SUCCESS;\r
-}\r
-\r
-/* EOF */\r
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TCP/IP protocol driver
+ * FILE:        transport/udp/udp.c
+ * PURPOSE:     User Datagram Protocol routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tcpip.h>
+#include <udp.h>
+#include <routines.h>
+#include <transmit.h>
+#include <datagram.h>
+#include <checksum.h>
+#include <address.h>
+#include <pool.h>
+
+
+BOOLEAN UDPInitialized = FALSE;
+
+
+NTSTATUS AddUDPHeaderIPv4(
+    PDATAGRAM_SEND_REQUEST SendRequest,
+    PIP_ADDRESS LocalAddress,
+    USHORT LocalPort,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Adds an IPv4 and UDP header to an IP packet
+ * ARGUMENTS:
+ *     SendRequest  = Pointer to send request
+ *     LocalAddress = Pointer to our local address
+ *     LocalPort    = The port we send this datagram from
+ *     IPPacket     = Pointer to IP packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIPv4_HEADER IPHeader;
+    PUDP_HEADER UDPHeader;
+    PVOID Header;
+       ULONG BufferSize;
+    NDIS_STATUS NdisStatus;
+    PNDIS_BUFFER HeaderBuffer;
+
+       BufferSize = MaxLLHeaderSize + sizeof(IPv4_HEADER) + sizeof(UDP_HEADER);
+    Header     = PoolAllocateBuffer(BufferSize);
+
+    if (!Header) {
+        TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Allocate NDIS buffer for maximum Link level, IP and UDP header */
+    NdisAllocateBuffer(&NdisStatus,
+                       &HeaderBuffer,
+                       GlobalBufferPool,
+                       Header,
+                       BufferSize);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus));
+        PoolFreeBuffer(Header);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Chain header at front of NDIS packet */
+    NdisChainBufferAtFront(IPPacket->NdisPacket, HeaderBuffer);
+    
+       IPPacket->Header     = (PVOID)((ULONG_PTR)Header + MaxLLHeaderSize);
+    IPPacket->HeaderSize = 20;
+
+    /* Build IPv4 header */
+    IPHeader = (PIPv4_HEADER)IPPacket->Header;
+    /* Version = 4, Length = 5 DWORDs */
+    IPHeader->VerIHL = 0x45;
+    /* Normal Type-of-Service */
+    IPHeader->Tos = 0;
+    /* Length of header and data */
+    IPHeader->TotalLength = WH2N((USHORT)IPPacket->TotalSize);
+    /* Identification */
+    IPHeader->Id = 0;
+    /* One fragment at offset 0 */
+    IPHeader->FlagsFragOfs = 0;
+    /* Time-to-Live is 128 */
+    IPHeader->Ttl = 128;
+    /* User Datagram Protocol */
+    IPHeader->Protocol = IPPROTO_UDP;
+    /* Checksum is 0 (for later calculation of this) */
+    IPHeader->Checksum = 0;
+    /* Source address */
+    IPHeader->SrcAddr = LocalAddress->Address.IPv4Address;
+    /* Destination address. FIXME: IPv4 only */
+    IPHeader->DstAddr = SendRequest->RemoteAddress->Address.IPv4Address;
+
+    /* Build UDP header */
+    UDPHeader = (PUDP_HEADER)((ULONG_PTR)IPHeader + sizeof(IPv4_HEADER));
+    /* Port values are already big-endian values */
+    UDPHeader->SourcePort = LocalPort;
+    UDPHeader->DestPort   = SendRequest->RemotePort;
+    /* FIXME: Calculate UDP checksum and put it in UDP header */
+    UDPHeader->Checksum   = 0;
+    /* Length of UDP header and data */
+    UDPHeader->Length     = WH2N((USHORT)IPPacket->TotalSize - IPPacket->HeaderSize);
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS BuildUDPPacket(
+    PVOID Context,
+    PIP_ADDRESS LocalAddress,
+    USHORT LocalPort,
+    PIP_PACKET *IPPacket)
+/*
+ * FUNCTION: Builds an UDP packet
+ * ARGUMENTS:
+ *     Context      = Pointer to context information (DATAGRAM_SEND_REQUEST)
+ *     LocalAddress = Pointer to our local address
+ *     LocalPort    = The port we send this datagram from
+ *     IPPacket     = Address of pointer to IP packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NTSTATUS Status;
+    PIP_PACKET Packet;
+    NDIS_STATUS NdisStatus;
+    PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Prepare packet */
+    Packet = PoolAllocateBuffer(sizeof(IP_PACKET));
+    if (!Packet) {
+        TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(Packet, sizeof(IP_PACKET));
+    Packet->RefCount   = 1;
+    Packet->TotalSize  = sizeof(IPv4_HEADER) +
+                         sizeof(UDP_HEADER)  +
+                         SendRequest->BufferSize;
+
+    /* Allocate NDIS packet */
+    NdisAllocatePacket(&NdisStatus, &Packet->NdisPacket, GlobalPacketPool);
+    if (NdisStatus != NDIS_STATUS_SUCCESS) {
+        TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS packet. NdisStatus = (0x%X)\n", NdisStatus));
+        PoolFreeBuffer(Packet);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    switch (SendRequest->RemoteAddress->Type) {
+    case IP_ADDRESS_V4:
+        Status = AddUDPHeaderIPv4(SendRequest, LocalAddress, LocalPort, Packet);
+        break;
+    case IP_ADDRESS_V6:
+        /* FIXME: Support IPv6 */
+        TI_DbgPrint(MIN_TRACE, ("IPv6 UDP datagrams are not supported.\n"));
+    default:
+        Status = STATUS_UNSUCCESSFUL;
+        break;
+    }
+    if (!NT_SUCCESS(Status)) {
+        TI_DbgPrint(MIN_TRACE, ("Cannot add UDP header. Status = (0x%X)\n", Status));
+        NdisFreePacket(Packet->NdisPacket);
+        PoolFreeBuffer(Packet);
+        return Status;
+    }
+
+    /* Chain data after header */
+    NdisChainBufferAtBack(Packet->NdisPacket, SendRequest->Buffer);
+
+    *IPPacket = Packet;
+
+    return STATUS_SUCCESS;
+}
+
+
+VOID DeliverUDPData(
+    PADDRESS_FILE AddrFile,
+    PIP_ADDRESS Address,
+    PIP_PACKET IPPacket,
+    UINT DataSize)
+/*
+ * FUNCTION: Delivers UDP data to a user
+ * ARGUMENTS:
+ *     AddrFile = Address file to deliver data to
+ *     Address  = Remote address the packet came from
+ *     IPPacket = Pointer to IP packet to deliver
+ *     DataSize = Number of bytes in data area
+ * NOTES:
+ *     If there is a receive request, then we copy the data to the
+ *     buffer supplied by the user and complete the receive request.
+ *     If no suitable receive request exists, then we call the event
+ *     handler if it exists, otherwise we drop the packet.
+ */
+{
+    KIRQL OldIrql;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+    if (!IsListEmpty(&AddrFile->ReceiveQueue)) {
+        PLIST_ENTRY CurrentEntry;
+        PDATAGRAM_RECEIVE_REQUEST Current;
+        BOOLEAN Found;
+
+        /* Search receive request list to find a match */
+        Found = FALSE;
+        CurrentEntry = AddrFile->ReceiveQueue.Flink;
+        while ((CurrentEntry != &AddrFile->ReceiveQueue) && (!Found)) {
+            Current = CONTAINING_RECORD(CurrentEntry, DATAGRAM_RECEIVE_REQUEST, ListEntry);
+            if (!Current->RemoteAddress)
+                Found = TRUE;
+            else if (AddrIsEqual(Address, Current->RemoteAddress))
+                Found = TRUE;
+
+            if (Found) {
+                /* FIXME: Maybe we should check if the buffer of this
+                   receive request is large enough and if not, search
+                   for another. Also a 'best fit' strategy could be used. */
+
+                /* Remove the request from the queue */
+                RemoveEntryList(&Current->ListEntry);
+                AddrFile->RefCount--;
+                break;
+            }
+            CurrentEntry = CurrentEntry->Flink;
+        }
+
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+        if (Found) {
+            /* Copy the data into buffer provided by the user */
+            CopyBufferToBufferChain(Current->Buffer,
+                                    0,
+                                    IPPacket->Data,
+                                    DataSize);
+
+            /* Complete the receive request */
+            (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize);
+
+            /* Finally free the receive request */
+            if (Current->RemoteAddress)
+                PoolFreeBuffer(Current->RemoteAddress);
+            PoolFreeBuffer(Current);
+        }
+    } else {
+        KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+        /* FIXME: Call event handler */
+        TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));
+    }
+
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+NTSTATUS UDPSendDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG DataSize)
+/*
+ * FUNCTION: Sends an UDP datagram to a remote address
+ * ARGUMENTS:
+ *     Request   = Pointer to TDI request
+ *     ConnInfo  = Pointer to connection information
+ *     Buffer    = Pointer to NDIS buffer with data
+ *     DataSize  = Size in bytes of data to be sent
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    return DGSendDatagram(Request,
+                          ConnInfo,
+                          Buffer,
+                          DataSize,
+                          BuildUDPPacket);
+}
+
+
+NTSTATUS UDPReceiveDatagram(
+    PTDI_REQUEST Request,
+    PTDI_CONNECTION_INFORMATION ConnInfo,
+    PNDIS_BUFFER Buffer,
+    ULONG ReceiveLength,
+    ULONG ReceiveFlags,
+    PTDI_CONNECTION_INFORMATION ReturnInfo,
+    PULONG BytesReceived)
+/*
+ * FUNCTION: Attempts to receive an UDP datagram from a remote address
+ * ARGUMENTS:
+ *     Request       = Pointer to TDI request
+ *     ConnInfo      = Pointer to connection information
+ *     Buffer        = Pointer to NDIS buffer chain to store received data
+ *     ReceiveLength = Maximum size to use of buffer, 0 if all can be used
+ *     ReceiveFlags  = Receive flags (None, Normal, Peek)
+ *     ReturnInfo    = Pointer to structure for return information
+ *     BytesReceive  = Pointer to structure for number of bytes received
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     This is the high level interface for receiving UDP datagrams
+ */
+{
+    return DGReceiveDatagram(Request,
+                             ConnInfo,
+                             Buffer,
+                             ReceiveLength,
+                             ReceiveFlags,
+                             ReturnInfo,
+                             BytesReceived);
+}
+
+
+VOID UDPReceive(
+    PNET_TABLE_ENTRY NTE,
+    PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives and queues a UDP datagram
+ * ARGUMENTS:
+ *     NTE      = Pointer to net table entry which the packet was received on
+ *     IPPacket = Pointer to an IP packet that was received
+ * NOTES:
+ *     This is the low level interface for receiving UDP datagrams. It strips
+ *     the UDP header from a packet and delivers the data to anyone that wants it
+ */
+{
+    AF_SEARCH SearchContext;
+    PIPv4_HEADER IPv4Header;
+    PADDRESS_FILE AddrFile;
+    PUDP_HEADER UDPHeader;
+    PIP_ADDRESS DstAddress;
+    UINT DataSize, i;
+
+    TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    switch (IPPacket->Type) {
+    /* IPv4 packet */
+    case IP_ADDRESS_V4:
+        IPv4Header = IPPacket->Header;
+        DstAddress = &IPPacket->DstAddr;
+        break;
+
+    /* IPv6 packet */
+    case IP_ADDRESS_V6:
+        TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 UDP datagram (%i bytes).\n", IPPacket->TotalSize));
+
+        /* FIXME: IPv6 is not supported */
+        return;
+    }
+
+    UDPHeader = (PUDP_HEADER)IPPacket->Data;
+
+    /* FIXME: Calculate and validate UDP checksum */
+
+    /* Sanity checks */
+    i = WH2N(UDPHeader->Length);
+    if ((i < sizeof(UDP_HEADER)) || (i > IPPacket->TotalSize - IPPacket->Position)) {
+        /* Incorrect or damaged packet received, discard it */
+        TI_DbgPrint(MIN_TRACE, ("Incorrect or damaged UDP packet received.\n"));
+        return;
+    }
+
+    DataSize = i - sizeof(UDP_HEADER);
+
+    /* Go to UDP data area */
+    (ULONG_PTR)IPPacket->Data += sizeof(UDP_HEADER);
+
+    /* Locate a receive request on destination address file object
+       and deliver the packet if one is found. If there is no receive
+       request on the address file object, call the associated receive
+       handler. If no receive handler is registered, drop the packet */
+
+    AddrFile = AddrSearchFirst(DstAddress,
+                               UDPHeader->DestPort,
+                               IPPROTO_UDP,
+                               &SearchContext);
+    if (AddrFile) {
+        do {
+            DeliverUDPData(AddrFile,
+                           DstAddress,
+                           IPPacket,
+                           DataSize);
+        } while ((AddrFile = AddrSearchNext(&SearchContext)) != NULL);
+    } else {
+        /* There are no open address files that will take this datagram */
+        /* FIXME: IPv4 only */
+        TI_DbgPrint(MID_TRACE, ("Cannot deliver IPv4 UDP datagram to address (0x%X).\n",
+            DN2H(DstAddress->Address.IPv4Address)));
+
+        /* FIXME: Send ICMP reply */
+    }
+    TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+NTSTATUS UDPStartup(
+    VOID)
+/*
+ * FUNCTION: Initializes the UDP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
+
+    /* Register this protocol with IP layer */
+    IPRegisterProtocol(IPPROTO_UDP, UDPReceive);
+
+    UDPInitialized = TRUE;
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS UDPShutdown(
+    VOID)
+/*
+ * FUNCTION: Shuts down the UDP subsystem
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    if (!UDPInitialized)
+        return STATUS_SUCCESS;
+
+    /* Deregister this protocol with IP layer */
+    IPRegisterProtocol(IPPROTO_UDP, NULL);
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
diff --git a/reactos/drivers/net/tditest/DIRS b/reactos/drivers/net/tditest/DIRS
new file mode 100644 (file)
index 0000000..0f4605a
--- /dev/null
@@ -0,0 +1 @@
+DIRS= tditest
diff --git a/reactos/drivers/net/tditest/include/debug.h b/reactos/drivers/net/tditest/include/debug.h
new file mode 100644 (file)
index 0000000..ee80cc3
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TDI test driver
+ * FILE:        include/debug.h
+ * PURPOSE:     Debugging support macros
+ * DEFINES:     DBG     - Enable debug output
+ *              NASSERT - Disable assertions
+ */
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#define NORMAL_MASK    0x000000FF
+#define SPECIAL_MASK   0xFFFFFF00
+#define MIN_TRACE      0x00000001
+#define MID_TRACE      0x00000002
+#define MAX_TRACE      0x00000003
+
+#define DEBUG_ULTRA    0xFFFFFFFF
+
+#ifdef DBG
+
+extern DWORD DebugTraceLevel;
+
+#ifdef _MSC_VER
+
+#define TDI_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d) ", __FILE__, __LINE__); \
+        DbgPrint _x_ ; \
+    }
+
+#else /* _MSC_VER */
+
+#define TDI_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
+        DbgPrint _x_ ; \
+    }
+
+#endif /* _MSC_VER */
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef NASSERT
+#define ASSERT(x)
+#else /* NASSERT */
+#define ASSERT(x) if (!(x)) { TDI_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); }
+#endif /* NASSERT */
+
+#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x))
+
+#else /* DBG */
+
+#define TDI_DbgPrint(_t_, _x_)
+
+#define ASSERT_IRQL(x)
+#define ASSERT(x)
+
+#endif /* DBG */
+
+
+#define assert(x) ASSERT(x)
+#define assert_irql(x) ASSERT_IRQL(x)
+
+
+#ifdef _MSC_VER
+
+#define UNIMPLEMENTED \
+    TDI_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \
+        but come back another day.\n", __FILE__, __LINE__));
+
+#else /* _MSC_VER */
+
+#define UNIMPLEMENTED \
+    TDI_DbgPrint(MIN_TRACE, ("%s at %s:%d is unimplemented, \
+        but come back another day.\n", __FUNCTION__, __FILE__, __LINE__));
+
+#endif /* _MSC_VER */
+
+
+#define CHECKPOINT \
+do { TDI_DbgPrint(MIN_TRACE, ("%s:%d\n", __FILE__, __LINE__)); } while(0);
+
+#endif /* __DEBUG_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/tditest/include/tditest.h b/reactos/drivers/net/tditest/include/tditest.h
new file mode 100644 (file)
index 0000000..fddda20
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TDI test driver
+ * FILE:        include/tditest.h
+ * PURPOSE:     Testing TDI drivers
+ */
+#ifndef __TDITEST_H
+#define __TDITEST_H
+
+#ifdef _MSC_VER
+#include <basetsd.h>
+#include <ntddk.h>
+#include <windef.h>
+#include <tdikrnl.h>
+#include <tdiinfo.h>
+#else
+#include <ddk/ntddk.h>
+#include <net/tdikrnl.h>
+#include <net/tdiinfo.h>
+#endif
+
+#include <debug.h>
+
+
+/* Name of UDP device */
+//#define UDP_DEVICE_NAME L"\\Device\\Udp"
+#define UDP_DEVICE_NAME L"\\Device\\NTUdp"
+
+
+#ifdef i386
+
+/* DWORD network to host byte order conversion for i386 */
+#define DN2H(dw) \
+    ((((dw) & 0xFF000000L) >> 24) | \
+        (((dw) & 0x00FF0000L) >> 8) | \
+        (((dw) & 0x0000FF00L) << 8) | \
+        (((dw) & 0x000000FFL) << 24))
+
+/* DWORD host to network byte order conversion for i386 */
+#define DH2N(dw) \
+       ((((dw) & 0xFF000000L) >> 24) | \
+        (((dw) & 0x00FF0000L) >> 8) | \
+        (((dw) & 0x0000FF00L) << 8) | \
+        (((dw) & 0x000000FFL) << 24))
+
+/* WORD network to host order conversion for i386 */
+#define WN2H(w) \
+       ((((w) & 0xFF00) >> 8) | \
+        (((w) & 0x00FF) << 8))
+
+/* WORD host to network byte order conversion for i386 */
+#define WH2N(w) \
+       ((((w) & 0xFF00) >> 8) | \
+        (((w) & 0x00FF) << 8))
+
+#else /* i386 */
+
+/* DWORD network to host byte order conversion for other architectures */
+#define DN2H(dw) \
+    (dw)
+
+/* DWORD host to network byte order conversion for other architectures */
+#define DH2N(dw) \
+    (dw)
+
+/* WORD network to host order conversion for other architectures */
+#define WN2H(w) \
+    (w)
+
+/* WORD host to network byte order conversion for other architectures */
+#define WH2N(w) \
+    (w)
+
+#endif /* i386 */
+
+
+typedef struct IPSNMP_INFO {
+       ULONG Forwarding;
+       ULONG DefaultTTL;
+       ULONG InReceives;
+       ULONG InHdrErrors;
+       ULONG InAddrErrors;
+       ULONG ForwDatagrams;
+       ULONG InUnknownProtos;
+       ULONG InDiscards;
+       ULONG InDelivers;
+       ULONG OutRequests;
+       ULONG RoutingDiscards;
+       ULONG OutDiscards;
+       ULONG OutNoRoutes;
+       ULONG ReasmTimeout;
+       ULONG ReasmReqds;
+       ULONG ReasmOks;
+       ULONG ReasmFails;
+       ULONG FragOks;
+       ULONG FragFails;
+       ULONG FragCreates;
+       ULONG NumIf;
+       ULONG NumAddr;
+       ULONG NumRoutes;
+} IPSNMP_INFO, *PIPSNMP_INFO;
+
+typedef struct IPADDR_ENTRY {
+       ULONG  Addr;
+       ULONG  Index;
+       ULONG  Mask;
+       ULONG  BcastAddr;
+       ULONG  ReasmSize;
+       USHORT Context;
+       USHORT Pad;
+} IPADDR_ENTRY, *PIPADDR_ENTRY;
+
+
+#define TL_INSTANCE 0
+
+#define IP_MIB_STATS_ID             0x1
+#define IP_MIB_ADDRTABLE_ENTRY_ID   0x102
+
+
+/* IOCTL codes */
+#define IOCTL_TCP_QUERY_INFORMATION_EX \
+           CTL_CODE(FILE_DEVICE_NETWORK, 0, METHOD_NEITHER, FILE_ANY_ACCESS)
+#define IOCTL_TCP_SET_INFORMATION_EX  \
+           CTL_CODE(FILE_DEVICE_NETWORK, 1, METHOD_BUFFERED, FILE_WRITE_ACCESS)
+
+
+#define TEST_PORT 2000
+
+#endif /*__TDITEST_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/tditest/makefile b/reactos/drivers/net/tditest/makefile
new file mode 100644 (file)
index 0000000..fa42377
--- /dev/null
@@ -0,0 +1,84 @@
+# TDITEST.SYS - TDI test driver
+
+TARGETNAME=tditest
+
+BASE_CFLAGS = -I./include -I../../../include
+
+RESOURCE_OBJECT = $(TARGETNAME).coff
+TDITEST_OBJECTS = tditest/tditest.o
+
+all: objects $(TARGETNAME).sys
+
+objects:
+       mkdir objects
+
+$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h
+
+OBJECTS = $(TDITEST_OBJECTS) $(RESOURCE_OBJECT) ../../../ntoskrnl/ntoskrnl.a
+
+
+ifeq ($(DOSCLI),yes)
+CLEAN_FILES = *.o objects\*.o tditest\*.o $(TARGETNAME).coff $(TARGETNAME).o \
+              junk.tmp base.tmp temp.exp $(TARGETNAME).sys $(TARGETNAME).sym
+else
+CLEAN_FILES = *.o objects/*.o tditest/*.o $(TARGETNAME).coff $(TARGETNAME).o \
+              junk.tmp base.tmp temp.exp $(TARGETNAME).sys $(TARGETNAME).sym
+endif
+
+$(TARGETNAME).sys: $(OBJECTS)
+       $(CC) \
+               -mdll \
+               -specs=../../svc_specs \
+               -Wl,-e,_DriverEntry@8 \
+               -Wl,--base-file,base.tmp \
+               -Wl,--defsym,_end=end  \
+               -Wl,--defsym,_edata=__data_end__ \
+               -Wl,--defsym,_etext=etext \
+        $(OBJECTS) \
+        -o junk.tmp
+       - $(RM) junk.tmp
+       $(DLLTOOL) \
+        --dllname $(TARGETNAME).sys \
+        --base-file base.tmp \
+        --output-exp temp.exp
+       - $(RM) base.tmp
+       $(CC) \
+               -mdll \
+               -specs=../../svc_specs \
+               -Wl,--image-base,0x10000 \
+               -Wl,-e,_DriverEntry@8 \
+               -Wl,temp.exp \
+        $(OBJECTS) \
+        -o $(TARGETNAME).sys
+       - $(RM) temp.exp
+       $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym
+
+clean: $(CLEAN_FILES:%=%_clean)
+
+$(CLEAN_FILES:%=%_clean): %_clean:
+       - $(RM) $*
+
+.PHONY: clean $(CLEAN_FILES:%=%_clean)
+
+floppy: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys
+
+$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys
+ifeq ($(DOSCLI),yes)
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys
+else
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys
+endif
+
+dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys
+
+$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys
+ifeq ($(DOSCLI),yes)
+       $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys
+else
+       $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys
+endif
+
+#WITH_DEBUGGING      = yes
+#WIN32_LEAN_AND_MEAN = yes
+#WARNINGS_ARE_ERRORS = yes
+include ../../../rules.mak
diff --git a/reactos/drivers/net/tditest/readme.txt b/reactos/drivers/net/tditest/readme.txt
new file mode 100644 (file)
index 0000000..41e6e9c
--- /dev/null
@@ -0,0 +1,18 @@
+Build instructions for TDITEST driver
+-------------------------------------
+
+Building with Visual C++ and Windows NT DDK:
+
+Variables:
+%BASEDIR%     = path to NT4 DDK (e.g. c:\ntddk)
+%DDKBUILDENV% = DDK build environment (free or checked)
+
+DDK environment variables must be set! (run setenv.bat)
+
+    - Create the directory objects/i386/%DDKBUILDENV%
+    - Run "build" to build the driver
+
+
+Building with Mingw32 and ReactOS include files:
+
+    - Run "make tditest" FROM THE ReactOS ROOT DIRECTORY to build the driver
diff --git a/reactos/drivers/net/tditest/tditest.def b/reactos/drivers/net/tditest/tditest.def
new file mode 100644 (file)
index 0000000..2acbb5b
--- /dev/null
@@ -0,0 +1,7 @@
+; TDI test driver - ReactOS Operating System
+
+LIBRARY TDITEST.SYS
+
+EXPORTS
+
+; EOF
diff --git a/reactos/drivers/net/tditest/tditest.rc b/reactos/drivers/net/tditest/tditest.rc
new file mode 100644 (file)
index 0000000..37601b2
--- /dev/null
@@ -0,0 +1,38 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",         RES_STR_COMPANY_NAME
+            VALUE "FileDescription",  "TDI test driver\0"
+            VALUE "FileVersion",         "0.0.0\0"
+            VALUE "InternalName",        "tditest\0"
+            VALUE "LegalCopyright",      RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalFilename", "tditest.sys\0"
+            VALUE "ProductName",         RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",      RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
diff --git a/reactos/drivers/net/tditest/tditest/Makefile b/reactos/drivers/net/tditest/tditest/Makefile
new file mode 100644 (file)
index 0000000..0ad3c88
--- /dev/null
@@ -0,0 +1,8 @@
+# MAKEFILE for ARTICLE
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the driver components of the Windows NT DDK
+#
+
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/reactos/drivers/net/tditest/tditest/SOURCES b/reactos/drivers/net/tditest/tditest/SOURCES
new file mode 100644 (file)
index 0000000..c2c4df0
--- /dev/null
@@ -0,0 +1,14 @@
+TARGETNAME=tditest
+TARGETPATH=..\objects
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
+           $(DDK_LIB_PATH)\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DDBG
+
+INCLUDES=..\include;..\..\..\..\include\net;$(BASEDIR)\inc
+
+SOURCES= tditest.c
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/reactos/drivers/net/tditest/tditest/tditest.c b/reactos/drivers/net/tditest/tditest/tditest.c
new file mode 100644 (file)
index 0000000..709e8f5
--- /dev/null
@@ -0,0 +1,947 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS TDI test driver
+ * FILE:        tditest.c
+ * PURPOSE:     Testing TDI drivers
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 01/08-2000 Created
+ */
+#include <tditest.h>
+
+
+#ifdef DBG
+
+/* See debug.h for debug/trace constants */
+DWORD DebugTraceLevel = MIN_TRACE;
+
+#endif /* DBG */
+
+
+HANDLE TdiTransport             = 0;
+PFILE_OBJECT TdiTransportObject = NULL;
+ULONG LocalAddress;
+BOOLEAN OpenError;
+KEVENT StopEvent;
+HANDLE SendThread;
+KEVENT SendThreadEvent;
+HANDLE ReceiveThread;
+KEVENT ReceiveThreadEvent;
+PVOID ReceiveThreadObject;
+PVOID SendThreadObject;
+
+
+NTSTATUS TdiCall(
+    PIRP Irp,
+    PDEVICE_OBJECT DeviceObject,
+    PIO_STATUS_BLOCK IoStatusBlock,
+    BOOLEAN CanCancel)
+/*
+ * FUNCTION: Calls a transport driver device
+ * ARGUMENTS:
+ *     Irp           = Pointer to I/O Request Packet
+ *     DeviceObject  = Pointer to device object to call
+ *     IoStatusBlock = Address of buffer with I/O status block
+ *     CanCancel     = TRUE if the IRP can be cancelled, FALSE if not
+ * RETURNS:
+ *     Status of operation
+ * NOTES
+ *     All requests are completed synchronously. A request may be cancelled
+ */
+{
+    KEVENT Event;
+    PKEVENT Events[2];
+    NTSTATUS Status;
+    Events[0] = &StopEvent;
+    Events[1] = &Event; 
+    
+    KeInitializeEvent(&Event, NotificationEvent, FALSE);
+    Irp->UserEvent = &Event;
+    Irp->UserIosb  = IoStatusBlock;
+    Status         = IoCallDriver(DeviceObject, Irp);
+    if (Status == STATUS_PENDING) {
+        if (CanCancel) {
+            Status = KeWaitForMultipleObjects(2,
+                                              (PVOID)&Events,
+                                              WaitAny,
+                                              Executive,
+                                              KernelMode,
+                                              FALSE,
+                                              NULL,
+                                              NULL);
+
+            if (KeReadStateEvent(&StopEvent) != 0) {
+                if (IoCancelIrp(Irp)) {
+                    TDI_DbgPrint(MAX_TRACE, ("Cancelled IRP.\n"));
+                } else {
+                    TDI_DbgPrint(MIN_TRACE, ("Could not cancel IRP.\n"));
+                }
+                return STATUS_CANCELLED;
+            }
+        } else
+            Status = KeWaitForSingleObject(&Event,
+                                           Executive,
+                                           KernelMode,
+                                           FALSE,
+                                           NULL);
+    }
+
+    return (Status == STATUS_SUCCESS)? IoStatusBlock->Status : STATUS_SUCCESS;
+}
+
+
+NTSTATUS TdiOpenDevice(
+    PWSTR Protocol,
+    ULONG EaLength,
+    PFILE_FULL_EA_INFORMATION EaInfo,
+    PHANDLE Handle,
+    PFILE_OBJECT *Object)
+/*
+ * FUNCTION: Opens a device
+ * ARGUMENTS:
+ *     Protocol = Pointer to buffer with name of device
+ *     EaLength = Length of EA information
+ *     EaInfo   = Pointer to buffer with EA information
+ *     Handle   = Address of buffer to place device handle
+ *     Object   = Address of buffer to place device object
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    OBJECT_ATTRIBUTES Attr;
+    IO_STATUS_BLOCK Iosb;
+    UNICODE_STRING Name;
+    NTSTATUS Status;
+
+    RtlInitUnicodeString(&Name, Protocol);
+    InitializeObjectAttributes(&Attr,                   /* Attribute buffer */
+                               &Name,                   /* Device name */
+                               OBJ_CASE_INSENSITIVE,    /* Attributes */
+                               NULL,                    /* Root directory */
+                               NULL);                   /* Security descriptor */
+
+    Status = ZwCreateFile(Handle,                               /* Return file handle */
+                          GENERIC_READ | GENERIC_WRITE,         /* Desired access */
+                          &Attr,                                /* Object attributes */
+                          &Iosb,                                /* IO status */
+                          0,                                    /* Initial allocation size */
+                          FILE_ATTRIBUTE_NORMAL,                /* File attributes */
+                          FILE_SHARE_READ | FILE_SHARE_WRITE,   /* Share access */
+                          FILE_OPEN_IF,                         /* Create disposition */
+                          0,                                    /* Create options */
+                          EaInfo,                               /* EA buffer */
+                          EaLength);                            /* EA length */
+    if (NT_SUCCESS(Status)) {
+        Status  = ObReferenceObjectByHandle(*Handle,                        /* Handle to open file */
+                                            GENERIC_READ | GENERIC_WRITE,   /* Access mode */
+                                            NULL,                           /* Object type */
+                                            KernelMode,                     /* Access mode */
+                                            (PVOID*)Object,                 /* Pointer to object */
+                                            NULL);                          /* Handle information */
+        if (!NT_SUCCESS(Status)) {
+            TDI_DbgPrint(MIN_TRACE, ("ObReferenceObjectByHandle() failed with status (0x%X).\n", Status));
+            ZwClose(*Handle);
+        }
+    } else {
+        TDI_DbgPrint(MIN_TRACE, ("ZwCreateFile() failed with status (0x%X)\n", Status));
+    }
+
+    return Status;
+}
+
+
+NTSTATUS TdiCloseDevice(
+    HANDLE Handle,
+    PFILE_OBJECT FileObject)
+{
+    if (FileObject)
+        ObDereferenceObject(FileObject);
+
+    if (Handle)
+        ZwClose(Handle);
+
+    return STATUS_SUCCESS;
+}
+
+
+NTSTATUS TdiOpenTransport(
+    PWSTR Protocol,
+    USHORT Port,
+    PHANDLE Transport,
+    PFILE_OBJECT *TransportObject)
+/*
+ * FUNCTION: Opens a transport driver
+ * ARGUMENTS:
+ *     Protocol        = Pointer to buffer with name of device
+ *     Port            = Port number to use
+ *     Transport       = Address of buffer to place transport device handle
+ *     TransportObject = Address of buffer to place transport object
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PFILE_FULL_EA_INFORMATION EaInfo;
+    PTA_ADDRESS_IP Address;
+    NTSTATUS Status;
+    ULONG EaLength;
+
+    EaLength = sizeof(FILE_FULL_EA_INFORMATION) +
+               sizeof(TdiTransportAddress) +
+               sizeof(TA_ADDRESS_IP) + 1;
+    EaInfo = (PFILE_FULL_EA_INFORMATION)ExAllocatePool(NonPagedPool, EaLength);
+    if (!EaInfo) {
+        TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    RtlZeroMemory(EaInfo, EaLength);
+    EaInfo->EaNameLength = TDI_TRANSPORT_ADDRESS_LENGTH;
+    RtlCopyMemory (EaInfo->EaName,
+                   TdiTransportAddress,
+                   sizeof(TdiTransportAddress));
+    EaInfo->EaValueLength = sizeof(TA_ADDRESS_IP);
+    Address = (PTA_ADDRESS_IP)(EaInfo->EaName + sizeof(TdiTransportAddress));
+    Address->TAAddressCount                 = 1;
+    Address->Address[0].AddressLength       = sizeof(TDI_ADDRESS_IP);
+    Address->Address[0].AddressType         = TDI_ADDRESS_TYPE_IP;
+    Address->Address[0].Address[0].sin_port = WH2N(Port);
+    Address->Address[0].Address[0].in_addr  = 0;
+    Status = TdiOpenDevice(Protocol,
+                           EaLength,
+                           EaInfo,
+                           Transport,
+                           TransportObject);
+    ExFreePool(EaInfo);
+
+    return Status;
+}
+
+
+NTSTATUS TdiQueryDeviceControl(
+    PFILE_OBJECT FileObject,
+    ULONG IoControlCode,
+    PVOID InputBuffer,
+    ULONG InputBufferLength,
+    PVOID OutputBuffer,
+    ULONG OutputBufferLength,
+    PULONG Return)
+/*
+ * FUNCTION: Queries a device for information
+ * ARGUMENTS:
+ *     FileObject         = Pointer to device object
+ *     IoControlCode      = I/O control code
+ *     InputBuffer        = Pointer to buffer with input data
+ *     InputBufferLength  = Length of InputBuffer
+ *     OutputBuffer       = Address of buffer to place output data
+ *     OutputBufferLength = Length of OutputBuffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PDEVICE_OBJECT DeviceObject;
+    PIO_STACK_LOCATION IoStack;
+    IO_STATUS_BLOCK Iosb;
+    NTSTATUS Status;
+    PIRP Irp;
+
+    DeviceObject = IoGetRelatedDeviceObject(FileObject);
+    Irp = IoBuildDeviceIoControlRequest(IoControlCode,
+                                        DeviceObject,
+                                        InputBuffer,
+                                        InputBufferLength,
+                                        OutputBuffer,
+                                        OutputBufferLength,
+                                        FALSE,
+                                        NULL,
+                                        NULL);
+    if (!Irp) {
+        TDI_DbgPrint(MIN_TRACE, ("IoBuildDeviceIoControlRequest() failed.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    IoStack               = IoGetNextIrpStackLocation(Irp);
+    IoStack->DeviceObject = DeviceObject;
+    IoStack->FileObject   = FileObject;
+    Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
+    if (Return)
+        *Return = Iosb.Information;
+
+   return Status;
+}
+
+
+NTSTATUS TdiQueryInformationEx(
+    PFILE_OBJECT FileObject,
+    ULONG Entity,
+    ULONG Instance,
+    ULONG Class,
+    ULONG Type,
+    ULONG Id,
+    PVOID OutputBuffer,
+    PULONG OutputLength)
+/*
+ * FUNCTION: Extended query for information
+ * ARGUMENTS:
+ *     FileObject   = Pointer to transport object
+ *     Entity       = Entity
+ *     Instance     = Instance
+ *     Class        = Entity class
+ *     Type         = Entity type
+ *     Id           = Entity id
+ *     OutputBuffer = Address of buffer to place data
+ *     OutputLength = Address of buffer with length of OutputBuffer (updated)
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    TCP_REQUEST_QUERY_INFORMATION_EX QueryInfo;
+
+    RtlZeroMemory(&QueryInfo, sizeof(TCP_REQUEST_QUERY_INFORMATION_EX));
+    QueryInfo.ID.toi_entity.tei_entity   = Entity;
+    QueryInfo.ID.toi_entity.tei_instance = Instance;
+    QueryInfo.ID.toi_class = Class;
+    QueryInfo.ID.toi_type  = Type;
+    QueryInfo.ID.toi_id    = Id;
+
+    return TdiQueryDeviceControl(FileObject,                                /* Transport/connection object */
+                                 IOCTL_TCP_QUERY_INFORMATION_EX,            /* Control code */
+                                 &QueryInfo,                                /* Input buffer */
+                                 sizeof(TCP_REQUEST_QUERY_INFORMATION_EX),  /* Input buffer length */
+                                 OutputBuffer,                              /* Output buffer */
+                                 *OutputLength,                             /* Output buffer length */
+                                 OutputLength);                             /* Return information */
+}
+
+
+NTSTATUS TdiQueryAddress(
+    PFILE_OBJECT FileObject,
+    PULONG Address)
+/*
+ * FUNCTION: Queries for a local IP address
+ * ARGUMENTS:
+ *     FileObject = Pointer to file object
+ *     Address    = Address of buffer to place local address
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    UINT i;
+    TDIEntityID *Entities;
+    ULONG EntityCount;
+    ULONG EntityType;
+    IPSNMP_INFO SnmpInfo;
+    PIPADDR_ENTRY IpAddress;
+    ULONG BufferSize;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    TDI_DbgPrint(MAX_TRACE, ("Called\n"));
+
+    BufferSize = sizeof(TDIEntityID) * 20;
+    Entities   = (TDIEntityID*)ExAllocatePool(NonPagedPool, BufferSize);
+    if (!Entities) {
+        TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Query device for supported entities */
+
+    Status = TdiQueryInformationEx(FileObject,          /* File object */
+                                   GENERIC_ENTITY,      /* Entity */
+                                   TL_INSTANCE,         /* Instance */
+                                   INFO_CLASS_GENERIC,  /* Entity class */
+                                   INFO_TYPE_PROVIDER,  /* Entity type */
+                                   ENTITY_LIST_ID,      /* Entity id */
+                                   Entities,            /* Output buffer */
+                                   &BufferSize);        /* Output buffer size */
+    if (!NT_SUCCESS(Status)) {
+        TDI_DbgPrint(MIN_TRACE, ("Unable to get list of supported entities (Status = 0x%X).\n", Status));
+        ExFreePool(Entities);
+        return Status;
+    }
+
+    /* Locate an IP entity */
+    EntityCount = BufferSize / sizeof(TDIEntityID);
+
+    TDI_DbgPrint(MAX_TRACE, ("EntityCount = %d\n", EntityCount));
+
+    for (i = 0; i < EntityCount; i++) {
+        if (Entities[i].tei_entity == CL_NL_ENTITY) {
+            /* Query device for entity type */
+
+            BufferSize = sizeof(EntityType);
+            Status = TdiQueryInformationEx(FileObject,                  /* File object */
+                                           CL_NL_ENTITY,                /* Entity */
+                                           Entities[i].tei_instance,    /* Instance */
+                                           INFO_CLASS_GENERIC,          /* Entity class */
+                                           INFO_TYPE_PROVIDER,          /* Entity type */
+                                           ENTITY_TYPE_ID,              /* Entity id */
+                                           &EntityType,                 /* Output buffer */
+                                           &BufferSize);                /* Output buffer size */
+            if (!NT_SUCCESS(Status) || (EntityType != CL_NL_IP)) {
+                TDI_DbgPrint(MIN_TRACE, ("Unable to get entity of type IP (Status = 0x%X).\n", Status));
+                break;
+            }
+
+            /* Query device for SNMP information */
+
+            BufferSize = sizeof(SnmpInfo);
+            Status = TdiQueryInformationEx(FileObject,                  /* File object */
+                                           CL_NL_ENTITY,                /* Entity */
+                                           Entities[i].tei_instance,    /* Instance */
+                                           INFO_CLASS_PROTOCOL,         /* Entity class */
+                                           INFO_TYPE_PROVIDER,          /* Entity type */
+                                           IP_MIB_STATS_ID,             /* Entity id */
+                                           &SnmpInfo,                   /* Output buffer */
+                                           &BufferSize);                /* Output buffer size */
+            if (!NT_SUCCESS(Status) || (SnmpInfo.NumAddr == 0)) {
+                TDI_DbgPrint(MIN_TRACE, ("Unable to get SNMP information or no IP addresses available (Status = 0x%X).\n", Status));
+                break;
+            }
+
+            /* Query device for all IP addresses */
+
+            if (SnmpInfo.NumAddr != 0) {
+                BufferSize = SnmpInfo.NumAddr * sizeof(IPADDR_ENTRY);
+                IpAddress = (PIPADDR_ENTRY)ExAllocatePool(NonPagedPool, BufferSize);
+                if (!IpAddress) {
+                    TDI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+                    break;
+                }
+
+                Status = TdiQueryInformationEx(FileObject,                  /* File object */
+                                               CL_NL_ENTITY,                /* Entity */
+                                               Entities[i].tei_instance,    /* Instance */
+                                               INFO_CLASS_PROTOCOL,         /* Entity class */
+                                               INFO_TYPE_PROVIDER,          /* Entity type */
+                                               IP_MIB_ADDRTABLE_ENTRY_ID,   /* Entity id */
+                                               IpAddress,                   /* Output buffer */
+                                               &BufferSize);                /* Output buffer size */
+                if (!NT_SUCCESS(Status)) {
+                    TDI_DbgPrint(MIN_TRACE, ("Unable to get IP address (Status = 0x%X).\n", Status));
+                    ExFreePool(IpAddress);
+                    break;
+                }
+
+                /* Select the first address returned */
+                *Address = DN2H(IpAddress->Addr);
+                ExFreePool(IpAddress);
+            } else {
+                Status = STATUS_UNSUCCESSFUL;
+                break;
+            }
+        }
+    }
+
+    ExFreePool(Entities);
+
+    TDI_DbgPrint(MAX_TRACE, ("Leaving\n"));
+
+    return Status;
+}
+
+
+NTSTATUS TdiSendDatagram(
+    PFILE_OBJECT TransportObject,
+    USHORT Port,
+    ULONG Address,
+    PVOID Buffer,
+    ULONG BufferSize)
+/*
+ * FUNCTION: Sends a datagram
+ * ARGUMENTS:
+ *     TransportObject = Pointer to transport object
+ *     Port            = Remote port
+ *     Address         = Remote address
+ *     Buffer          = Pointer to buffer with data to send
+ *     BufferSize      = Length of Buffer
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PIRP Irp;
+    PMDL Mdl;
+    PDEVICE_OBJECT DeviceObject;
+    PTDI_CONNECTION_INFORMATION ConnectInfo;
+    PTA_ADDRESS_IP TA;
+    PTDI_ADDRESS_IP IpAddress;
+    IO_STATUS_BLOCK Iosb;
+    NTSTATUS Status;
+
+    DeviceObject = IoGetRelatedDeviceObject(TransportObject);
+    ConnectInfo  = (PTDI_CONNECTION_INFORMATION)
+        ExAllocatePool(NonPagedPool,
+        sizeof(TDI_CONNECTION_INFORMATION) +
+        sizeof(TA_ADDRESS_IP));
+
+    if (!ConnectInfo)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    RtlZeroMemory(ConnectInfo,
+                  sizeof(TDI_CONNECTION_INFORMATION) +
+                  sizeof(TA_ADDRESS_IP));
+
+    ConnectInfo->RemoteAddressLength = sizeof(TA_ADDRESS_IP);
+    ConnectInfo->RemoteAddress       = (PUCHAR)
+        ((ULONG)ConnectInfo + sizeof(TDI_CONNECTION_INFORMATION));
+
+    TA = (PTA_ADDRESS_IP)(ConnectInfo->RemoteAddress);
+    TA->TAAddressCount           = 1;
+    TA->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
+    TA->Address[0].AddressType   = TDI_ADDRESS_TYPE_IP;
+    IpAddress           = (PTDI_ADDRESS_IP)(TA->Address[0].Address);
+    IpAddress->sin_port = WH2N(Port);
+    IpAddress->in_addr  = DH2N(Address);
+    Irp = TdiBuildInternalDeviceControlIrp(TDI_SEND_DATAGRAM,   /* Sub function */
+                                           DeviceObject,        /* Device object */
+                                           TransportObject,     /* File object */
+                                           NULL,                /* Event */
+                                           NULL);               /* Return buffer */
+    if (!Irp) {
+        TDI_DbgPrint(MIN_TRACE, ("TdiBuildInternalDeviceControlIrp() failed.\n"));
+        ExFreePool(ConnectInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Mdl = IoAllocateMdl(Buffer,     /* Virtual address of buffer */
+                        BufferSize, /* Length of buffer */
+                        FALSE,      /* Not secondary */
+                        FALSE,      /* Don't charge quota */
+                        NULL);      /* Don't use IRP */
+    if (!Mdl) {
+        TDI_DbgPrint(MIN_TRACE, ("IoAllocateMdl() failed.\n"));
+        IoFreeIrp(Irp);
+        ExFreePool(ConnectInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+#ifdef _MSC_VER
+    try {
+#endif
+        MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
+#ifdef _MSC_VER
+    } except(EXCEPTION_EXECUTE_HANDLER) {
+        TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
+        IoFreeMdl(Mdl);
+        IoFreeIrp(Irp);
+        ExFreePool(ConnectInfo);
+        return STATUS_UNSUCCESSFUL;
+    }
+#endif
+
+    TdiBuildSendDatagram(Irp,               /* I/O Request Packet */
+                         DeviceObject,      /* Device object */
+                         TransportObject,   /* File object */
+                         NULL,              /* Completion routine */
+                         NULL,              /* Completion context */
+                         Mdl,               /* Descriptor for data buffer */
+                         BufferSize,        /* Size of data to send */
+                         ConnectInfo);      /* Connection information */
+
+    Status = TdiCall(Irp, DeviceObject, &Iosb, FALSE);
+
+    ExFreePool(ConnectInfo);
+
+    return Status;
+}
+
+
+NTSTATUS TdiReceiveDatagram(
+    PFILE_OBJECT TransportObject,
+    USHORT Port,
+    PULONG Address,
+    PUCHAR Buffer,
+    PULONG BufferSize)
+/*
+ * FUNCTION: Receives a datagram
+ * ARGUMENTS:
+ *     TransportObject = Pointer to transport object
+ *     Port            = Port to receive on
+ *     Address         = Address of buffer to place remote address
+ *     Buffer          = Address of buffer to place received data
+ *     BufferSize      = Address of buffer with length of Buffer (updated)
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PTDI_CONNECTION_INFORMATION ReceiveInfo;
+    PTDI_CONNECTION_INFORMATION ReturnInfo;
+    PTA_ADDRESS_IP ReturnAddress;
+    PDEVICE_OBJECT DeviceObject;
+    PTDI_ADDRESS_IP IpAddress;
+    IO_STATUS_BLOCK Iosb;
+    PVOID MdlBuffer;
+    NTSTATUS Status;
+    PIRP Irp;
+    PMDL Mdl;
+
+    DeviceObject = IoGetRelatedDeviceObject(TransportObject);
+    if (!DeviceObject)
+        return STATUS_INVALID_PARAMETER;
+
+    ReceiveInfo = (PTDI_CONNECTION_INFORMATION)
+        ExAllocatePool(NonPagedPool,
+                       sizeof(TDI_CONNECTION_INFORMATION) +
+                       sizeof(TDI_CONNECTION_INFORMATION) +
+                       sizeof(TA_ADDRESS_IP));
+    if (!ReceiveInfo)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+    MdlBuffer = ExAllocatePool(PagedPool, *BufferSize);
+    if (!MdlBuffer)
+        return STATUS_INSUFFICIENT_RESOURCES;
+
+
+    RtlZeroMemory(ReceiveInfo,
+                  sizeof(TDI_CONNECTION_INFORMATION) +
+                  sizeof(TDI_CONNECTION_INFORMATION) +
+                  sizeof(TA_ADDRESS_IP));
+    RtlCopyMemory(MdlBuffer, Buffer, *BufferSize);
+
+    /* Receive from any address */
+    ReceiveInfo->RemoteAddressLength = 0;
+    ReceiveInfo->RemoteAddress       = NULL;
+
+    ReturnInfo = (PTDI_CONNECTION_INFORMATION)
+        ((ULONG)ReceiveInfo + sizeof(TDI_CONNECTION_INFORMATION));
+
+    ReturnInfo->RemoteAddressLength = sizeof(TA_ADDRESS_IP);
+    ReturnInfo->RemoteAddress       = (PUCHAR)
+        ((ULONG)ReturnInfo + sizeof(TDI_CONNECTION_INFORMATION));
+
+    ReturnAddress = (PTA_ADDRESS_IP)(ReturnInfo->RemoteAddress);
+    ReturnAddress->TAAddressCount           = 1;
+    ReturnAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
+    ReturnAddress->Address[0].AddressType   = TDI_ADDRESS_TYPE_IP;
+
+    IpAddress = (PTDI_ADDRESS_IP)(ReturnAddress->Address[0].Address);
+    IpAddress->sin_port = WH2N(Port);
+    IpAddress->in_addr  = DH2N(LocalAddress);
+
+    Irp = TdiBuildInternalDeviceControlIrp(TDI_RECEIVE_DATAGRAM,    /* Sub function */
+                                           DeviceObject,            /* Device object */
+                                           TransportObject,         /* File object */
+                                           NULL,                    /* Event */
+                                           NULL);                   /* Return buffer */
+    if (!Irp) {
+        ExFreePool(MdlBuffer);
+        ExFreePool(ReceiveInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    Mdl = IoAllocateMdl(MdlBuffer,      /* Virtual address */
+                        *BufferSize,    /* Length of buffer */
+                        FALSE,          /* Not secondary */
+                        FALSE,          /* Don't charge quota */
+                        NULL);          /* Don't use IRP */
+    if (!Mdl) {
+        IoFreeIrp(Irp);
+        ExFreePool(MdlBuffer);
+        ExFreePool(ReceiveInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+#ifdef _MSC_VER
+    try {
+#endif
+        MmProbeAndLockPages(Mdl, KernelMode, IoModifyAccess);
+#ifdef _MSC_VER
+    } except (EXCEPTION_EXECUTE_HANDLER) {
+        TDI_DbgPrint(MIN_TRACE, ("MmProbeAndLockPages() failed.\n"));
+        IoFreeMdl(Mdl);
+        IoFreeIrp(Irp);
+        ExFreePool(MdlBuffer);
+        ExFreePool(ReceiveInfo);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+#endif
+
+    TdiBuildReceiveDatagram(Irp,                    /* I/O Request Packet */
+                            DeviceObject,           /* Device object */
+                            TransportObject,        /* File object */
+                            NULL,                   /* Completion routine */
+                            NULL,                   /* Completion context */
+                            Mdl,                    /* Data buffer */
+                            *BufferSize,            /* Size of data buffer */
+                            ReceiveInfo,            /* Connection information */
+                            ReturnInfo,             /* Connection information */
+                            TDI_RECEIVE_NORMAL);    /* Flags */
+    Status = TdiCall(Irp, DeviceObject, &Iosb, TRUE);
+    if (NT_SUCCESS(Status)) {
+        RtlCopyMemory(Buffer, MdlBuffer, Iosb.Information);
+        *BufferSize = Iosb.Information;
+        *Address    = DN2H(IpAddress->in_addr);
+    }
+
+    ExFreePool(MdlBuffer);
+    ExFreePool(ReceiveInfo);
+
+    return Status;
+}
+
+
+VOID TdiSendThread(
+    PVOID Context)
+/*
+ * FUNCTION: Send thread
+ * ARGUMENTS:
+ *     Context = Pointer to context information
+ * NOTES:
+ *     Transmits an UDP packet every two seconds to ourselves on the chosen port
+ */
+{
+    KEVENT Event;
+    PKEVENT Events[2];
+    LARGE_INTEGER Timeout;
+    NTSTATUS Status = STATUS_SUCCESS;
+    UCHAR Data[40]  = "Testing one, two, three, ...";
+
+    if (!OpenError) {
+        Timeout.QuadPart = 10000000L;           /* Second factor */
+        Timeout.QuadPart *= 2;                  /* Number of seconds */
+        Timeout.QuadPart = -(Timeout.QuadPart); /* Relative time */
+        KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+
+        Events[0] = &StopEvent;
+        Events[1] = &Event;
+
+        while (NT_SUCCESS(Status)) {
+            /* Wait until timeout or stop flag is set */
+            KeWaitForMultipleObjects(
+                2,
+                (PVOID)&Events,
+                WaitAny,
+                Executive,
+                KernelMode,
+                FALSE,
+                &Timeout,
+                NULL);
+
+            if (KeReadStateEvent(&StopEvent) != 0) {
+                TDI_DbgPrint(MAX_TRACE, ("Received terminate signal...\n"));
+                break;
+            }
+
+            DbgPrint("Sending data - '%s'\n", Data);
+
+            Status = TdiSendDatagram(TdiTransportObject,
+                                     TEST_PORT,
+                                     LocalAddress,
+                                     Data,
+                                     sizeof(Data));
+            if (!NT_SUCCESS(Status))
+                DbgPrint("Failed sending data (Status = 0x%X)\n", Status);
+        }
+    }
+
+    TDI_DbgPrint(MAX_TRACE, ("Terminating send thread...\n"));
+
+    KeSetEvent(&SendThreadEvent, 0, FALSE);
+
+    PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+
+VOID TdiReceiveThread(
+    PVOID Context)
+/*
+ * FUNCTION: Receive thread
+ * ARGUMENTS:
+ *     Context = Pointer to context information
+ * NOTES:
+ *     Waits until an UDP packet is received on the chosen endpoint and displays the data
+ */
+{
+    ULONG Address;
+    UCHAR Data[40];
+    ULONG Size;
+    NTSTATUS Status = STATUS_SUCCESS;
+
+    if (!OpenError) {
+        while (NT_SUCCESS(Status)) {
+            Size = sizeof(Data);
+            RtlZeroMemory(Data, Size);
+
+            Status = TdiReceiveDatagram(TdiTransportObject,
+                                        TEST_PORT,
+                                        &Address,
+                                        Data,
+                                        &Size);
+            if (NT_SUCCESS(Status)) {
+                DbgPrint("Received data - '%s'\n", Data);
+            } else
+                if (Status != STATUS_CANCELLED) {
+                    TDI_DbgPrint(MIN_TRACE, ("Receive error (Status = 0x%X).\n", Status));
+                } else {
+                    TDI_DbgPrint(MAX_TRACE, ("IRP was cancelled.\n"));
+                }
+        }
+    }
+
+    TDI_DbgPrint(MAX_TRACE, ("Terminating receive thread...\n"));
+
+    KeSetEvent(&ReceiveThreadEvent, 0, FALSE);
+
+    PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+
+VOID TdiOpenThread(
+    PVOID Context)
+/*
+ * FUNCTION: Open thread
+ * ARGUMENTS:
+ *     Context = Pointer to context information (event)
+ */
+{
+    NTSTATUS Status;
+
+    TDI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    OpenError = TRUE;
+
+    Status = TdiOpenTransport(UDP_DEVICE_NAME,
+                              TEST_PORT,
+                              &TdiTransport,
+                              &TdiTransportObject);
+    if (NT_SUCCESS(Status)) {
+        Status = TdiQueryAddress(TdiTransportObject, &LocalAddress);
+        if (NT_SUCCESS(Status)) {
+            OpenError = FALSE;
+            DbgPrint("Using local IP address 0x%X\n", LocalAddress);
+        } else {
+            TDI_DbgPrint(MIN_TRACE, ("Unable to determine local IP address.\n"));
+        }
+    } else
+        TDI_DbgPrint(MIN_TRACE, ("Cannot open transport (Status = 0x%X).\n", Status));
+
+    TDI_DbgPrint(MAX_TRACE, ("Setting close event.\n"));
+
+    KeSetEvent((PKEVENT)Context, 0, FALSE);
+
+    TDI_DbgPrint(MIN_TRACE, ("Leaving.\n"));
+}
+
+
+VOID TdiUnload(
+    PDRIVER_OBJECT DriverObject)
+/*
+ * FUNCTION: Unload routine
+ * ARGUMENTS:
+ *     DriverObject = Pointer to a driver object for this driver
+ */
+{
+    TDI_DbgPrint(MAX_TRACE, ("Setting stop flag\n"));
+
+    KeSetEvent(&StopEvent, 0, FALSE);
+
+    /* Wait for send thread to stop */
+    KeWaitForSingleObject(&SendThreadEvent,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    ObDereferenceObject(SendThreadObject);
+
+    /* Wait for receive thread to stop */
+    KeWaitForSingleObject(&ReceiveThreadEvent,
+                          Executive,
+                          KernelMode,
+                          FALSE,
+                          NULL);
+
+    ObDereferenceObject(ReceiveThreadObject);
+
+    /* Close device */
+    TdiCloseDevice(TdiTransport, TdiTransportObject);
+}
+
+
+NTSTATUS
+#ifndef _MSC_VER
+STDCALL
+#endif
+DriverEntry(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Main driver entry point
+ * ARGUMENTS:
+ *     DriverObject = Pointer to a driver object for this driver
+ *     RegistryPath = Registry node for configuration parameters
+ * RETURNS:
+ *     Status of driver initialization
+ */
+{
+    KEVENT Event;
+    NTSTATUS Status;
+    WORK_QUEUE_ITEM WorkItem;
+
+    KeInitializeEvent(&StopEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&SendThreadEvent, NotificationEvent, FALSE);
+    KeInitializeEvent(&ReceiveThreadEvent, NotificationEvent, FALSE);
+
+    KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
+    ExInitializeWorkItem(&WorkItem, TdiOpenThread, &Event);
+    ExQueueWorkItem(&WorkItem, DelayedWorkQueue);
+
+    KeWaitForSingleObject(&Event,
+                          Executive,
+                          KernelMode,
+                          TRUE,
+                          NULL);
+
+
+    Status = PsCreateSystemThread(&SendThread,                      /* Thread handle */
+                                  0,                                /* Desired access */
+                                  NULL,                             /* Object attributes */
+                                  NULL,                             /* Process handle */
+                                  NULL,                             /* Client id */
+                                  (PKSTART_ROUTINE)TdiSendThread,   /* Start routine */
+                                  NULL);                            /* Start context */
+    if (!NT_SUCCESS(Status)) {
+        TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for send thread (Status = 0x%X).\n", Status));
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Get a pointer to the thread object */
+    ObReferenceObjectByHandle(SendThread,
+                              THREAD_ALL_ACCESS,
+                              NULL,
+                              KernelMode,
+                              &SendThreadObject,
+                              NULL);
+
+
+    Status = PsCreateSystemThread(&ReceiveThread,                       /* Thread handle */
+                                  0,                                    /* Desired access */
+                                  NULL,                                 /* Object attributes */
+                                  NULL,                                 /* Process handle */
+                                  NULL,                                 /* Client id */
+                                  (PKSTART_ROUTINE)TdiReceiveThread,    /* Start routine */
+                                  NULL);                                /* Start context */
+    if (!NT_SUCCESS(Status)) {
+        TDI_DbgPrint(MIN_TRACE, ("PsCreateSystemThread() failed for receive thread (Status = 0x%X).\n", Status));
+        ZwClose(SendThread);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* Get a pointer to the thread object */
+    ObReferenceObjectByHandle(ReceiveThread,
+                              THREAD_ALL_ACCESS,
+                              NULL,
+                              KernelMode,
+                              &ReceiveThreadObject,
+                              NULL);
+
+    /* Don't need these for anything, so we might as well close them now.
+       The threads will call PsTerminateSystemThread themselves when they are done */
+    ZwClose(SendThread);
+    ZwClose(ReceiveThread);
+
+    DriverObject->DriverUnload = (PDRIVER_UNLOAD)TdiUnload;
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */