--- /dev/null
+#include <limits.h>
+#include <roscfg.h>
+#include <ddk/ntddk.h>
+#include <rosrtl/string.h>
+#include <rosrtl/recmutex.h>
+#include <tcpip.h>
+#include <loopback.h>
+#include <ip.h>
+#include <icmp.h>
+#include <udp.h>
+#include <tcp.h>
+#include <rawip.h>
+#include <address.h>
+#include <receive.h>
+#include <transmit.h>
+#include <routines.h>
+#include <neighbor.h>
+#include <checksum.h>
+#include <route.h>
+#include <router.h>
+#include <prefix.h>
+#include <pool.h>
+#include <arp.h>
+#include <lan.h>
+#include <irp.h>
+#include <tilists.h>
+#include <dispatch.h>
+#include <fileobjs.h>
+#include <datagram.h>
+#include <info.h>
+#include <ndishack.h>
+#include <memtrack.h>
+#include <interface.h>
+#include <oskittcp.h>
--- /dev/null
+# $Id: makefile,v 1.1 2004/09/29 05:10:46 arty Exp $
+
+PATH_TO_TOP = ../../..
+
+TARGET_TYPE = library
+
+TARGET_NAME = ip$(KERNEL)
+
+TARGET_PCH = $(PATH_TO_TOP)/drivers/lib/ip/include/precomp.h
+
+# -DMEMTRACK
+TARGET_CFLAGS = \
+ -D__USE_W32API \
+ $(DRIVER) \
+ -Wall -Werror \
+ -Iinclude \
+ -I../../net/tcpip/include \
+ -I../undis/include \
+ -I../oskittcp/include \
+ -I$(PATH_TO_TOP)/include
+
+TARGET_CLEAN = network/*.o
+
+TARGET_OBJECTS = \
+ network/address.o \
+ network/arp.o \
+ network/checksum.o \
+ network/i386/checksum.o \
+ network/icmp.o \
+ network/interface.o \
+ network/ip.o \
+ network/loopback.o \
+ network/memtrack.o \
+ network/neighbor.o \
+ network/prefix.o \
+ network/receive.o \
+ network/route.o \
+ network/router.o \
+ network/routines.o \
+ network/transmit.o \
+ transport/datagram/datagram.o \
+ transport/rawip/rawip.o \
+ transport/tcp/event.o \
+ transport/tcp/if.o \
+ transport/tcp/tcp.o \
+ transport/udp/udp.o
+
+include $(PATH_TO_TOP)/rules.mak
+
+include $(TOOLS_PATH)/helper.mk
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+extern int sprintf( char *out, const char *fmt, ... );
+
+#ifdef DBG
+
+CHAR A2SStr[128];
+
+PCHAR A2S(
+ PIP_ADDRESS Address)
+/*
+ * FUNCTION: Convert an IP address to a string (for debugging)
+ * ARGUMENTS:
+ * Address = Pointer to an IP address structure
+ * RETURNS:
+ * Pointer to buffer with string representation of IP address
+ */
+{
+ ULONG ip;
+ PCHAR p;
+
+ p = A2SStr;
+
+ if (!Address) {
+ TI_DbgPrint(MIN_TRACE, ("NULL address given.\n"));
+ strcpy(p, "(NULL)");
+ return p;
+ }
+
+ switch (Address->Type) {
+ case IP_ADDRESS_V4:
+ ip = DN2H(Address->Address.IPv4Address);
+ sprintf(p, "%d.%d.%d.%d",
+ (INT)((ip >> 24) & 0xFF),
+ (INT)((ip >> 16) & 0xFF),
+ (INT)((ip >> 8) & 0xFF),
+ (INT)(ip & 0xFF));
+ break;
+
+ case IP_ADDRESS_V6:
+ /* FIXME: IPv6 is not supported */
+ strcpy(p, "(IPv6 address not supported)");
+ break;
+ }
+ return p;
+}
+
+#endif /* DBG */
+
+ULONG IPv4NToHl( ULONG Address ) {
+ return
+ ((Address & 0xff) << 24) |
+ ((Address & 0xff00) << 8) |
+ ((Address >> 8) & 0xff00) |
+ ((Address >> 24) & 0xff);
+}
+
+UINT AddrCountPrefixBits( PIP_ADDRESS Netmask ) {
+ UINT Prefix = 0;
+ if( Netmask->Type == IP_ADDRESS_V4 ) {
+ ULONG BitTest = 0x80000000;
+
+ /* The mask has been read in network order. Put it in host order
+ * in order to scan it. */
+
+ ULONG TestMask = IPv4NToHl(Netmask->Address.IPv4Address);
+
+ while( (BitTest & TestMask) == BitTest ) {
+ Prefix++;
+ BitTest >>= 1;
+ }
+ return Prefix;
+ } else {
+ TI_DbgPrint(DEBUG_DATALINK, ("Don't know address type %d\n",
+ Netmask->Type));
+ return 0;
+ }
+}
+
+VOID IPAddressFree(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an IP_ADDRESS object
+ * ARGUMENTS:
+ * Object = Pointer to an IP address structure
+ * RETURNS:
+ * Nothing
+ */
+{
+ ExFreePool(Object);
+}
+
+
+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)
+{
+ 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 */
+ PTDI_ADDRESS_IP ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;
+ *Port = ValidAddr->sin_port;
+ Address->Type = CurAddr->AddressType;
+ ValidAddr = (PTDI_ADDRESS_IP)CurAddr->Address;
+ AddrInitIPv4(Address, ValidAddr->in_addr);
+ return STATUS_SUCCESS;
+ }
+ }
+ }
+
+ return STATUS_INVALID_ADDRESS;
+}
+
+
+/*
+ * FUNCTION: Extract IP address from TDI address structure
+ * ARGUMENTS:
+ * TdiAddress = 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
+ * RETURNS:
+ * Status of operation
+ */
+NTSTATUS AddrBuildAddress(
+ PTA_ADDRESS TdiAddress,
+ PIP_ADDRESS *Address,
+ PUSHORT Port)
+{
+ PTDI_ADDRESS_IP ValidAddr;
+ PIP_ADDRESS IPAddress;
+
+ if (TdiAddress->AddressType != TDI_ADDRESS_TYPE_IP) {
+ TI_DbgPrint
+ (MID_TRACE,("AddressType %x, Not valid\n",
+ TdiAddress->AddressType));
+ return STATUS_INVALID_ADDRESS;
+ }
+ if (TdiAddress->AddressLength < TDI_ADDRESS_LENGTH_IP) {
+ TI_DbgPrint
+ (MID_TRACE,("AddressLength %x, Not valid (expected %x)\n",
+ TdiAddress->AddressLength, TDI_ADDRESS_LENGTH_IP));
+ return STATUS_INVALID_ADDRESS;
+ }
+
+
+ ValidAddr = (PTDI_ADDRESS_IP)TdiAddress->Address;
+
+ IPAddress = ExAllocatePool(NonPagedPool, sizeof(IP_ADDRESS));
+ if (!IPAddress)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ AddrInitIPv4(IPAddress, ValidAddr->in_addr);
+ *Address = IPAddress;
+ *Port = ValidAddr->sin_port;
+
+ return STATUS_SUCCESS;
+}
+
+
+/*
+ * 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 (network byte order)
+ * 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 = ExAllocatePool(NonPagedPool, sizeof(IP_ADDRESS));
+ if (IPAddress != NULL) {
+ IPAddress->RefCount = 1;
+ IPAddress->Type = IP_ADDRESS_V4;
+ IPAddress->Address.IPv4Address = Address;
+ IPAddress->Free = IPAddressFree;
+ }
+
+ return IPAddress;
+}
+
+
+/*
+ * FUNCTION: Clone an IP address
+ * ARGUMENTS:
+ * IPAddress = Pointer to IP address
+ * RETURNS:
+ * Pointer to new IP address structure, NULL if there was not enough free
+ * non-paged memory
+ */
+PIP_ADDRESS AddrCloneAddress(
+ PIP_ADDRESS Address)
+{
+ if (Address->Type == IP_ADDRESS_V4)
+ {
+ return AddrBuildIPv4(Address->Address.IPv4Address);
+ }
+ else
+ {
+ TI_DbgPrint(MIN_TRACE, ("Cannot clone IPv6 address.\n"));
+ return NULL;
+ }
+}
+
+
+/*
+ * 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);
+}
+
+unsigned long PASCAL inet_addr(const char *AddrString)
+/*
+ * Convert an ansi string dotted-quad address to a ulong
+ * NOTES:
+ * - this isn't quite like the real inet_addr() - * it doesn't
+ * handle "10.1" and similar - but it's good enough.
+ * - Returns in *host* byte order, unlike real inet_addr()
+ */
+{
+ ULONG Octets[4] = {0,0,0,0};
+ ULONG i = 0;
+
+ if(!AddrString)
+ return -1;
+
+ while(*AddrString)
+ {
+ CHAR c = *AddrString;
+ AddrString++;
+
+ if(c == '.')
+ {
+ i++;
+ continue;
+ }
+
+ if(c < '0' || c > '9')
+ return -1;
+
+ Octets[i] *= 10;
+ Octets[i] += (c - '0');
+
+ if(Octets[i] > 255)
+ return -1;
+ }
+
+ return (Octets[3] << 24) + (Octets[2] << 16) + (Octets[1] << 8) + Octets[0];
+}
+
+/* EOF */
--- /dev/null
+/*
+ * 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 "precomp.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;
+ NDIS_STATUS NdisStatus;
+ PARP_HEADER Header;
+ PVOID DataBuffer;
+ ULONG Size, Contig;
+
+ TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
+
+ /* Prepare ARP packet */
+ Size = MaxLLHeaderSize +
+ sizeof(ARP_HEADER) +
+ 2 * LinkAddressLength + /* Hardware address length */
+ 2 * ProtoAddressLength; /* Protocol address length */
+ Size = MAX(Size, MinLLFrameSize);
+
+ NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
+ if( !NT_SUCCESS(NdisStatus) ) return NULL;
+
+ GetDataPtr( NdisPacket, 0, (PCHAR *)&DataBuffer, (PUINT)&Contig );
+
+ 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);
+ DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength);
+
+ /* Our protocol address */
+ RtlCopyMemory(DataBuffer, SenderProtoAddress, ProtoAddressLength);
+
+ if (TargetLinkAddress) {
+ DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + ProtoAddressLength);
+ /* Target hardware address */
+ RtlCopyMemory(DataBuffer, TargetLinkAddress, LinkAddressLength);
+ DataBuffer = (PVOID)((ULONG_PTR)DataBuffer + LinkAddressLength);
+ } else
+ /* Don't care about target hardware address */
+ DataBuffer = (PVOID)((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(DEBUG_ARP, ("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(DEBUG_ARP, ("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:
+ TI_DbgPrint(DEBUG_ARP,("Bad Address Type %x\n", Address->Type));
+ KeBugCheck(0);
+ /* 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;
+
+ TI_DbgPrint(DEBUG_ARP,("Sending ARP Packet\n"));
+
+ (*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(DEBUG_ARP, ("Called.\n"));
+
+ Header = (PARP_HEADER)Packet->Header;
+
+ /* FIXME: Ethernet only */
+ if (WN2H(Header->HWType) != 1) {
+ TI_DbgPrint(DEBUG_ARP, ("Unknown ARP hardware type (0x%X).\n", WN2H(Header->HWType)));
+ return;
+ }
+
+ /* Check protocol type */
+ if (Header->ProtoType != ETYPE_IPv4) {
+ TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType)));
+ 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(DEBUG_ARP, ("Target address (0x%X) is not mine.\n", *((PULONG)TargetProtoAddress)));
+ 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 */
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+
+ULONG ChecksumFold(
+ ULONG Sum)
+{
+ /* Fold 32-bit sum to 16 bits */
+ while (Sum >> 16)
+ {
+ Sum = (Sum & 0xFFFF) + (Sum >> 16);
+ }
+
+ return Sum;
+}
+
+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
+ */
+{
+ register ULONG Sum = Seed;
+
+ while (Count > 1)
+ {
+ Sum += *(PUSHORT)Data;
+ Count -= 2;
+ Data = (PVOID)((ULONG_PTR) Data + 2);
+ }
+
+ /* Add left-over byte, if any */
+ if (Count > 0)
+ {
+ Sum += *(PUCHAR)Data;
+ }
+
+ return Sum;
+}
--- /dev/null
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * IP/TCP/UDP checksumming routines
+ *
+ * Authors: Jorge Cwik, <jorge@laser.satlink.net>
+ * Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ * Tom May, <ftom@netcom.com>
+ * Pentium Pro/II routines:
+ * Alexander Kjeldaas <astor@guardian.no>
+ * Finn Arne Gangstad <finnag@guardian.no>
+ * Lots of code moved from tcp.c and ip.c; see those files
+ * for more names.
+ *
+ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ * handling.
+ * Andi Kleen, add zeroing on error
+ * converted to pure assembler
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+
+.text
+.align 4
+.globl _csum_partial
+
+#ifndef CONFIG_X86_USE_PPRO_CHECKSUM
+
+ /*
+ * Experiments with Ethernet and SLIP connections show that buff
+ * is aligned on either a 2-byte or 4-byte boundary. We get at
+ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+ * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+ * alignment for the unrolled loop.
+ */
+_csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: unsigned char *buff
+ testl $3, %esi # Check alignment.
+ jz 2f # Jump if alignment is ok.
+ testl $1, %esi # Check alignment.
+ jz 10f # Jump if alignment is boundary of 2bytes.
+
+ # buf is odd
+ dec %ecx
+ jl 8f
+ movzbl (%esi), %ebx
+ adcl %ebx, %eax
+ roll $8, %eax
+ inc %esi
+ testl $2, %esi
+ jz 2f
+10:
+ subl $2, %ecx # Alignment uses up two bytes.
+ jae 1f # Jump if we had at least two bytes.
+ addl $2, %ecx # ecx was < 2. Deal with it.
+ jmp 4f
+1: movw (%esi), %bx
+ addl $2, %esi
+ addw %bx, %ax
+ adcl $0, %eax
+2:
+ movl %ecx, %edx
+ shrl $5, %ecx
+ jz 2f
+ testl %esi, %esi
+1: movl (%esi), %ebx
+ adcl %ebx, %eax
+ movl 4(%esi), %ebx
+ adcl %ebx, %eax
+ movl 8(%esi), %ebx
+ adcl %ebx, %eax
+ movl 12(%esi), %ebx
+ adcl %ebx, %eax
+ movl 16(%esi), %ebx
+ adcl %ebx, %eax
+ movl 20(%esi), %ebx
+ adcl %ebx, %eax
+ movl 24(%esi), %ebx
+ adcl %ebx, %eax
+ movl 28(%esi), %ebx
+ adcl %ebx, %eax
+ lea 32(%esi), %esi
+ dec %ecx
+ jne 1b
+ adcl $0, %eax
+2: movl %edx, %ecx
+ andl $0x1c, %edx
+ je 4f
+ shrl $2, %edx # This clears CF
+3: adcl (%esi), %eax
+ lea 4(%esi), %esi
+ dec %edx
+ jne 3b
+ adcl $0, %eax
+4: andl $3, %ecx
+ jz 7f
+ cmpl $2, %ecx
+ jb 5f
+ movw (%esi),%cx
+ leal 2(%esi),%esi
+ je 6f
+ shll $16,%ecx
+5: movb (%esi),%cl
+6: addl %ecx,%eax
+ adcl $0, %eax
+7:
+ testl $1, 12(%esp)
+ jz 8f
+ roll $8, %eax
+8:
+ popl %ebx
+ popl %esi
+ ret
+
+#else
+
+/* Version for PentiumII/PPro */
+
+csum_partial:
+ pushl %esi
+ pushl %ebx
+ movl 20(%esp),%eax # Function arg: unsigned int sum
+ movl 16(%esp),%ecx # Function arg: int len
+ movl 12(%esp),%esi # Function arg: const unsigned char *buf
+
+ testl $3, %esi
+ jnz 25f
+10:
+ movl %ecx, %edx
+ movl %ecx, %ebx
+ andl $0x7c, %ebx
+ shrl $7, %ecx
+ addl %ebx,%esi
+ shrl $2, %ebx
+ negl %ebx
+ lea 45f(%ebx,%ebx,2), %ebx
+ testl %esi, %esi
+ jmp *%ebx
+
+ # Handle 2-byte-aligned regions
+20: addw (%esi), %ax
+ lea 2(%esi), %esi
+ adcl $0, %eax
+ jmp 10b
+25:
+ testl $1, %esi
+ jz 30f
+ # buf is odd
+ dec %ecx
+ jl 90f
+ movzbl (%esi), %ebx
+ addl %ebx, %eax
+ adcl $0, %eax
+ roll $8, %eax
+ inc %esi
+ testl $2, %esi
+ jz 10b
+
+30: subl $2, %ecx
+ ja 20b
+ je 32f
+ addl $2, %ecx
+ jz 80f
+ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned
+ addl %ebx, %eax
+ adcl $0, %eax
+ jmp 80f
+32:
+ addw (%esi), %ax # csumming 2 bytes, 2-aligned
+ adcl $0, %eax
+ jmp 80f
+
+40:
+ addl -128(%esi), %eax
+ adcl -124(%esi), %eax
+ adcl -120(%esi), %eax
+ adcl -116(%esi), %eax
+ adcl -112(%esi), %eax
+ adcl -108(%esi), %eax
+ adcl -104(%esi), %eax
+ adcl -100(%esi), %eax
+ adcl -96(%esi), %eax
+ adcl -92(%esi), %eax
+ adcl -88(%esi), %eax
+ adcl -84(%esi), %eax
+ adcl -80(%esi), %eax
+ adcl -76(%esi), %eax
+ adcl -72(%esi), %eax
+ adcl -68(%esi), %eax
+ adcl -64(%esi), %eax
+ adcl -60(%esi), %eax
+ adcl -56(%esi), %eax
+ adcl -52(%esi), %eax
+ adcl -48(%esi), %eax
+ adcl -44(%esi), %eax
+ adcl -40(%esi), %eax
+ adcl -36(%esi), %eax
+ adcl -32(%esi), %eax
+ adcl -28(%esi), %eax
+ adcl -24(%esi), %eax
+ adcl -20(%esi), %eax
+ adcl -16(%esi), %eax
+ adcl -12(%esi), %eax
+ adcl -8(%esi), %eax
+ adcl -4(%esi), %eax
+45:
+ lea 128(%esi), %esi
+ adcl $0, %eax
+ dec %ecx
+ jge 40b
+ movl %edx, %ecx
+50: andl $3, %ecx
+ jz 80f
+
+ # Handle the last 1-3 bytes without jumping
+ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked
+ movl $0xffffff,%ebx # by the shll and shrl instructions
+ shll $3,%ecx
+ shrl %cl,%ebx
+ andl -128(%esi),%ebx # esi is 4-aligned so should be ok
+ addl %ebx,%eax
+ adcl $0,%eax
+80:
+ testl $1, 12(%esp)
+ jz 90f
+ roll $8, %eax
+90:
+ popl %ebx
+ popl %esi
+ ret
+
+#endif
--- /dev/null
+/*
+ * 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 "precomp.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 = NULL;
+ IPPacket =(PIP_PACKET)Context;
+
+ TI_DbgPrint(DEBUG_ICMP, ("Freeing NDIS packet (%X).\n", Packet));
+
+ /* Free packet */
+ FreeNdisPacket(Packet);
+
+ TI_DbgPrint(DEBUG_ICMP, ("Freeing IP packet at %X.\n", 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(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize));
+
+ /* Prepare ICMP packet */
+
+ /* FIXME: Assumes IPv4*/
+ IPPacket = IPCreatePacket(IP_ADDRESS_V4);
+ if (!IPPacket)
+ return NULL;
+
+ /* No special flags */
+ IPPacket->Flags = 0;
+
+ Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) +
+ sizeof(ICMP_HEADER) + DataSize;
+ DataBuffer = exAllocatePool(NonPagedPool, Size);
+ if (!DataBuffer) {
+ return NULL;
+ }
+
+ TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, DataBuffer));
+
+ /* Allocate NDIS packet */
+ NdisAllocatePacket(&NdisStatus, &NdisPacket, GlobalPacketPool);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ exFreePool(DataBuffer);
+ return NULL;
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("NdisPacket at (0x%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) {
+ FreeNdisPacket(NdisPacket);
+ exFreePool(DataBuffer);
+ return NULL;
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("NdisBuffer at (0x%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;
+
+ TI_DbgPrint(DEBUG_ICMP, ("Called.\n"));
+
+ ICMPHeader = (PICMP_HEADER)IPPacket->Data;
+
+ TI_DbgPrint(DEBUG_ICMP, ("Size (%d).\n", IPPacket->TotalSize));
+
+ TI_DbgPrint(DEBUG_ICMP, ("HeaderSize (%d).\n", IPPacket->HeaderSize));
+
+ TI_DbgPrint(DEBUG_ICMP, ("Type (%d).\n", ICMPHeader->Type));
+
+ TI_DbgPrint(DEBUG_ICMP, ("Code (%d).\n", ICMPHeader->Code));
+
+ TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum));
+
+ /* Checksum ICMP header and data */
+ if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) {
+ TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n"));
+ /* 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;
+
+#ifdef DBG
+ DisplayIPPacket(IPPacket);
+ DisplayIPPacket(NewPacket);
+#endif
+
+ ICMPTransmit(NTE, NewPacket);
+
+ TI_DbgPrint(DEBUG_ICMP, ("Echo reply sent.\n"));
+ return;
+
+ case ICMP_TYPE_ECHO_REPLY:
+ break;
+
+ default:
+ TI_DbgPrint(DEBUG_ICMP, ("Discarded ICMP datagram of unknown type %d.\n",
+ ICMPHeader->Type));
+ /* Discard packet */
+ break;
+ }
+
+ /* Send datagram up the protocol stack */
+ RawIPReceive(NTE, IPPacket);
+}
+
+
+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(DEBUG_ICMP, ("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, NULL, &RCN) == IP_SUCCESS) {
+ /* Send the packet */
+ if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS) {
+ FreeNdisPacket(IPPacket->NdisPacket);
+ }
+ /* 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(DEBUG_ICMP, ("No route to destination address 0x%X.\n",
+ IPPacket->DstAddr.Address.IPv4Address));
+ /* Discard packet */
+ FreeNdisPacket(IPPacket->NdisPacket);
+ }
+}
+
+
+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(DEBUG_ICMP, ("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 */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: tcpip/interface.c
+ * PURPOSE: Convenient abstraction for getting and setting information
+ * in IP_INTERFACE.
+ * PROGRAMMERS: Art Yerkes
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+
+NTSTATUS GetInterfaceIPv4Address( PIP_INTERFACE Interface,
+ ULONG TargetType,
+ PULONG Address ) {
+ ADE_LIST_ITER(CurrentADE);
+
+ ForEachADE(Interface->ADEListHead,CurrentADE) {
+ if (CurrentADE->Type == TargetType) {
+ *Address = CurrentADE->Address->Address.IPv4Address;
+ return STATUS_SUCCESS;
+ }
+ } EndFor(CurrentADE);
+
+ return STATUS_UNSUCCESSFUL;
+}
+
+UINT CountInterfaces() {
+ DWORD Count = 0;
+ KIRQL OldIrql;
+ IF_LIST_ITER(CurrentIF);
+
+ KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+ ForEachInterface(CurrentIF) {
+ Count++;
+ } EndFor(CurrentIF);
+
+ KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+ return Count;
+}
+
+UINT CountInterfaceAddresses( PIP_INTERFACE Interface ) {
+ UINT AddrCount = 0;
+ ADE_LIST_ITER(CurrentADE);
+
+ ForEachADE(Interface->ADEListHead,CurrentADE) {
+ if( CurrentADE->Type == ADE_UNICAST )
+ AddrCount++;
+ } EndFor(CurrentADE);
+
+ return AddrCount;
+}
+
+NTSTATUS GetInterfaceSpeed( PIP_INTERFACE Interface, PUINT Speed ) {
+ NDIS_STATUS NdisStatus;
+ PLAN_ADAPTER IF = (PLAN_ADAPTER)Interface->Context;
+
+#ifdef __NTDRIVER__
+ /* Get maximum link speed */
+ NdisStatus = NDISCall(IF,
+ NdisRequestQueryInformation,
+ OID_GEN_LINK_SPEED,
+ Speed,
+ sizeof(UINT));
+#else
+ (void)IF;
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ *Speed = 10000;
+#endif
+
+ return
+ NdisStatus != NDIS_STATUS_SUCCESS ?
+ STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
+}
+
+NTSTATUS GetInterfaceName( PIP_INTERFACE Interface,
+ PCHAR NameBuffer,
+ UINT Len ) {
+ NDIS_STATUS NdisStatus;
+ PLAN_ADAPTER IF = (PLAN_ADAPTER)Interface->Context;
+
+#ifdef __NTDRIVER__
+ /* Get maximum link speed */
+ NdisStatus = NDISCall(IF,
+ NdisRequestQueryInformation,
+ OID_GEN_FRIENDLY_NAME,
+ NameBuffer,
+ Len);
+#else
+ (void)IF;
+ NdisStatus = NDIS_STATUS_SUCCESS;
+ strncpy( NameBuffer, "eth", Len );
+#endif
+
+ return
+ NdisStatus != NDIS_STATUS_SUCCESS ?
+ STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
+}
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+
+KTIMER IPTimer;
+KDPC IPTimeoutDpc;
+LIST_ENTRY InterfaceListHead;
+KSPIN_LOCK InterfaceListLock;
+LIST_ENTRY NetTableListHead;
+KSPIN_LOCK NetTableListLock;
+UINT MaxLLHeaderSize; /* Largest maximum header size */
+UINT MinLLFrameSize; /* Largest minimum frame size */
+BOOLEAN IPInitialized = FALSE;
+NPAGED_LOOKASIDE_LIST IPPacketList;
+
+IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
+
+
+VOID FreePacket(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an IP packet object
+ * ARGUMENTS:
+ * Object = Pointer to an IP packet structure
+ */
+{
+ ExFreeToNPagedLookasideList(&IPPacketList, Object);
+}
+
+
+VOID DontFreePacket(
+ PVOID Object)
+/*
+ * FUNCTION: Do nothing for when the IPPacket struct is part of another
+ * ARGUMENTS:
+ * Object = Pointer to an IP packet structure
+ */
+{
+}
+
+
+VOID FreeADE(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an address entry object
+ * ARGUMENTS:
+ * Object = Pointer to an address entry structure
+ */
+{
+ exFreePool(Object);
+}
+
+
+VOID FreeNTE(
+ PVOID Object)
+/*
+ * FUNCTION: Frees a net table entry object
+ * ARGUMENTS:
+ * Object = Pointer to an net table entry structure
+ */
+{
+ exFreePool(Object);
+}
+
+
+VOID FreeIF(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an interface object
+ * ARGUMENTS:
+ * Object = Pointer to an interface structure
+ */
+{
+ exFreePool(Object);
+}
+
+
+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));
+
+ TI_DbgPrint(DEBUG_IP, ("Address (%s) NTE (%s).\n",
+ A2S(Address), A2S(NTE->Address)));
+
+ /* Allocate space for an ADE and set it up */
+ ADE = exAllocatePool(NonPagedPool, sizeof(ADDRESS_ENTRY));
+ if (!ADE) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ INIT_TAG(ADE, TAG('A','D','E',' '));
+ ADE->Free = FreeADE;
+ 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));
+
+ TI_DbgPrint(DEBUG_IP, ("ADE (%s).\n", ADE->Address));
+
+ /* 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 */
+ FreeADE(ADE);
+}
+
+
+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;
+ }
+}
+
+
+PIP_PACKET IPCreatePacket(
+ ULONG Type)
+/*
+ * FUNCTION: Creates an IP packet object
+ * ARGUMENTS:
+ * Type = Type of IP packet
+ * RETURNS:
+ * Pointer to the created IP packet. NULL if there was not enough free resources.
+ */
+{
+ PIP_PACKET IPPacket;
+
+ IPPacket = ExAllocateFromNPagedLookasideList(&IPPacketList);
+ if (!IPPacket)
+ return NULL;
+
+ /* FIXME: Is this needed? */
+ RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
+
+ INIT_TAG(IPPacket, TAG('I','P','K','T'));
+
+ IPPacket->Free = FreePacket;
+ IPPacket->RefCount = 1;
+ IPPacket->Type = Type;
+ IPPacket->HeaderSize = 20;
+
+ return IPPacket;
+}
+
+PIP_PACKET IPInitializePacket(
+ PIP_PACKET IPPacket,
+ ULONG Type)
+/*
+ * FUNCTION: Creates an IP packet object
+ * ARGUMENTS:
+ * Type = Type of IP packet
+ * RETURNS:
+ * Pointer to the created IP packet. NULL if there was not enough free resources.
+ */
+{
+ /* FIXME: Is this needed? */
+ RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
+
+ INIT_TAG(IPPacket, TAG('I','P','K','T'));
+
+ IPPacket->Free = DontFreePacket;
+ IPPacket->RefCount = 1;
+ IPPacket->Type = Type;
+
+ return IPPacket;
+}
+
+
+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));
+
+ TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
+
+ /* Allocate room for an NTE */
+ NTE = exAllocatePool(NonPagedPool, sizeof(NET_TABLE_ENTRY));
+ if (!NTE) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ INIT_TAG(NTE, TAG('N','T','E',' '));
+ INIT_TAG(Address, TAG('A','D','R','S'));
+
+ NTE->Free = FreeNTE;
+
+ 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"));
+ exFreePool(NTE);
+ return NULL;
+ }
+
+ /* Create a prefix list entry for unicast address */
+ NTE->PLE = CreatePLE(IF, NTE->Address, PrefixLength);
+ if (!NTE->PLE) {
+ DestroyADE(IF, ADE);
+ exFreePool(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));
+
+ TI_DbgPrint(DEBUG_IP, ("NTE (%s).\n", NTE->Address));
+
+ /* 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 */
+
+/* TODO: DEBUG: removed by RobD to prevent failure when testing under bochs 6 sept 2002.
+
+ 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 */
+ exFreePool(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 (%s) AddressType (0x%X).\n",
+ IF, A2S(Address), AddressType));
+
+ KeAcquireSpinLock(&IF->Lock, &OldIrql);
+
+ /* Search the list and return the NTE if found */
+ CurrentEntry = IF->ADEListHead.Flink;
+
+ if (CurrentEntry == &IF->ADEListHead) {
+ TI_DbgPrint(DEBUG_IP, ("NTE list is empty!!!\n"));
+ }
+
+ 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));
+
+// TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
+
+ 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;
+ IF_LIST_ITER(CurrentIF);
+ ADE_LIST_ITER(CurrentADE);
+
+// TI_DbgPrint(DEBUG_IP, ("Called. Address (0x%X) AddressType (0x%X).\n",
+// Address, AddressType));
+
+// TI_DbgPrint(DEBUG_IP, ("Address (%s).\n", A2S(Address)));
+
+ KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+ /* Search the interface list */
+ ForEachInterface(CurrentIF) {
+ /* Search the address entry list and return the ADE if found */
+ ForEachADE(CurrentIF->ADEListHead,CurrentADE) {
+ if ((AddrIsEqual(Address, CurrentADE->Address)) &&
+ (CurrentADE->Type == AddressType)) {
+ ReferenceObject(CurrentADE);
+ KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+ return CurrentADE;
+ }
+ } EndFor(CurrentADE);
+ } EndFor(CurrentIF);
+
+ 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;
+ ADE_LIST_ITER(CurrentADE);
+ IF_LIST_ITER(CurrentIF);
+ BOOLEAN LoopbackIsRegistered = FALSE;
+
+ TI_DbgPrint(DEBUG_IP, ("Called. AddressType (0x%X).\n", AddressType));
+
+ KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+
+ /* Search the interface list */
+ ForEachInterface(CurrentIF) {
+ if (CurrentIF != Loopback) {
+ /* Search the address entry list and return the first appropriate ADE found */
+ TI_DbgPrint(DEBUG_IP,("Checking interface %x\n", CurrentIF));
+ ForEachADE(CurrentIF->ADEListHead,CurrentADE) {
+ if (CurrentADE->Type == AddressType) {
+ ReferenceObject(CurrentADE);
+ KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+ return CurrentADE;
+ }
+ } EndFor(CurrentADE);
+ } else
+ LoopbackIsRegistered = TRUE;
+ } EndFor(CurrentIF);
+
+ /* No address was found. Use loopback interface if available */
+ if (LoopbackIsRegistered) {
+ ForEachADE(CurrentIF->ADEListHead,CurrentADE) {
+ if (CurrentADE->Type == AddressType) {
+ ReferenceObject(CurrentADE);
+ KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+ return CurrentADE;
+ }
+ } EndFor(CurrentADE);
+ }
+
+ KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+ return NULL;
+}
+
+
+VOID STDCALL 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();
+
+ /* Call upper layer timeout routines */
+ TCPTimeout();
+}
+
+
+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));
+
+#ifdef DBG
+ if (BindInfo->Address) {
+ PUCHAR A = BindInfo->Address;
+ TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
+ A[0], A[1], A[2], A[3], A[4], A[5]));
+ }
+#endif
+
+ IF = exAllocatePool(NonPagedPool, sizeof(IP_INTERFACE));
+ if (!IF) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ INIT_TAG(IF, TAG('F','A','C','E'));
+
+ IF->Free = FreeIF;
+ 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);
+
+#ifdef __NTDRIVER__
+ InsertTDIInterfaceEntity( IF );
+#endif
+
+ 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));
+
+#ifdef __NTDRIVER__
+ RemoveTDIInterfaceEntity( IF );
+#endif
+
+ 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
+
+ exFreePool(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(MID_TRACE, ("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;
+ }
+
+ /* Reference objects for forward information base */
+ ReferenceObject(Current->Address);
+ ReferenceObject(Current->PLE->Prefix);
+ ReferenceObject(NCE);
+
+ /* NCE is already referenced */
+ if (!RouterAddRoute(Current->Address, Current->PLE->Prefix, NCE, 1)) {
+ TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
+ DereferenceObject(Current->Address);
+ DereferenceObject(Current->PLE->Prefix);
+ DereferenceObject(NCE);
+ }
+
+ 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);
+ }
+ /* 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 */
+ ASSERT(&IF->ListEntry);
+ ExInterlockedInsertTailList(&InterfaceListHead,
+ &IF->ListEntry,
+ &InterfaceListLock);
+
+ /* Allow TCP to hang some configuration on this interface */
+ IF->TCPContext = TCPPrepareInterface( IF );
+
+ 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;
+
+ /* Initialize lookaside lists */
+ ExInitializeNPagedLookasideList(
+ &IPDRList, /* Lookaside list */
+ NULL, /* Allocate routine */
+ NULL, /* Free routine */
+ 0, /* Flags */
+ sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
+ TAG('I','P','D','R'), /* Tag */
+ 0); /* Depth */
+
+ ExInitializeNPagedLookasideList(
+ &IPPacketList, /* Lookaside list */
+ NULL, /* Allocate routine */
+ NULL, /* Free routine */
+ 0, /* Flags */
+ sizeof(IP_PACKET), /* Size of each entry */
+ TAG('I','P','P','K'), /* Tag */
+ 0); /* Depth */
+
+ ExInitializeNPagedLookasideList(
+ &IPFragmentList, /* Lookaside list */
+ NULL, /* Allocate routine */
+ NULL, /* Free routine */
+ 0, /* Flags */
+ sizeof(IP_FRAGMENT), /* Size of each entry */
+ TAG('I','P','F','G'), /* Tag */
+ 0); /* Depth */
+
+ ExInitializeNPagedLookasideList(
+ &IPHoleList, /* Lookaside list */
+ NULL, /* Allocate routine */
+ NULL, /* Free routine */
+ 0, /* Flags */
+ sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
+ TAG('I','P','H','L'), /* Tag */
+ 0); /* Depth */
+
+ /* 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);
+
+ InitPLE();
+
+ /* 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();
+
+ /* Destroy lookaside lists */
+ ExDeleteNPagedLookasideList(&IPHoleList);
+ ExDeleteNPagedLookasideList(&IPDRList);
+ ExDeleteNPagedLookasideList(&IPPacketList);
+ ExDeleteNPagedLookasideList(&IPFragmentList);
+
+ IPInitialized = FALSE;
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * 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 "precomp.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 LoopQueueLock;
+
+
+VOID STDCALL RealTransmit(
+ PVOID Context)
+/*
+ * FUNCTION: Transmits one or more packet(s) in loopback queue to ourselves
+ * ARGUMENTS:
+ * Context = Pointer to context information (loopback interface)
+ */
+{
+ PNDIS_PACKET NdisPacket;
+ PNDIS_BUFFER NdisBuffer;
+ IP_PACKET IPPacket;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ KeAcquireSpinLockAtDpcLevel(&LoopQueueLock);
+
+ while (TRUE)
+ {
+ /* Get the next packet from the queue (if any) */
+ NdisPacket = LoopQueueHead;
+ if (!NdisPacket)
+ break;
+
+ TI_DbgPrint(MAX_TRACE, ("NdisPacket (0x%X)\n", NdisPacket));
+
+ LoopQueueHead = *(PNDIS_PACKET*)NdisPacket->u.s3.MacReserved;
+ KeReleaseSpinLockFromDpcLevel(&LoopQueueLock);
+ IPPacket.NdisPacket = NdisPacket;
+
+ NdisGetFirstBufferFromPacket(NdisPacket,
+ &NdisBuffer,
+ &IPPacket.Header,
+ &IPPacket.ContigSize,
+ &IPPacket.TotalSize);
+ IPReceive(Context, &IPPacket);
+ AdjustPacket(NdisPacket, 0, PC(NdisPacket)->DLOffset);
+ PC(NdisPacket)->DLComplete(Context, NdisPacket, NDIS_STATUS_SUCCESS);
+ KeAcquireSpinLockAtDpcLevel(&LoopQueueLock);
+ }
+
+ LoopBusy = FALSE;
+ KeReleaseSpinLockFromDpcLevel(&LoopQueueLock);
+}
+
+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->u.s3.MacReserved;
+ *pNdisPacket = NULL;
+
+ KeAcquireSpinLock(&LoopQueueLock, &OldIrql);
+
+ /* Add packet to transmit queue */
+ if (LoopQueueHead != NULL)
+ {
+ /* Transmit queue is not empty */
+ pNdisPacket = (PNDIS_PACKET*)LoopQueueTail->u.s3.MacReserved;
+ *pNdisPacket = NdisPacket;
+ }
+ else
+ {
+ /* Transmit queue is empty */
+ LoopQueueHead = NdisPacket;
+ }
+
+ LoopQueueTail = NdisPacket;
+
+ /* If RealTransmit is not running (or scheduled to run) then schedule it to run now */
+ if (!LoopBusy)
+ {
+ LoopBusy = TRUE; /* The loopback interface is now busy */
+ ExQueueWorkItem(&LoopWorkItem, CriticalWorkQueue);
+ }
+
+ KeReleaseSpinLock(&LoopQueueLock, OldIrql);
+}
+
+NDIS_STATUS LoopRegisterAdapter(
+ PNDIS_STRING AdapterName,
+ PLAN_ADAPTER *Adapter)
+/*
+ * FUNCTION: Registers loopback adapter with the network layer
+ * ARGUMENTS:
+ * AdapterName = Unused
+ * Adapter = Unused
+ * RETURNS:
+ * Status of operation
+ */
+{
+ PIP_ADDRESS Address;
+ NDIS_STATUS Status;
+
+ Status = NDIS_STATUS_SUCCESS;
+
+ TI_DbgPrint(MID_TRACE, ("Called.\n"));
+
+ Address = AddrBuildIPv4(LOOPBACK_ADDRESS_IPv4);
+ if (Address != NULL)
+ {
+ LLIP_BIND_INFO BindInfo;
+
+ /* Bind the adapter to network (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 != NULL) && (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(&LoopQueueLock);
+ 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 with the network layer
+ * 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 != NULL)
+ {
+ IPUnregisterInterface(Loopback);
+ IPDestroyInterface(Loopback);
+ Loopback = NULL;
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+ return NDIS_STATUS_SUCCESS;
+}
--- /dev/null
+#define MEMTRACK_NO_POOL
+#include "precomp.h"
+
+#ifdef MEMTRACK
+
+LIST_ENTRY AllocatedObjectsList;
+KSPIN_LOCK AllocatedObjectsLock;
+DWORD TagsToShow[MEMTRACK_MAX_TAGS_TO_TRACK] = { 0 };
+
+VOID TrackTag( DWORD Tag ) {
+ UINT i;
+
+ for( i = 0; TagsToShow[i]; i++ );
+ TagsToShow[i] = Tag;
+}
+
+VOID TrackingInit() {
+ KeInitializeSpinLock( &AllocatedObjectsLock );
+ InitializeListHead( &AllocatedObjectsList );
+}
+
+VOID ShowTrackedThing( PCHAR What, PALLOCATION_TRACKER Thing,
+ PCHAR File, UINT Line ) {
+ /* if( ShowTag( Thing->Tag ) ) */
+ if( File ) {
+ DbgPrint( "[%s] Thing %08x %c%c%c%c (%s:%d) (Called from %s:%d)\n",
+ What,
+ Thing->Thing,
+ ((PCHAR)&Thing->Tag)[3],
+ ((PCHAR)&Thing->Tag)[2],
+ ((PCHAR)&Thing->Tag)[1],
+ ((PCHAR)&Thing->Tag)[0],
+ Thing->FileName,
+ Thing->LineNo,
+ File, Line );
+ } else {
+ DbgPrint( "[%s] Thing %08x %c%c%c%c (%s:%d)\n",
+ What,
+ Thing->Thing,
+ ((PCHAR)&Thing->Tag)[3],
+ ((PCHAR)&Thing->Tag)[2],
+ ((PCHAR)&Thing->Tag)[1],
+ ((PCHAR)&Thing->Tag)[0],
+ Thing->FileName,
+ Thing->LineNo );
+ }
+}
+
+VOID TrackWithTag( DWORD Tag, PVOID Thing, PCHAR FileName, DWORD LineNo ) {
+ PALLOCATION_TRACKER TrackedThing =
+ ExAllocatePool( NonPagedPool, sizeof(*TrackedThing) );
+
+ KIRQL OldIrql;
+ PLIST_ENTRY Entry;
+ PALLOCATION_TRACKER ThingInList;
+
+ KeAcquireSpinLock( &AllocatedObjectsLock, &OldIrql );
+ Entry = AllocatedObjectsList.Flink;
+ while( Entry != &AllocatedObjectsList ) {
+ ThingInList = CONTAINING_RECORD(Entry, ALLOCATION_TRACKER, Entry);
+ if( ThingInList->Thing == Thing ) {
+ RemoveEntryList(Entry);
+
+ KeReleaseSpinLock( &AllocatedObjectsLock, OldIrql );
+ ShowTrackedThing( "Alloc", ThingInList, FileName, LineNo );
+ ExFreePool( ThingInList );
+ TrackDumpFL( FileName, LineNo );
+ DbgPrint("TRACK: SPECIFIED ALREADY ALLOCATED ITEM %x\n", Thing);
+ KeBugCheck( 0 );
+ }
+ Entry = Entry->Flink;
+ }
+
+ KeReleaseSpinLock( &AllocatedObjectsLock, OldIrql );
+
+ if( TrackedThing ) {
+ TrackedThing->Tag = Tag;
+ TrackedThing->Thing = Thing;
+ TrackedThing->FileName = FileName;
+ TrackedThing->LineNo = LineNo;
+
+ ExInterlockedInsertTailList( &AllocatedObjectsList,
+ &TrackedThing->Entry,
+ &AllocatedObjectsLock );
+ ShowTrackedThing( "Alloc", TrackedThing, FileName, LineNo );
+ }
+
+ /*TrackDumpFL( FileName, LineNo );*/
+}
+
+BOOL ShowTag( DWORD Tag ) {
+ UINT i;
+
+ for( i = 0; TagsToShow[i] && TagsToShow[i] != Tag; i++ );
+
+ return TagsToShow[i] ? TRUE : FALSE;
+}
+
+VOID UntrackFL( PCHAR File, DWORD Line, PVOID Thing ) {
+ KIRQL OldIrql;
+ PLIST_ENTRY Entry;
+ PALLOCATION_TRACKER ThingInList;
+
+ KeAcquireSpinLock( &AllocatedObjectsLock, &OldIrql );
+ Entry = AllocatedObjectsList.Flink;
+ while( Entry != &AllocatedObjectsList ) {
+ ThingInList = CONTAINING_RECORD(Entry, ALLOCATION_TRACKER, Entry);
+ if( ThingInList->Thing == Thing ) {
+ RemoveEntryList(Entry);
+
+ ShowTrackedThing( "Free ", ThingInList, File, Line );
+
+ ExFreePool( ThingInList );
+ KeReleaseSpinLock( &AllocatedObjectsLock, OldIrql );
+ /* TrackDumpFL( File, Line ); */
+ return;
+ }
+ Entry = Entry->Flink;
+ }
+ KeReleaseSpinLock( &AllocatedObjectsLock, OldIrql );
+ TrackDumpFL( File, Line );
+ DbgPrint("UNTRACK: SPECIFIED ALREADY FREE ITEM %x\n", Thing);
+ KeBugCheck( 0 );
+}
+
+VOID TrackDumpFL( PCHAR File, DWORD Line ) {
+ KIRQL OldIrql;
+ PLIST_ENTRY Entry;
+ PALLOCATION_TRACKER Thing;
+
+ DbgPrint("Dump: %s:%d\n", File, Line);
+
+ KeAcquireSpinLock( &AllocatedObjectsLock, &OldIrql );
+ Entry = AllocatedObjectsList.Flink;
+ while( Entry != &AllocatedObjectsList ) {
+ Thing = CONTAINING_RECORD(Entry, ALLOCATION_TRACKER, Entry);
+ ShowTrackedThing( "Dump ", Thing, 0, 0 );
+ Entry = Entry->Flink;
+ }
+ KeReleaseSpinLock( &AllocatedObjectsLock, OldIrql );
+}
+
+#endif/*MEMTRACK*/
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+
+NEIGHBOR_CACHE_TABLE NeighborCache[NB_HASHMASK + 1];
+
+
+VOID FreeNCE(
+ PVOID Object)
+{
+ ExFreePool(Object);
+}
+
+VOID NCETimeout(
+ PNEIGHBOR_CACHE_ENTRY NCE)
+/*
+ * FUNCTION: Neighbor cache entry timeout handler
+ * NOTES:
+ * The neighbor cache lock must be held
+ */
+{
+ PNDIS_PACKET NdisPacket;
+ PNDIS_PACKET NextNdisPacket;
+
+ 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 != NULL)
+ {
+ NextNdisPacket = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;
+ IPSendComplete((PVOID)NCE->Interface,
+ NdisPacket,
+ NDIS_STATUS_REQUEST_ABORTED);
+ NdisPacket = NextNdisPacket;
+ }
+ NCE->WaitQueue = NULL;
+
+ NCE->EventCount = 0;
+
+ /* Remove route cache entries with references to this NCE.
+ Remember that neighbor cache lock is acquired before the
+ 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 the event timer is not used in the other states */
+ 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) {
+ NCE->EventTimer--;
+ 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
+ */
+{
+ PNEIGHBOR_CACHE_ENTRY NextNCE;
+ PNEIGHBOR_CACHE_ENTRY CurNCE;
+ PNDIS_PACKET NextNdisPacket;
+ PNDIS_PACKET NdisPacket;
+ KIRQL OldIrql;
+ UINT i;
+
+ 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)
+ {
+ NextNdisPacket = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;
+ FreeNdisPacket(NdisPacket);
+ NdisPacket = NextNdisPacket;
+ }
+
+#ifdef 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 */
+ if (!NCE->Interface || !NCE->Interface->NTEListHead.Flink) {
+ TI_DbgPrint(MID_TRACE,
+ ("NCE->Interface: %x, "
+ "NCE->Interface->NTEListHead.Flink %x\n",
+ NCE->Interface,
+ NCE->Interface ? NCE->Interface->NTEListHead.Flink : 0));
+ }
+ if (!IsListEmpty(&NCE->Interface->NTEListHead))
+ {
+ CurrentEntry = NCE->Interface->NTEListHead.Flink;
+ 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
+ */
+{
+ PNEIGHBOR_CACHE_ENTRY NCE;
+ ULONG HashValue;
+ KIRQL OldIrql;
+
+ 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));
+
+ ASSERT(Address->Type == IP_ADDRESS_V4);
+
+ NCE = ExAllocatePool(NonPagedPool, sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength);
+ if (NCE == NULL)
+ {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ INIT_TAG(NCE, TAG('N','C','E',' '));
+
+ /* Initialize NCE free routine */
+ NCE->Free = FreeNCE;
+
+ /* 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)&NCE[1];
+ if (LinkAddress != NULL)
+ {
+ 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
+ */
+{
+ PNDIS_PACKET Current;
+ PNDIS_PACKET Next;
+ KIRQL OldIrql;
+
+ 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);
+
+ /* Send any waiting packets */
+ while (Current != NULL)
+ {
+ /* 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;
+ }
+}
+
+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
+ */
+{
+ PNEIGHBOR_CACHE_ENTRY NCE;
+ UINT HashValue;
+ KIRQL OldIrql;
+
+ 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 (in case 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 == NULL)
+ {
+ 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
+ */
+{
+ PKSPIN_LOCK Lock;
+ KIRQL OldIrql;
+
+ 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
+ */
+{
+ PNEIGHBOR_CACHE_ENTRY *PrevNCE;
+ PNEIGHBOR_CACHE_ENTRY CurNCE;
+ PNDIS_PACKET NextNdisPacket;
+ PNDIS_PACKET NdisPacket;
+ ULONG HashValue;
+ KIRQL OldIrql;
+
+ 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 != NULL)
+ {
+ NextNdisPacket = (PNDIS_PACKET)PC(NdisPacket)->DLComplete;
+ FreeNdisPacket(NdisPacket);
+ NdisPacket = NextNdisPacket;
+ }
+
+ /* Remove all references from route cache */
+ RouteInvalidateNCE(CurNCE);
+
+#ifdef 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
+ ExFreePool(CurNCE);
+
+ KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+
+ return;
+ }
+ }
+
+ KeReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
+}
--- /dev/null
+/*
+ * 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)
+ * Art Yerkes (arty@users.sourceforge.net)
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+
+LIST_ENTRY PrefixListHead;
+KSPIN_LOCK PrefixListLock;
+
+/* --------- The Prefix List ---------- */
+
+VOID InitPLE() {
+ /* Initialize the prefix list and protecting lock */
+ InitializeListHead(&PrefixListHead);
+ KeInitializeSpinLock(&PrefixListLock);
+}
+
+
+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));
+
+ TI_DbgPrint(DEBUG_IP, ("Prefix (%s).\n", A2S(Prefix)));
+
+ /* Allocate space for an PLE and set it up */
+ PLE = ExAllocatePool(NonPagedPool, sizeof(PREFIX_LIST_ENTRY));
+ if (!PLE) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ INIT_TAG(PLE, TAG('P','L','E',' '));
+ 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));
+
+ TI_DbgPrint(DEBUG_IP, ("PLE (%s).\n", PLE->Prefix));
+
+ /* 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 */
+ ExFreePool(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);
+}
+
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: network/receive.c
+ * PURPOSE: Internet Protocol receive routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * NOTES: The IP datagram reassembly algorithm is taken from
+ * from RFC 815
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+LIST_ENTRY ReassemblyListHead;
+KSPIN_LOCK ReassemblyListLock;
+NPAGED_LOOKASIDE_LIST IPDRList;
+NPAGED_LOOKASIDE_LIST IPFragmentList;
+NPAGED_LOOKASIDE_LIST IPHoleList;
+
+
+PIPDATAGRAM_HOLE CreateHoleDescriptor(
+ ULONG First,
+ ULONG Last)
+/*
+ * FUNCTION: Returns a pointer to a IP datagram hole descriptor
+ * ARGUMENTS:
+ * First = Offset of first octet of the hole
+ * Last = Offset of last octet of the hole
+ * RETURNS:
+ * Pointer to descriptor, NULL if there was not enough free
+ * resources
+ */
+{
+ PIPDATAGRAM_HOLE Hole;
+
+ TI_DbgPrint(DEBUG_IP, ("Called. First (%d) Last (%d).\n", First, Last));
+
+ Hole = ExAllocateFromNPagedLookasideList(&IPHoleList);
+ if (!Hole) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ Hole->First = First;
+ Hole->Last = Last;
+
+ TI_DbgPrint(DEBUG_IP, ("Returning hole descriptor at (0x%X).\n", Hole));
+
+ return Hole;
+}
+
+
+VOID FreeIPDR(
+ PIPDATAGRAM_REASSEMBLY IPDR)
+/*
+ * FUNCTION: Frees an IP datagram reassembly structure
+ * ARGUMENTS:
+ * IPDR = Pointer to IP datagram reassembly structure
+ */
+{
+ PLIST_ENTRY CurrentEntry;
+ PLIST_ENTRY NextEntry;
+ PIPDATAGRAM_HOLE CurrentH;
+ PIP_FRAGMENT CurrentF;
+
+ TI_DbgPrint(DEBUG_IP, ("Freeing IP datagram reassembly descriptor (0x%X).\n", IPDR));
+
+ /* Free all descriptors */
+ CurrentEntry = IPDR->HoleListHead.Flink;
+ while (CurrentEntry != &IPDR->HoleListHead) {
+ NextEntry = CurrentEntry->Flink;
+ CurrentH = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+ /* Unlink it from the list */
+ RemoveEntryList(CurrentEntry);
+
+ TI_DbgPrint(DEBUG_IP, ("Freeing hole descriptor at (0x%X).\n", CurrentH));
+
+ /* And free the hole descriptor */
+ ExFreeToNPagedLookasideList(&IPHoleList, CurrentH);
+
+ CurrentEntry = NextEntry;
+ }
+
+ /* Free all fragments */
+ CurrentEntry = IPDR->FragmentListHead.Flink;
+ while (CurrentEntry != &IPDR->FragmentListHead) {
+ NextEntry = CurrentEntry->Flink;
+ CurrentF = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
+ /* Unlink it from the list */
+ RemoveEntryList(CurrentEntry);
+
+ TI_DbgPrint(DEBUG_IP, ("Freeing fragment data at (0x%X).\n", CurrentF->Data));
+
+ /* Free the fragment data buffer */
+ exFreePool(CurrentF->Data);
+
+ TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
+
+ /* And free the fragment descriptor */
+ ExFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
+ CurrentEntry = NextEntry;
+ }
+
+ /* Free resources for the header, if it exists */
+ if (IPDR->IPv4Header) {
+ TI_DbgPrint(DEBUG_IP, ("Freeing IPv4 header data at (0x%X).\n", IPDR->IPv4Header));
+ exFreePool(IPDR->IPv4Header);
+ }
+
+ TI_DbgPrint(DEBUG_IP, ("Freeing IPDR data at (0x%X).\n", IPDR));
+
+ ExFreeToNPagedLookasideList(&IPDRList, IPDR);
+}
+
+
+VOID RemoveIPDR(
+ PIPDATAGRAM_REASSEMBLY IPDR)
+/*
+ * FUNCTION: Removes an IP datagram reassembly structure from the global list
+ * ARGUMENTS:
+ * IPDR = Pointer to IP datagram reassembly structure
+ */
+{
+ KIRQL OldIrql;
+
+ TI_DbgPrint(DEBUG_IP, ("Removing IPDR at (0x%X).\n", IPDR));
+
+ KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+ RemoveEntryList(&IPDR->ListEntry);
+ KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+}
+
+
+PIPDATAGRAM_REASSEMBLY GetReassemblyInfo(
+ PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Returns a pointer to an IP datagram reassembly structure
+ * ARGUMENTS:
+ * IPPacket = Pointer to IP packet
+ * NOTES:
+ * A datagram is identified by four paramters, which are
+ * Source and destination address, protocol number and
+ * identification number
+ */
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY CurrentEntry;
+ PIPDATAGRAM_REASSEMBLY Current;
+ PIPv4_HEADER Header = (PIPv4_HEADER)IPPacket->Header;
+
+ TI_DbgPrint(DEBUG_IP, ("Searching for IPDR for IP packet at (0x%X).\n", IPPacket));
+
+ KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+
+ /* FIXME: Assume IPv4 */
+
+ CurrentEntry = ReassemblyListHead.Flink;
+ while (CurrentEntry != &ReassemblyListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
+ if (AddrIsEqual(&IPPacket->SrcAddr, &Current->SrcAddr) &&
+ (Header->Id == Current->Id) &&
+ (Header->Protocol == Current->Protocol) &&
+ (AddrIsEqual(&IPPacket->DstAddr, &Current->DstAddr))) {
+ KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+
+ return Current;
+ }
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+
+ return NULL;
+}
+
+
+PIP_PACKET ReassembleDatagram(
+ PIPDATAGRAM_REASSEMBLY IPDR)
+/*
+ * FUNCTION: Reassembles an IP datagram
+ * ARGUMENTS:
+ * IPDR = Pointer to IP datagram reassembly structure
+ * NOTES:
+ * This routine concatenates fragments into a complete IP datagram.
+ * The lock is held when this routine is called
+ * RETURNS:
+ * Pointer to IP packet, NULL if there was not enough free resources
+ * NOTES:
+ * At this point, header is expected to point to the IP header
+ */
+{
+ PIP_PACKET IPPacket;
+ PLIST_ENTRY CurrentEntry;
+ PIP_FRAGMENT Current;
+ PVOID Data;
+
+ TI_DbgPrint(DEBUG_IP, ("Reassembling datagram from IPDR at (0x%X).\n", IPDR));
+ TI_DbgPrint(DEBUG_IP, ("IPDR->HeaderSize = %d\n", IPDR->HeaderSize));
+ TI_DbgPrint(DEBUG_IP, ("IPDR->DataSize = %d\n", IPDR->DataSize));
+
+ TI_DbgPrint(DEBUG_IP, ("Fragment header:\n"));
+ //OskitDumpBuffer((PCHAR)IPDR->IPv4Header, IPDR->HeaderSize);
+
+ /* FIXME: Assume IPv4 */
+ IPPacket = IPCreatePacket(IP_ADDRESS_V4);
+ if (!IPPacket)
+ return NULL;
+
+ IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
+ IPPacket->ContigSize = IPPacket->TotalSize;
+ IPPacket->HeaderSize = IPDR->HeaderSize;
+ /*IPPacket->Position = IPDR->HeaderSize;*/
+
+ RtlCopyMemory(&IPPacket->SrcAddr, &IPDR->SrcAddr, sizeof(IP_ADDRESS));
+ RtlCopyMemory(&IPPacket->DstAddr, &IPDR->DstAddr, sizeof(IP_ADDRESS));
+
+ /* Allocate space for full IP datagram */
+ IPPacket->Header = exAllocatePool(NonPagedPool, IPPacket->TotalSize);
+ if (!IPPacket->Header) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ (*IPPacket->Free)(IPPacket);
+ return NULL;
+ }
+
+ /* Copy the header into the buffer */
+ RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);
+
+ Data = IPPacket->Header + IPDR->HeaderSize;
+ IPPacket->Data = Data;
+
+ /* Copy data from all fragments into buffer */
+ CurrentEntry = IPDR->FragmentListHead.Flink;
+ while (CurrentEntry != &IPDR->FragmentListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
+
+ TI_DbgPrint(DEBUG_IP, ("Copying (%d) bytes of fragment data from (0x%X) to offset (%d).\n",
+ Current->Size, Data, Current->Offset));
+ /* Copy fragment data to the destination buffer at the correct offset */
+ RtlCopyMemory((PVOID)((ULONG_PTR)Data + Current->Offset),
+ Current->Data,
+ Current->Size);
+ //OskitDumpBuffer( Data, Current->Offset + Current->Size );
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ return IPPacket;
+}
+
+
+__inline VOID Cleanup(
+ PKSPIN_LOCK Lock,
+ KIRQL OldIrql,
+ PIPDATAGRAM_REASSEMBLY IPDR,
+ PVOID Buffer OPTIONAL)
+/*
+ * FUNCTION: Performs cleaning operations on errors
+ * ARGUMENTS:
+ * Lock = Pointer to spin lock to be released
+ * OldIrql = Value of IRQL when spin lock was acquired
+ * IPDR = Pointer to IP datagram reassembly structure to free
+ * Buffer = Optional pointer to a buffer to free
+ */
+{
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+
+ KeReleaseSpinLock(Lock, OldIrql);
+ RemoveIPDR(IPDR);
+ FreeIPDR(IPDR);
+ if (Buffer)
+ exFreePool(Buffer);
+}
+
+
+VOID ProcessFragment(
+ PIP_INTERFACE IF,
+ PIP_PACKET IPPacket,
+ PNET_TABLE_ENTRY NTE)
+/*
+ * FUNCTION: Processes an IP datagram or fragment
+ * ARGUMENTS:
+ * IF = Pointer to IP interface packet was receive on
+ * IPPacket = Pointer to IP packet
+ * NTE = Pointer to NTE packet was received on
+ * NOTES:
+ * This routine reassembles fragments and, if a whole datagram can
+ * be assembled, passes the datagram on to the IP protocol dispatcher
+ */
+{
+ KIRQL OldIrql;
+ PIPDATAGRAM_REASSEMBLY IPDR;
+ PLIST_ENTRY CurrentEntry;
+ PIPDATAGRAM_HOLE Hole, NewHole;
+ USHORT FragFirst;
+ USHORT FragLast;
+ BOOLEAN MoreFragments;
+ PIPv4_HEADER IPv4Header;
+ PIP_PACKET Datagram;
+ PIP_FRAGMENT Fragment;
+
+ /* FIXME: Assume IPv4 */
+
+ IPv4Header = (PIPv4_HEADER)IPPacket->Header;
+
+ /* Check if we already have an reassembly structure for this datagram */
+ IPDR = GetReassemblyInfo(IPPacket);
+ if (IPDR) {
+ TI_DbgPrint(DEBUG_IP, ("Continueing assembly.\n"));
+ /* We have a reassembly structure */
+ KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
+ CurrentEntry = IPDR->HoleListHead.Flink;
+ Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+ } else {
+ TI_DbgPrint(DEBUG_IP, ("Starting new assembly.\n"));
+
+ /* We don't have a reassembly structure, create one */
+ IPDR = ExAllocateFromNPagedLookasideList(&IPDRList);
+ if (!IPDR)
+ /* We don't have the resources to process this packet, discard it */
+ return;
+
+ /* Create a descriptor spanning from zero to infinity.
+ Actually, we use a value slightly greater than the
+ maximum number of octets an IP datagram can contain */
+ Hole = CreateHoleDescriptor(0, 65536);
+ if (!Hole) {
+ /* We don't have the resources to process this packet, discard it */
+ ExFreeToNPagedLookasideList(&IPDRList, IPDR);
+ return;
+ }
+ AddrInitIPv4(&IPDR->SrcAddr, IPv4Header->SrcAddr);
+ AddrInitIPv4(&IPDR->DstAddr, IPv4Header->DstAddr);
+ IPDR->Id = IPv4Header->Id;
+ IPDR->Protocol = IPv4Header->Protocol;
+ IPDR->IPv4Header = NULL;
+ InitializeListHead(&IPDR->FragmentListHead);
+ InitializeListHead(&IPDR->HoleListHead);
+ InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
+ CurrentEntry = IPDR->HoleListHead.Flink;
+
+ KeInitializeSpinLock(&IPDR->Lock);
+
+ KeAcquireSpinLock(&IPDR->Lock, &OldIrql);
+
+ /* Update the reassembly list */
+ ExInterlockedInsertTailList(
+ &ReassemblyListHead,
+ &IPDR->ListEntry,
+ &ReassemblyListLock);
+ }
+
+ FragFirst = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_FRAGOFS_MASK) << 3;
+ FragLast = FragFirst + WN2H(IPv4Header->TotalLength);
+ MoreFragments = (WN2H(IPv4Header->FlagsFragOfs) & IPv4_MF_MASK) > 0;
+
+ for (;;) {
+ if (CurrentEntry == &IPDR->HoleListHead)
+ /* No more entries */
+ break;
+
+ TI_DbgPrint(DEBUG_IP, ("Comparing Fragment (%d,%d) to Hole (%d,%d).\n",
+ FragFirst, FragLast, Hole->First, Hole->Last));
+
+ if ((FragFirst > Hole->Last) || (FragLast < Hole->First)) {
+ TI_DbgPrint(MID_TRACE, ("No overlap.\n"));
+ /* The fragment does not overlap with the hole, try next
+ descriptor in the list */
+
+ CurrentEntry = CurrentEntry->Flink;
+ if (CurrentEntry != &IPDR->HoleListHead)
+ Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
+ continue;
+ }
+
+ /* The fragment overlap with the hole, unlink the descriptor */
+ RemoveEntryList(CurrentEntry);
+
+ if (FragFirst > Hole->First) {
+ NewHole = CreateHoleDescriptor(Hole->First, FragLast - 1);
+ if (!NewHole) {
+ /* We don't have the resources to process this packet, discard it */
+ Cleanup(&IPDR->Lock, OldIrql, IPDR, Hole);
+ return;
+ }
+
+ /* Put the new descriptor in the list */
+ InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
+ }
+
+ if ((FragLast < Hole->Last) && (MoreFragments)) {
+ /* We can reuse the descriptor for the new hole */
+ Hole->First = FragLast + 1;
+
+ /* Put the new hole descriptor in the list */
+ InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
+ } else
+ ExFreeToNPagedLookasideList(&IPHoleList, Hole);
+
+ /* If this is the first fragment, save the IP header */
+ if (FragFirst == 0) {
+ IPDR->IPv4Header = exAllocatePool(NonPagedPool, IPPacket->HeaderSize);
+ if (!IPDR->IPv4Header) {
+ /* We don't have the resources to process this packet, discard it */
+ Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
+ return;
+ }
+
+ TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
+ "Header size is (%d).\n", IPDR->IPv4Header, IPPacket->HeaderSize));
+
+ RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
+ IPDR->HeaderSize = IPPacket->HeaderSize;
+ }
+
+ /* Create a buffer, copy the data into it and put it
+ in the fragment list */
+
+ Fragment = ExAllocateFromNPagedLookasideList(&IPFragmentList);
+ if (!Fragment) {
+ /* We don't have the resources to process this packet, discard it */
+ Cleanup(&IPDR->Lock, OldIrql, IPDR, NULL);
+ return;
+ }
+
+ TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
+
+ Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
+ Fragment->Data = exAllocatePool(NonPagedPool, Fragment->Size);
+ if (!Fragment->Data) {
+ /* We don't have the resources to process this packet, discard it */
+ Cleanup(&IPDR->Lock, OldIrql, IPDR, Fragment);
+ return;
+ }
+
+ /* Position here is an offset from the NdisPacket start, not the header */
+ TI_DbgPrint(DEBUG_IP, ("Fragment data buffer allocated at (0x%X) Size (%d) Pos (%d).\n",
+ Fragment->Data, Fragment->Size, IPPacket->Position));
+
+ /* Copy datagram data into fragment buffer */
+ CopyPacketToBuffer(Fragment->Data,
+ IPPacket->NdisPacket,
+ IPPacket->Position,
+ Fragment->Size);
+ Fragment->Offset = FragFirst;
+
+ /* If this is the last fragment, compute and save the datagram data size */
+ if (!MoreFragments)
+ IPDR->DataSize = FragFirst + Fragment->Size;
+
+ /* Put the fragment in the list */
+ InsertTailList(&IPDR->FragmentListHead, &Fragment->ListEntry);
+ break;
+ }
+
+ TI_DbgPrint(DEBUG_IP, ("Done searching for hole descriptor.\n"));
+
+ if (IsListEmpty(&IPDR->HoleListHead)) {
+ /* Hole list is empty which means a complete datagram can be assembled.
+ Assemble the datagram and pass it to an upper layer protocol */
+
+ TI_DbgPrint(DEBUG_IP, ("Complete datagram received.\n"));
+
+ Datagram = ReassembleDatagram(IPDR);
+
+ KeReleaseSpinLock(&IPDR->Lock, OldIrql);
+
+ RemoveIPDR(IPDR);
+ FreeIPDR(IPDR);
+
+ if (!Datagram)
+ /* Not enough free resources, discard the packet */
+ return;
+
+ DISPLAY_IP_PACKET(Datagram);
+
+ /* Give the packet to the protocol dispatcher */
+ IPDispatchProtocol(NTE, Datagram);
+
+ /* We're done with this datagram */
+ exFreePool(Datagram->Header);
+ TI_DbgPrint(MAX_TRACE, ("Freeing datagram at (0x%X).\n", Datagram));
+ (*Datagram->Free)(Datagram);
+ } else
+ KeReleaseSpinLock(&IPDR->Lock, OldIrql);
+}
+
+
+VOID IPFreeReassemblyList(
+ VOID)
+/*
+ * FUNCTION: Frees all IP datagram reassembly structures in the list
+ */
+{
+ KIRQL OldIrql;
+ PLIST_ENTRY CurrentEntry;
+ PIPDATAGRAM_REASSEMBLY Current;
+
+ KeAcquireSpinLock(&ReassemblyListLock, &OldIrql);
+
+ CurrentEntry = ReassemblyListHead.Flink;
+ while (CurrentEntry != &ReassemblyListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
+ /* Unlink it from the list */
+ RemoveEntryList(CurrentEntry);
+
+ /* And free the descriptor */
+ FreeIPDR(Current);
+
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ KeReleaseSpinLock(&ReassemblyListLock, OldIrql);
+}
+
+
+VOID IPDatagramReassemblyTimeout(
+ VOID)
+/*
+ * FUNCTION: IP datagram reassembly timeout handler
+ * NOTES:
+ * This routine is called by IPTimeout to free any resources used
+ * to hold IP fragments that have taken too long to reassemble
+ */
+{
+}
+
+VOID IPv4Receive(PIP_INTERFACE IF, PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives an IPv4 datagram (or fragment)
+ * ARGUMENTS:
+ * Context = Pointer to context information (IP_INTERFACE)
+ * IPPacket = Pointer to IP packet
+ */
+{
+ PNEIGHBOR_CACHE_ENTRY NCE;
+ PNET_TABLE_ENTRY NTE;
+ UINT AddressType;
+
+ TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
+
+ IPPacket->HeaderSize = (((PIPv4_HEADER)IPPacket->Header)->VerIHL & 0x0F) << 2;
+ TI_DbgPrint(DEBUG_IP, ("IPPacket->HeaderSize = %d\n", IPPacket->HeaderSize));
+
+ if (IPPacket->HeaderSize > IPv4_MAX_HEADER_SIZE) {
+ TI_DbgPrint
+ (MIN_TRACE,
+ ("Datagram received with incorrect header size (%d).\n",
+ IPPacket->HeaderSize));
+ /* Discard packet */
+ return;
+ }
+
+ /* Checksum IPv4 header */
+ if (!IPv4CorrectChecksum(IPPacket->Header, IPPacket->HeaderSize)) {
+ TI_DbgPrint
+ (MIN_TRACE,
+ ("Datagram received with bad checksum. Checksum field (0x%X)\n",
+ WN2H(((PIPv4_HEADER)IPPacket->Header)->Checksum)));
+ /* Discard packet */
+ return;
+ }
+
+ IPPacket->TotalSize = WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength);
+
+ AddrInitIPv4(&IPPacket->SrcAddr, ((PIPv4_HEADER)IPPacket->Header)->SrcAddr);
+ AddrInitIPv4(&IPPacket->DstAddr, ((PIPv4_HEADER)IPPacket->Header)->DstAddr);
+
+ IPPacket->Position += IPPacket->HeaderSize;
+ IPPacket->Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPPacket->HeaderSize);
+
+ TI_DbgPrint(MID_TRACE,("IPPacket->Position = %d\n",
+ IPPacket->Position));
+
+ //OskitDumpBuffer(IPPacket->Header, IPPacket->TotalSize);
+
+ /* FIXME: Possibly forward packets with multicast addresses */
+
+ /* FIXME: Should we allow packets to be received on the wrong interface? */
+ NTE = IPLocateNTEOnInterface(IF, &IPPacket->DstAddr, &AddressType);
+
+ if (NTE) {
+ /* This packet is destined for us */
+ ProcessFragment(IF, IPPacket, NTE);
+
+ /* Done with this NTE */
+ DereferenceObject(NTE);
+ } else {
+ /* This packet is not destined for us. If we are a router,
+ try to find a route and forward the packet */
+
+ /* FIXME: Check if acting as a router */
+ NCE = NULL;
+ if (NCE) {
+ /* FIXME: Possibly fragment datagram */
+ /* Forward the packet */
+ IPSendFragment(IPPacket->NdisPacket, NCE);
+ } else {
+ TI_DbgPrint(MIN_TRACE, ("No route to destination (0x%X).\n",
+ IPPacket->DstAddr.Address.IPv4Address));
+
+ /* FIXME: Send ICMP error code */
+ }
+ }
+}
+
+
+VOID IPReceive( PIP_INTERFACE IF, PIP_PACKET IPPacket )
+/*
+ * FUNCTION: Receives an IP datagram (or fragment)
+ * ARGUMENTS:
+ * IF = Interface
+ * IPPacket = Pointer to IP packet
+ */
+{
+ UINT Version;
+
+ /* Check that IP header has a supported version */
+ Version = (((PIPv4_HEADER)IPPacket->Header)->VerIHL >> 4);
+
+ switch (Version) {
+ case 4:
+ IPPacket->Type = IP_ADDRESS_V4;
+ IPv4Receive(IF, IPPacket);
+ break;
+ case 6:
+ IPPacket->Type = IP_ADDRESS_V6;
+ TI_DbgPrint(MAX_TRACE, ("Datagram of type IPv6 discarded.\n"));
+ return;
+ default:
+ TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
+ return;
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * 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
+ *
+ * This data is not authoritative. It is a searchable cache that allows
+ * quick access to route information to selected hosts. This information
+ * should always defer to the FIB.
+ *
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.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;
+NPAGED_LOOKASIDE_LIST IPRCNList;
+
+
+#ifdef 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
+
+UINT CountRouteNodes( PROUTE_CACHE_NODE Node ) {
+ if( !Node ) Node = RouteCache;
+ if( IsInternalRCN(Node) )
+ return
+ /* Traverse left subtree */
+ CountRouteNodes(Node->Left) +
+ /* Traverse right subtree */
+ CountRouteNodes(Node->Right) + 1;
+ else
+ return 0;
+}
+
+VOID FreeRCN(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an route cache node object
+ * ARGUMENTS:
+ * Object = Pointer to an route cache node structure
+ */
+{
+ ExFreeToNPagedLookasideList(&IPRCNList, Object);
+}
+
+
+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;
+
+ MTMARK();
+
+ TI_DbgPrint(DEBUG_RCACHE, ("Called.\n"));
+
+ RCN = ExAllocateFromNPagedLookasideList(&IPRCNList);
+ if (!RCN) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ MTMARK();
+
+ RCN->Free = FreeRCN;
+
+ 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;
+
+ MTMARK();
+
+ 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 */
+
+ /* 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 */
+ 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);
+
+#ifdef 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"));
+
+ ExInitializeNPagedLookasideList(
+ &IPRCNList, /* Lookaside list */
+ NULL, /* Allocate routine */
+ NULL, /* Free routine */
+ 0, /* Flags */
+ sizeof(ROUTE_CACHE_NODE), /* Size of each entry */
+ TAG('I','P','R','C'), /* Tag */
+ 0); /* Depth */
+
+ /* Initialize the pseudo external route cache node */
+ ExternalRCN = ExAllocateFromNPagedLookasideList(&IPRCNList);
+ if (!ExternalRCN) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ INIT_TAG(ExternalRCN, TAG('R','C','N',' '));
+
+ ExternalRCN->Free = FreeRCN;
+ 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);
+
+ FreeRCN(ExternalRCN);
+
+ KeReleaseSpinLock(&RouteCacheLock, OldIrql);
+
+ ExDeleteNPagedLookasideList(&IPRCNList);
+
+ 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));
+
+ TI_DbgPrint(DEBUG_RCACHE, ("Destination (%s) NTE (%s).\n",
+ A2S(Destination), NTE ? A2S(NTE->Address) : ""));
+
+ 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));
+
+ TI_DbgPrint(DEBUG_RCACHE, ("Destination (%s) NTE (%s) NCE (%s).\n",
+ A2S(Destination),
+ A2S(NTE->Address),
+ A2S(&NCE->Address)));
+
+ 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 */
+
+ INIT_TAG(RCN, TAG('R','C','N',' '));
+
+ /* 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);
+}
+
+NTSTATUS
+RouteFriendlyAddRoute( PIPROUTE_ENTRY ire ) {
+ KIRQL OldIrql;
+
+
+ /* Find IF */
+ KeAcquireSpinLock(&InterfaceListLock, &OldIrql);
+ //RouteAddRouteToDestination(&Dest,Nte,If,Nce);
+ KeReleaseSpinLock(&InterfaceListLock, OldIrql);
+
+ return STATUS_SUCCESS;
+}
+
+/* EOF */
--- /dev/null
+/*
+ * 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)
+ * NOTES:
+ * This file holds authoritative routing information.
+ * Information queries on the route table should be handled here.
+ * This information should always override the route cache info.
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+
+LIST_ENTRY FIBListHead;
+KSPIN_LOCK FIBLock;
+
+
+VOID FreeFIB(
+ PVOID Object)
+/*
+ * FUNCTION: Frees an forward information base object
+ * ARGUMENTS:
+ * Object = Pointer to an forward information base structure
+ */
+{
+ ExFreePool(Object);
+}
+
+
+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
+ */
+{
+ TI_DbgPrint(DEBUG_ROUTER, ("Called. FIBE (0x%X).\n", FIBE));
+
+ /* Unlink the FIB entry from the list */
+ RemoveEntryList(&FIBE->ListEntry);
+
+ /* Dereference the referenced objects */
+ DereferenceObject(FIBE->NetworkAddress);
+ DereferenceObject(FIBE->Netmask);
+ DereferenceObject(FIBE->Router);
+
+#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 */
+ FreeFIB(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 CountFIBs() {
+ UINT FibCount = 0;
+ PLIST_ENTRY CurrentEntry;
+ PLIST_ENTRY NextEntry;
+
+ /* Search the list and remove every FIB entry we find */
+ CurrentEntry = FIBListHead.Flink;
+ while (CurrentEntry != &FIBListHead) {
+ NextEntry = CurrentEntry->Flink;
+ CurrentEntry = NextEntry;
+ FibCount++;
+ }
+
+ return FibCount;
+}
+
+
+UINT CopyFIBs( PFIB_ENTRY Target ) {
+ UINT FibCount = 0;
+ 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);
+ Target[FibCount] = *Current;
+ CurrentEntry = NextEntry;
+ FibCount++;
+ }
+
+ return FibCount;
+}
+
+
+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_ROUTER, ("Called. Address1 (0x%X) Address2 (0x%X).\n", Address1, Address2));
+
+ /*TI_DbgPrint(DEBUG_ROUTER, ("Target (%s) \n", A2S(Address1)));*/
+ /*TI_DbgPrint(DEBUG_ROUTER, ("Adapter (%s).\n", A2S(Address2)));*/
+
+ if (Address1->Type == IP_ADDRESS_V4)
+ Size = sizeof(IPv4_RAW_ADDRESS);
+ else
+ Size = sizeof(IPv6_RAW_ADDRESS);
+
+ Addr1 = (PUCHAR)&Address1->Address.IPv4Address;
+ Addr2 = (PUCHAR)&Address2->Address.IPv4Address;
+
+ /* Find first non-matching byte */
+ for (i = 0; i < Size && Addr1[i] == Addr2[i]; i++);
+ if( i == Size ) return 8 * i;
+
+ /* Find first non-matching bit */
+ Bitmask = 0x80;
+ for (j = 0; (Addr1[i] & Bitmask) != (Addr2[i] & Bitmask); j++)
+ 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_ROUTER, ("Called. Address (0x%X) Prefix (0x%X) Length (%d).\n", Address, Prefix, Length));
+
+#if 0
+ TI_DbgPrint(DEBUG_ROUTER, ("Address (%s) Prefix (%s).\n",
+ A2S(Address), A2S(Prefix)));
+#endif
+
+ /* 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_ROUTER, ("Called. Interface (0x%X) Destination (0x%X).\n", Interface, Destination));
+
+ TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s).\n", A2S(Destination)));
+
+ KeAcquireSpinLock(&Interface->Lock, &OldIrql);
+
+ CurrentEntry = Interface->NTEListHead.Flink;
+ while (CurrentEntry != &Interface->NTEListHead) {
+ Current = CONTAINING_RECORD(CurrentEntry, NET_TABLE_ENTRY, IFListEntry);
+ TI_DbgPrint(DEBUG_ROUTER, ("Looking at NTE %s\n", A2S(Current->Address)));
+
+ 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_ROUTER, ("Called. Address (0x%X) NTE (0x%X).\n", Address, NTE));
+
+ TI_DbgPrint(DEBUG_ROUTER, ("Address (%s) NTE (%s).\n",
+ A2S(Address), NTE ? A2S(NTE->Address) : ""));
+
+ 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,
+ 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
+ * 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 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) "
+ "Router (0x%X) Metric (%d).\n", NetworkAddress, Netmask, Router, Metric));
+
+ TI_DbgPrint(DEBUG_ROUTER, ("NetworkAddress (%s) Netmask (%s) Router (%s).\n",
+ A2S(NetworkAddress),
+ A2S(Netmask),
+ A2S(&Router->Address)));
+
+ FIBE = ExAllocatePool(NonPagedPool, sizeof(FIB_ENTRY));
+ if (!FIBE) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ INIT_TAG(Router, TAG('R','O','U','T'));
+
+ FIBE->Free = FreeFIB;
+ FIBE->NetworkAddress = NetworkAddress;
+ FIBE->Netmask = Netmask;
+ 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));
+
+ TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s)\n", A2S(Destination)));
+ if( NTE )
+ TI_DbgPrint(DEBUG_ROUTER, ("NTE (%s).\n", A2S(NTE->Address)));
+
+ 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));
+
+ TI_DbgPrint(DEBUG_ROUTER, ("FIBE (%s).\n", A2S(FIBE->NetworkAddress)));
+
+ 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 (!pNetworkAddress) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ return NULL;
+ }
+
+ pNetmask = AddrBuildIPv4(Netmask);
+ if (!pNetmask) {
+ TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+ DereferenceObject(pNetworkAddress);
+ return NULL;
+ }
+
+ pRouterAddress = AddrBuildIPv4(RouterAddress);
+ if (!pRouterAddress) {
+ 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, NCE, 1);
+ if (!FIBE) {
+ /* Not enough free resources */
+ NBRemoveNeighbor(NCE);
+ DereferenceObject(pNetworkAddress);
+ DereferenceObject(pNetmask);
+ DereferenceObject(pRouterAddress);
+
+ (pNetworkAddress->Free)(pNetworkAddress);
+ (pNetmask->Free)(pNetmask);
+ (pRouterAddress->Free)(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 */
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+static 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,
+ PCHAR *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, (PVOID)Data, Size);
+
+ if (Offset < *Size) {
+ *Data = (PCHAR)((ULONG_PTR) *Data + Offset);
+ *Size -= Offset;
+ break;
+ }
+
+ Offset -= *Size;
+
+ NdisGetNextBuffer(Buffer, &Buffer);
+ }
+
+ return Offset;
+}
+
+
+UINT CopyBufferToBufferChain(
+ PNDIS_BUFFER DstBuffer,
+ UINT DstOffset,
+ PCHAR 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;
+ PCHAR DstData;
+
+ TI_DbgPrint(DEBUG_PBUFFER, ("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;
+ SrcData = (PCHAR)((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, (PVOID)&DstData, &DstSize);
+ }
+ }
+
+ return BytesCopied;
+}
+
+
+UINT CopyBufferChainToBuffer(
+ PCHAR 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;
+ PCHAR SrcData;
+
+ TI_DbgPrint(DEBUG_PBUFFER, ("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_PBUFFER, ("Copying (%d) bytes from 0x%X to 0x%X\n", BytesToCopy, SrcData, DstData));
+
+ RtlCopyMemory((PVOID)DstData, (PVOID)SrcData, BytesToCopy);
+ BytesCopied += BytesToCopy;
+ DstData = (PCHAR)((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, (PVOID)&SrcData, &SrcSize);
+ }
+ }
+
+ return BytesCopied;
+}
+
+
+UINT CopyPacketToBuffer(
+ PCHAR 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_PBUFFER, ("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;
+ PCHAR DstData, SrcData;
+ UINT DstSize, SrcSize;
+ UINT Count, Total;
+
+ TI_DbgPrint(DEBUG_PBUFFER, ("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, (PVOID)&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, (PVOID)&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, (PVOID)&SrcData, &SrcSize);
+ }
+ }
+
+ return Total;
+}
+
+
+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_PBUFFER, ("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) {
+ NdisBuffer->MappedSystemVa = (PVOID) ((ULONG_PTR)(NdisBuffer->MappedSystemVa) + Adjust);
+ NdisBuffer->ByteOffset += Adjust;
+ NdisBuffer->ByteCount -= Adjust;
+ }
+
+ 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;
+}
+
+#ifdef DBG
+
+static VOID DisplayIPHeader(
+ PCHAR Header,
+ UINT Length)
+{
+ /* FIXME: IPv4 only */
+ PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header;
+
+ DbgPrint("IPv4 header:\n");
+ DbgPrint("VerIHL: 0x%x (version 0x%x, length %d 32-bit words)\n",
+ IPHeader->VerIHL, (IPHeader->VerIHL & 0xF0) >> 4, IPHeader->VerIHL & 0x0F);
+ DbgPrint(" Tos: %d\n", IPHeader->Tos);
+ DbgPrint(" TotalLength: %d\n", WN2H(IPHeader->TotalLength));
+ DbgPrint(" Id: %d\n", WN2H(IPHeader->Id));
+ DbgPrint(" FlagsFragOfs: 0x%x (offset 0x%x)\n", WN2H(IPHeader->FlagsFragOfs), WN2H(IPHeader->FlagsFragOfs) & IPv4_FRAGOFS_MASK);
+ if ((WN2H(IPHeader->FlagsFragOfs) & IPv4_DF_MASK) > 0) DbgPrint(" IPv4_DF - Don't fragment\n");
+ if ((WN2H(IPHeader->FlagsFragOfs) & IPv4_MF_MASK) > 0) DbgPrint(" IPv4_MF - More fragments\n");
+ DbgPrint(" Ttl: %d\n", IPHeader->Ttl);
+ DbgPrint(" Protocol: %d\n", IPHeader->Protocol);
+ DbgPrint(" Checksum: 0x%x\n", WN2H(IPHeader->Checksum));
+ DbgPrint(" SrcAddr: %d.%d.%d.%d\n",
+ ((IPHeader->SrcAddr >> 0) & 0xFF), ((IPHeader->SrcAddr >> 8) & 0xFF),
+ ((IPHeader->SrcAddr >> 16) & 0xFF), ((IPHeader->SrcAddr >> 24) & 0xFF));
+ DbgPrint(" DstAddr: %d.%d.%d.%d\n",
+ ((IPHeader->DstAddr >> 0) & 0xFF), ((IPHeader->DstAddr >> 8) & 0xFF),
+ ((IPHeader->DstAddr >> 16) & 0xFF), ((IPHeader->DstAddr >> 24) & 0xFF));
+}
+
+VOID DisplayIPPacket(
+ PIP_PACKET IPPacket)
+{
+ PCHAR p;
+ UINT Length;
+ PNDIS_BUFFER Buffer;
+ PNDIS_BUFFER NextBuffer;
+ PCHAR CharBuffer;
+
+ if ((DebugTraceLevel & (DEBUG_PBUFFER | DEBUG_IP)) != (DEBUG_PBUFFER | DEBUG_IP)) {
+ return;
+ }
+
+ if (!IPPacket) {
+ TI_DbgPrint(MIN_TRACE, ("Cannot display null packet.\n"));
+ return;
+ }
+
+ TI_DbgPrint(MIN_TRACE, ("IPPacket is at (0x%X).\n", IPPacket));
+ TI_DbgPrint(MIN_TRACE, ("Header buffer is at (0x%X).\n", IPPacket->Header));
+ TI_DbgPrint(MIN_TRACE, ("Header size is (%d).\n", IPPacket->HeaderSize));
+ TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
+ TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
+ TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
+
+ if (IPPacket->NdisPacket) {
+ NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, &Buffer, NULL);
+ for (; Buffer != NULL; Buffer = NextBuffer) {
+ NdisGetNextBuffer(Buffer, &NextBuffer);
+ NdisQueryBuffer(Buffer, (PVOID)&p, &Length);
+ //OskitDumpBuffer( p, Length );
+ }
+ } else {
+ p = IPPacket->Header;
+ Length = IPPacket->ContigSize;
+ //OskitDumpBuffer( p, Length );
+ }
+
+ if (IPPacket->NdisPacket) {
+ NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length);
+ Length -= MaxLLHeaderSize;
+ CharBuffer = exAllocatePool(NonPagedPool, Length);
+ Length = CopyPacketToBuffer(CharBuffer, IPPacket->NdisPacket, MaxLLHeaderSize, Length);
+ DisplayIPHeader(CharBuffer, Length);
+ exFreePool(CharBuffer);
+ } else {
+ CharBuffer = IPPacket->Header;
+ Length = IPPacket->ContigSize;
+ DisplayIPHeader(CharBuffer, Length);
+ }
+}
+
+
+static VOID DisplayTCPHeader(
+ PCHAR Header,
+ UINT Length)
+{
+ /* FIXME: IPv4 only */
+ PIPv4_HEADER IPHeader = (PIPv4_HEADER)Header;
+ PTCPv4_HEADER TCPHeader;
+
+ if (IPHeader->Protocol != IPPROTO_TCP) {
+ DbgPrint("This is not a TCP datagram. Protocol is %d\n", IPHeader->Protocol);
+ return;
+ }
+
+ TCPHeader = (PTCPv4_HEADER)((PCHAR)IPHeader + (IPHeader->VerIHL & 0x0F) * 4);
+
+ DbgPrint("TCP header:\n");
+ DbgPrint(" SourcePort: %d\n", WN2H(TCPHeader->SourcePort));
+ DbgPrint(" DestinationPort: %d\n", WN2H(TCPHeader->DestinationPort));
+ DbgPrint(" SequenceNumber: 0x%x\n", DN2H(TCPHeader->SequenceNumber));
+ DbgPrint(" AckNumber: 0x%x\n", DN2H(TCPHeader->AckNumber));
+ DbgPrint(" DataOffset: 0x%x (0x%x) 32-bit words\n", TCPHeader->DataOffset, TCPHeader->DataOffset >> 4);
+ DbgPrint(" Flags: 0x%x (0x%x)\n", TCPHeader->Flags, TCPHeader->Flags & 0x3F);
+ if ((TCPHeader->Flags & TCP_URG) > 0) DbgPrint(" TCP_URG - Urgent Pointer field significant\n");
+ if ((TCPHeader->Flags & TCP_ACK) > 0) DbgPrint(" TCP_ACK - Acknowledgement field significant\n");
+ if ((TCPHeader->Flags & TCP_PSH) > 0) DbgPrint(" TCP_PSH - Push Function\n");
+ if ((TCPHeader->Flags & TCP_RST) > 0) DbgPrint(" TCP_RST - Reset the connection\n");
+ if ((TCPHeader->Flags & TCP_SYN) > 0) DbgPrint(" TCP_SYN - Synchronize sequence numbers\n");
+ if ((TCPHeader->Flags & TCP_FIN) > 0) DbgPrint(" TCP_FIN - No more data from sender\n");
+ DbgPrint(" Window: 0x%x\n", WN2H(TCPHeader->Window));
+ DbgPrint(" Checksum: 0x%x\n", WN2H(TCPHeader->Checksum));
+ DbgPrint(" Urgent: 0x%x\n", WN2H(TCPHeader->Urgent));
+}
+
+
+VOID DisplayTCPPacket(
+ PIP_PACKET IPPacket)
+{
+ UINT Length;
+ PCHAR Buffer;
+
+ if ((DebugTraceLevel & (DEBUG_PBUFFER | DEBUG_TCP)) != (DEBUG_PBUFFER | DEBUG_TCP)) {
+ return;
+ }
+
+ if (!IPPacket) {
+ TI_DbgPrint(MIN_TRACE, ("Cannot display null packet.\n"));
+ return;
+ }
+
+ DisplayIPPacket(IPPacket);
+
+ TI_DbgPrint(MIN_TRACE, ("IPPacket is at (0x%X).\n", IPPacket));
+ TI_DbgPrint(MIN_TRACE, ("Header buffer is at (0x%X).\n", IPPacket->Header));
+ TI_DbgPrint(MIN_TRACE, ("Header size is (%d).\n", IPPacket->HeaderSize));
+ TI_DbgPrint(MIN_TRACE, ("TotalSize (%d).\n", IPPacket->TotalSize));
+ TI_DbgPrint(MIN_TRACE, ("ContigSize (%d).\n", IPPacket->ContigSize));
+ TI_DbgPrint(MIN_TRACE, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
+
+ if (IPPacket->NdisPacket) {
+ NdisQueryPacket(IPPacket->NdisPacket, NULL, NULL, NULL, &Length);
+ Length -= MaxLLHeaderSize;
+ Buffer = exAllocatePool(NonPagedPool, Length);
+ Length = CopyPacketToBuffer(Buffer, IPPacket->NdisPacket, MaxLLHeaderSize, Length);
+ DisplayTCPHeader(Buffer, Length);
+ exFreePool(Buffer);
+ } else {
+ Buffer = IPPacket->Header;
+ Length = IPPacket->ContigSize;
+ DisplayTCPHeader(Buffer, Length);
+ }
+}
+
+#endif/* DBG */
+
+void GetDataPtr( PNDIS_PACKET Packet,
+ UINT Offset,
+ PCHAR *DataOut,
+ PUINT Size ) {
+ PNDIS_BUFFER Buffer;
+
+ NdisQueryPacket(Packet, NULL, NULL, &Buffer, NULL);
+ if( !Buffer ) return;
+ SkipToOffset( Buffer, Offset, DataOut, Size );
+}
+
+NDIS_STATUS AllocatePacketWithBufferX( PNDIS_PACKET *NdisPacket,
+ PCHAR Data, UINT Len,
+ PCHAR File, UINT Line ) {
+ PNDIS_PACKET Packet;
+ PNDIS_BUFFER Buffer;
+ NDIS_STATUS Status;
+ PCHAR NewData;
+
+ NewData = ExAllocatePool( NonPagedPool, Len );
+ if( !NewData ) return NDIS_STATUS_NOT_ACCEPTED; // XXX
+ TrackWithTag(EXALLOC_TAG, NewData, File, Line);
+
+ if( Data )
+ RtlCopyMemory(NewData, Data, Len);
+
+ NdisAllocatePacket( &Status, &Packet, GlobalPacketPool );
+ if( Status != NDIS_STATUS_SUCCESS ) {
+ ExFreePool( NewData );
+ return Status;
+ }
+ TrackWithTag(NDIS_PACKET_TAG, Packet, File, Line);
+
+ NdisAllocateBuffer( &Status, &Buffer, GlobalBufferPool, NewData, Len );
+ if( Status != NDIS_STATUS_SUCCESS ) {
+ ExFreePool( NewData );
+ FreeNdisPacket( Packet );
+ }
+ TrackWithTag(NDIS_BUFFER_TAG, Buffer, File, Line);
+
+ NdisChainBufferAtFront( Packet, Buffer );
+ *NdisPacket = Packet;
+
+ return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID FreeNdisPacketX
+( PNDIS_PACKET Packet,
+ PCHAR File,
+ UINT Line )
+/*
+ * FUNCTION: Frees an NDIS packet
+ * ARGUMENTS:
+ * Packet = Pointer to NDIS packet to be freed
+ */
+{
+ PNDIS_BUFFER Buffer, NextBuffer;
+
+ TI_DbgPrint(DEBUG_PBUFFER, ("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);
+ UntrackFL(File,Line,Buffer);
+ NdisFreeBuffer(Buffer);
+ UntrackFL(File,Line,Data);
+ ExFreePool(Data);
+ }
+
+ /* Finally free the NDIS packet discriptor */
+ UntrackFL(File,Line,Packet);
+ NdisFreePacket(Packet);
+}
--- /dev/null
+/*
+ * 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 "precomp.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. IFC (0x%X)\n", IFC));
+
+ 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);
+ TI_DbgPrint(MID_TRACE,("IP Check: %x\n", Header->Checksum));
+
+ /* Update pointers */
+ IFC->DatagramData = (PVOID)((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. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
+ IPPacket, NCE, PathMTU));
+
+ IFC = exAllocatePool(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT));
+ if (IFC == NULL)
+ 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 (Data == NULL) {
+ exFreePool(IFC);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Allocate NDIS packet */
+ NdisAllocatePacket(&NdisStatus, &IFC->NdisPacket, GlobalPacketPool);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ exFreePool(Data);
+ exFreePool(IFC);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Allocate NDIS buffer */
+ NdisAllocateBuffer(&NdisStatus, &IFC->NdisBuffer,
+ GlobalBufferPool, Data, MaxLLHeaderSize + PathMTU);
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ FreeNdisPacket(IFC->NdisPacket);
+ exFreePool(Data);
+ exFreePool(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. Context (0x%X) NdisPacket (0x%X) NdisStatus (0x%X)\n",
+ Context, NdisPacket, NdisStatus));
+
+ /* FIXME: Stop sending fragments and cleanup datagram buffers if
+ there was an error */
+
+ if (PC(NdisPacket) && 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);
+ exFreePool(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. NdisPacket (0x%X) NCE (0x%X).\n", NdisPacket, NCE));
+
+ TI_DbgPrint(MAX_TRACE, ("NCE->State = %d.\n", NCE->State));
+
+ PC(NdisPacket)->DLComplete = IPSendComplete;
+
+ 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;
+ }
+
+ (*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. IPPacket (0x%X) RCN (0x%X)\n", IPPacket, RCN));
+
+ DISPLAY_IP_PACKET(IPPacket);
+ /*OskitDumpBuffer( IPPacket->Header, IPPacket->TotalSize );*/
+
+ NCE = RCN->NCE;
+
+#ifdef 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;
+ TI_DbgPrint(MID_TRACE,("PathMTU: %d\n", PathMTU));
+
+ if (IPPacket->TotalSize > PathMTU) {
+ TI_DbgPrint(MID_TRACE,("Doing SendFragments\n"));
+ return SendFragments(IPPacket, NCE, PathMTU);
+ } else {
+ if ((IPPacket->Flags & IP_PACKET_FLAG_RAW) == 0) {
+ /* Calculate checksum of IP header */
+ TI_DbgPrint(MID_TRACE,("-> not IP_PACKET_FLAG_RAW\n"));
+ ((PIPv4_HEADER)IPPacket->Header)->Checksum = 0;
+
+ ((PIPv4_HEADER)IPPacket->Header)->Checksum = (USHORT)
+ IPv4Checksum(IPPacket->Header, IPPacket->HeaderSize, 0);
+ TI_DbgPrint(MID_TRACE,("IP Check: %x\n", ((PIPv4_HEADER)IPPacket->Header)->Checksum));
+
+ TI_DbgPrint(MAX_TRACE, ("Sending packet (length is %d).\n",
+ WN2H(((PIPv4_HEADER)IPPacket->Header)->TotalLength)));
+ } else {
+ TI_DbgPrint(MAX_TRACE, ("Sending raw packet (flags are 0x%X).\n",
+ IPPacket->Flags));
+ }
+
+ return IPSendFragment(IPPacket->NdisPacket, NCE);
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+
+/* Pending request queue */
+LIST_ENTRY DGPendingListHead;
+KSPIN_LOCK DGPendingListLock;
+/* Work queue item for pending requests */
+WORK_QUEUE_ITEM DGWorkItem;
+
+
+VOID STDCALL DatagramWorker(
+ PVOID Context)
+/*
+ * FUNCTION: Handles pending send 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;
+ 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;
+
+ /* If there are pending send requests, shedule worker function */
+ KeAcquireSpinLock(&DGPendingListLock, &OldIrql);
+ QueueWorkItem = (!IsListEmpty(&DGPendingListHead));
+ KeReleaseSpinLock(&DGPendingListLock, OldIrql);
+ if (QueueWorkItem)
+ ExQueueWorkItem(&DGWorkItem, CriticalWorkQueue);
+
+ TI_DbgPrint(MAX_TRACE, ("Calling 0x%X.\n", Complete));
+
+ /* Call completion routine for send request */
+ (*Complete)(Context, 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);
+ ASSERT(AddrFile->ADE);
+ 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 (;;)
+ {
+ TI_DbgPrint(MIN_TRACE, ("Looping on DGSend !!!! WHEE!\n"));
+ if (!NT_SUCCESS(Status))
+ {
+ KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+ /* An error occurred, enqueue the send request again and return */
+ InsertHeadList(&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 */
+ IPPacket = &SendRequest->Packet;
+ PC(IPPacket->NdisPacket)->Complete = SendDatagramComplete;
+ PC(IPPacket->NdisPacket)->Context = SendRequest;
+ if (IPSendDatagram(IPPacket, RCN) != STATUS_SUCCESS)
+ {
+ TI_DbgPrint(MIN_TRACE, ("!! Datagram sent !! (completing)\n"));
+ 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);
+ }
+
+ /* 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);
+ TI_DbgPrint(MIN_TRACE, ("List is not empty\n"));
+ }
+ 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 DGDeliverData(
+ PADDRESS_FILE AddrFile,
+ PIP_ADDRESS Address,
+ PIP_PACKET IPPacket,
+ UINT DataSize)
+/*
+ * FUNCTION: Delivers datagram 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
+ * (incl. IP header for raw IP file objects)
+ * 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;
+ PTDI_IND_RECEIVE_DATAGRAM ReceiveHandler;
+ PVOID HandlerContext;
+ LONG AddressLength;
+ PVOID SourceAddress;
+ ULONG BytesTaken;
+ NTSTATUS Status;
+ PVOID DataBuffer;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+ if (AddrFile->Protocol == IPPROTO_UDP)
+ {
+ DataBuffer = IPPacket->Data;
+ }
+ else
+ {
+ /* Give client the IP header too if it is a raw IP file object */
+ DataBuffer = IPPacket->Header;
+ }
+
+ if (!IsListEmpty(&AddrFile->ReceiveQueue))
+ {
+ PLIST_ENTRY CurrentEntry;
+ PDATAGRAM_RECEIVE_REQUEST Current;
+ BOOLEAN Found;
+
+ TI_DbgPrint(MAX_TRACE, ("There is a receive request.\n"));
+
+ /* 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 (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 */
+
+ /* Remove the request from the queue */
+ RemoveEntryList(&Current->ListEntry);
+ AddrFile->RefCount--;
+ break;
+ }
+ CurrentEntry = CurrentEntry->Flink;
+ }
+
+ KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+ if (Found)
+ {
+ TI_DbgPrint(MAX_TRACE, ("Suitable receive request found.\n"));
+
+ /* Copy the data into buffer provided by the user */
+ CopyBufferToBufferChain(Current->Buffer,
+ 0,
+ DataBuffer,
+ DataSize);
+
+ /* Complete the receive request */
+ (*Current->Complete)(Current->Context, STATUS_SUCCESS, DataSize);
+
+ exFreePool(Current);
+ }
+ }
+ else if (AddrFile->RegisteredReceiveDatagramHandler)
+ {
+ TI_DbgPrint(MAX_TRACE, ("Calling receive event handler.\n"));
+
+ ReceiveHandler = AddrFile->ReceiveDatagramHandler;
+ HandlerContext = AddrFile->ReceiveDatagramHandlerContext;
+
+ KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+
+ if (Address->Type == IP_ADDRESS_V4)
+ {
+ AddressLength = sizeof(IPv4_RAW_ADDRESS);
+ SourceAddress = &Address->Address.IPv4Address;
+ }
+ else /* (Address->Type == IP_ADDRESS_V6) */
+ {
+ AddressLength = sizeof(IPv6_RAW_ADDRESS);
+ SourceAddress = Address->Address.IPv6Address;
+ }
+
+ Status = (*ReceiveHandler)(HandlerContext,
+ AddressLength,
+ SourceAddress,
+ 0,
+ NULL,
+ TDI_RECEIVE_ENTIRE_MESSAGE,
+ DataSize,
+ DataSize,
+ &BytesTaken,
+ DataBuffer,
+ NULL);
+ }
+ else
+ {
+ TI_DbgPrint(MAX_TRACE, ("Discarding datagram.\n"));
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+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);
+ exFreePool(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);
+
+ exFreePool(Current);
+ }
+ else
+ {
+ TI_DbgPrint(MID_TRACE, ("Cannot find receive request.\n"));
+ }
+}
+
+
+NTSTATUS DGTransmit(
+ PADDRESS_FILE AddressFile,
+ PDATAGRAM_SEND_REQUEST SendRequest)
+/*
+ * FUNCTION: Transmits or queues a send request
+ * ARGUMENTS:
+ * AddressFile = Pointer to address file
+ * SendRequest = Pointer to send request
+ * RETURNS:
+ * Status of operation
+ */
+{
+ KIRQL OldIrql;
+
+ KeAcquireSpinLock(&AddressFile->Lock, &OldIrql);
+ if (AF_IS_BUSY(AddressFile))
+ {
+ /* Queue send request on the transmit queue */
+ InsertTailList(&AddressFile->TransmitQueue, &SendRequest->ListEntry);
+ /* Reference address file and set pending send request flag */
+ ReferenceObject(AddressFile);
+ AF_SET_PENDING(AddressFile, AFF_SEND);
+ KeReleaseSpinLock(&AddressFile->Lock, OldIrql);
+ TI_DbgPrint(MAX_TRACE, ("Leaving (queued).\n"));
+ }
+ else
+ {
+ KeReleaseSpinLock(&AddressFile->Lock, OldIrql);
+ /* Send the datagram */
+ DGSend(AddressFile, SendRequest);
+ TI_DbgPrint(MAX_TRACE, ("Leaving (pending).\n"));
+ }
+ return STATUS_PENDING;
+}
+
+NTSTATUS DGSendDatagram( PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PIP_PACKET Packet ) {
+/*
+ * FUNCTION: Sends a datagram to a remote address
+ * ARGUMENTS:
+ * Request = Pointer to TDI request
+ * ConnInfo = Pointer to connection information
+ * Packet = Pointer to NDIS buffer with data
+ * RETURNS:
+ * Status of operation
+ */
+ PADDRESS_FILE AddrFile;
+ KIRQL OldIrql;
+ NTSTATUS Status;
+ PDATAGRAM_SEND_REQUEST SendRequest;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ AddrFile = Request->Handle.AddressHandle;
+
+ KeAcquireSpinLock(&AddrFile->Lock, &OldIrql);
+
+ if (AF_IS_VALID(AddrFile)) {
+ /* Initialize a send request */
+ SendRequest = exAllocatePool( NonPagedPool,
+ sizeof( DATAGRAM_SEND_REQUEST ) );
+
+ if( SendRequest ) {
+ KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ SendRequest->Complete = Request->RequestNotifyObject;
+ SendRequest->Context = Request->RequestContext;
+ NdisQueryPacketLength( Packet->NdisPacket,
+ &SendRequest->BufferSize );
+ SendRequest->Packet = *Packet;
+
+ if (NT_SUCCESS(Status)) {
+ Status = AddrGetAddress(ConnInfo->RemoteAddress,
+ &SendRequest->RemoteAddress,
+ &SendRequest->RemotePort);
+ if (NT_SUCCESS(Status))
+ {
+ KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ return DGTransmit(AddrFile, SendRequest);
+ }
+ else
+ {
+ exFreePool(SendRequest);
+ }
+ }
+ 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 = exAllocatePool(NonPagedPool, 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);
+ if (!NT_SUCCESS(Status))
+ {
+ KeReleaseSpinLock(&AddrFile->Lock, OldIrql);
+ exFreePool(ReceiveRequest);
+ return Status;
+ }
+ }
+ else
+ {
+ ReceiveRequest->RemotePort = 0;
+ }
+ 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;
+}
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+
+BOOLEAN RawIPInitialized = FALSE;
+
+
+NTSTATUS BuildRawIPPacket(
+ PIP_PACKET Packet,
+ UINT DataLength,
+ PIP_ADDRESS LocalAddress,
+ USHORT LocalPort )
+/*
+ * 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
+ */
+{
+ PVOID Header;
+ NDIS_STATUS NdisStatus;
+ PNDIS_BUFFER HeaderBuffer;
+ PNDIS_PACKET NdisPacket = Packet->NdisPacket;
+ /* Will be zeroed in packet by IPInitializePacket */
+
+ /* Prepare packet */
+ IPInitializePacket(Packet,IP_ADDRESS_V4);
+ Packet->Flags = IP_PACKET_FLAG_RAW; /* Don't touch IP header */
+ Packet->TotalSize = DataLength;
+ Packet->NdisPacket = NdisPacket;
+
+ if (MaxLLHeaderSize != 0) {
+ Header = ExAllocatePool(NonPagedPool, MaxLLHeaderSize);
+ if (!Header) {
+ TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n",
+ MaxLLHeaderSize, Header));
+
+ /* Allocate NDIS buffer for maximum link level header */
+ NdisAllocateBuffer(&NdisStatus,
+ &HeaderBuffer,
+ GlobalBufferPool,
+ Header,
+ MaxLLHeaderSize);
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MIN_TRACE, ("Cannot allocate NDIS buffer for packet headers. NdisStatus = (0x%X)\n", NdisStatus));
+ ExFreePool(Header);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Chain header at front of packet */
+ NdisChainBufferAtFront(Packet->NdisPacket, HeaderBuffer);
+ }
+
+ DISPLAY_IP_PACKET(Packet);
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS RawIPSendDatagram(
+ PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PNDIS_BUFFER Buffer,
+ ULONG DataSize,
+ PULONG DataUsed )
+/*
+ * 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
+ */
+{
+ NDIS_STATUS Status;
+ PCHAR BufferData;
+ UINT BufferLen;
+ PADDRESS_FILE AddrFile =
+ (PADDRESS_FILE)Request->Handle.AddressHandle;
+ IP_PACKET Packet;
+
+ NdisQueryBuffer( Buffer, &BufferData, &BufferLen );
+ Status = AllocatePacketWithBuffer( &Packet.NdisPacket,
+ BufferData,
+ BufferLen );
+
+ TI_DbgPrint(MID_TRACE,("Packet.NdisPacket %x\n", Packet.NdisPacket));
+
+ *DataUsed = BufferLen;
+
+ if( Status == NDIS_STATUS_SUCCESS )
+ Status = BuildRawIPPacket( &Packet,
+ BufferLen,
+ AddrFile->ADE->Address,
+ AddrFile->Port );
+ if( Status == NDIS_STATUS_SUCCESS )
+ Status = DGSendDatagram(Request, ConnInfo, &Packet);
+ else
+ FreeNdisPacket( Packet.NdisPacket );
+
+ /* NdisFreeBuffer( Buffer ); */
+
+ return Status;
+}
+
+
+VOID RawIPReceive(
+ PNET_TABLE_ENTRY NTE,
+ PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives and queues a raw IP 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 ICMP datagrams.
+ * It delivers the packet header and data to anyone that wants it
+ * When we get here the datagram has already passed sanity checks
+ */
+{
+ PIP_ADDRESS DstAddress;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ switch (IPPacket->Type) {
+ /* IPv4 packet */
+ case IP_ADDRESS_V4:
+ DstAddress = &IPPacket->DstAddr;
+ break;
+
+ /* IPv6 packet */
+ case IP_ADDRESS_V6:
+ TI_DbgPrint(MIN_TRACE, ("Discarded IPv6 raw IP datagram (%i bytes).\n",
+ IPPacket->TotalSize));
+
+ /* FIXME: IPv6 is not supported */
+ return;
+
+ default:
+ return;
+ }
+
+ /* 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 */
+
+#if 0 /* Decide what to do here */
+ AddrFile = AddrSearchFirst(DstAddress,
+ 0,
+ IPPROTO_ICMP,
+ &SearchContext);
+ if (AddrFile) {
+ do {
+ DGDeliverData(AddrFile,
+ DstAddress,
+ IPPacket,
+ IPPacket->TotalSize);
+ } 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 ICMP datagram to address (0x%X).\n",
+ DN2H(DstAddress->Address.IPv4Address)));
+ }
+#endif
+ TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+}
+
+
+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 */
--- /dev/null
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS TCP/IP protocol driver
+ * FILE: transport/tcp/event.c
+ * PURPOSE: Transmission Control Protocol -- Events from oskittcp
+ * PROGRAMMERS: Art Yerkes
+ * REVISIONS:
+ * CSH 01/08-2000 Created
+ */
+
+#include "precomp.h"
+
+extern ULONG TCP_IPIdentification;
+extern LIST_ENTRY SleepingThreadsList;
+extern FAST_MUTEX SleepingThreadsLock;
+
+int TCPSocketState(void *ClientData,
+ void *WhichSocket,
+ void *WhichConnection,
+ OSK_UINT NewState ) {
+ PCONNECTION_ENDPOINT Connection = WhichConnection;
+ PTCP_COMPLETION_ROUTINE Complete;
+ PTDI_BUCKET Bucket;
+ PLIST_ENTRY Entry;
+
+ TI_DbgPrint(MID_TRACE,("Called: NewState %x (Conn %x)\n",
+ NewState, Connection));
+
+ if( !Connection ) {
+ TI_DbgPrint(MID_TRACE,("Socket closing.\n"));
+ return 0;
+ }
+
+ if( (NewState & SEL_CONNECT) &&
+ !(Connection->State & SEL_CONNECT) ) {
+ while( !IsListEmpty( &Connection->ConnectRequest ) ) {
+ Connection->State |= SEL_CONNECT;
+ Entry = RemoveHeadList( &Connection->ConnectRequest );
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Complete = Bucket->Request.RequestNotifyObject;
+ TI_DbgPrint(MID_TRACE,
+ ("Completing Connect Request %x\n", Bucket->Request));
+ Complete( Bucket->Request.RequestContext, STATUS_SUCCESS, 0 );
+ /* Frees the bucket allocated in TCPConnect */
+ ExFreePool( Bucket );
+ }
+ } else if( (NewState & SEL_READ) || (NewState & SEL_FIN) ) {
+ TI_DbgPrint(MID_TRACE,("Readable (or closed): irp list %s\n",
+ IsListEmpty(&Connection->ReceiveRequest) ?
+ "empty" : "nonempty"));
+
+ while( !IsListEmpty( &Connection->ReceiveRequest ) ) {
+ PIRP Irp;
+ OSK_UINT RecvLen = 0, Received = 0;
+ OSK_PCHAR RecvBuffer = 0;
+ PMDL Mdl;
+ NTSTATUS Status;
+
+ Entry = RemoveHeadList( &Connection->ReceiveRequest );
+ Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+ Complete = Bucket->Request.RequestNotifyObject;
+
+ TI_DbgPrint(MID_TRACE,
+ ("Readable, Completing read request %x\n",
+ Bucket->Request));
+
+ Irp = Bucket->Request.RequestContext;
+ Mdl = Irp->MdlAddress;
+
+ TI_DbgPrint(MID_TRACE,
+ ("Getting the user buffer from %x\n", Mdl));
+
+ NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
+
+ TI_DbgPrint(MID_TRACE,
+ ("Reading %d bytes to %x\n", RecvLen, RecvBuffer));
+
+ if( NewState & SEL_FIN && !RecvLen ) {
+ Status = STATUS_END_OF_FILE;
+ Received = 0;
+ } else
+ Status = TCPTranslateError
+ ( OskitTCPRecv( Connection->SocketContext,
+ RecvBuffer,
+ RecvLen,
+ &Received,
+ 0 ) );
+
+ TI_DbgPrint(MID_TRACE,("TCP Bytes: %d\n", Received));
+
+ if( Status == STATUS_SUCCESS && Received != 0 ) {
+ TI_DbgPrint(MID_TRACE,("Received %d bytes with status %x\n",
+ Received, Status));
+
+ TI_DbgPrint(MID_TRACE,
+ ("Completing Receive Request: %x\n",
+ Bucket->Request));
+
+ Complete( Bucket->Request.RequestContext,
+ STATUS_SUCCESS, Received );
+ } else if( Status == STATUS_PENDING ||
+ (Status == STATUS_SUCCESS && Received == 0) ) {
+ InsertHeadList( &Connection->ReceiveRequest,
+ &Bucket->Entry );
+ break;
+ } else {
+ TI_DbgPrint(MID_TRACE,
+ ("Completing Receive request: %x %x\n",
+ Bucket->Request, Status));
+ Complete( Bucket->Request.RequestContext, Status, 0 );
+ }
+ }
+ }
+
+ return 0;
+}
+
+void TCPPacketSendComplete( PVOID Context,
+ PNDIS_PACKET NdisPacket,
+ NDIS_STATUS NdisStatus ) {
+ TI_DbgPrint(MID_TRACE,("called\n"));
+}
+
+#define STRINGIFY(x) #x
+
+int TCPPacketSend(void *ClientData, OSK_PCHAR data, OSK_UINT len ) {
+ NTSTATUS Status;
+ KIRQL OldIrql;
+ NDIS_STATUS NdisStatus;
+ ROUTE_CACHE_NODE *RCN;
+ IP_PACKET Packet = { 0 };
+ IP_ADDRESS RemoteAddress, LocalAddress;
+ PIPv4_HEADER Header;
+
+ TI_DbgPrint(MID_TRACE,("TCP OUTPUT (%x:%d):\n", data, len));
+ OskitDumpBuffer( data, len );
+
+ if( *data == 0x45 ) { /* IPv4 */
+ Header = (PIPv4_HEADER)data;
+ LocalAddress.Type = IP_ADDRESS_V4;
+ LocalAddress.Address.IPv4Address = Header->SrcAddr;
+ RemoteAddress.Type = IP_ADDRESS_V4;
+ RemoteAddress.Address.IPv4Address = Header->DstAddr;
+ } else {
+ DbgPrint("Don't currently handle IPv6\n");
+ KeBugCheck(4);
+ }
+
+ RemoteAddress.Type = LocalAddress.Type = IP_ADDRESS_V4;
+
+ DbgPrint("OSKIT SENDING PACKET *** %x -> %x\n",
+ LocalAddress.Address.IPv4Address,
+ RemoteAddress.Address.IPv4Address);
+
+ ASSERT( (LocalAddress.Address.IPv4Address & 0xc0000000) != 0xc0000000 );
+
+
+ Status = RouteGetRouteToDestination( &RemoteAddress,
+ NULL,
+ &RCN );
+
+ if( !NT_SUCCESS(Status) || !RCN ) return OSK_EADDRNOTAVAIL;
+
+ KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
+
+ NdisStatus =
+ AllocatePacketWithBuffer( &Packet.NdisPacket, data, len );
+
+ if (NdisStatus != NDIS_STATUS_SUCCESS) {
+ TI_DbgPrint(MAX_TRACE, ("Error from NDIS: %08x\n", NdisStatus));
+ goto end;
+ }
+
+ AdjustPacket( Packet.NdisPacket, 0, MaxLLHeaderSize );
+ GetDataPtr( Packet.NdisPacket, 0, (PCHAR *)&Packet.Header, &Packet.ContigSize );
+ TI_DbgPrint(MAX_TRACE,("PC(Packet.NdisPacket) is %s (%x)\n", STRINGIFY(PC(Packet.NdisPacket)), PC(Packet.NdisPacket)));
+ PC(Packet.NdisPacket)->Complete = TCPPacketSendComplete;
+ OskitDumpBuffer((PCHAR)(PC(Packet.NdisPacket)),sizeof(*(PC(Packet.NdisPacket))));
+
+ Packet.HeaderSize = sizeof(IPv4_HEADER);
+ Packet.TotalSize = len;
+ Packet.SrcAddr = LocalAddress;
+ Packet.DstAddr = RemoteAddress;
+
+ IPSendFragment( Packet.NdisPacket, RCN->NCE );
+
+end:
+ KeLowerIrql( OldIrql );
+
+ if( !NT_SUCCESS(NdisStatus) ) return OSK_EINVAL;
+ else return 0;
+}
+
+void *TCPMalloc( void *ClientData,
+ OSK_UINT Bytes, OSK_PCHAR File, OSK_UINT Line ) {
+ void *v = ExAllocatePool( NonPagedPool, Bytes );
+ if( v ) TrackWithTag( FOURCC('f','b','s','d'), v, File, Line );
+ return v;
+}
+
+void TCPFree( void *ClientData,
+ void *data, OSK_PCHAR File, OSK_UINT Line ) {
+ UntrackFL( File, Line, data );
+ ExFreePool( data );
+}
+
+int TCPSleep( void *ClientData, void *token, int priority, char *msg,
+ int tmio ) {
+ PSLEEPING_THREAD SleepingThread;
+
+ TI_DbgPrint(MID_TRACE,
+ ("Called TSLEEP: tok = %x, pri = %d, wmesg = %s, tmio = %x\n",
+ token, priority, msg, tmio));
+
+ SleepingThread = ExAllocatePool( NonPagedPool, sizeof( *SleepingThread ) );
+ if( SleepingThread ) {
+ KeInitializeEvent( &SleepingThread->Event, NotificationEvent, FALSE );
+ SleepingThread->SleepToken = token;
+
+ ExAcquireFastMutex( &SleepingThreadsLock );
+ InsertTailList( &SleepingThreadsList, &SleepingThread->Entry );
+ ExReleaseFastMutex( &SleepingThreadsLock );
+
+ TI_DbgPrint(MID_TRACE,("Waiting on %x\n", token));
+ KeWaitForSingleObject( &SleepingThread->Event,
+ WrSuspended,
+ KernelMode,
+ TRUE,
+ NULL );
+
+ ExAcquireFastMutex( &SleepingThreadsLock );
+ RemoveEntryList( &SleepingThread->Entry );
+ ExReleaseFastMutex( &SleepingThreadsLock );
+
+ ExFreePool( SleepingThread );
+ }
+ TI_DbgPrint(MID_TRACE,("Waiting finished: %x\n", token));
+ return 0;
+}
+
+void TCPWakeup( void *ClientData, void *token ) {
+ PLIST_ENTRY Entry;
+ PSLEEPING_THREAD SleepingThread;
+
+ ExAcquireFastMutex( &SleepingThreadsLock );
+ Entry = SleepingThreadsList.Flink;
+ while( Entry != &SleepingThreadsList ) {
+ SleepingThread = CONTAINING_RECORD(Entry, SLEEPING_THREAD, Entry);
+ TI_DbgPrint(MID_TRACE,("Sleeper @ %x\n", SleepingThread));
+ if( SleepingThread->SleepToken == token ) {
+ TI_DbgPrint(MID_TRACE,("Setting event to wake %x\n", token));
+ KeSetEvent( &SleepingThread->Event, IO_NETWORK_INCREMENT, FALSE );
+ }
+ Entry = Entry->Flink;
+ }
+ ExReleaseFastMutex( &SleepingThreadsLock );
+}
--- /dev/null
+/*
+ * Copyright (c) 1997-1998 University of Utah and the Flux Group.
+ * All rights reserved.
+ *
+ * This file is part of the Flux OSKit. The OSKit is free software, also known
+ * as "open source;" you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License (GPL), version 2, as published by the Free
+ * Software Foundation (FSF). To explore alternate licensing terms, contact
+ * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
+ *
+ * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
+ * received a copy of the GPL along with the OSKit; see the file COPYING. If
+ * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
+ */
+
+#include "precomp.h"
+
+
+#if 0
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <oskit/c/assert.h>
+#include <net/if.h>
+#endif
+
+int if_index = 0;
+struct ifaddr **ifnet_addrs;
+
+int ifqmaxlen = OSK_IFQ_MAXLEN;
+struct ifnet *ifnet;
+
+/*
+ * Network interface utility routines.
+ *
+ * Routines with ifa_ifwith* names take sockaddr *'s as
+ * parameters.
+ */
+
+PVOID TCPPrepareInterface( PIP_INTERFACE IF ) {
+ NTSTATUS Status;
+ POSK_IFADDR ifaddr = exAllocatePool
+ ( NonPagedPool, sizeof(*ifaddr) + 2 * sizeof( struct sockaddr_in ) );
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)&ifaddr[1];
+ struct sockaddr_in *dstaddr_in = (struct sockaddr_in *)&addr_in[1];
+ if( !ifaddr ) return NULL;
+
+ TI_DbgPrint(MID_TRACE,("Called\n"));
+
+ ifaddr->ifa_dstaddr = (struct sockaddr *)dstaddr_in;
+ /* XXX - Point-to-point interfaces not supported yet */
+ memset( &ifaddr->ifa_dstaddr, 0, sizeof( struct sockaddr ) );
+
+ ifaddr->ifa_addr = (struct sockaddr *)addr_in;
+ Status = GetInterfaceIPv4Address( IF,
+ ADE_UNICAST,
+ (PULONG)&addr_in->sin_addr.s_addr );
+
+ if( !NT_SUCCESS(Status) )
+ addr_in->sin_addr.s_addr = 0;
+
+ TI_DbgPrint(MID_TRACE,("Prepare interface %x : addr %x\n",
+ IF, addr_in->sin_addr.s_addr));
+
+ ifaddr->ifa_flags = 0; /* XXX what goes here? */
+ ifaddr->ifa_refcnt = 0; /* Anachronistic */
+ ifaddr->ifa_metric = 1; /* We can get it like in ninfo.c, if we want */
+ ifaddr->ifa_mtu = IF->MTU;
+
+ TI_DbgPrint(MID_TRACE,("Leaving\n"));
+
+ return ifaddr;
+}
+
+POSK_IFADDR TCPFindInterface( void *ClientData,
+ OSK_UINT AddrType,
+ OSK_UINT FindType,
+ OSK_SOCKADDR *ReqAddr,
+ OSK_IFADDR *Interface ) {
+ PNEIGHBOR_CACHE_ENTRY NCE;
+ IP_ADDRESS Destination;
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)ReqAddr;
+
+ TI_DbgPrint(MID_TRACE,("called for type %d\n", FindType));
+
+ if( !ReqAddr ) {
+ TI_DbgPrint(MID_TRACE,("no addr or no ifaddr (%x)\n", ReqAddr));
+ return NULL;
+ }
+
+ Destination.Type = IP_ADDRESS_V4;
+ Destination.Address.IPv4Address = addr_in->sin_addr.s_addr;
+
+ TI_DbgPrint(MID_TRACE,("Address is %x\n", addr_in->sin_addr.s_addr));
+
+ NCE = RouterGetRoute(&Destination, NULL);
+
+ if( !NCE || !NCE->Interface ) {
+ TI_DbgPrint(MID_TRACE,("no neighbor cache or no interface (%x %x)\n",
+ NCE, NCE->Interface));
+ return NULL;
+ }
+
+ addr_in = (struct sockaddr_in *)
+ ((POSK_IFADDR)NCE->Interface->TCPContext)->ifa_addr;
+ TI_DbgPrint(MID_TRACE,("returning addr %x\n", addr_in->sin_addr.s_addr));
+
+ return NCE->Interface->TCPContext;
+}
+
--- /dev/null
+/*
+ * 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 "precomp.h"
+
+LONG TCP_IPIdentification = 0;
+static BOOLEAN TCPInitialized = FALSE;
+static NPAGED_LOOKASIDE_LIST TCPSegmentList;
+LIST_ENTRY SleepingThreadsList;
+FAST_MUTEX SleepingThreadsLock;
+RECURSIVE_MUTEX TCPLock;
+
+NTSTATUS TCPSocket( PCONNECTION_ENDPOINT Connection,
+ UINT Family, UINT Type, UINT Proto ) {
+ NTSTATUS Status;
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+ Status = TCPTranslateError( OskitTCPSocket( Connection,
+ &Connection->SocketContext,
+ Family,
+ Type,
+ Proto ) );
+ RecursiveMutexLeave( &TCPLock );
+
+ return Status;
+}
+
+VOID TCPReceive(PNET_TABLE_ENTRY NTE, PIP_PACKET IPPacket)
+/*
+ * FUNCTION: Receives and queues TCP data
+ * 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 TCP data
+ */
+{
+ TI_DbgPrint(MID_TRACE,("Sending packet %d (%d) to oskit\n",
+ IPPacket->TotalSize,
+ IPPacket->HeaderSize));
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+
+ OskitTCPReceiveDatagram( IPPacket->Header,
+ IPPacket->TotalSize,
+ IPPacket->HeaderSize );
+
+ RecursiveMutexLeave( &TCPLock );
+}
+
+/* event.c */
+int TCPSocketState( void *ClientData,
+ void *WhichSocket,
+ void *WhichConnection,
+ OSK_UINT NewState );
+
+int TCPPacketSend( void *ClientData,
+ OSK_PCHAR Data,
+ OSK_UINT Len );
+
+POSK_IFADDR TCPFindInterface( void *ClientData,
+ OSK_UINT AddrType,
+ OSK_UINT FindType,
+ OSK_SOCKADDR *ReqAddr );
+
+void *TCPMalloc( void *ClientData,
+ OSK_UINT bytes, OSK_PCHAR file, OSK_UINT line );
+void TCPFree( void *ClientData,
+ void *data, OSK_PCHAR file, OSK_UINT line );
+
+int TCPSleep( void *ClientData, void *token, int priority, char *msg,
+ int tmio );
+
+void TCPWakeup( void *ClientData, void *token );
+
+OSKITTCP_EVENT_HANDLERS EventHandlers = {
+ NULL, /* Client Data */
+ TCPSocketState, /* SocketState */
+ TCPPacketSend, /* PacketSend */
+ TCPFindInterface, /* FindInterface */
+ TCPMalloc, /* Malloc */
+ TCPFree, /* Free */
+ TCPSleep, /* Sleep */
+ TCPWakeup /* Wakeup */
+};
+
+NTSTATUS TCPStartup(VOID)
+/*
+ * FUNCTION: Initializes the TCP subsystem
+ * RETURNS:
+ * Status of operation
+ */
+{
+ RecursiveMutexInit( &TCPLock );
+ ExInitializeFastMutex( &SleepingThreadsLock );
+ InitializeListHead( &SleepingThreadsList );
+
+ RegisterOskitTCPEventHandlers( &EventHandlers );
+ InitOskitTCP();
+
+ /* Register this protocol with IP layer */
+ IPRegisterProtocol(IPPROTO_TCP, TCPReceive);
+
+ ExInitializeNPagedLookasideList(
+ &TCPSegmentList, /* Lookaside list */
+ NULL, /* Allocate routine */
+ NULL, /* Free routine */
+ 0, /* Flags */
+ sizeof(TCP_SEGMENT), /* Size of each entry */
+ TAG('T','C','P','S'), /* Tag */
+ 0); /* Depth */
+
+ TCPInitialized = TRUE;
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS TCPShutdown(VOID)
+/*
+ * FUNCTION: Shuts down the TCP subsystem
+ * RETURNS:
+ * Status of operation
+ */
+{
+ if (!TCPInitialized)
+ return STATUS_SUCCESS;
+
+ /* Deregister this protocol with IP layer */
+ IPRegisterProtocol(IPPROTO_TCP, NULL);
+
+ ExDeleteNPagedLookasideList(&TCPSegmentList);
+
+ TCPInitialized = FALSE;
+
+ DeinitOskitTCP();
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS TCPTranslateError( int OskitError ) {
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ switch( OskitError ) {
+ case 0: Status = STATUS_SUCCESS; break;
+ case OSK_EADDRNOTAVAIL:
+ case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
+ case OSK_ECONNREFUSED:
+ case OSK_ECONNRESET: Status = STATUS_REMOTE_NOT_LISTENING; break;
+ case OSK_EINPROGRESS:
+ case OSK_EAGAIN: Status = STATUS_PENDING; break;
+ default: Status = STATUS_INVALID_CONNECTION; break;
+ }
+
+ TI_DbgPrint(MID_TRACE,("Error %d -> %x\n", OskitError, Status));
+ return Status;
+}
+
+#if 0
+NTSTATUS TCPBind
+( PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo ) {
+ NTSTATUS Status;
+ PCONNECTION_ENDPOINT Connection = Request->Handle.ConnectionContext;
+ SOCKADDR_IN AddressToConnect;
+ PIP_ADDRESS LocalAddress;
+ USHORT LocalPort;
+
+ TI_DbgPrint(MID_TRACE,("Called\n"));
+
+ Status = AddrBuildAddress
+ ((PTA_ADDRESS)ConnInfo->LocalAddress,
+ &LocalAddress,
+ &LocalPort);
+
+ AddressToBind.sin_family = AF_INET;
+ memcpy( &AddressToBind.sin_addr,
+ &LocalAddress->Address.IPv4Address,
+ sizeof(AddressToBind.sin_addr) );
+ AddressToBind.sin_port = LocalPort;
+
+ Status = OskitTCPBind( Connection->SocketContext,
+ Connection,
+ &AddressToBind,
+ sizeof(AddressToBind));
+
+ TI_DbgPrint(MID_TRACE,("Leaving %x\n", Status));
+
+ return Status;
+}
+#endif
+
+NTSTATUS TCPConnect
+( PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PTDI_CONNECTION_INFORMATION ReturnInfo ) {
+ NTSTATUS Status;
+ SOCKADDR_IN AddressToConnect = { 0 }, AddressToBind = { 0 };
+ PCONNECTION_ENDPOINT Connection = Request->Handle.ConnectionContext;
+ PIP_ADDRESS RemoteAddress;
+ USHORT RemotePort;
+ PTDI_BUCKET Bucket;
+
+ DbgPrint("TCPConnect: Called\n");
+
+ Bucket = ExAllocatePool( NonPagedPool, sizeof(*Bucket) );
+ if( !Bucket ) return STATUS_NO_MEMORY;
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+
+ /* Freed in TCPSocketState */
+ Bucket->Request = *Request;
+ InsertHeadList( &Connection->ConnectRequest, &Bucket->Entry );
+
+ Status = AddrBuildAddress
+ ((PTA_ADDRESS)ConnInfo->RemoteAddress,
+ &RemoteAddress,
+ &RemotePort);
+
+ DbgPrint("Connecting to address %x:%x\n",
+ RemoteAddress->Address.IPv4Address,
+ RemotePort);
+
+ if (!NT_SUCCESS(Status)) {
+ TI_DbgPrint(MID_TRACE, ("Could not AddrBuildAddress in TCPConnect\n"));
+ return Status;
+ }
+
+ AddressToConnect.sin_family = AF_INET;
+ AddressToBind = AddressToConnect;
+
+ OskitTCPBind( Connection->SocketContext,
+ Connection,
+ &AddressToBind,
+ sizeof(AddressToBind) );
+
+ memcpy( &AddressToConnect.sin_addr,
+ &RemoteAddress->Address.IPv4Address,
+ sizeof(AddressToConnect.sin_addr) );
+ AddressToConnect.sin_port = RemotePort;
+
+ Status = OskitTCPConnect(Connection->SocketContext,
+ Connection,
+ &AddressToConnect,
+ sizeof(AddressToConnect));
+
+ RecursiveMutexLeave( &TCPLock );
+
+ if( Status == OSK_EINPROGRESS || Status == STATUS_SUCCESS )
+ return STATUS_PENDING;
+ else
+ return Status;
+}
+
+NTSTATUS TCPClose
+( PCONNECTION_ENDPOINT Connection ) {
+ NTSTATUS Status;
+
+ TI_DbgPrint(MID_TRACE,("TCPClose started\n"));
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+
+ Status = TCPTranslateError( OskitTCPClose( Connection->SocketContext ) );
+
+ RecursiveMutexLeave( &TCPLock );
+
+ TI_DbgPrint(MID_TRACE,("TCPClose finished %x\n", Status));
+
+ return Status;
+}
+
+NTSTATUS TCPListen
+( PTDI_REQUEST Request,
+ UINT Backlog ) {
+ PCONNECTION_ENDPOINT Connection;
+ NTSTATUS Status;
+
+ Connection = Request->Handle.ConnectionContext;
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+
+ Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext,
+ Backlog ) );
+
+ RecursiveMutexLeave( &TCPLock );
+
+ return Status;
+}
+
+NTSTATUS TCPAccept
+( PTDI_REQUEST Request,
+ VOID **NewSocketContext ) {
+ return STATUS_UNSUCCESSFUL;
+}
+
+NTSTATUS TCPReceiveData
+( PTDI_REQUEST Request,
+ PNDIS_BUFFER Buffer,
+ ULONG ReceiveLength,
+ ULONG ReceiveFlags,
+ PULONG BytesReceived ) {
+ PCONNECTION_ENDPOINT Connection;
+ PCHAR DataBuffer;
+ UINT DataLen, Received = 0;
+ NTSTATUS Status;
+ PTDI_BUCKET Bucket;
+
+ TI_DbgPrint(MID_TRACE,("Called for %d bytes\n", ReceiveLength));
+
+ Connection = Request->Handle.ConnectionContext;
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+
+ NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
+
+ TI_DbgPrint(MID_TRACE,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
+
+ Status = TCPTranslateError
+ ( OskitTCPRecv
+ ( Connection->SocketContext,
+ DataBuffer,
+ DataLen,
+ &Received,
+ ReceiveFlags ) );
+
+ TI_DbgPrint(MID_TRACE,("OskitTCPReceive: %x, %d\n", Status, Received));
+
+ /* Keep this request around ... there was no data yet */
+ if( Status == STATUS_PENDING ||
+ (Status == STATUS_SUCCESS && Received == 0) ) {
+ /* Freed in TCPSocketState */
+ Bucket = ExAllocatePool( NonPagedPool, sizeof(*Bucket) );
+ if( !Bucket ) {
+ TI_DbgPrint(MID_TRACE,("Failed to allocate bucket\n"));
+ return STATUS_NO_MEMORY;
+ }
+
+ Bucket->Request = *Request;
+ *BytesReceived = 0;
+ InsertHeadList( &Connection->ReceiveRequest, &Bucket->Entry );
+ Status = STATUS_PENDING;
+ TI_DbgPrint(MID_TRACE,("Queued read irp\n"));
+ } else {
+ TI_DbgPrint(MID_TRACE,("Got status %x, bytes %d\n", Status, Received));
+ *BytesReceived = Received;
+ }
+
+ RecursiveMutexLeave( &TCPLock );
+
+ TI_DbgPrint(MID_TRACE,("Status %x\n", Status));
+
+ return Status;
+}
+
+NTSTATUS TCPSendData
+( PTDI_REQUEST Request,
+ PNDIS_BUFFER Buffer,
+ ULONG DataSize,
+ ULONG Flags,
+ PULONG DataUsed ) {
+ NTSTATUS Status;
+ PCONNECTION_ENDPOINT Connection;
+ PCHAR BufferData;
+ ULONG PacketSize;
+
+ Connection = Request->Handle.ConnectionContext;
+
+ RecursiveMutexEnter( &TCPLock, TRUE );
+
+ NdisQueryBuffer( Buffer, &BufferData, &PacketSize );
+
+ TI_DbgPrint(MID_TRACE,("Connection = %x\n", Connection));
+ TI_DbgPrint(MID_TRACE,("Connection->SocketContext = %x\n",
+ Connection->SocketContext));
+
+ OskitDumpBuffer( BufferData, PacketSize );
+
+ Status = OskitTCPSend( Connection->SocketContext,
+ BufferData, PacketSize, (PUINT)DataUsed, 0 );
+
+ RecursiveMutexLeave( &TCPLock );
+
+ return Status;
+}
+
+VOID TCPTimeout(VOID) {
+ static int Times = 0;
+ if( (Times++ % 5) == 0 ) {
+ RecursiveMutexEnter( &TCPLock, TRUE );
+ TimerOskitTCP();
+ RecursiveMutexLeave( &TCPLock );
+ }
+}
+
+/* EOF */
--- /dev/null
+/*
+ * 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 "precomp.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 = ExAllocatePool(NonPagedPool, BufferSize);
+ if (!Header) {
+ TI_DbgPrint(MIN_TRACE, ("Cannot allocate memory for packet headers.\n"));
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ TI_DbgPrint(MAX_TRACE, ("Allocated %d bytes for headers at 0x%X.\n", BufferSize, Header));
+
+ /* 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));
+ ExFreePool(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)
+/*
+ * 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;
+ PDATAGRAM_SEND_REQUEST SendRequest = (PDATAGRAM_SEND_REQUEST)Context;
+ PIP_PACKET Packet = &SendRequest->Packet;
+
+ TI_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+ /* Prepare packet */
+
+ /* FIXME: Assumes IPv4 */
+ IPInitializePacket(&SendRequest->Packet, IP_ADDRESS_V4);
+ if (!Packet)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ Packet->TotalSize = sizeof(IPv4_HEADER) +
+ sizeof(UDP_HEADER) +
+ SendRequest->BufferSize;
+
+ 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));
+ FreeNdisPacket(Packet->NdisPacket);
+ return Status;
+ }
+
+ DISPLAY_IP_PACKET(Packet);
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS UDPSendDatagram(
+ PTDI_REQUEST Request,
+ PTDI_CONNECTION_INFORMATION ConnInfo,
+ PNDIS_BUFFER Buffer,
+ ULONG DataSize,
+ PULONG DataUsed )
+/*
+ * 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
+ */
+{
+ PDATAGRAM_SEND_REQUEST SendRequest;
+ PADDRESS_FILE AddrFile =
+ (PADDRESS_FILE)Request->Handle.AddressHandle;
+ PCHAR BufferData;
+ UINT BufferLen;
+
+ NdisQueryBuffer( Buffer, &BufferData, &BufferLen );
+
+ *DataUsed = BufferLen;
+
+ BuildUDPPacket( SendRequest,
+ (PIP_ADDRESS)&AddrFile->ADE->Address->Address.
+ IPv4Address,
+ AddrFile->Port );
+
+ return DGSendDatagram(Request,
+ ConnInfo,
+ &SendRequest->Packet);
+}
+
+
+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;
+
+ default:
+ 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 */
+ IPPacket->Data = (PVOID)((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 {
+ DGDeliverData(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
+ */
+{
+#ifdef __NTDRIVER__
+ RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
+#endif
+
+ /* 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 */