mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-09-02 12:23:31 +00:00
Most files moved to linkable library drivers/lib/ip, which can be linked
from kernel land, or from userland with the help of drivers/lib/undis. Hopefully, I'll be able to simulate a sufficient environment with undis that we'll be able to test most problems with the ip system in userland. This follows my general priniciple of getting most interesting code into a place where we can really examine it and work with it. The interface to the ip library is still a bit raw. I was hoping to do a better job of isolating it and especially digging nt kernel dependencies out into the remaining framework files (tcpip/dispatch.c, tcpip/fileobjs.c), but it was taking too long. Hopefully I can return to that later. svn path=/trunk/; revision=11127
This commit is contained in:
@@ -1,264 +0,0 @@
|
||||
/*
|
||||
* 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 ([email protected])
|
||||
* 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 */
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
@@ -1,20 +0,0 @@
|
||||
TARGETNAME=network
|
||||
TARGETPATH=..\objects
|
||||
TARGETTYPE=LIBRARY
|
||||
|
||||
TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
|
||||
$(DDK_LIB_PATH)\ndis.lib
|
||||
|
||||
INCLUDES=..\include;$(BASEDIR)\INC;..\..\..\..\include\net
|
||||
|
||||
|
||||
SOURCES= icmp.c \
|
||||
ip.c \
|
||||
neighbor.c \
|
||||
receive.c \
|
||||
route.c \
|
||||
router.c \
|
||||
transmit.c
|
||||
|
||||
MSC_WARNING_LEVEL=/W3 /WX
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
/*
|
||||
* 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 ([email protected])
|
||||
* 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 */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,544 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
@@ -1,635 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -1,738 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -1,573 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -1,347 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -1,489 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION: Searches through address file entries to find the first match
|
||||
* ARGUMENTS:
|
||||
* Address = IP address
|
||||
* Port = Port number
|
||||
* Protocol = Protocol number
|
||||
* SearchContext = Pointer to search context
|
||||
* RETURNS:
|
||||
* Pointer to address file, NULL if none was found
|
||||
*/
|
||||
PADDRESS_FILE AddrSearchFirst(
|
||||
PIP_ADDRESS Address,
|
||||
USHORT Port,
|
||||
USHORT Protocol,
|
||||
PAF_SEARCH SearchContext)
|
||||
{
|
||||
SearchContext->Address = Address;
|
||||
SearchContext->Port = Port;
|
||||
SearchContext->Next = AddressFileListHead.Flink;
|
||||
SearchContext->Protocol = Protocol;
|
||||
|
||||
return AddrSearchNext(SearchContext);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION: Searches through address file entries to find next match
|
||||
* ARGUMENTS:
|
||||
* SearchContext = Pointer to search context
|
||||
* RETURNS:
|
||||
* Pointer to address file, NULL if none was found
|
||||
*/
|
||||
PADDRESS_FILE AddrSearchNext(
|
||||
PAF_SEARCH SearchContext)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PIP_ADDRESS IPAddress;
|
||||
KIRQL OldIrql;
|
||||
PADDRESS_FILE Current = NULL;
|
||||
BOOLEAN Found = FALSE;
|
||||
|
||||
if (IsListEmpty(SearchContext->Next))
|
||||
return NULL;
|
||||
|
||||
CurrentEntry = SearchContext->Next;
|
||||
|
||||
KeAcquireSpinLock(&AddressFileListLock, &OldIrql);
|
||||
|
||||
while (CurrentEntry != &AddressFileListHead) {
|
||||
Current = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
|
||||
|
||||
IPAddress = Current->ADE->Address;
|
||||
|
||||
TI_DbgPrint(DEBUG_ADDRFILE, ("Comparing: ((%d, %d, %s), (%d, %d, %s)).\n",
|
||||
WN2H(Current->Port),
|
||||
Current->Protocol,
|
||||
A2S(IPAddress),
|
||||
WN2H(SearchContext->Port),
|
||||
SearchContext->Protocol,
|
||||
A2S(SearchContext->Address)));
|
||||
|
||||
/* See if this address matches the search criteria */
|
||||
if (((Current->Port == SearchContext->Port) &&
|
||||
(Current->Protocol == SearchContext->Protocol) &&
|
||||
(AddrIsEqual(IPAddress, SearchContext->Address))) ||
|
||||
(AddrIsUnspecified(IPAddress))) {
|
||||
/* We've found a match */
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&AddressFileListLock, OldIrql);
|
||||
|
||||
if (Found) {
|
||||
SearchContext->Next = CurrentEntry->Flink;
|
||||
return Current;
|
||||
} else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 */
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* Get maximum link speed */
|
||||
NdisStatus = NDISCall(IF,
|
||||
NdisRequestQueryInformation,
|
||||
OID_GEN_LINK_SPEED,
|
||||
Speed,
|
||||
sizeof(UINT));
|
||||
|
||||
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;
|
||||
|
||||
/* Get maximum link speed */
|
||||
NdisStatus = NDISCall(IF,
|
||||
NdisRequestQueryInformation,
|
||||
OID_GEN_FRIENDLY_NAME,
|
||||
NameBuffer,
|
||||
Len);
|
||||
|
||||
return
|
||||
NdisStatus != NDIS_STATUS_SUCCESS ?
|
||||
STATUS_UNSUCCESSFUL : STATUS_SUCCESS;
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
#define MEMTRACK_NO_POOL
|
||||
#include <roscfg.h>
|
||||
#include <tcpip.h>
|
||||
#include <ntddk.h>
|
||||
#include <memtrack.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*/
|
||||
@@ -1,606 +0,0 @@
|
||||
/*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
#undef NdisAllocatePacket
|
||||
#undef NdisAllocateBuffer
|
||||
#undef NdisFreeBuffer
|
||||
#undef NdisFreePacket
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
DIRS= datagram \
|
||||
rawip \
|
||||
tcp \
|
||||
udp
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
@@ -1,13 +0,0 @@
|
||||
TARGETNAME=datagram
|
||||
TARGETPATH=..\..\objects
|
||||
TARGETTYPE=LIBRARY
|
||||
|
||||
TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
|
||||
$(DDK_LIB_PATH)\ndis.lib
|
||||
|
||||
INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
|
||||
|
||||
SOURCES= datagram.c
|
||||
|
||||
MSC_WARNING_LEVEL=/W3 /WX
|
||||
|
||||
@@ -1,705 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
@@ -1,13 +0,0 @@
|
||||
TARGETNAME=rawip
|
||||
TARGETPATH=..\..\objects
|
||||
TARGETTYPE=LIBRARY
|
||||
|
||||
TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
|
||||
$(DDK_LIB_PATH)\ndis.lib
|
||||
|
||||
INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
|
||||
|
||||
SOURCES= rawip.c
|
||||
|
||||
MSC_WARNING_LEVEL=/W3 /WX
|
||||
|
||||
@@ -1,219 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
{
|
||||
AF_SEARCH SearchContext;
|
||||
PADDRESS_FILE AddrFile;
|
||||
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 */
|
||||
|
||||
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)));
|
||||
}
|
||||
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 */
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
@@ -1,13 +0,0 @@
|
||||
TARGETNAME=tcp
|
||||
TARGETPATH=..\..\objects
|
||||
TARGETTYPE=LIBRARY
|
||||
|
||||
TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
|
||||
$(DDK_LIB_PATH)\ndis.lib
|
||||
|
||||
INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
|
||||
|
||||
SOURCES= tcp.c
|
||||
|
||||
MSC_WARNING_LEVEL=/W3 /WX
|
||||
|
||||
@@ -1,257 +0,0 @@
|
||||
/*
|
||||
* 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 );
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -1,389 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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
|
||||
( PTDI_REQUEST Request ) {
|
||||
PCONNECTION_ENDPOINT Connection;
|
||||
NTSTATUS Status;
|
||||
Connection = Request->Handle.ConnectionContext;
|
||||
|
||||
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 */
|
||||
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
|
||||
# file to this component. This file merely indirects to the real make file
|
||||
# that is shared by all the driver components of the Windows NT DDK
|
||||
#
|
||||
|
||||
!INCLUDE $(NTMAKEENV)\makefile.def
|
||||
@@ -1,12 +0,0 @@
|
||||
TARGETNAME=udp
|
||||
TARGETPATH=..\..\objects
|
||||
TARGETTYPE=LIBRARY
|
||||
|
||||
TARGETLIBS=$(DDK_LIB_PATH)\tdi.lib \
|
||||
$(DDK_LIB_PATH)\ndis.lib
|
||||
|
||||
INCLUDES=..\..\include;$(BASEDIR)\INC;..\..\..\..\..\include\net
|
||||
|
||||
SOURCES= udp.c
|
||||
|
||||
MSC_WARNING_LEVEL=/W3 /WX
|
||||
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
{
|
||||
RtlZeroMemory(&UDPStats, sizeof(UDP_STATISTICS));
|
||||
|
||||
/* Register this protocol with IP layer */
|
||||
IPRegisterProtocol(IPPROTO_UDP, UDPReceive);
|
||||
|
||||
UDPInitialized = TRUE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS UDPShutdown(
|
||||
VOID)
|
||||
/*
|
||||
* FUNCTION: Shuts down the UDP subsystem
|
||||
* RETURNS:
|
||||
* Status of operation
|
||||
*/
|
||||
{
|
||||
if (!UDPInitialized)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
/* Deregister this protocol with IP layer */
|
||||
IPRegisterProtocol(IPPROTO_UDP, NULL);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
Reference in New Issue
Block a user