mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:23:07 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
346
sdk/lib/drivers/ip/network/address.c
Normal file
346
sdk/lib/drivers/ip/network/address.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
/*
|
||||
* 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, ... );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 AddrWidenAddress( PIP_ADDRESS Network, PIP_ADDRESS Source,
|
||||
PIP_ADDRESS Netmask ) {
|
||||
if( Netmask->Type == IP_ADDRESS_V4 ) {
|
||||
Network->Type = Netmask->Type;
|
||||
Network->Address.IPv4Address =
|
||||
Source->Address.IPv4Address & Netmask->Address.IPv4Address;
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_DATALINK, ("Don't know address type %d\n",
|
||||
Netmask->Type));
|
||||
*Network = *Source;
|
||||
}
|
||||
}
|
||||
|
||||
VOID IPAddressFree(
|
||||
PVOID Object)
|
||||
/*
|
||||
* FUNCTION: Frees an IP_ADDRESS object
|
||||
* ARGUMENTS:
|
||||
* Object = Pointer to an IP address structure
|
||||
* RETURNS:
|
||||
* Nothing
|
||||
*/
|
||||
{
|
||||
ExFreePoolWithTag(Object, IP_ADDRESS_TAG);
|
||||
}
|
||||
|
||||
|
||||
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 ||
|
||||
Address->Address.IPv4Address == 0xFFFFFFFF);
|
||||
|
||||
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(
|
||||
PTRANSPORT_ADDRESS TaAddress,
|
||||
PIP_ADDRESS Address,
|
||||
PUSHORT Port)
|
||||
{
|
||||
PTDI_ADDRESS_IP ValidAddr;
|
||||
PTA_ADDRESS TdiAddress = &TaAddress->Address[0];
|
||||
|
||||
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;
|
||||
|
||||
AddrInitIPv4(Address, ValidAddr->in_addr);
|
||||
*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) {
|
||||
DbgPrint("AddrIsEqual: Unequal Address Types\n");
|
||||
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;
|
||||
|
||||
default:
|
||||
DbgPrint("AddrIsEqual: Bad address type\n");
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
unsigned long NTAPI 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 */
|
320
sdk/lib/drivers/ip/network/arp.c
Normal file
320
sdk/lib/drivers/ip/network/arp.c
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS TCP/IP protocol driver
|
||||
* FILE: datalink/arp.c
|
||||
* PURPOSE: Address Resolution Protocol routines
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
* REVISIONS:
|
||||
* CSH 01/08-2000 Created
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
PNDIS_PACKET PrepareARPPacket(
|
||||
PIP_INTERFACE IF,
|
||||
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 = sizeof(ARP_HEADER) +
|
||||
2 * LinkAddressLength + /* Hardware address length */
|
||||
2 * ProtoAddressLength; /* Protocol address length */
|
||||
Size = MAX(Size, IF->MinFrameSize - IF->HeaderSize);
|
||||
|
||||
NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
|
||||
if( !NT_SUCCESS(NdisStatus) ) return NULL;
|
||||
|
||||
GetDataPtr( NdisPacket, 0, (PCHAR *)&DataBuffer, (PUINT)&Contig );
|
||||
ASSERT(DataBuffer);
|
||||
|
||||
RtlZeroMemory(DataBuffer, Size);
|
||||
Header = (PARP_HEADER)((ULONG_PTR)DataBuffer);
|
||||
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, PVOID LinkAddress,
|
||||
PIP_INTERFACE Interface)
|
||||
/*
|
||||
* FUNCTION: Creates an ARP request and transmits it on a network
|
||||
* ARGUMENTS:
|
||||
* Address = Pointer to IP address to resolve
|
||||
* RETURNS:
|
||||
* TRUE if the request was successfully sent, FALSE if not
|
||||
*/
|
||||
{
|
||||
PNDIS_PACKET NdisPacket;
|
||||
UCHAR ProtoAddrLen;
|
||||
USHORT ProtoType;
|
||||
|
||||
TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
|
||||
|
||||
/* If Address is NULL then the caller wants an
|
||||
* gratuitous ARP packet sent */
|
||||
if (!Address)
|
||||
Address = &Interface->Unicast;
|
||||
|
||||
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));
|
||||
DbgBreakPoint();
|
||||
/* Should not happen */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
NdisPacket = PrepareARPPacket(
|
||||
Interface,
|
||||
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 */
|
||||
&Interface->Unicast.Address.IPv4Address,/* Sender's (local) protocol address */
|
||||
LinkAddress, /* Target's (remote) hardware address */
|
||||
&Address->Address.IPv4Address, /* Target's (remote) protocol address */
|
||||
ARP_OPCODE_REQUEST); /* ARP request */
|
||||
|
||||
if( !NdisPacket ) return FALSE;
|
||||
|
||||
ASSERT_KM_POINTER(NdisPacket);
|
||||
ASSERT_KM_POINTER(PC(NdisPacket));
|
||||
PC(NdisPacket)->DLComplete = ARPTransmitComplete;
|
||||
|
||||
TI_DbgPrint(DEBUG_ARP,("Sending ARP Packet\n"));
|
||||
|
||||
(*Interface->Transmit)(Interface->Context, NdisPacket,
|
||||
0, 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;
|
||||
IP_ADDRESS SrcAddress;
|
||||
IP_ADDRESS DstAddress;
|
||||
PCHAR SenderHWAddress, SenderProtoAddress, TargetProtoAddress;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
PNDIS_PACKET NdisPacket;
|
||||
PIP_INTERFACE Interface = (PIP_INTERFACE)Context;
|
||||
ULONG BytesCopied, DataSize;
|
||||
PCHAR DataBuffer;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
TI_DbgPrint(DEBUG_ARP, ("Called.\n"));
|
||||
|
||||
Packet->Header = ExAllocatePoolWithTag(PagedPool,
|
||||
sizeof(ARP_HEADER),
|
||||
PACKET_BUFFER_TAG);
|
||||
if (!Packet->Header)
|
||||
{
|
||||
TI_DbgPrint(DEBUG_ARP, ("Unable to allocate header buffer\n"));
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
Packet->MappedHeader = FALSE;
|
||||
|
||||
BytesCopied = CopyPacketToBuffer((PCHAR)Packet->Header,
|
||||
Packet->NdisPacket,
|
||||
Packet->Position,
|
||||
sizeof(ARP_HEADER));
|
||||
if (BytesCopied != sizeof(ARP_HEADER))
|
||||
{
|
||||
TI_DbgPrint(DEBUG_ARP, ("Unable to copy in header buffer\n"));
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
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)));
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check protocol type */
|
||||
if (Header->ProtoType != ETYPE_IPv4) {
|
||||
TI_DbgPrint(DEBUG_ARP, ("Unknown ARP protocol type (0x%X).\n", WN2H(Header->ProtoType)));
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
DataSize = (2 * Header->HWAddrLen) + (2 * Header->ProtoAddrLen);
|
||||
DataBuffer = ExAllocatePool(PagedPool,
|
||||
DataSize);
|
||||
if (!DataBuffer)
|
||||
{
|
||||
TI_DbgPrint(DEBUG_ARP, ("Unable to allocate data buffer\n"));
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
BytesCopied = CopyPacketToBuffer(DataBuffer,
|
||||
Packet->NdisPacket,
|
||||
Packet->Position + sizeof(ARP_HEADER),
|
||||
DataSize);
|
||||
if (BytesCopied != DataSize)
|
||||
{
|
||||
TI_DbgPrint(DEBUG_ARP, ("Unable to copy in data buffer\n"));
|
||||
ExFreePool(DataBuffer);
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
SenderHWAddress = (PVOID)(DataBuffer);
|
||||
SenderProtoAddress = (PVOID)(SenderHWAddress + Header->HWAddrLen);
|
||||
TargetProtoAddress = (PVOID)(SenderProtoAddress + Header->ProtoAddrLen + Header->HWAddrLen);
|
||||
|
||||
AddrInitIPv4(&DstAddress, *((PULONG)TargetProtoAddress));
|
||||
if (!AddrIsEqual(&DstAddress, &Interface->Unicast))
|
||||
{
|
||||
ExFreePool(DataBuffer);
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
AddrInitIPv4(&SrcAddress, *((PULONG)SenderProtoAddress));
|
||||
|
||||
/* Check if we know the sender */
|
||||
NCE = NBLocateNeighbor(&SrcAddress, Interface);
|
||||
if (NCE) {
|
||||
/* We know the sender. Update the hardware address
|
||||
and state in our neighbor address cache */
|
||||
NBUpdateNeighbor(NCE, SenderHWAddress, 0);
|
||||
} 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 */
|
||||
NBAddNeighbor(Interface, &SrcAddress, SenderHWAddress,
|
||||
Header->HWAddrLen, 0, ARP_COMPLETE_TIMEOUT);
|
||||
}
|
||||
|
||||
if (Header->Opcode != ARP_OPCODE_REQUEST)
|
||||
{
|
||||
ExFreePool(DataBuffer);
|
||||
Packet->Free(Packet);
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is a request for our address. Swap the addresses and
|
||||
send an ARP reply back to the sender */
|
||||
NdisPacket = PrepareARPPacket(
|
||||
Interface,
|
||||
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 */
|
||||
&Interface->Unicast.Address.IPv4Address,/* 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,
|
||||
0,
|
||||
SenderHWAddress,
|
||||
LAN_PROTO_ARP);
|
||||
}
|
||||
|
||||
ExFreePool(DataBuffer);
|
||||
Packet->Free(Packet);
|
||||
}
|
||||
|
||||
/* EOF */
|
105
sdk/lib/drivers/ip/network/checksum.c
Normal file
105
sdk/lib/drivers/ip/network/checksum.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
ULONG
|
||||
UDPv4ChecksumCalculate(
|
||||
PIPv4_HEADER IPHeader,
|
||||
PUCHAR PacketBuffer,
|
||||
ULONG DataLength)
|
||||
{
|
||||
ULONG Sum = 0;
|
||||
USHORT TmpSum;
|
||||
ULONG i;
|
||||
BOOLEAN Pad;
|
||||
|
||||
/* Pad the data if needed */
|
||||
Pad = (DataLength & 1);
|
||||
if (Pad)
|
||||
DataLength++;
|
||||
|
||||
/* Add from the UDP header and data */
|
||||
for (i = 0; i < DataLength; i += 2)
|
||||
{
|
||||
TmpSum = ((PacketBuffer[i] << 8) & 0xFF00) +
|
||||
((Pad && i == DataLength - 2) ? 0 : (PacketBuffer[i+1] & 0x00FF));
|
||||
Sum += TmpSum;
|
||||
}
|
||||
|
||||
/* Add the source address */
|
||||
for (i = 0; i < sizeof(IPv4_RAW_ADDRESS); i += 2)
|
||||
{
|
||||
TmpSum = ((((PUCHAR)&IPHeader->SrcAddr)[i] << 8) & 0xFF00) +
|
||||
(((PUCHAR)&IPHeader->SrcAddr)[i+1] & 0x00FF);
|
||||
Sum += TmpSum;
|
||||
}
|
||||
|
||||
/* Add the destination address */
|
||||
for (i = 0; i < sizeof(IPv4_RAW_ADDRESS); i += 2)
|
||||
{
|
||||
TmpSum = ((((PUCHAR)&IPHeader->DstAddr)[i] << 8) & 0xFF00) +
|
||||
(((PUCHAR)&IPHeader->DstAddr)[i+1] & 0x00FF);
|
||||
Sum += TmpSum;
|
||||
}
|
||||
|
||||
/* Add the proto number and length */
|
||||
Sum += IPPROTO_UDP + (DataLength - (Pad ? 1 : 0));
|
||||
|
||||
/* Fold the checksum and return the one's complement */
|
||||
return ~ChecksumFold(Sum);
|
||||
}
|
||||
|
253
sdk/lib/drivers/ip/network/i386/checksum.S
Normal file
253
sdk/lib/drivers/ip/network/i386/checksum.S
Normal file
|
@ -0,0 +1,253 @@
|
|||
/*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
#include <asm.inc>
|
||||
|
||||
.code
|
||||
.align 4
|
||||
PUBLIC _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:
|
||||
push esi
|
||||
push ebx
|
||||
mov eax, [esp + 20] // Function arg: unsigned int sum
|
||||
mov ecx, [esp + 16] // Function arg: int len
|
||||
mov esi, [esp + 12] // Function arg: unsigned char *buff
|
||||
test esi, 3 // Check alignment.
|
||||
jz m2 // Jump if alignment is ok.
|
||||
test esi, 1 // Check alignment.
|
||||
jz l10 // Jump if alignment is boundary of 2bytes.
|
||||
|
||||
// buf is odd
|
||||
dec ecx
|
||||
jl l8
|
||||
movzx ebx, byte ptr [esi]
|
||||
adc eax, ebx
|
||||
rol eax, 8
|
||||
inc esi
|
||||
test esi, 2
|
||||
jz m2
|
||||
l10:
|
||||
sub ecx, 2 // Alignment uses up two bytes.
|
||||
jae m1 // Jump if we had at least two bytes.
|
||||
add ecx, 2 // ecx was < 2. Deal with it.
|
||||
jmp l4
|
||||
m1: mov bx, [esi]
|
||||
add esi, 2
|
||||
add ax, bx
|
||||
adc eax, 0
|
||||
m2:
|
||||
mov edx, ecx
|
||||
shr ecx, 5
|
||||
jz l2
|
||||
test esi, esi
|
||||
l1: mov ebx, [esi]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 4]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 8]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 12]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 16]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 20]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 24]
|
||||
adc eax, ebx
|
||||
mov ebx, [esi + 28]
|
||||
adc eax, ebx
|
||||
lea esi, [esi + 32]
|
||||
dec ecx
|
||||
jne l1
|
||||
adc eax, 0
|
||||
l2: mov ecx, edx
|
||||
and edx, HEX(1c)
|
||||
je l4
|
||||
shr edx, 2 // This clears CF
|
||||
l3: adc eax, [esi]
|
||||
lea esi, [esi + 4]
|
||||
dec edx
|
||||
jne l3
|
||||
adc eax, 0
|
||||
l4: and ecx, 3
|
||||
jz l7
|
||||
cmp ecx, 2
|
||||
jb l5
|
||||
mov cx, [esi]
|
||||
lea esi, [esi + 2]
|
||||
je l6
|
||||
shl ecx, 16
|
||||
l5: mov cl, [esi]
|
||||
l6: add eax, ecx
|
||||
adc eax, 0
|
||||
l7:
|
||||
test dword ptr [esp + 12], 1
|
||||
jz l8
|
||||
rol eax, 8
|
||||
l8:
|
||||
pop ebx
|
||||
pop esi
|
||||
ret
|
||||
|
||||
#else
|
||||
|
||||
/* Version for PentiumII/PPro */
|
||||
|
||||
csum_partial:
|
||||
push esi
|
||||
push ebx
|
||||
mov eax, [esp + 20] # Function arg: unsigned int sum
|
||||
mov ecx, [esp + 16] # Function arg: int len
|
||||
mov esi, [esp + 12] # Function arg: const unsigned char *buf
|
||||
|
||||
test esi, 3
|
||||
jnz l25f
|
||||
l10:
|
||||
mov edx, ecx
|
||||
mov ebx, ecx
|
||||
and ebx, HEX(7c)
|
||||
shr ecx, 7
|
||||
add esi, ebx
|
||||
shr ebx, 2
|
||||
neg ebx
|
||||
lea ebx, l45[ebx + ebx * 2]
|
||||
test esi, esi
|
||||
jmp dword ptr [ebx]
|
||||
|
||||
// Handle 2-byte-aligned regions
|
||||
l20: add ax, [esi]
|
||||
lea esi, [esi + 2]
|
||||
adc eax, 0
|
||||
jmp l10b
|
||||
l25:
|
||||
test esi, 1
|
||||
jz l30f
|
||||
// buf is odd
|
||||
dec ecx
|
||||
jl l90
|
||||
movzb ebx, [esi]
|
||||
add eax, ebx
|
||||
adc eax, 0
|
||||
rol eax, 8
|
||||
inc esi
|
||||
test esi, 2
|
||||
jz l10b
|
||||
|
||||
l30: sub ecx, 2
|
||||
ja l20
|
||||
je l32
|
||||
add ecx, 2
|
||||
jz l80
|
||||
movzb ebx, [esi] // csumming 1 byte, 2-aligned
|
||||
add eax, ebx
|
||||
adc eax, 0
|
||||
jmp l80
|
||||
l32:
|
||||
add ax, [esi] // csumming 2 bytes, 2-aligned
|
||||
adc eax, 0
|
||||
jmp l80
|
||||
|
||||
l40:
|
||||
add eax, [esi -128]
|
||||
adc eax, [esi -124]
|
||||
adc eax, [esi -120]
|
||||
adc eax, [esi -116]
|
||||
adc eax, [esi -112]
|
||||
adc eax, [esi -108]
|
||||
adc eax, [esi -104]
|
||||
adc eax, [esi -100]
|
||||
adc eax, [esi -96]
|
||||
adc eax, [esi -92]
|
||||
adc eax, [esi -88]
|
||||
adc eax, [esi -84]
|
||||
adc eax, [esi -80]
|
||||
adc eax, [esi -76]
|
||||
adc eax, [esi -72]
|
||||
adc eax, [esi -68]
|
||||
adc eax, [esi -64]
|
||||
adc eax, [esi -60]
|
||||
adc eax, [esi -56]
|
||||
adc eax, [esi -52]
|
||||
adc eax, [esi -48]
|
||||
adc eax, [esi -44]
|
||||
adc eax, [esi -40]
|
||||
adc eax, [esi -36]
|
||||
adc eax, [esi -32]
|
||||
adc eax, [esi -28]
|
||||
adc eax, [esi -24]
|
||||
adc eax, [esi -20]
|
||||
adc eax, [esi -16]
|
||||
adc eax, [esi -12]
|
||||
adc eax, [esi -8]
|
||||
adc eax, [esi -4]
|
||||
l45:
|
||||
lea esi, [esi + 128]
|
||||
adc eax, 0
|
||||
dec ecx
|
||||
jge l40
|
||||
mov ecx, edx
|
||||
l50: and ecx, 3
|
||||
jz l80
|
||||
|
||||
// Handle the last 1-3 bytes without jumping
|
||||
not ecx // 1->2, 2->1, 3->0, higher bits are masked
|
||||
mov ebx, HEX(ffffff) // by the shll and shrl instructions
|
||||
shl ecx, 3
|
||||
shr ebx, cl
|
||||
and ebx, [esi -128] // esi is 4-aligned so should be ok
|
||||
add eax, ebx
|
||||
adc eax, 0
|
||||
l80:
|
||||
test dword ptr [esp + 12], 1
|
||||
jz l90
|
||||
rol eax, 8
|
||||
l90:
|
||||
pop ebx
|
||||
pop esi
|
||||
ret
|
||||
|
||||
#endif
|
||||
|
||||
END
|
332
sdk/lib/drivers/ip/network/icmp.c
Normal file
332
sdk/lib/drivers/ip/network/icmp.c
Normal file
|
@ -0,0 +1,332 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS TCP/IP protocol driver
|
||||
* FILE: network/icmp.c
|
||||
* PURPOSE: Internet Control Message Protocol routines
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
* REVISIONS:
|
||||
* CSH 01/08-2000 Created
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#include <icmp.h>
|
||||
|
||||
NTSTATUS ICMPStartup()
|
||||
{
|
||||
IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS ICMPShutdown()
|
||||
{
|
||||
IPRegisterProtocol(IPPROTO_ICMP, NULL);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN PrepareICMPPacket(
|
||||
PADDRESS_FILE AddrFile,
|
||||
PIP_INTERFACE Interface,
|
||||
PIP_PACKET IPPacket,
|
||||
PIP_ADDRESS Destination,
|
||||
PCHAR Data,
|
||||
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
|
||||
*/
|
||||
{
|
||||
PNDIS_PACKET NdisPacket;
|
||||
NDIS_STATUS NdisStatus;
|
||||
PIPv4_HEADER IPHeader;
|
||||
ULONG Size;
|
||||
|
||||
TI_DbgPrint(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize));
|
||||
|
||||
IPInitializePacket(IPPacket, IP_ADDRESS_V4);
|
||||
|
||||
/* No special flags */
|
||||
IPPacket->Flags = 0;
|
||||
|
||||
Size = sizeof(IPv4_HEADER) + DataSize;
|
||||
|
||||
/* Allocate NDIS packet */
|
||||
NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
|
||||
|
||||
if( !NT_SUCCESS(NdisStatus) ) return FALSE;
|
||||
|
||||
IPPacket->NdisPacket = NdisPacket;
|
||||
IPPacket->MappedHeader = TRUE;
|
||||
|
||||
GetDataPtr( IPPacket->NdisPacket, 0,
|
||||
(PCHAR *)&IPPacket->Header, &IPPacket->TotalSize );
|
||||
ASSERT(IPPacket->TotalSize == Size);
|
||||
|
||||
TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, Data));
|
||||
TI_DbgPrint(DEBUG_ICMP, ("NdisPacket at (0x%X).\n", NdisPacket));
|
||||
|
||||
IPPacket->HeaderSize = sizeof(IPv4_HEADER);
|
||||
IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
|
||||
|
||||
TI_DbgPrint(DEBUG_ICMP, ("Copying Address: %x -> %x\n",
|
||||
&IPPacket->DstAddr, Destination));
|
||||
|
||||
RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS));
|
||||
RtlCopyMemory(IPPacket->Data, Data, DataSize);
|
||||
|
||||
/* 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));
|
||||
/* Identification */
|
||||
IPHeader->Id = (USHORT)Random();
|
||||
/* One fragment at offset 0 */
|
||||
IPHeader->FlagsFragOfs = 0;
|
||||
/* Set TTL */
|
||||
if (AddrFile)
|
||||
IPHeader->Ttl = AddrFile->TTL;
|
||||
else
|
||||
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 = Interface->Unicast.Address.IPv4Address;
|
||||
/* Destination address */
|
||||
IPHeader->DstAddr = Destination->Address.IPv4Address;
|
||||
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("Leaving\n"));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
NTSTATUS ICMPSendDatagram(
|
||||
PADDRESS_FILE AddrFile,
|
||||
PTDI_CONNECTION_INFORMATION ConnInfo,
|
||||
PCHAR BufferData,
|
||||
ULONG DataSize,
|
||||
PULONG DataUsed )
|
||||
/*
|
||||
* FUNCTION: Sends an ICMP 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
|
||||
*/
|
||||
{
|
||||
IP_PACKET Packet;
|
||||
PTA_IP_ADDRESS RemoteAddressTa = (PTA_IP_ADDRESS)ConnInfo->RemoteAddress;
|
||||
IP_ADDRESS RemoteAddress, LocalAddress;
|
||||
NTSTATUS Status;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
KIRQL OldIrql;
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("Sending Datagram(%x %x %x %d)\n",
|
||||
AddrFile, ConnInfo, BufferData, DataSize));
|
||||
TI_DbgPrint(MID_TRACE,("RemoteAddressTa: %x\n", RemoteAddressTa));
|
||||
|
||||
switch( RemoteAddressTa->Address[0].AddressType ) {
|
||||
case TDI_ADDRESS_TYPE_IP:
|
||||
RemoteAddress.Type = IP_ADDRESS_V4;
|
||||
RemoteAddress.Address.IPv4Address =
|
||||
RemoteAddressTa->Address[0].Address[0].in_addr;
|
||||
break;
|
||||
|
||||
default:
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("About to get route to destination\n"));
|
||||
|
||||
LockObject(AddrFile, &OldIrql);
|
||||
|
||||
LocalAddress = AddrFile->Address;
|
||||
if (AddrIsUnspecified(&LocalAddress))
|
||||
{
|
||||
/* If the local address is unspecified (0),
|
||||
* then use the unicast address of the
|
||||
* interface we're sending over
|
||||
*/
|
||||
if(!(NCE = RouteGetRouteToDestination( &RemoteAddress )))
|
||||
{
|
||||
UnlockObject(AddrFile, OldIrql);
|
||||
return STATUS_NETWORK_UNREACHABLE;
|
||||
}
|
||||
|
||||
LocalAddress = NCE->Interface->Unicast;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!(NCE = NBLocateNeighbor( &LocalAddress, NULL )))
|
||||
{
|
||||
UnlockObject(AddrFile, OldIrql);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
Status = PrepareICMPPacket( AddrFile,
|
||||
NCE->Interface,
|
||||
&Packet,
|
||||
&RemoteAddress,
|
||||
BufferData,
|
||||
DataSize );
|
||||
|
||||
UnlockObject(AddrFile, OldIrql);
|
||||
|
||||
if( !NT_SUCCESS(Status) )
|
||||
return Status;
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("About to send datagram\n"));
|
||||
|
||||
Status = IPSendDatagram(&Packet, NCE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
return Status;
|
||||
|
||||
*DataUsed = DataSize;
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("Leaving\n"));
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
VOID ICMPReceive(
|
||||
PIP_INTERFACE Interface,
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
RawIpReceive(Interface, IPPacket);
|
||||
|
||||
switch (ICMPHeader->Type) {
|
||||
case ICMP_TYPE_ECHO_REQUEST:
|
||||
ICMPReply( Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0 );
|
||||
break;
|
||||
|
||||
case ICMP_TYPE_ECHO_REPLY:
|
||||
break;
|
||||
|
||||
default:
|
||||
TI_DbgPrint(DEBUG_ICMP,
|
||||
("Discarded ICMP datagram of unknown type %d.\n",
|
||||
ICMPHeader->Type));
|
||||
/* Discard packet */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID ICMPTransmit(
|
||||
PIP_PACKET IPPacket,
|
||||
PIP_TRANSMIT_COMPLETE Complete,
|
||||
PVOID Context)
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
{
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
|
||||
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 ((NCE = RouteGetRouteToDestination(&IPPacket->DstAddr))) {
|
||||
/* Send the packet */
|
||||
IPSendDatagram(IPPacket, NCE);
|
||||
} else {
|
||||
/* No route to destination (or no free resources) */
|
||||
TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n",
|
||||
IPPacket->DstAddr.Address.IPv4Address));
|
||||
IPPacket->Free(IPPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
VOID ICMPReply(
|
||||
PIP_INTERFACE Interface,
|
||||
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;
|
||||
IP_PACKET NewPacket;
|
||||
|
||||
TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d) Code (%d).\n", Type, Code));
|
||||
|
||||
DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
|
||||
|
||||
if( !PrepareICMPPacket(NULL, Interface, &NewPacket, &IPPacket->SrcAddr,
|
||||
IPPacket->Data, DataSize) ) return;
|
||||
|
||||
((PICMP_HEADER)NewPacket.Data)->Type = Type;
|
||||
((PICMP_HEADER)NewPacket.Data)->Code = Code;
|
||||
((PICMP_HEADER)NewPacket.Data)->Checksum = 0;
|
||||
|
||||
ICMPTransmit(&NewPacket, NULL, NULL);
|
||||
}
|
||||
|
||||
/* EOF */
|
265
sdk/lib/drivers/ip/network/interface.c
Normal file
265
sdk/lib/drivers/ip/network/interface.c
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* 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"
|
||||
|
||||
#include <ntifs.h>
|
||||
#include <ipifcons.h>
|
||||
|
||||
ULONG NextDefaultAdapter = 0;
|
||||
|
||||
NTSTATUS GetInterfaceIPv4Address( PIP_INTERFACE Interface,
|
||||
ULONG TargetType,
|
||||
PULONG Address ) {
|
||||
switch( TargetType ) {
|
||||
case ADE_UNICAST:
|
||||
*Address = Interface->Unicast.Address.IPv4Address;
|
||||
break;
|
||||
|
||||
case ADE_ADDRMASK:
|
||||
*Address = Interface->Netmask.Address.IPv4Address;
|
||||
break;
|
||||
|
||||
case ADE_BROADCAST:
|
||||
*Address = Interface->Broadcast.Address.IPv4Address;
|
||||
break;
|
||||
|
||||
case ADE_POINTOPOINT:
|
||||
*Address = Interface->PointToPoint.Address.IPv4Address;
|
||||
break;
|
||||
|
||||
default:
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
UINT CountInterfaces() {
|
||||
ULONG Count = 0;
|
||||
KIRQL OldIrql;
|
||||
IF_LIST_ITER(CurrentIF);
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
|
||||
ForEachInterface(CurrentIF) {
|
||||
Count++;
|
||||
} EndFor(CurrentIF);
|
||||
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
NTSTATUS GetInterfaceSpeed( PIP_INTERFACE Interface, PUINT Speed ) {
|
||||
PLAN_ADAPTER IF = (PLAN_ADAPTER)Interface->Context;
|
||||
|
||||
*Speed = IF->Speed;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS GetInterfaceName( PIP_INTERFACE Interface,
|
||||
PCHAR NameBuffer,
|
||||
UINT Len ) {
|
||||
ULONG ResultSize = 0;
|
||||
NTSTATUS Status =
|
||||
RtlUnicodeToMultiByteN( NameBuffer,
|
||||
Len,
|
||||
&ResultSize,
|
||||
Interface->Name.Buffer,
|
||||
Interface->Name.Length );
|
||||
|
||||
if( NT_SUCCESS(Status) )
|
||||
NameBuffer[ResultSize] = 0;
|
||||
else
|
||||
NameBuffer[0] = 0;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
PIP_INTERFACE AddrLocateInterface(
|
||||
PIP_ADDRESS MatchAddress)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PIP_INTERFACE RetIF = NULL;
|
||||
IF_LIST_ITER(CurrentIF);
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
|
||||
ForEachInterface(CurrentIF) {
|
||||
if( AddrIsEqual( &CurrentIF->Unicast, MatchAddress ) ||
|
||||
AddrIsEqual( &CurrentIF->Broadcast, MatchAddress ) ) {
|
||||
RetIF = CurrentIF;
|
||||
break;
|
||||
}
|
||||
} EndFor(CurrentIF);
|
||||
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
return RetIF;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
/* Don't report matches for empty prefixes */
|
||||
if (Length == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
PIP_INTERFACE GetDefaultInterface(VOID)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
ULONG Index = 0;
|
||||
ULONG IfStatus;
|
||||
|
||||
IF_LIST_ITER(CurrentIF);
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
/* DHCP hack: Always return the adapter without an IP address */
|
||||
ForEachInterface(CurrentIF) {
|
||||
if (CurrentIF->Context && AddrIsUnspecified(&CurrentIF->Unicast)) {
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
|
||||
if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
|
||||
return CurrentIF;
|
||||
}
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
}
|
||||
} EndFor(CurrentIF);
|
||||
|
||||
/* Try to continue from the next adapter */
|
||||
ForEachInterface(CurrentIF) {
|
||||
if (CurrentIF->Context && (Index++ == NextDefaultAdapter)) {
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
|
||||
if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
|
||||
NextDefaultAdapter++;
|
||||
return CurrentIF;
|
||||
}
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
}
|
||||
} EndFor(CurrentIF);
|
||||
|
||||
/* No luck, so we'll choose the first adapter this time */
|
||||
Index = 0;
|
||||
ForEachInterface(CurrentIF) {
|
||||
if (CurrentIF->Context) {
|
||||
Index++;
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
GetInterfaceConnectionStatus(CurrentIF, &IfStatus);
|
||||
if (IfStatus == MIB_IF_OPER_STATUS_OPERATIONAL) {
|
||||
NextDefaultAdapter = Index;
|
||||
return CurrentIF;
|
||||
}
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
}
|
||||
} EndFor(CurrentIF);
|
||||
|
||||
/* Even that didn't work, so we'll just go with loopback */
|
||||
NextDefaultAdapter = 0;
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
/* There are no physical interfaces on the system
|
||||
* so we must pick the loopback interface */
|
||||
|
||||
return Loopback;
|
||||
}
|
||||
|
||||
PIP_INTERFACE FindOnLinkInterface(PIP_ADDRESS Address)
|
||||
/*
|
||||
* FUNCTION: Checks all on-link prefixes to find out if an address is on-link
|
||||
* ARGUMENTS:
|
||||
* Address = Pointer to address to check
|
||||
* RETURNS:
|
||||
* Pointer to interface if address is on-link, NULL if not
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
IF_LIST_ITER(CurrentIF);
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Called. Address (0x%X)\n", Address));
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Address (%s)\n", A2S(Address)));
|
||||
|
||||
if (AddrIsUnspecified(Address))
|
||||
return GetDefaultInterface();
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql);
|
||||
|
||||
ForEachInterface(CurrentIF) {
|
||||
if (HasPrefix(Address, &CurrentIF->Unicast,
|
||||
AddrCountPrefixBits(&CurrentIF->Netmask))) {
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
return CurrentIF;
|
||||
}
|
||||
} EndFor(CurrentIF);
|
||||
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID GetInterfaceConnectionStatus(PIP_INTERFACE Interface, PULONG Result)
|
||||
{
|
||||
PLAN_ADAPTER Adapter = Interface->Context;
|
||||
|
||||
/* Loopback has no adapter context */
|
||||
if (Adapter == NULL || Adapter->State == LAN_STATE_STARTED) {
|
||||
*Result = MIB_IF_OPER_STATUS_OPERATIONAL;
|
||||
}
|
||||
else {
|
||||
*Result = MIB_IF_OPER_STATUS_DISCONNECTED;
|
||||
}
|
||||
}
|
508
sdk/lib/drivers/ip/network/ip.c
Normal file
508
sdk/lib/drivers/ip/network/ip.c
Normal file
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS TCP/IP protocol driver
|
||||
* FILE: network/ip.c
|
||||
* PURPOSE: Internet Protocol module
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
* REVISIONS:
|
||||
* CSH 01/08-2000 Created
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
#define __LWIP_INET_H__
|
||||
#include "lwip/netifapi.h"
|
||||
|
||||
|
||||
LIST_ENTRY InterfaceListHead;
|
||||
KSPIN_LOCK InterfaceListLock;
|
||||
LIST_ENTRY NetTableListHead;
|
||||
KSPIN_LOCK NetTableListLock;
|
||||
BOOLEAN IPInitialized = FALSE;
|
||||
BOOLEAN IpWorkItemQueued = FALSE;
|
||||
/* Work around calling timer at Dpc level */
|
||||
|
||||
IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
|
||||
|
||||
ULONG IpTimerExpirations;
|
||||
|
||||
VOID
|
||||
TCPRegisterInterface(PIP_INTERFACE IF);
|
||||
|
||||
VOID
|
||||
TCPUnregisterInterface(PIP_INTERFACE IF);
|
||||
|
||||
VOID DeinitializePacket(
|
||||
PVOID Object)
|
||||
/*
|
||||
* FUNCTION: Frees buffers attached to the packet
|
||||
* ARGUMENTS:
|
||||
* Object = Pointer to an IP packet structure
|
||||
*/
|
||||
{
|
||||
PIP_PACKET IPPacket = Object;
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Freeing object: 0x%p\n", Object));
|
||||
|
||||
/* Detect double free */
|
||||
ASSERT(IPPacket->Type != 0xFF);
|
||||
IPPacket->Type = 0xFF;
|
||||
|
||||
/* Check if there's a packet to free */
|
||||
if (IPPacket->NdisPacket != NULL)
|
||||
{
|
||||
if (IPPacket->ReturnPacket)
|
||||
{
|
||||
/* Return the packet to the miniport driver */
|
||||
TI_DbgPrint(MAX_TRACE, ("Returning packet 0x%p\n",
|
||||
IPPacket->NdisPacket));
|
||||
NdisReturnPackets(&IPPacket->NdisPacket, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Free it the conventional way */
|
||||
TI_DbgPrint(MAX_TRACE, ("Freeing packet 0x%p\n",
|
||||
IPPacket->NdisPacket));
|
||||
FreeNdisPacket(IPPacket->NdisPacket);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we have a pool-allocated header */
|
||||
if (!IPPacket->MappedHeader && IPPacket->Header)
|
||||
{
|
||||
/* Free it */
|
||||
TI_DbgPrint(MAX_TRACE, ("Freeing header: 0x%p\n",
|
||||
IPPacket->Header));
|
||||
ExFreePoolWithTag(IPPacket->Header,
|
||||
PACKET_BUFFER_TAG);
|
||||
}
|
||||
}
|
||||
|
||||
VOID FreeIF(
|
||||
PVOID Object)
|
||||
/*
|
||||
* FUNCTION: Frees an interface object
|
||||
* ARGUMENTS:
|
||||
* Object = Pointer to an interface structure
|
||||
*/
|
||||
{
|
||||
ExFreePoolWithTag(Object, IP_INTERFACE_TAG);
|
||||
}
|
||||
|
||||
PIP_PACKET IPInitializePacket(
|
||||
PIP_PACKET IPPacket,
|
||||
ULONG Type)
|
||||
/*
|
||||
* FUNCTION: Creates an IP packet object
|
||||
* ARGUMENTS:
|
||||
* Type = Type of IP packet
|
||||
* RETURNS:
|
||||
* Pointer to the created IP packet. NULL if there was not enough free resources.
|
||||
*/
|
||||
{
|
||||
RtlZeroMemory(IPPacket, sizeof(IP_PACKET));
|
||||
|
||||
IPPacket->Free = DeinitializePacket;
|
||||
IPPacket->Type = Type;
|
||||
|
||||
return IPPacket;
|
||||
}
|
||||
|
||||
|
||||
VOID NTAPI IPTimeoutDpcFn(PKDPC Dpc,
|
||||
PVOID DeferredContext,
|
||||
PVOID SystemArgument1,
|
||||
PVOID SystemArgument2)
|
||||
/*
|
||||
* FUNCTION: Timeout DPC
|
||||
* ARGUMENTS:
|
||||
* Dpc = Pointer to our DPC object
|
||||
* DeferredContext = Pointer to context information (unused)
|
||||
* SystemArgument1 = Unused
|
||||
* SystemArgument2 = Unused
|
||||
* NOTES:
|
||||
* This routine is dispatched once in a while to do maintenance jobs
|
||||
*/
|
||||
{
|
||||
IpTimerExpirations++;
|
||||
|
||||
if ((IpTimerExpirations % 10) == 0)
|
||||
{
|
||||
LogActiveObjects();
|
||||
}
|
||||
|
||||
/* Check if datagram fragments have taken too long to assemble */
|
||||
IPDatagramReassemblyTimeout();
|
||||
|
||||
/* Clean possible outdated cached neighbor addresses */
|
||||
NBTimeout();
|
||||
}
|
||||
|
||||
|
||||
VOID IPDispatchProtocol(
|
||||
PIP_INTERFACE Interface,
|
||||
PIP_PACKET IPPacket)
|
||||
/*
|
||||
* FUNCTION: IP protocol dispatcher
|
||||
* ARGUMENTS:
|
||||
* NTE = Pointer to net table entry which the packet was received on
|
||||
* IPPacket = Pointer to an IP packet that was received
|
||||
* NOTES:
|
||||
* This routine examines the IP header and passes the packet on to the
|
||||
* right upper level protocol receive handler
|
||||
*/
|
||||
{
|
||||
UINT Protocol;
|
||||
IP_ADDRESS SrcAddress;
|
||||
|
||||
switch (IPPacket->Type) {
|
||||
case IP_ADDRESS_V4:
|
||||
Protocol = ((PIPv4_HEADER)(IPPacket->Header))->Protocol;
|
||||
AddrInitIPv4(&SrcAddress, ((PIPv4_HEADER)(IPPacket->Header))->SrcAddr);
|
||||
break;
|
||||
case IP_ADDRESS_V6:
|
||||
/* FIXME: IPv6 adresses not supported */
|
||||
TI_DbgPrint(MIN_TRACE, ("IPv6 datagram discarded.\n"));
|
||||
return;
|
||||
default:
|
||||
TI_DbgPrint(MIN_TRACE, ("Unrecognized datagram discarded.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
NBResetNeighborTimeout(&SrcAddress);
|
||||
|
||||
if (Protocol < IP_PROTOCOL_TABLE_SIZE)
|
||||
{
|
||||
/* Call the appropriate protocol handler */
|
||||
(*ProtocolTable[Protocol])(Interface, IPPacket);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PIP_INTERFACE IPCreateInterface(
|
||||
PLLIP_BIND_INFO BindInfo)
|
||||
/*
|
||||
* FUNCTION: Creates an IP interface
|
||||
* ARGUMENTS:
|
||||
* BindInfo = Pointer to link layer to IP binding information
|
||||
* RETURNS:
|
||||
* Pointer to IP_INTERFACE structure, NULL if there was
|
||||
* not enough free resources
|
||||
*/
|
||||
{
|
||||
PIP_INTERFACE IF;
|
||||
|
||||
TI_DbgPrint(DEBUG_IP, ("Called. BindInfo (0x%X).\n", BindInfo));
|
||||
|
||||
#if DBG
|
||||
if (BindInfo->Address) {
|
||||
PUCHAR A = BindInfo->Address;
|
||||
TI_DbgPrint(DEBUG_IP, ("Interface address (%02X %02X %02X %02X %02X %02X).\n",
|
||||
A[0], A[1], A[2], A[3], A[4], A[5]));
|
||||
}
|
||||
#endif
|
||||
|
||||
IF = ExAllocatePoolWithTag(NonPagedPool, sizeof(IP_INTERFACE),
|
||||
IP_INTERFACE_TAG);
|
||||
if (!IF) {
|
||||
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RtlZeroMemory(IF, sizeof(IP_INTERFACE));
|
||||
|
||||
IF->Free = FreeIF;
|
||||
IF->Context = BindInfo->Context;
|
||||
IF->HeaderSize = BindInfo->HeaderSize;
|
||||
IF->MinFrameSize = BindInfo->MinFrameSize;
|
||||
IF->Address = BindInfo->Address;
|
||||
IF->AddressLength = BindInfo->AddressLength;
|
||||
IF->Transmit = BindInfo->Transmit;
|
||||
|
||||
IF->Unicast.Type = IP_ADDRESS_V4;
|
||||
IF->PointToPoint.Type = IP_ADDRESS_V4;
|
||||
IF->Netmask.Type = IP_ADDRESS_V4;
|
||||
IF->Broadcast.Type = IP_ADDRESS_V4;
|
||||
|
||||
TcpipInitializeSpinLock(&IF->Lock);
|
||||
|
||||
IF->TCPContext = ExAllocatePool
|
||||
( NonPagedPool, sizeof(struct netif));
|
||||
if (!IF->TCPContext) {
|
||||
ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
TCPRegisterInterface(IF);
|
||||
|
||||
#ifdef __NTDRIVER__
|
||||
InsertTDIInterfaceEntity( IF );
|
||||
#endif
|
||||
|
||||
return IF;
|
||||
}
|
||||
|
||||
|
||||
VOID IPDestroyInterface(
|
||||
PIP_INTERFACE IF)
|
||||
/*
|
||||
* FUNCTION: Destroys an IP interface
|
||||
* ARGUMENTS:
|
||||
* IF = Pointer to interface to destroy
|
||||
*/
|
||||
{
|
||||
TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
|
||||
|
||||
#ifdef __NTDRIVER__
|
||||
RemoveTDIInterfaceEntity( IF );
|
||||
#endif
|
||||
|
||||
TCPUnregisterInterface(IF);
|
||||
|
||||
ExFreePool(IF->TCPContext);
|
||||
ExFreePoolWithTag(IF, IP_INTERFACE_TAG);
|
||||
}
|
||||
|
||||
VOID IPAddInterfaceRoute( PIP_INTERFACE IF ) {
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
IP_ADDRESS NetworkAddress;
|
||||
|
||||
/* Add a permanent neighbor for this NTE */
|
||||
NCE = NBAddNeighbor(IF, &IF->Unicast,
|
||||
IF->Address, IF->AddressLength,
|
||||
NUD_PERMANENT, 0);
|
||||
if (!NCE) {
|
||||
TI_DbgPrint(MIN_TRACE, ("Could not create NCE.\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
AddrWidenAddress( &NetworkAddress, &IF->Unicast, &IF->Netmask );
|
||||
|
||||
if (!RouterAddRoute(&NetworkAddress, &IF->Netmask, NCE, 1)) {
|
||||
TI_DbgPrint(MIN_TRACE, ("Could not add route due to insufficient resources.\n"));
|
||||
}
|
||||
|
||||
/* Send a gratuitous ARP packet to update the route caches of
|
||||
* other computers */
|
||||
if (IF != Loopback)
|
||||
ARPTransmit(NULL, NULL, IF);
|
||||
|
||||
TCPUpdateInterfaceIPInformation(IF);
|
||||
}
|
||||
|
||||
BOOLEAN IPRegisterInterface(
|
||||
PIP_INTERFACE IF)
|
||||
/*
|
||||
* FUNCTION: Registers an IP interface with IP layer
|
||||
* ARGUMENTS:
|
||||
* IF = Pointer to interface to register
|
||||
* RETURNS;
|
||||
* TRUE if interface was successfully registered, FALSE if not
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
UINT ChosenIndex = 0;
|
||||
BOOLEAN IndexHasBeenChosen;
|
||||
IF_LIST_ITER(Interface);
|
||||
|
||||
TI_DbgPrint(MID_TRACE, ("Called. IF (0x%X).\n", IF));
|
||||
|
||||
TcpipAcquireSpinLock(&IF->Lock, &OldIrql);
|
||||
|
||||
/* Choose an index */
|
||||
do {
|
||||
IndexHasBeenChosen = TRUE;
|
||||
ForEachInterface(Interface) {
|
||||
if( Interface->Index == ChosenIndex ) {
|
||||
ChosenIndex++;
|
||||
IndexHasBeenChosen = FALSE;
|
||||
}
|
||||
} EndFor(Interface);
|
||||
} while( !IndexHasBeenChosen );
|
||||
|
||||
IF->Index = ChosenIndex;
|
||||
|
||||
/* Add interface to the global interface list */
|
||||
TcpipInterlockedInsertTailList(&InterfaceListHead,
|
||||
&IF->ListEntry,
|
||||
&InterfaceListLock);
|
||||
|
||||
TcpipReleaseSpinLock(&IF->Lock, OldIrql);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID IPRemoveInterfaceRoute( PIP_INTERFACE IF ) {
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
IP_ADDRESS GeneralRoute;
|
||||
|
||||
NCE = NBLocateNeighbor(&IF->Unicast, IF);
|
||||
if (NCE)
|
||||
{
|
||||
TI_DbgPrint(DEBUG_IP,("Removing interface Addr %s\n", A2S(&IF->Unicast)));
|
||||
TI_DbgPrint(DEBUG_IP,(" Mask %s\n", A2S(&IF->Netmask)));
|
||||
|
||||
AddrWidenAddress(&GeneralRoute,&IF->Unicast,&IF->Netmask);
|
||||
|
||||
RouterRemoveRoute(&GeneralRoute, &IF->Unicast);
|
||||
|
||||
NBRemoveNeighbor(NCE);
|
||||
}
|
||||
}
|
||||
|
||||
VOID IPUnregisterInterface(
|
||||
PIP_INTERFACE IF)
|
||||
/*
|
||||
* FUNCTION: Unregisters an IP interface with IP layer
|
||||
* ARGUMENTS:
|
||||
* IF = Pointer to interface to unregister
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql3;
|
||||
|
||||
TI_DbgPrint(DEBUG_IP, ("Called. IF (0x%X).\n", IF));
|
||||
|
||||
IPRemoveInterfaceRoute( IF );
|
||||
|
||||
TcpipAcquireSpinLock(&InterfaceListLock, &OldIrql3);
|
||||
RemoveEntryList(&IF->ListEntry);
|
||||
TcpipReleaseSpinLock(&InterfaceListLock, OldIrql3);
|
||||
}
|
||||
|
||||
|
||||
VOID DefaultProtocolHandler(
|
||||
PIP_INTERFACE Interface,
|
||||
PIP_PACKET IPPacket)
|
||||
/*
|
||||
* FUNCTION: Default handler for Internet protocols
|
||||
* ARGUMENTS:
|
||||
* NTE = Pointer to net table entry which the packet was received on
|
||||
* IPPacket = Pointer to an IP packet that was received
|
||||
*/
|
||||
{
|
||||
TI_DbgPrint(MID_TRACE, ("[IF %x] Packet of unknown Internet protocol "
|
||||
"discarded.\n", Interface));
|
||||
|
||||
Interface->Stats.InDiscardedUnknownProto++;
|
||||
}
|
||||
|
||||
|
||||
VOID IPRegisterProtocol(
|
||||
UINT ProtocolNumber,
|
||||
IP_PROTOCOL_HANDLER Handler)
|
||||
/*
|
||||
* FUNCTION: Registers a handler for an IP protocol number
|
||||
* ARGUMENTS:
|
||||
* ProtocolNumber = Internet Protocol number for which to register handler
|
||||
* Handler = Pointer to handler to be called when a packet is received
|
||||
* NOTES:
|
||||
* To unregister a protocol handler, call this function with Handler = NULL
|
||||
*/
|
||||
{
|
||||
if (ProtocolNumber >= IP_PROTOCOL_TABLE_SIZE) {
|
||||
TI_DbgPrint(MIN_TRACE, ("Protocol number is out of range (%d).\n", ProtocolNumber));
|
||||
return;
|
||||
}
|
||||
|
||||
ProtocolTable[ProtocolNumber] = Handler ? Handler : DefaultProtocolHandler;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS IPStartup(PUNICODE_STRING RegistryPath)
|
||||
/*
|
||||
* FUNCTION: Initializes the IP subsystem
|
||||
* ARGUMENTS:
|
||||
* RegistryPath = Our registry node for configuration parameters
|
||||
* RETURNS:
|
||||
* Status of operation
|
||||
*/
|
||||
{
|
||||
UINT i;
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Called.\n"));
|
||||
|
||||
/* Initialize lookaside lists */
|
||||
ExInitializeNPagedLookasideList(
|
||||
&IPDRList, /* Lookaside list */
|
||||
NULL, /* Allocate routine */
|
||||
NULL, /* Free routine */
|
||||
0, /* Flags */
|
||||
sizeof(IPDATAGRAM_REASSEMBLY), /* Size of each entry */
|
||||
DATAGRAM_REASSEMBLY_TAG, /* Tag */
|
||||
0); /* Depth */
|
||||
|
||||
ExInitializeNPagedLookasideList(
|
||||
&IPFragmentList, /* Lookaside list */
|
||||
NULL, /* Allocate routine */
|
||||
NULL, /* Free routine */
|
||||
0, /* Flags */
|
||||
sizeof(IP_FRAGMENT), /* Size of each entry */
|
||||
DATAGRAM_FRAGMENT_TAG, /* Tag */
|
||||
0); /* Depth */
|
||||
|
||||
ExInitializeNPagedLookasideList(
|
||||
&IPHoleList, /* Lookaside list */
|
||||
NULL, /* Allocate routine */
|
||||
NULL, /* Free routine */
|
||||
0, /* Flags */
|
||||
sizeof(IPDATAGRAM_HOLE), /* Size of each entry */
|
||||
DATAGRAM_HOLE_TAG, /* Tag */
|
||||
0); /* Depth */
|
||||
|
||||
/* Start routing subsystem */
|
||||
RouterStartup();
|
||||
|
||||
/* Start neighbor cache subsystem */
|
||||
NBStartup();
|
||||
|
||||
/* Fill the protocol dispatch table with pointers
|
||||
to the default protocol handler */
|
||||
for (i = 0; i < IP_PROTOCOL_TABLE_SIZE; i++)
|
||||
IPRegisterProtocol(i, DefaultProtocolHandler);
|
||||
|
||||
/* Initialize NTE list and protecting lock */
|
||||
InitializeListHead(&NetTableListHead);
|
||||
TcpipInitializeSpinLock(&NetTableListLock);
|
||||
|
||||
/* Initialize reassembly list and protecting lock */
|
||||
InitializeListHead(&ReassemblyListHead);
|
||||
TcpipInitializeSpinLock(&ReassemblyListLock);
|
||||
|
||||
IPInitialized = TRUE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS IPShutdown(
|
||||
VOID)
|
||||
/*
|
||||
* FUNCTION: Shuts down the IP subsystem
|
||||
* RETURNS:
|
||||
* Status of operation
|
||||
*/
|
||||
{
|
||||
TI_DbgPrint(MAX_TRACE, ("Called.\n"));
|
||||
|
||||
if (!IPInitialized)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
/* Shutdown neighbor cache subsystem */
|
||||
NBShutdown();
|
||||
|
||||
/* Shutdown routing subsystem */
|
||||
RouterShutdown();
|
||||
|
||||
IPFreeReassemblyList();
|
||||
|
||||
/* Destroy lookaside lists */
|
||||
ExDeleteNPagedLookasideList(&IPHoleList);
|
||||
ExDeleteNPagedLookasideList(&IPDRList);
|
||||
ExDeleteNPagedLookasideList(&IPFragmentList);
|
||||
|
||||
IPInitialized = FALSE;
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
160
sdk/lib/drivers/ip/network/loopback.c
Normal file
160
sdk/lib/drivers/ip/network/loopback.c
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS TCP/IP protocol driver
|
||||
* FILE: datalink/loopback.c
|
||||
* PURPOSE: Loopback adapter
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
* REVISIONS:
|
||||
* CSH 01/08-2000 Created
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
PIP_INTERFACE Loopback = NULL;
|
||||
|
||||
VOID LoopPassiveWorker(
|
||||
PVOID Context)
|
||||
{
|
||||
PIP_PACKET IPPacket = Context;
|
||||
|
||||
/* IPReceive() takes care of the NDIS packet */
|
||||
IPReceive(Loopback, IPPacket);
|
||||
|
||||
ExFreePool(IPPacket);
|
||||
}
|
||||
|
||||
VOID LoopTransmit(
|
||||
PVOID Context,
|
||||
PNDIS_PACKET NdisPacket,
|
||||
UINT Offset,
|
||||
PVOID LinkAddress,
|
||||
USHORT Type)
|
||||
/*
|
||||
* FUNCTION: Transmits a packet
|
||||
* ARGUMENTS:
|
||||
* Context = Pointer to context information (NULL)
|
||||
* NdisPacket = Pointer to NDIS packet to send
|
||||
* Offset = Offset in packet where packet data starts
|
||||
* LinkAddress = Pointer to link address
|
||||
* Type = LAN protocol type (unused)
|
||||
*/
|
||||
{
|
||||
PCHAR PacketBuffer;
|
||||
UINT PacketLength;
|
||||
PNDIS_PACKET XmitPacket;
|
||||
NDIS_STATUS NdisStatus;
|
||||
PIP_PACKET IPPacket;
|
||||
|
||||
ASSERT_KM_POINTER(NdisPacket);
|
||||
ASSERT_KM_POINTER(PC(NdisPacket));
|
||||
ASSERT_KM_POINTER(PC(NdisPacket)->DLComplete);
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Called (NdisPacket = %x)\n", NdisPacket));
|
||||
|
||||
GetDataPtr( NdisPacket, 0, &PacketBuffer, &PacketLength );
|
||||
|
||||
NdisStatus = AllocatePacketWithBuffer
|
||||
( &XmitPacket, PacketBuffer, PacketLength );
|
||||
|
||||
if( NT_SUCCESS(NdisStatus) ) {
|
||||
IPPacket = ExAllocatePool(NonPagedPool, sizeof(IP_PACKET));
|
||||
if (IPPacket)
|
||||
{
|
||||
IPInitializePacket(IPPacket, 0);
|
||||
|
||||
IPPacket->NdisPacket = XmitPacket;
|
||||
|
||||
GetDataPtr(IPPacket->NdisPacket,
|
||||
0,
|
||||
(PCHAR*)&IPPacket->Header,
|
||||
&IPPacket->TotalSize);
|
||||
|
||||
IPPacket->MappedHeader = TRUE;
|
||||
|
||||
if (!ChewCreate(LoopPassiveWorker, IPPacket))
|
||||
{
|
||||
IPPacket->Free(IPPacket);
|
||||
ExFreePool(IPPacket);
|
||||
NdisStatus = NDIS_STATUS_RESOURCES;
|
||||
}
|
||||
}
|
||||
else
|
||||
NdisStatus = NDIS_STATUS_RESOURCES;
|
||||
}
|
||||
|
||||
(PC(NdisPacket)->DLComplete)
|
||||
( PC(NdisPacket)->Context, NdisPacket, NdisStatus );
|
||||
}
|
||||
|
||||
NDIS_STATUS LoopRegisterAdapter(
|
||||
PNDIS_STRING AdapterName,
|
||||
PLAN_ADAPTER *Adapter)
|
||||
/*
|
||||
* FUNCTION: Registers loopback adapter with the network layer
|
||||
* ARGUMENTS:
|
||||
* AdapterName = Unused
|
||||
* Adapter = Unused
|
||||
* RETURNS:
|
||||
* Status of operation
|
||||
*/
|
||||
{
|
||||
LLIP_BIND_INFO BindInfo;
|
||||
|
||||
TI_DbgPrint(MID_TRACE, ("Called.\n"));
|
||||
|
||||
/* Bind the adapter to network (IP) layer */
|
||||
BindInfo.Context = NULL;
|
||||
BindInfo.HeaderSize = 0;
|
||||
BindInfo.MinFrameSize = 0;
|
||||
BindInfo.Address = NULL;
|
||||
BindInfo.AddressLength = 0;
|
||||
BindInfo.Transmit = LoopTransmit;
|
||||
|
||||
Loopback = IPCreateInterface(&BindInfo);
|
||||
if (!Loopback) return NDIS_STATUS_RESOURCES;
|
||||
|
||||
Loopback->MTU = 16384;
|
||||
|
||||
Loopback->Name.Buffer = L"Loopback";
|
||||
Loopback->Name.MaximumLength = Loopback->Name.Length =
|
||||
wcslen(Loopback->Name.Buffer) * sizeof(WCHAR);
|
||||
|
||||
AddrInitIPv4(&Loopback->Unicast, LOOPBACK_ADDRESS_IPv4);
|
||||
AddrInitIPv4(&Loopback->Netmask, LOOPBACK_ADDRMASK_IPv4);
|
||||
AddrInitIPv4(&Loopback->Broadcast, LOOPBACK_BCASTADDR_IPv4);
|
||||
|
||||
IPRegisterInterface(Loopback);
|
||||
|
||||
IPAddInterfaceRoute(Loopback);
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
|
||||
|
||||
return NDIS_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NDIS_STATUS LoopUnregisterAdapter(
|
||||
PLAN_ADAPTER Adapter)
|
||||
/*
|
||||
* FUNCTION: Unregisters loopback adapter with the network layer
|
||||
* ARGUMENTS:
|
||||
* Adapter = Unused
|
||||
* RETURNS:
|
||||
* Status of operation
|
||||
* NOTES:
|
||||
* Does not care wether we have registered loopback adapter
|
||||
*/
|
||||
{
|
||||
TI_DbgPrint(MID_TRACE, ("Called.\n"));
|
||||
|
||||
if (Loopback != NULL)
|
||||
{
|
||||
IPUnregisterInterface(Loopback);
|
||||
IPDestroyInterface(Loopback);
|
||||
Loopback = NULL;
|
||||
}
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
|
||||
|
||||
return NDIS_STATUS_SUCCESS;
|
||||
}
|
672
sdk/lib/drivers/ip/network/neighbor.c
Normal file
672
sdk/lib/drivers/ip/network/neighbor.c
Normal file
|
@ -0,0 +1,672 @@
|
|||
/*
|
||||
* 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 NBCompleteSend( PVOID Context,
|
||||
PNDIS_PACKET NdisPacket,
|
||||
NDIS_STATUS Status ) {
|
||||
PNEIGHBOR_PACKET Packet = (PNEIGHBOR_PACKET)Context;
|
||||
TI_DbgPrint(MID_TRACE, ("Called\n"));
|
||||
ASSERT_KM_POINTER(Packet);
|
||||
ASSERT_KM_POINTER(Packet->Complete);
|
||||
Packet->Complete( Packet->Context, Packet->Packet, Status );
|
||||
TI_DbgPrint(MID_TRACE, ("Completed\n"));
|
||||
ExFreePoolWithTag( Packet, NEIGHBOR_PACKET_TAG );
|
||||
TI_DbgPrint(MID_TRACE, ("Freed\n"));
|
||||
}
|
||||
|
||||
VOID NBSendPackets( PNEIGHBOR_CACHE_ENTRY NCE ) {
|
||||
PLIST_ENTRY PacketEntry;
|
||||
PNEIGHBOR_PACKET Packet;
|
||||
UINT HashValue;
|
||||
|
||||
ASSERT(!(NCE->State & NUD_INCOMPLETE));
|
||||
|
||||
HashValue = *(PULONG)(&NCE->Address.Address);
|
||||
HashValue ^= HashValue >> 16;
|
||||
HashValue ^= HashValue >> 8;
|
||||
HashValue ^= HashValue >> 4;
|
||||
HashValue &= NB_HASHMASK;
|
||||
|
||||
/* Send any waiting packets */
|
||||
while ((PacketEntry = ExInterlockedRemoveHeadList(&NCE->PacketQueue,
|
||||
&NeighborCache[HashValue].Lock)) != NULL)
|
||||
{
|
||||
Packet = CONTAINING_RECORD( PacketEntry, NEIGHBOR_PACKET, Next );
|
||||
|
||||
TI_DbgPrint
|
||||
(MID_TRACE,
|
||||
("PacketEntry: %x, NdisPacket %x\n",
|
||||
PacketEntry, Packet->Packet));
|
||||
|
||||
PC(Packet->Packet)->DLComplete = NBCompleteSend;
|
||||
PC(Packet->Packet)->Context = Packet;
|
||||
|
||||
NCE->Interface->Transmit
|
||||
( NCE->Interface->Context,
|
||||
Packet->Packet,
|
||||
0,
|
||||
NCE->LinkAddress,
|
||||
LAN_PROTO_IPv4 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with table lock acquired */
|
||||
VOID NBFlushPacketQueue( PNEIGHBOR_CACHE_ENTRY NCE,
|
||||
NTSTATUS ErrorCode ) {
|
||||
PLIST_ENTRY PacketEntry;
|
||||
PNEIGHBOR_PACKET Packet;
|
||||
|
||||
while( !IsListEmpty(&NCE->PacketQueue) ) {
|
||||
PacketEntry = RemoveHeadList(&NCE->PacketQueue);
|
||||
Packet = CONTAINING_RECORD
|
||||
( PacketEntry, NEIGHBOR_PACKET, Next );
|
||||
|
||||
ASSERT_KM_POINTER(Packet);
|
||||
|
||||
TI_DbgPrint
|
||||
(MID_TRACE,
|
||||
("PacketEntry: %x, NdisPacket %x\n",
|
||||
PacketEntry, Packet->Packet));
|
||||
|
||||
ASSERT_KM_POINTER(Packet->Complete);
|
||||
Packet->Complete( Packet->Context,
|
||||
Packet->Packet,
|
||||
ErrorCode );
|
||||
|
||||
ExFreePoolWithTag( Packet, NEIGHBOR_PACKET_TAG );
|
||||
}
|
||||
}
|
||||
|
||||
VOID NBTimeout(VOID)
|
||||
/*
|
||||
* FUNCTION: Neighbor address cache timeout handler
|
||||
* NOTES:
|
||||
* This routine is called by IPTimeout to remove outdated cache
|
||||
* entries.
|
||||
*/
|
||||
{
|
||||
UINT i;
|
||||
PNEIGHBOR_CACHE_ENTRY *PrevNCE;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
NDIS_STATUS Status;
|
||||
|
||||
for (i = 0; i <= NB_HASHMASK; i++) {
|
||||
TcpipAcquireSpinLockAtDpcLevel(&NeighborCache[i].Lock);
|
||||
|
||||
for (PrevNCE = &NeighborCache[i].Cache;
|
||||
(NCE = *PrevNCE) != NULL;) {
|
||||
if (NCE->State & NUD_INCOMPLETE)
|
||||
{
|
||||
/* Solicit for an address */
|
||||
NBSendSolicit(NCE);
|
||||
if (NCE->EventTimer == 0)
|
||||
{
|
||||
NCE->EventCount++;
|
||||
if (NCE->EventCount == ARP_INCOMPLETE_TIMEOUT)
|
||||
{
|
||||
NBFlushPacketQueue(NCE, NDIS_STATUS_NETWORK_UNREACHABLE);
|
||||
NCE->EventCount = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if event timer is running */
|
||||
if (NCE->EventTimer > 0) {
|
||||
ASSERT(!(NCE->State & NUD_PERMANENT));
|
||||
NCE->EventCount++;
|
||||
|
||||
if ((NCE->EventCount > ARP_RATE &&
|
||||
NCE->EventCount % ARP_TIMEOUT_RETRANSMISSION == 0) ||
|
||||
(NCE->EventCount == ARP_RATE))
|
||||
{
|
||||
/* We haven't gotten a packet from them in
|
||||
* EventCount seconds so we mark them as stale
|
||||
* and solicit now */
|
||||
NCE->State |= NUD_STALE;
|
||||
NBSendSolicit(NCE);
|
||||
}
|
||||
if (NCE->EventTimer - NCE->EventCount == 0) {
|
||||
/* Unlink and destroy the NCE */
|
||||
*PrevNCE = NCE->Next;
|
||||
|
||||
/* Choose the proper failure status */
|
||||
if (NCE->State & NUD_INCOMPLETE)
|
||||
{
|
||||
/* We couldn't get an address to this IP at all */
|
||||
Status = NDIS_STATUS_NETWORK_UNREACHABLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This guy was stale for way too long */
|
||||
Status = NDIS_STATUS_REQUEST_ABORTED;
|
||||
}
|
||||
|
||||
NBFlushPacketQueue(NCE, Status);
|
||||
|
||||
ExFreePoolWithTag(NCE, NCE_TAG);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
PrevNCE = &NCE->Next;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLockFromDpcLevel(&NeighborCache[i].Lock);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
TcpipInitializeSpinLock(&NeighborCache[i].Lock);
|
||||
}
|
||||
}
|
||||
|
||||
VOID NBShutdown(VOID)
|
||||
/*
|
||||
* FUNCTION: Shuts down the neighbor cache
|
||||
*/
|
||||
{
|
||||
PNEIGHBOR_CACHE_ENTRY NextNCE;
|
||||
PNEIGHBOR_CACHE_ENTRY CurNCE;
|
||||
KIRQL OldIrql;
|
||||
UINT i;
|
||||
|
||||
TI_DbgPrint(DEBUG_NCACHE, ("Called.\n"));
|
||||
|
||||
/* Remove possible entries from the cache */
|
||||
for (i = 0; i <= NB_HASHMASK; i++)
|
||||
{
|
||||
TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
|
||||
|
||||
CurNCE = NeighborCache[i].Cache;
|
||||
while (CurNCE) {
|
||||
NextNCE = CurNCE->Next;
|
||||
|
||||
/* Flush wait queue */
|
||||
NBFlushPacketQueue( CurNCE, NDIS_STATUS_NOT_ACCEPTED );
|
||||
|
||||
ExFreePoolWithTag(CurNCE, NCE_TAG);
|
||||
|
||||
CurNCE = NextNCE;
|
||||
}
|
||||
|
||||
NeighborCache[i].Cache = NULL;
|
||||
|
||||
TcpipReleaseSpinLock(&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
|
||||
*/
|
||||
{
|
||||
TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X).\n", NCE));
|
||||
|
||||
ARPTransmit(&NCE->Address,
|
||||
(NCE->State & NUD_INCOMPLETE) ? NULL : NCE->LinkAddress,
|
||||
NCE->Interface);
|
||||
}
|
||||
|
||||
VOID NBDestroyNeighborsForInterface(PIP_INTERFACE Interface)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PNEIGHBOR_CACHE_ENTRY *PrevNCE;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
ULONG i;
|
||||
|
||||
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
||||
for (i = 0; i <= NB_HASHMASK; i++)
|
||||
{
|
||||
TcpipAcquireSpinLockAtDpcLevel(&NeighborCache[i].Lock);
|
||||
|
||||
for (PrevNCE = &NeighborCache[i].Cache;
|
||||
(NCE = *PrevNCE) != NULL;)
|
||||
{
|
||||
if (NCE->Interface == Interface)
|
||||
{
|
||||
/* Unlink and destroy the NCE */
|
||||
*PrevNCE = NCE->Next;
|
||||
|
||||
NBFlushPacketQueue(NCE, NDIS_STATUS_REQUEST_ABORTED);
|
||||
ExFreePoolWithTag(NCE, NCE_TAG);
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrevNCE = &NCE->Next;
|
||||
}
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLockFromDpcLevel(&NeighborCache[i].Lock);
|
||||
}
|
||||
KeLowerIrql(OldIrql);
|
||||
}
|
||||
|
||||
PNEIGHBOR_CACHE_ENTRY NBAddNeighbor(
|
||||
PIP_INTERFACE Interface,
|
||||
PIP_ADDRESS Address,
|
||||
PVOID LinkAddress,
|
||||
UINT LinkAddressLength,
|
||||
UCHAR State,
|
||||
UINT EventTimer)
|
||||
/*
|
||||
* 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));
|
||||
|
||||
NCE = ExAllocatePoolWithTag
|
||||
(NonPagedPool, sizeof(NEIGHBOR_CACHE_ENTRY) + LinkAddressLength,
|
||||
NCE_TAG);
|
||||
if (NCE == NULL)
|
||||
{
|
||||
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NCE->Interface = Interface;
|
||||
NCE->Address = *Address;
|
||||
NCE->LinkAddressLength = LinkAddressLength;
|
||||
NCE->LinkAddress = (PVOID)&NCE[1];
|
||||
if( LinkAddress )
|
||||
RtlCopyMemory(NCE->LinkAddress, LinkAddress, LinkAddressLength);
|
||||
else
|
||||
memset(NCE->LinkAddress, 0xff, LinkAddressLength);
|
||||
NCE->State = State;
|
||||
NCE->EventTimer = EventTimer;
|
||||
NCE->EventCount = 0;
|
||||
InitializeListHead( &NCE->PacketQueue );
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("NCE: %x\n", NCE));
|
||||
|
||||
HashValue = *(PULONG)&Address->Address;
|
||||
HashValue ^= HashValue >> 16;
|
||||
HashValue ^= HashValue >> 8;
|
||||
HashValue ^= HashValue >> 4;
|
||||
HashValue &= NB_HASHMASK;
|
||||
|
||||
TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
|
||||
|
||||
NCE->Next = NeighborCache[HashValue].Cache;
|
||||
NeighborCache[HashValue].Cache = NCE;
|
||||
|
||||
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
|
||||
|
||||
return NCE;
|
||||
}
|
||||
|
||||
VOID NBUpdateNeighbor(
|
||||
PNEIGHBOR_CACHE_ENTRY NCE,
|
||||
PVOID LinkAddress,
|
||||
UCHAR State)
|
||||
/*
|
||||
* FUNCTION: Update link address information in NCE
|
||||
* ARGUMENTS:
|
||||
* NCE = Pointer to NCE to update
|
||||
* LinkAddress = Pointer to link address
|
||||
* State = State of NCE
|
||||
* NOTES:
|
||||
* The link address and state is updated. Any waiting packets are sent
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
UINT HashValue;
|
||||
|
||||
TI_DbgPrint(DEBUG_NCACHE, ("Called. NCE (0x%X) LinkAddress (0x%X) State (0x%X).\n", NCE, LinkAddress, State));
|
||||
|
||||
HashValue = *(PULONG)(&NCE->Address.Address);
|
||||
HashValue ^= HashValue >> 16;
|
||||
HashValue ^= HashValue >> 8;
|
||||
HashValue ^= HashValue >> 4;
|
||||
HashValue &= NB_HASHMASK;
|
||||
|
||||
TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
|
||||
|
||||
RtlCopyMemory(NCE->LinkAddress, LinkAddress, NCE->LinkAddressLength);
|
||||
NCE->State = State;
|
||||
NCE->EventCount = 0;
|
||||
|
||||
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
|
||||
|
||||
if( !(NCE->State & NUD_INCOMPLETE) )
|
||||
{
|
||||
if (NCE->EventTimer) NCE->EventTimer = ARP_COMPLETE_TIMEOUT;
|
||||
NBSendPackets( NCE );
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NBResetNeighborTimeout(PIP_ADDRESS Address)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
UINT HashValue;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
|
||||
TI_DbgPrint(DEBUG_NCACHE, ("Resetting NCE timout for 0x%s\n", A2S(Address)));
|
||||
|
||||
HashValue = *(PULONG)(&Address->Address);
|
||||
HashValue ^= HashValue >> 16;
|
||||
HashValue ^= HashValue >> 8;
|
||||
HashValue ^= HashValue >> 4;
|
||||
HashValue &= NB_HASHMASK;
|
||||
|
||||
TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
|
||||
|
||||
for (NCE = NeighborCache[HashValue].Cache;
|
||||
NCE != NULL;
|
||||
NCE = NCE->Next)
|
||||
{
|
||||
if (AddrIsEqual(Address, &NCE->Address))
|
||||
{
|
||||
NCE->EventCount = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
|
||||
}
|
||||
|
||||
PNEIGHBOR_CACHE_ENTRY NBLocateNeighbor(
|
||||
PIP_ADDRESS Address,
|
||||
PIP_INTERFACE Interface)
|
||||
/*
|
||||
* FUNCTION: Locates a neighbor in the neighbor cache
|
||||
* ARGUMENTS:
|
||||
* Address = Pointer to IP address
|
||||
* Interface = Pointer to IP interface
|
||||
* 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;
|
||||
PIP_INTERFACE FirstInterface;
|
||||
|
||||
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;
|
||||
|
||||
TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
|
||||
|
||||
/* If there's no adapter specified, we'll look for a match on
|
||||
* each one. */
|
||||
if (Interface == NULL)
|
||||
{
|
||||
FirstInterface = GetDefaultInterface();
|
||||
Interface = FirstInterface;
|
||||
}
|
||||
else
|
||||
{
|
||||
FirstInterface = NULL;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
NCE = NeighborCache[HashValue].Cache;
|
||||
while (NCE != NULL)
|
||||
{
|
||||
if (NCE->Interface == Interface &&
|
||||
AddrIsEqual(Address, &NCE->Address))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
NCE = NCE->Next;
|
||||
}
|
||||
|
||||
if (NCE != NULL)
|
||||
break;
|
||||
}
|
||||
while ((FirstInterface != NULL) &&
|
||||
((Interface = GetDefaultInterface()) != FirstInterface));
|
||||
|
||||
if ((NCE == NULL) && (FirstInterface != NULL))
|
||||
{
|
||||
/* This time we'll even match loopback NCEs */
|
||||
NCE = NeighborCache[HashValue].Cache;
|
||||
while (NCE != NULL)
|
||||
{
|
||||
if (AddrIsEqual(Address, &NCE->Address))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
NCE = NCE->Next;
|
||||
}
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
|
||||
|
||||
return NCE;
|
||||
}
|
||||
|
||||
PNEIGHBOR_CACHE_ENTRY NBFindOrCreateNeighbor(
|
||||
PIP_INTERFACE Interface,
|
||||
PIP_ADDRESS Address,
|
||||
BOOLEAN NoTimeout)
|
||||
/*
|
||||
* 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, Interface);
|
||||
if (NCE == NULL)
|
||||
{
|
||||
TI_DbgPrint(MID_TRACE,("BCAST: %s\n", A2S(&Interface->Broadcast)));
|
||||
if( AddrIsEqual(Address, &Interface->Broadcast) ||
|
||||
AddrIsUnspecified(Address) ) {
|
||||
TI_DbgPrint(MID_TRACE,("Packet targeted at broadcast addr\n"));
|
||||
NCE = NBAddNeighbor(Interface, Address, NULL,
|
||||
Interface->AddressLength, NUD_PERMANENT, 0);
|
||||
} else {
|
||||
NCE = NBAddNeighbor(Interface, Address, NULL,
|
||||
Interface->AddressLength, NUD_INCOMPLETE, NoTimeout ? 0 : ARP_INCOMPLETE_TIMEOUT);
|
||||
if (!NCE) return NULL;
|
||||
NBSendSolicit(NCE);
|
||||
}
|
||||
}
|
||||
|
||||
return NCE;
|
||||
}
|
||||
|
||||
BOOLEAN NBQueuePacket(
|
||||
PNEIGHBOR_CACHE_ENTRY NCE,
|
||||
PNDIS_PACKET NdisPacket,
|
||||
PNEIGHBOR_PACKET_COMPLETE PacketComplete,
|
||||
PVOID PacketContext)
|
||||
/*
|
||||
* FUNCTION: Queues a packet on an NCE for later transmission
|
||||
* ARGUMENTS:
|
||||
* NCE = Pointer to NCE to queue packet on
|
||||
* NdisPacket = Pointer to NDIS packet to queue
|
||||
* RETURNS:
|
||||
* TRUE if the packet was successfully queued, FALSE if not
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PNEIGHBOR_PACKET Packet;
|
||||
UINT HashValue;
|
||||
|
||||
TI_DbgPrint
|
||||
(DEBUG_NCACHE,
|
||||
("Called. NCE (0x%X) NdisPacket (0x%X).\n", NCE, NdisPacket));
|
||||
|
||||
Packet = ExAllocatePoolWithTag( NonPagedPool, sizeof(NEIGHBOR_PACKET),
|
||||
NEIGHBOR_PACKET_TAG );
|
||||
if( !Packet ) return FALSE;
|
||||
|
||||
/* FIXME: Should we limit the number of queued packets? */
|
||||
|
||||
HashValue = *(PULONG)(&NCE->Address.Address);
|
||||
HashValue ^= HashValue >> 16;
|
||||
HashValue ^= HashValue >> 8;
|
||||
HashValue ^= HashValue >> 4;
|
||||
HashValue &= NB_HASHMASK;
|
||||
|
||||
TcpipAcquireSpinLock(&NeighborCache[HashValue].Lock, &OldIrql);
|
||||
|
||||
Packet->Complete = PacketComplete;
|
||||
Packet->Context = PacketContext;
|
||||
Packet->Packet = NdisPacket;
|
||||
InsertTailList( &NCE->PacketQueue, &Packet->Next );
|
||||
|
||||
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
|
||||
|
||||
if( !(NCE->State & NUD_INCOMPLETE) )
|
||||
NBSendPackets( NCE );
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
TcpipAcquireSpinLock(&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;
|
||||
|
||||
NBFlushPacketQueue( CurNCE, NDIS_STATUS_REQUEST_ABORTED );
|
||||
ExFreePoolWithTag(CurNCE, NCE_TAG);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&NeighborCache[HashValue].Lock, OldIrql);
|
||||
}
|
||||
|
||||
ULONG NBCopyNeighbors
|
||||
(PIP_INTERFACE Interface,
|
||||
PIPARP_ENTRY ArpTable)
|
||||
{
|
||||
PNEIGHBOR_CACHE_ENTRY CurNCE;
|
||||
KIRQL OldIrql;
|
||||
UINT Size = 0, i;
|
||||
|
||||
for (i = 0; i <= NB_HASHMASK; i++) {
|
||||
TcpipAcquireSpinLock(&NeighborCache[i].Lock, &OldIrql);
|
||||
for( CurNCE = NeighborCache[i].Cache;
|
||||
CurNCE;
|
||||
CurNCE = CurNCE->Next ) {
|
||||
if( CurNCE->Interface == Interface &&
|
||||
!AddrIsEqual( &CurNCE->Address, &CurNCE->Interface->Unicast ) ) {
|
||||
if( ArpTable ) {
|
||||
ArpTable[Size].Index = Interface->Index;
|
||||
ArpTable[Size].AddrSize = CurNCE->LinkAddressLength;
|
||||
RtlCopyMemory
|
||||
(ArpTable[Size].PhysAddr,
|
||||
CurNCE->LinkAddress,
|
||||
CurNCE->LinkAddressLength);
|
||||
ArpTable[Size].LogAddr = CurNCE->Address.Address.IPv4Address;
|
||||
if( CurNCE->State & NUD_PERMANENT )
|
||||
ArpTable[Size].Type = ARP_ENTRY_STATIC;
|
||||
else if( CurNCE->State & NUD_INCOMPLETE )
|
||||
ArpTable[Size].Type = ARP_ENTRY_INVALID;
|
||||
else
|
||||
ArpTable[Size].Type = ARP_ENTRY_DYNAMIC;
|
||||
}
|
||||
Size++;
|
||||
}
|
||||
}
|
||||
TcpipReleaseSpinLock(&NeighborCache[i].Lock, OldIrql);
|
||||
}
|
||||
|
||||
return Size;
|
||||
}
|
110
sdk/lib/drivers/ip/network/ports.c
Normal file
110
sdk/lib/drivers/ip/network/ports.c
Normal file
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS TCP/IP protocol driver
|
||||
* FILE: tcpip/ports.c
|
||||
* PURPOSE: Port allocation
|
||||
* PROGRAMMERS: arty (ayerkes@speakeasy.net)
|
||||
* REVISIONS:
|
||||
* arty 20041114 Created
|
||||
*/
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
NTSTATUS PortsStartup( PPORT_SET PortSet,
|
||||
UINT StartingPort,
|
||||
UINT PortsToManage ) {
|
||||
PortSet->StartingPort = StartingPort;
|
||||
PortSet->PortsToOversee = PortsToManage;
|
||||
|
||||
PortSet->ProtoBitBuffer =
|
||||
ExAllocatePoolWithTag( NonPagedPool, (PortSet->PortsToOversee + 7) / 8,
|
||||
PORT_SET_TAG );
|
||||
if(!PortSet->ProtoBitBuffer) return STATUS_INSUFFICIENT_RESOURCES;
|
||||
RtlInitializeBitMap( &PortSet->ProtoBitmap,
|
||||
PortSet->ProtoBitBuffer,
|
||||
PortSet->PortsToOversee );
|
||||
RtlClearAllBits( &PortSet->ProtoBitmap );
|
||||
KeInitializeSpinLock( &PortSet->Lock );
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID PortsShutdown( PPORT_SET PortSet ) {
|
||||
ExFreePoolWithTag( PortSet->ProtoBitBuffer, PORT_SET_TAG );
|
||||
}
|
||||
|
||||
VOID DeallocatePort( PPORT_SET PortSet, ULONG Port ) {
|
||||
KIRQL OldIrql;
|
||||
|
||||
Port = htons(Port);
|
||||
ASSERT(Port >= PortSet->StartingPort);
|
||||
ASSERT(Port < PortSet->StartingPort + PortSet->PortsToOversee);
|
||||
|
||||
KeAcquireSpinLock( &PortSet->Lock, &OldIrql );
|
||||
RtlClearBits( &PortSet->ProtoBitmap, Port - PortSet->StartingPort, 1 );
|
||||
KeReleaseSpinLock( &PortSet->Lock, OldIrql );
|
||||
}
|
||||
|
||||
BOOLEAN AllocatePort( PPORT_SET PortSet, ULONG Port ) {
|
||||
BOOLEAN Clear;
|
||||
KIRQL OldIrql;
|
||||
|
||||
Port = htons(Port);
|
||||
|
||||
if ((Port < PortSet->StartingPort) ||
|
||||
(Port >= PortSet->StartingPort + PortSet->PortsToOversee))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Port -= PortSet->StartingPort;
|
||||
|
||||
KeAcquireSpinLock( &PortSet->Lock, &OldIrql );
|
||||
Clear = RtlAreBitsClear( &PortSet->ProtoBitmap, Port, 1 );
|
||||
if( Clear ) RtlSetBits( &PortSet->ProtoBitmap, Port, 1 );
|
||||
KeReleaseSpinLock( &PortSet->Lock, OldIrql );
|
||||
|
||||
return Clear;
|
||||
}
|
||||
|
||||
ULONG AllocateAnyPort( PPORT_SET PortSet ) {
|
||||
ULONG AllocatedPort;
|
||||
KIRQL OldIrql;
|
||||
|
||||
KeAcquireSpinLock( &PortSet->Lock, &OldIrql );
|
||||
AllocatedPort = RtlFindClearBits( &PortSet->ProtoBitmap, 1, 0 );
|
||||
if( AllocatedPort != (ULONG)-1 ) {
|
||||
RtlSetBit( &PortSet->ProtoBitmap, AllocatedPort );
|
||||
AllocatedPort += PortSet->StartingPort;
|
||||
KeReleaseSpinLock( &PortSet->Lock, OldIrql );
|
||||
return htons(AllocatedPort);
|
||||
}
|
||||
KeReleaseSpinLock( &PortSet->Lock, OldIrql );
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ULONG AllocatePortFromRange( PPORT_SET PortSet, ULONG Lowest, ULONG Highest ) {
|
||||
ULONG AllocatedPort;
|
||||
KIRQL OldIrql;
|
||||
|
||||
if ((Lowest < PortSet->StartingPort) ||
|
||||
(Highest >= PortSet->StartingPort + PortSet->PortsToOversee))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Lowest -= PortSet->StartingPort;
|
||||
Highest -= PortSet->StartingPort;
|
||||
|
||||
KeAcquireSpinLock( &PortSet->Lock, &OldIrql );
|
||||
AllocatedPort = RtlFindClearBits( &PortSet->ProtoBitmap, 1, Lowest );
|
||||
if( AllocatedPort != (ULONG)-1 && AllocatedPort <= Highest) {
|
||||
RtlSetBit( &PortSet->ProtoBitmap, AllocatedPort );
|
||||
AllocatedPort += PortSet->StartingPort;
|
||||
KeReleaseSpinLock( &PortSet->Lock, OldIrql );
|
||||
return htons(AllocatedPort);
|
||||
}
|
||||
KeReleaseSpinLock( &PortSet->Lock, OldIrql );
|
||||
|
||||
return -1;
|
||||
}
|
681
sdk/lib/drivers/ip/network/receive.c
Normal file
681
sdk/lib/drivers/ip/network/receive.c
Normal file
|
@ -0,0 +1,681 @@
|
|||
/*
|
||||
* 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 packet at (0x%X).\n", CurrentF->Packet));
|
||||
|
||||
/* Free the fragment data buffer */
|
||||
if (CurrentF->ReturnPacket)
|
||||
{
|
||||
NdisReturnPackets(&CurrentF->Packet, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FreeNdisPacket(CurrentF->Packet);
|
||||
}
|
||||
|
||||
TI_DbgPrint(DEBUG_IP, ("Freeing fragment at (0x%X).\n", CurrentF));
|
||||
|
||||
/* And free the fragment descriptor */
|
||||
ExFreeToNPagedLookasideList(&IPFragmentList, CurrentF);
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
if (IPDR->IPv4Header)
|
||||
{
|
||||
TI_DbgPrint(DEBUG_IP, ("Freeing IPDR header at (0x%X).\n", IPDR->IPv4Header));
|
||||
ExFreePoolWithTag(IPDR->IPv4Header, PACKET_BUFFER_TAG);
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
|
||||
RemoveEntryList(&IPDR->ListEntry);
|
||||
TcpipReleaseSpinLock(&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));
|
||||
|
||||
TcpipAcquireSpinLock(&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))) {
|
||||
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
|
||||
|
||||
return Current;
|
||||
}
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&ReassemblyListLock, OldIrql);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
BOOLEAN
|
||||
ReassembleDatagram(
|
||||
PIP_PACKET IPPacket,
|
||||
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
|
||||
*/
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PIP_FRAGMENT Fragment;
|
||||
PCHAR Data;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
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));
|
||||
|
||||
IPPacket->TotalSize = IPDR->HeaderSize + IPDR->DataSize;
|
||||
IPPacket->HeaderSize = 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 = ExAllocatePoolWithTag(PagedPool, IPPacket->TotalSize, PACKET_BUFFER_TAG);
|
||||
if (!IPPacket->Header) {
|
||||
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
||||
(*IPPacket->Free)(IPPacket);
|
||||
return FALSE;
|
||||
}
|
||||
IPPacket->MappedHeader = FALSE;
|
||||
|
||||
/* Copy the header into the buffer */
|
||||
RtlCopyMemory(IPPacket->Header, IPDR->IPv4Header, IPDR->HeaderSize);
|
||||
|
||||
Data = (PVOID)((ULONG_PTR)IPPacket->Header + IPDR->HeaderSize);
|
||||
IPPacket->Data = Data;
|
||||
|
||||
/* Copy data from all fragments into buffer */
|
||||
CurrentEntry = IPDR->FragmentListHead.Flink;
|
||||
while (CurrentEntry != &IPDR->FragmentListHead) {
|
||||
Fragment = CONTAINING_RECORD(CurrentEntry, IP_FRAGMENT, ListEntry);
|
||||
|
||||
/* Copy fragment data into datagram buffer */
|
||||
CopyPacketToBuffer(Data + Fragment->Offset,
|
||||
Fragment->Packet,
|
||||
Fragment->PacketOffset,
|
||||
Fragment->Size);
|
||||
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
__inline VOID Cleanup(
|
||||
PKSPIN_LOCK Lock,
|
||||
KIRQL OldIrql,
|
||||
PIPDATAGRAM_REASSEMBLY IPDR)
|
||||
/*
|
||||
* 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"));
|
||||
|
||||
TcpipReleaseSpinLock(Lock, OldIrql);
|
||||
RemoveIPDR(IPDR);
|
||||
FreeIPDR(IPDR);
|
||||
}
|
||||
|
||||
|
||||
VOID ProcessFragment(
|
||||
PIP_INTERFACE IF,
|
||||
PIP_PACKET IPPacket)
|
||||
/*
|
||||
* FUNCTION: Processes an IP datagram or fragment
|
||||
* ARGUMENTS:
|
||||
* IF = Pointer to IP interface packet was receive on
|
||||
* IPPacket = Pointer to IP packet
|
||||
* 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;
|
||||
IP_PACKET Datagram;
|
||||
PIP_FRAGMENT Fragment;
|
||||
BOOLEAN Success;
|
||||
|
||||
/* 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 */
|
||||
TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
|
||||
|
||||
/* Reset the timeout since we received a fragment */
|
||||
IPDR->TimeoutCount = 0;
|
||||
} 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->TimeoutCount = 0;
|
||||
InitializeListHead(&IPDR->FragmentListHead);
|
||||
InitializeListHead(&IPDR->HoleListHead);
|
||||
InsertTailList(&IPDR->HoleListHead, &Hole->ListEntry);
|
||||
|
||||
TcpipInitializeSpinLock(&IPDR->Lock);
|
||||
|
||||
TcpipAcquireSpinLock(&IPDR->Lock, &OldIrql);
|
||||
|
||||
/* Update the reassembly list */
|
||||
TcpipInterlockedInsertTailList(
|
||||
&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;
|
||||
|
||||
CurrentEntry = IPDR->HoleListHead.Flink;
|
||||
for (;;) {
|
||||
if (CurrentEntry == &IPDR->HoleListHead)
|
||||
break;
|
||||
|
||||
Hole = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_HOLE, ListEntry);
|
||||
|
||||
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;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The fragment overlap with the hole, unlink the descriptor */
|
||||
RemoveEntryList(CurrentEntry);
|
||||
|
||||
if (FragFirst > Hole->First) {
|
||||
NewHole = CreateHoleDescriptor(Hole->First, FragFirst - 1);
|
||||
if (!NewHole) {
|
||||
/* We don't have the resources to process this packet, discard it */
|
||||
ExFreeToNPagedLookasideList(&IPHoleList, Hole);
|
||||
Cleanup(&IPDR->Lock, OldIrql, IPDR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put the new descriptor in the list */
|
||||
InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
|
||||
}
|
||||
|
||||
if ((FragLast < Hole->Last) && MoreFragments) {
|
||||
NewHole = CreateHoleDescriptor(FragLast + 1, Hole->Last);
|
||||
if (!NewHole) {
|
||||
/* We don't have the resources to process this packet, discard it */
|
||||
ExFreeToNPagedLookasideList(&IPHoleList, Hole);
|
||||
Cleanup(&IPDR->Lock, OldIrql, IPDR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Put the new hole descriptor in the list */
|
||||
InsertTailList(&IPDR->HoleListHead, &NewHole->ListEntry);
|
||||
}
|
||||
|
||||
ExFreeToNPagedLookasideList(&IPHoleList, Hole);
|
||||
|
||||
/* If this is the first fragment, save the IP header */
|
||||
if (FragFirst == 0) {
|
||||
IPDR->IPv4Header = ExAllocatePoolWithTag(NonPagedPool,
|
||||
IPPacket->HeaderSize,
|
||||
PACKET_BUFFER_TAG);
|
||||
if (!IPDR->IPv4Header)
|
||||
{
|
||||
Cleanup(&IPDR->Lock, OldIrql, IPDR);
|
||||
return;
|
||||
}
|
||||
|
||||
RtlCopyMemory(IPDR->IPv4Header, IPPacket->Header, IPPacket->HeaderSize);
|
||||
IPDR->HeaderSize = IPPacket->HeaderSize;
|
||||
|
||||
TI_DbgPrint(DEBUG_IP, ("First fragment found. Header buffer is at (0x%X). "
|
||||
"Header size is (%d).\n", &IPDR->IPv4Header, 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);
|
||||
return;
|
||||
}
|
||||
|
||||
TI_DbgPrint(DEBUG_IP, ("Fragment descriptor allocated at (0x%X).\n", Fragment));
|
||||
|
||||
Fragment->Size = IPPacket->TotalSize - IPPacket->HeaderSize;
|
||||
Fragment->Packet = IPPacket->NdisPacket;
|
||||
Fragment->ReturnPacket = IPPacket->ReturnPacket;
|
||||
Fragment->PacketOffset = IPPacket->Position + IPPacket->HeaderSize;
|
||||
Fragment->Offset = FragFirst;
|
||||
|
||||
/* Disassociate the NDIS packet so it isn't freed upon return from IPReceive() */
|
||||
IPPacket->NdisPacket = NULL;
|
||||
|
||||
/* 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"));
|
||||
|
||||
RemoveIPDR(IPDR);
|
||||
TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
|
||||
|
||||
/* FIXME: Assumes IPv4 */
|
||||
IPInitializePacket(&Datagram, IP_ADDRESS_V4);
|
||||
|
||||
Success = ReassembleDatagram(&Datagram, IPDR);
|
||||
|
||||
FreeIPDR(IPDR);
|
||||
|
||||
if (!Success)
|
||||
/* Not enough free resources, discard the packet */
|
||||
return;
|
||||
|
||||
DISPLAY_IP_PACKET(&Datagram);
|
||||
|
||||
/* Give the packet to the protocol dispatcher */
|
||||
IPDispatchProtocol(IF, &Datagram);
|
||||
|
||||
/* We're done with this datagram */
|
||||
TI_DbgPrint(MAX_TRACE, ("Freeing datagram at (0x%X).\n", Datagram));
|
||||
Datagram.Free(&Datagram);
|
||||
} else
|
||||
TcpipReleaseSpinLock(&IPDR->Lock, OldIrql);
|
||||
}
|
||||
|
||||
|
||||
VOID IPFreeReassemblyList(
|
||||
VOID)
|
||||
/*
|
||||
* FUNCTION: Frees all IP datagram reassembly structures in the list
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY CurrentEntry, NextEntry;
|
||||
PIPDATAGRAM_REASSEMBLY Current;
|
||||
|
||||
TcpipAcquireSpinLock(&ReassemblyListLock, &OldIrql);
|
||||
|
||||
CurrentEntry = ReassemblyListHead.Flink;
|
||||
while (CurrentEntry != &ReassemblyListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
|
||||
|
||||
/* Unlink it from the list */
|
||||
RemoveEntryList(CurrentEntry);
|
||||
|
||||
/* And free the descriptor */
|
||||
FreeIPDR(Current);
|
||||
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&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
|
||||
*/
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry, NextEntry;
|
||||
PIPDATAGRAM_REASSEMBLY CurrentIPDR;
|
||||
|
||||
TcpipAcquireSpinLockAtDpcLevel(&ReassemblyListLock);
|
||||
|
||||
CurrentEntry = ReassemblyListHead.Flink;
|
||||
while (CurrentEntry != &ReassemblyListHead)
|
||||
{
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
CurrentIPDR = CONTAINING_RECORD(CurrentEntry, IPDATAGRAM_REASSEMBLY, ListEntry);
|
||||
|
||||
TcpipAcquireSpinLockAtDpcLevel(&CurrentIPDR->Lock);
|
||||
|
||||
if (++CurrentIPDR->TimeoutCount == MAX_TIMEOUT_COUNT)
|
||||
{
|
||||
TcpipReleaseSpinLockFromDpcLevel(&CurrentIPDR->Lock);
|
||||
RemoveEntryList(CurrentEntry);
|
||||
FreeIPDR(CurrentIPDR);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(CurrentIPDR->TimeoutCount < MAX_TIMEOUT_COUNT);
|
||||
TcpipReleaseSpinLockFromDpcLevel(&CurrentIPDR->Lock);
|
||||
}
|
||||
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLockFromDpcLevel(&ReassemblyListLock);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
{
|
||||
UCHAR FirstByte;
|
||||
ULONG BytesCopied;
|
||||
|
||||
TI_DbgPrint(DEBUG_IP, ("Received IPv4 datagram.\n"));
|
||||
|
||||
/* Read in the first IP header byte for size information */
|
||||
BytesCopied = CopyPacketToBuffer((PCHAR)&FirstByte,
|
||||
IPPacket->NdisPacket,
|
||||
IPPacket->Position,
|
||||
sizeof(UCHAR));
|
||||
if (BytesCopied != sizeof(UCHAR))
|
||||
{
|
||||
TI_DbgPrint(MIN_TRACE, ("Failed to copy in first byte\n"));
|
||||
/* Discard packet */
|
||||
return;
|
||||
}
|
||||
|
||||
IPPacket->HeaderSize = (FirstByte & 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;
|
||||
}
|
||||
|
||||
/* This is freed by IPPacket->Free() */
|
||||
IPPacket->Header = ExAllocatePoolWithTag(NonPagedPool,
|
||||
IPPacket->HeaderSize,
|
||||
PACKET_BUFFER_TAG);
|
||||
if (!IPPacket->Header)
|
||||
{
|
||||
TI_DbgPrint(MIN_TRACE, ("No resources to allocate header\n"));
|
||||
/* Discard packet */
|
||||
return;
|
||||
}
|
||||
|
||||
IPPacket->MappedHeader = FALSE;
|
||||
|
||||
BytesCopied = CopyPacketToBuffer((PCHAR)IPPacket->Header,
|
||||
IPPacket->NdisPacket,
|
||||
IPPacket->Position,
|
||||
IPPacket->HeaderSize);
|
||||
if (BytesCopied != IPPacket->HeaderSize)
|
||||
{
|
||||
TI_DbgPrint(MIN_TRACE, ("Failed to copy in header\n"));
|
||||
/* 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);
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("IPPacket->Position = %d\n",
|
||||
IPPacket->Position));
|
||||
|
||||
/* FIXME: Possibly forward packets with multicast addresses */
|
||||
|
||||
/* FIXME: Should we allow packets to be received on the wrong interface? */
|
||||
/* XXX Find out if this packet is destined for us */
|
||||
ProcessFragment(IF, IPPacket);
|
||||
}
|
||||
|
||||
|
||||
VOID IPReceive( PIP_INTERFACE IF, PIP_PACKET IPPacket )
|
||||
/*
|
||||
* FUNCTION: Receives an IP datagram (or fragment)
|
||||
* ARGUMENTS:
|
||||
* IF = Interface
|
||||
* IPPacket = Pointer to IP packet
|
||||
*/
|
||||
{
|
||||
UCHAR FirstByte;
|
||||
UINT Version, BytesCopied;
|
||||
|
||||
/* Read in the first IP header byte for version information */
|
||||
BytesCopied = CopyPacketToBuffer((PCHAR)&FirstByte,
|
||||
IPPacket->NdisPacket,
|
||||
IPPacket->Position,
|
||||
sizeof(UCHAR));
|
||||
if (BytesCopied != sizeof(UCHAR))
|
||||
{
|
||||
TI_DbgPrint(MIN_TRACE, ("Failed to copy in first byte\n"));
|
||||
IPPacket->Free(IPPacket);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check that IP header has a supported version */
|
||||
Version = (FirstByte >> 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"));
|
||||
break;
|
||||
default:
|
||||
TI_DbgPrint(MIN_TRACE, ("Datagram has an unsupported IP version %d.\n", Version));
|
||||
break;
|
||||
}
|
||||
|
||||
IPPacket->Free(IPPacket);
|
||||
}
|
||||
|
||||
/* EOF */
|
520
sdk/lib/drivers/ip/network/router.c
Normal file
520
sdk/lib/drivers/ip/network/router.c
Normal file
|
@ -0,0 +1,520 @@
|
|||
/*
|
||||
* 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 RouterDumpRoutes() {
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PFIB_ENTRY Current;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Dumping Routes\n"));
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
|
||||
NCE = Current->Router;
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Examining FIBE %x\n", Current));
|
||||
TI_DbgPrint(DEBUG_ROUTER,("... NetworkAddress %s\n", A2S(&Current->NetworkAddress)));
|
||||
TI_DbgPrint(DEBUG_ROUTER,("... NCE->Address . %s\n", A2S(&NCE->Address)));
|
||||
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Dumping Routes ... Done\n"));
|
||||
}
|
||||
|
||||
VOID FreeFIB(
|
||||
PVOID Object)
|
||||
/*
|
||||
* FUNCTION: Frees an forward information base object
|
||||
* ARGUMENTS:
|
||||
* Object = Pointer to an forward information base structure
|
||||
*/
|
||||
{
|
||||
ExFreePoolWithTag(Object, FIB_TAG);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
|
||||
/* 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(PIP_INTERFACE IF) {
|
||||
UINT FibCount = 0;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PFIB_ENTRY Current;
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
if (Current->Router->Interface == IF)
|
||||
FibCount++;
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
return FibCount;
|
||||
}
|
||||
|
||||
|
||||
UINT CopyFIBs( PIP_INTERFACE IF, PFIB_ENTRY Target ) {
|
||||
UINT FibCount = 0;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PFIB_ENTRY Current;
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
if (Current->Router->Interface == IF)
|
||||
{
|
||||
Target[FibCount] = *Current;
|
||||
FibCount++;
|
||||
}
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Returning %d\n", 8 * i + j));
|
||||
|
||||
return 8 * i + j;
|
||||
}
|
||||
|
||||
|
||||
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 = ExAllocatePoolWithTag(NonPagedPool, sizeof(FIB_ENTRY), FIB_TAG);
|
||||
if (!FIBE) {
|
||||
TI_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RtlCopyMemory( &FIBE->NetworkAddress, NetworkAddress,
|
||||
sizeof(FIBE->NetworkAddress) );
|
||||
RtlCopyMemory( &FIBE->Netmask, Netmask,
|
||||
sizeof(FIBE->Netmask) );
|
||||
FIBE->Router = Router;
|
||||
FIBE->Metric = Metric;
|
||||
|
||||
/* Add FIB to the forward information base */
|
||||
TcpipInterlockedInsertTailList(&FIBListHead, &FIBE->ListEntry, &FIBLock);
|
||||
|
||||
return FIBE;
|
||||
}
|
||||
|
||||
|
||||
PNEIGHBOR_CACHE_ENTRY RouterGetRoute(PIP_ADDRESS Destination)
|
||||
/*
|
||||
* FUNCTION: Finds a router to use to get to Destination
|
||||
* ARGUMENTS:
|
||||
* Destination = Pointer to destination address (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;
|
||||
UINT Length, BestLength = 0, MaskLength;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE, BestNCE = NULL;
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Called. Destination (0x%X)\n", Destination));
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Destination (%s)\n", A2S(Destination)));
|
||||
|
||||
TcpipAcquireSpinLock(&FIBLock, &OldIrql);
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
|
||||
NCE = Current->Router;
|
||||
State = NCE->State;
|
||||
|
||||
Length = CommonPrefixLength(Destination, &Current->NetworkAddress);
|
||||
MaskLength = AddrCountPrefixBits(&Current->Netmask);
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER,("This-Route: %s (Sharing %d bits)\n",
|
||||
A2S(&NCE->Address), Length));
|
||||
|
||||
if(Length >= MaskLength && (Length > BestLength || !BestNCE) &&
|
||||
((!(State & NUD_STALE) && !(State & NUD_INCOMPLETE)) || !BestNCE)) {
|
||||
/* This seems to be a better router */
|
||||
BestNCE = NCE;
|
||||
BestLength = Length;
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Route selected\n"));
|
||||
}
|
||||
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&FIBLock, OldIrql);
|
||||
|
||||
if( BestNCE ) {
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Routing to %s\n", A2S(&BestNCE->Address)));
|
||||
} else {
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Packet won't be routed\n"));
|
||||
}
|
||||
|
||||
return BestNCE;
|
||||
}
|
||||
|
||||
PNEIGHBOR_CACHE_ENTRY RouteGetRouteToDestination(PIP_ADDRESS Destination)
|
||||
/*
|
||||
* FUNCTION: Locates an RCN describing a route to a destination address
|
||||
* ARGUMENTS:
|
||||
* Destination = Pointer to destination address to find route to
|
||||
* 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
|
||||
*/
|
||||
{
|
||||
PNEIGHBOR_CACHE_ENTRY NCE = NULL;
|
||||
PIP_INTERFACE Interface;
|
||||
|
||||
TI_DbgPrint(DEBUG_RCACHE, ("Called. Destination (0x%X)\n", Destination));
|
||||
|
||||
TI_DbgPrint(DEBUG_RCACHE, ("Destination (%s)\n", A2S(Destination)));
|
||||
|
||||
#if 0
|
||||
TI_DbgPrint(MIN_TRACE, ("Displaying tree (before).\n"));
|
||||
PrintTree(RouteCache);
|
||||
#endif
|
||||
|
||||
/* Check if the destination is on-link */
|
||||
Interface = FindOnLinkInterface(Destination);
|
||||
if (Interface) {
|
||||
/* The destination address is on-link. Check our neighbor cache */
|
||||
NCE = NBFindOrCreateNeighbor(Interface, Destination, FALSE);
|
||||
} else {
|
||||
/* Destination is not on any subnets we're on. Find a router to use */
|
||||
NCE = RouterGetRoute(Destination);
|
||||
}
|
||||
|
||||
if( NCE )
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Interface->MTU: %d\n", NCE->Interface->MTU));
|
||||
|
||||
return NCE;
|
||||
}
|
||||
|
||||
VOID RouterRemoveRoutesForInterface(PIP_INTERFACE Interface)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PFIB_ENTRY Current;
|
||||
|
||||
TcpipAcquireSpinLock(&FIBLock, &OldIrql);
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
|
||||
if (Interface == Current->Router->Interface)
|
||||
DestroyFIBE(Current);
|
||||
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&FIBLock, OldIrql);
|
||||
}
|
||||
|
||||
NTSTATUS RouterRemoveRoute(PIP_ADDRESS Target, PIP_ADDRESS Router)
|
||||
/*
|
||||
* FUNCTION: Removes a route from the Forward Information Base (FIB)
|
||||
* ARGUMENTS:
|
||||
* Target: The machine or network targeted by the route
|
||||
* Router: The router used to pass the packet to the destination
|
||||
*
|
||||
* Searches the FIB and removes a route matching the indicated parameters.
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PFIB_ENTRY Current;
|
||||
BOOLEAN Found = FALSE;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Called\n"));
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Deleting Route From: %s\n", A2S(Router)));
|
||||
TI_DbgPrint(DEBUG_ROUTER, (" To: %s\n", A2S(Target)));
|
||||
|
||||
TcpipAcquireSpinLock(&FIBLock, &OldIrql);
|
||||
|
||||
RouterDumpRoutes();
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
|
||||
NCE = Current->Router;
|
||||
|
||||
if( AddrIsEqual( &Current->NetworkAddress, Target ) &&
|
||||
AddrIsEqual( &NCE->Address, Router ) ) {
|
||||
Found = TRUE;
|
||||
break;
|
||||
}
|
||||
|
||||
Current = NULL;
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
if( Found ) {
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Deleting route\n"));
|
||||
DestroyFIBE( Current );
|
||||
}
|
||||
|
||||
RouterDumpRoutes();
|
||||
|
||||
TcpipReleaseSpinLock(&FIBLock, OldIrql);
|
||||
|
||||
TI_DbgPrint(DEBUG_ROUTER, ("Leaving\n"));
|
||||
|
||||
return Found ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
PFIB_ENTRY RouterCreateRoute(
|
||||
PIP_ADDRESS NetworkAddress,
|
||||
PIP_ADDRESS Netmask,
|
||||
PIP_ADDRESS RouterAddress,
|
||||
PIP_INTERFACE Interface,
|
||||
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
|
||||
*/
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PLIST_ENTRY NextEntry;
|
||||
PFIB_ENTRY Current;
|
||||
PNEIGHBOR_CACHE_ENTRY NCE;
|
||||
|
||||
TcpipAcquireSpinLock(&FIBLock, &OldIrql);
|
||||
|
||||
CurrentEntry = FIBListHead.Flink;
|
||||
while (CurrentEntry != &FIBListHead) {
|
||||
NextEntry = CurrentEntry->Flink;
|
||||
Current = CONTAINING_RECORD(CurrentEntry, FIB_ENTRY, ListEntry);
|
||||
|
||||
NCE = Current->Router;
|
||||
|
||||
if(AddrIsEqual(NetworkAddress, &Current->NetworkAddress) &&
|
||||
AddrIsEqual(Netmask, &Current->Netmask) &&
|
||||
NCE->Interface == Interface)
|
||||
{
|
||||
TI_DbgPrint(DEBUG_ROUTER,("Attempting to add duplicate route to %s\n", A2S(NetworkAddress)));
|
||||
TcpipReleaseSpinLock(&FIBLock, OldIrql);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CurrentEntry = NextEntry;
|
||||
}
|
||||
|
||||
TcpipReleaseSpinLock(&FIBLock, OldIrql);
|
||||
|
||||
/* The NCE references RouterAddress. The NCE is referenced for us */
|
||||
NCE = NBFindOrCreateNeighbor(Interface, RouterAddress, TRUE);
|
||||
|
||||
if (!NCE) {
|
||||
/* Not enough free resources */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return RouterAddRoute(NetworkAddress, Netmask, NCE, Metric);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
TcpipInitializeSpinLock(&FIBLock);
|
||||
|
||||
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 */
|
||||
TcpipAcquireSpinLock(&FIBLock, &OldIrql);
|
||||
DestroyFIBEs();
|
||||
TcpipReleaseSpinLock(&FIBLock, OldIrql);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
88
sdk/lib/drivers/ip/network/routines.c
Normal file
88
sdk/lib/drivers/ip/network/routines.c
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
#if 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));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
VOID DisplayIPPacket(
|
||||
PIP_PACKET IPPacket)
|
||||
{
|
||||
#if DBG
|
||||
UINT Length;
|
||||
PCHAR CharBuffer;
|
||||
|
||||
/* DbgQueryDebugFilterState returns (NTSTATUS)TRUE, (NTSTATUS)FALSE or a failure status code */
|
||||
if ((DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_PBUFFER | DPFLTR_MASK) != (NTSTATUS)TRUE) ||
|
||||
(DbgQueryDebugFilterState(DPFLTR_TCPIP_ID, DEBUG_IP | DPFLTR_MASK) != (NTSTATUS)TRUE)) {
|
||||
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, ("NdisPacket (0x%X).\n", IPPacket->NdisPacket));
|
||||
|
||||
CharBuffer = IPPacket->Header;
|
||||
Length = IPPacket->HeaderSize;
|
||||
DisplayIPHeader(CharBuffer, Length);
|
||||
#endif
|
||||
}
|
||||
|
247
sdk/lib/drivers/ip/network/transmit.c
Normal file
247
sdk/lib/drivers/ip/network/transmit.c
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* 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);
|
||||
NTSTATUS IPSendFragment(PNDIS_PACKET NdisPacket,
|
||||
PNEIGHBOR_CACHE_ENTRY NCE,
|
||||
PIPFRAGMENT_CONTEXT IFC);
|
||||
|
||||
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
|
||||
*/
|
||||
{
|
||||
PIPFRAGMENT_CONTEXT IFC = (PIPFRAGMENT_CONTEXT)Context;
|
||||
|
||||
TI_DbgPrint
|
||||
(MAX_TRACE,
|
||||
("Called. Context (0x%X) NdisPacket (0x%X) NdisStatus (0x%X)\n",
|
||||
Context, NdisPacket, NdisStatus));
|
||||
|
||||
IFC->Status = NdisStatus;
|
||||
KeSetEvent(&IFC->Event, 0, FALSE);
|
||||
}
|
||||
|
||||
NTSTATUS IPSendFragment(
|
||||
PNDIS_PACKET NdisPacket,
|
||||
PNEIGHBOR_CACHE_ENTRY NCE,
|
||||
PIPFRAGMENT_CONTEXT IFC)
|
||||
/*
|
||||
* 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));
|
||||
return NBQueuePacket(NCE, NdisPacket, IPSendComplete, IFC);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("Copying data from %x to %x (%d)\n",
|
||||
IFC->DatagramData, IFC->Data, DataSize));
|
||||
|
||||
RtlCopyMemory(IFC->Data, IFC->DatagramData, DataSize); // SAFE
|
||||
|
||||
/* Fragment offset is in 8 byte blocks */
|
||||
FragOfs = (USHORT)(IFC->Position / 8);
|
||||
|
||||
if (MoreFragments)
|
||||
FragOfs |= IPv4_MF_MASK;
|
||||
else
|
||||
FragOfs &= ~IPv4_MF_MASK;
|
||||
|
||||
Header = IFC->Header;
|
||||
Header->FlagsFragOfs = WH2N(FragOfs);
|
||||
Header->TotalLength = WH2N((USHORT)(DataSize + IFC->HeaderSize));
|
||||
|
||||
/* 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;
|
||||
UINT BufferSize = PathMTU, InSize;
|
||||
PCHAR InData;
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X) PathMTU (%d).\n",
|
||||
IPPacket, NCE, PathMTU));
|
||||
|
||||
/* Make a smaller buffer if we will only send one fragment */
|
||||
GetDataPtr( IPPacket->NdisPacket, IPPacket->Position, &InData, &InSize );
|
||||
if( InSize < BufferSize ) BufferSize = InSize;
|
||||
|
||||
TI_DbgPrint(MAX_TRACE, ("Fragment buffer is %d bytes\n", BufferSize));
|
||||
|
||||
IFC = ExAllocatePoolWithTag(NonPagedPool, sizeof(IPFRAGMENT_CONTEXT), IFC_TAG);
|
||||
if (IFC == NULL)
|
||||
{
|
||||
IPPacket->Free(IPPacket);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* Allocate NDIS packet */
|
||||
NdisStatus = AllocatePacketWithBuffer
|
||||
( &IFC->NdisPacket, NULL, BufferSize );
|
||||
|
||||
if( !NT_SUCCESS(NdisStatus) ) {
|
||||
IPPacket->Free(IPPacket);
|
||||
ExFreePoolWithTag( IFC, IFC_TAG );
|
||||
return NdisStatus;
|
||||
}
|
||||
|
||||
GetDataPtr( IFC->NdisPacket, 0, (PCHAR *)&Data, &InSize );
|
||||
|
||||
IFC->Header = ((PCHAR)Data);
|
||||
IFC->Datagram = IPPacket->NdisPacket;
|
||||
IFC->DatagramData = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
|
||||
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);
|
||||
KeInitializeEvent(&IFC->Event, NotificationEvent, FALSE);
|
||||
|
||||
TI_DbgPrint(MID_TRACE,("Copying header from %x to %x (%d)\n",
|
||||
IPPacket->Header, IFC->Header,
|
||||
IPPacket->HeaderSize));
|
||||
|
||||
RtlCopyMemory( IFC->Header, IPPacket->Header, IPPacket->HeaderSize );
|
||||
|
||||
while (PrepareNextFragment(IFC))
|
||||
{
|
||||
NdisStatus = IPSendFragment(IFC->NdisPacket, NCE, IFC);
|
||||
if (NT_SUCCESS(NdisStatus))
|
||||
{
|
||||
KeWaitForSingleObject(&IFC->Event,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
NdisStatus = IFC->Status;
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(NdisStatus))
|
||||
break;
|
||||
}
|
||||
|
||||
FreeNdisPacket(IFC->NdisPacket);
|
||||
ExFreePoolWithTag(IFC, IFC_TAG);
|
||||
IPPacket->Free(IPPacket);
|
||||
|
||||
return NdisStatus;
|
||||
}
|
||||
|
||||
NTSTATUS IPSendDatagram(PIP_PACKET IPPacket, PNEIGHBOR_CACHE_ENTRY NCE)
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
{
|
||||
TI_DbgPrint(MAX_TRACE, ("Called. IPPacket (0x%X) NCE (0x%X)\n", IPPacket, NCE));
|
||||
|
||||
DISPLAY_IP_PACKET(IPPacket);
|
||||
|
||||
/* Fetch path MTU now, because it may change */
|
||||
TI_DbgPrint(MID_TRACE,("PathMTU: %d\n", NCE->Interface->MTU));
|
||||
|
||||
return SendFragments(IPPacket, NCE, NCE->Interface->MTU);
|
||||
}
|
||||
|
||||
/* EOF */
|
Loading…
Add table
Add a link
Reference in a new issue