Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.

This commit is contained in:
Colin Finck 2017-10-03 07:45:34 +00:00
parent b94e2d8ca0
commit c2c66aff7d
24198 changed files with 0 additions and 37285 deletions

View 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 */

View 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 */

View 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);
}

View 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

View 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 */

View 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;
}
}

View 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 */

View 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;
}

View 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;
}

View 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;
}

View 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 */

View 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 */

View 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
}

View 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 */