2004-09-29 05:10:48 +00:00
|
|
|
/*
|
|
|
|
* 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"
|
|
|
|
|
2009-07-19 14:48:48 +00:00
|
|
|
NTSTATUS ICMPStartup()
|
|
|
|
{
|
|
|
|
IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS ICMPShutdown()
|
|
|
|
{
|
|
|
|
IPRegisterProtocol(IPPROTO_ICMP, NULL);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
2004-09-29 05:10:48 +00:00
|
|
|
|
|
|
|
VOID SendICMPComplete(
|
|
|
|
PVOID Context,
|
|
|
|
PNDIS_PACKET Packet,
|
|
|
|
NDIS_STATUS NdisStatus)
|
|
|
|
/*
|
|
|
|
* FUNCTION: ICMP datagram transmit completion handler
|
|
|
|
* ARGUMENTS:
|
|
|
|
* Context = Pointer to context infomation (IP_PACKET)
|
|
|
|
* Packet = Pointer to NDIS packet
|
|
|
|
* NdisStatus = Status of transmit operation
|
|
|
|
* NOTES:
|
|
|
|
* This routine is called by IP when a ICMP send completes
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("Freeing NDIS packet (%X).\n", Packet));
|
|
|
|
|
|
|
|
/* Free packet */
|
|
|
|
FreeNdisPacket(Packet);
|
|
|
|
|
2004-11-07 20:37:21 +00:00
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("Done\n"));
|
2004-09-29 05:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-04-04 00:23:09 +00:00
|
|
|
BOOLEAN PrepareICMPPacket(
|
2010-01-09 16:25:11 +00:00
|
|
|
PADDRESS_FILE AddrFile,
|
2004-11-25 23:56:59 +00:00
|
|
|
PIP_INTERFACE Interface,
|
2004-11-07 20:37:21 +00:00
|
|
|
PIP_PACKET IPPacket,
|
2004-09-29 05:10:48 +00:00
|
|
|
PIP_ADDRESS Destination,
|
2004-11-07 20:37:21 +00:00
|
|
|
PCHAR Data,
|
2004-09-29 05:10:48 +00:00
|
|
|
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));
|
|
|
|
|
2009-04-04 00:23:09 +00:00
|
|
|
IPInitializePacket(IPPacket, IP_ADDRESS_V4);
|
|
|
|
|
2004-09-29 05:10:48 +00:00
|
|
|
/* No special flags */
|
|
|
|
IPPacket->Flags = 0;
|
|
|
|
|
2009-10-04 19:23:53 +00:00
|
|
|
Size = sizeof(IPv4_HEADER) + DataSize;
|
2004-11-07 20:37:21 +00:00
|
|
|
|
|
|
|
/* Allocate NDIS packet */
|
|
|
|
NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2009-04-04 00:23:09 +00:00
|
|
|
if( !NT_SUCCESS(NdisStatus) ) return FALSE;
|
2004-09-29 05:10:48 +00:00
|
|
|
|
2004-11-07 20:37:21 +00:00
|
|
|
IPPacket->NdisPacket = NdisPacket;
|
|
|
|
|
2009-10-04 19:23:53 +00:00
|
|
|
GetDataPtr( IPPacket->NdisPacket, 0,
|
2004-11-07 20:37:21 +00:00
|
|
|
(PCHAR *)&IPPacket->Header, &IPPacket->ContigSize );
|
|
|
|
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, Data));
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("NdisPacket at (0x%X).\n", NdisPacket));
|
2004-09-29 05:10:48 +00:00
|
|
|
|
|
|
|
IPPacket->HeaderSize = sizeof(IPv4_HEADER);
|
2009-10-04 19:23:53 +00:00
|
|
|
IPPacket->TotalSize = Size;
|
2009-04-04 01:22:33 +00:00
|
|
|
IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
|
2004-11-07 20:37:21 +00:00
|
|
|
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("Copying Address: %x -> %x\n",
|
|
|
|
&IPPacket->DstAddr, Destination));
|
|
|
|
|
2004-09-29 05:10:48 +00:00
|
|
|
RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS));
|
2004-11-07 20:37:21 +00:00
|
|
|
RtlCopyMemory(IPPacket->Data, Data, DataSize);
|
2004-09-29 05:10:48 +00:00
|
|
|
|
|
|
|
/* 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 */
|
2004-11-07 20:37:21 +00:00
|
|
|
IPHeader->TotalLength = WH2N((USHORT)DataSize + sizeof(IPv4_HEADER));
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Identification */
|
|
|
|
IPHeader->Id = (USHORT)Random();
|
|
|
|
/* One fragment at offset 0 */
|
|
|
|
IPHeader->FlagsFragOfs = 0;
|
2010-01-09 16:25:11 +00:00
|
|
|
/* Set TTL */
|
|
|
|
if (AddrFile)
|
|
|
|
IPHeader->Ttl = AddrFile->TTL;
|
|
|
|
else
|
|
|
|
IPHeader->Ttl = 128;
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Internet Control Message Protocol */
|
|
|
|
IPHeader->Protocol = IPPROTO_ICMP;
|
|
|
|
/* Checksum is 0 (for later calculation of this) */
|
|
|
|
IPHeader->Checksum = 0;
|
|
|
|
/* Source address */
|
2004-11-25 23:56:59 +00:00
|
|
|
IPHeader->SrcAddr = Interface->Unicast.Address.IPv4Address;
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Destination address */
|
|
|
|
IPHeader->DstAddr = Destination->Address.IPv4Address;
|
|
|
|
|
2004-10-03 20:38:48 +00:00
|
|
|
|
|
|
|
TI_DbgPrint(MID_TRACE,("Leaving\n"));
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2009-04-04 00:23:09 +00:00
|
|
|
return TRUE;
|
2004-09-29 05:10:48 +00:00
|
|
|
}
|
|
|
|
|
2009-07-19 14:48:48 +00:00
|
|
|
VOID ICMPSendPacketComplete
|
|
|
|
( PVOID Context, PNDIS_PACKET Packet, NDIS_STATUS Status ) {
|
|
|
|
FreeNdisPacket( Packet );
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
USHORT RemotePort;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PNEIGHBOR_CACHE_ENTRY NCE;
|
2010-01-08 18:10:05 +00:00
|
|
|
KIRQL OldIrql;
|
2009-07-19 14:48:48 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
RemotePort = RemoteAddressTa->Address[0].Address[0].sin_port;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
TI_DbgPrint(MID_TRACE,("About to get route to destination\n"));
|
|
|
|
|
2010-01-08 18:10:05 +00:00
|
|
|
LockObject(AddrFile, &OldIrql);
|
|
|
|
|
2009-07-19 14:48:48 +00:00
|
|
|
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
|
|
|
|
*/
|
2009-12-30 12:46:14 +00:00
|
|
|
if(!(NCE = RouteGetRouteToDestination( &RemoteAddress )))
|
2010-01-08 18:10:05 +00:00
|
|
|
{
|
|
|
|
UnlockObject(AddrFile, OldIrql);
|
2009-12-30 12:46:14 +00:00
|
|
|
return STATUS_NETWORK_UNREACHABLE;
|
2010-01-08 18:10:05 +00:00
|
|
|
}
|
2009-12-30 12:46:14 +00:00
|
|
|
|
2009-07-19 14:48:48 +00:00
|
|
|
LocalAddress = NCE->Interface->Unicast;
|
|
|
|
}
|
2009-12-30 12:46:14 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if(!(NCE = NBLocateNeighbor( &LocalAddress )))
|
2010-01-08 18:10:05 +00:00
|
|
|
{
|
|
|
|
UnlockObject(AddrFile, OldIrql);
|
2009-12-30 12:46:14 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
2010-01-08 18:10:05 +00:00
|
|
|
}
|
2009-12-30 12:46:14 +00:00
|
|
|
}
|
2009-07-19 14:48:48 +00:00
|
|
|
|
2010-01-09 16:25:11 +00:00
|
|
|
Status = PrepareICMPPacket( AddrFile,
|
|
|
|
NCE->Interface,
|
2009-07-19 14:48:48 +00:00
|
|
|
&Packet,
|
|
|
|
&RemoteAddress,
|
|
|
|
BufferData,
|
|
|
|
DataSize );
|
|
|
|
|
2010-01-09 16:25:11 +00:00
|
|
|
UnlockObject(AddrFile, OldIrql);
|
|
|
|
|
2009-07-19 14:48:48 +00:00
|
|
|
if( !NT_SUCCESS(Status) )
|
|
|
|
return Status;
|
|
|
|
|
|
|
|
TI_DbgPrint(MID_TRACE,("About to send datagram\n"));
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status = IPSendDatagram( &Packet, NCE, ICMPSendPacketComplete, NULL )))
|
|
|
|
{
|
|
|
|
FreeNdisPacket(Packet.NdisPacket);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
TI_DbgPrint(MID_TRACE,("Leaving\n"));
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-09-29 05:10:48 +00:00
|
|
|
|
|
|
|
VOID ICMPReceive(
|
2004-11-25 23:56:59 +00:00
|
|
|
PIP_INTERFACE Interface,
|
2004-09-29 05:10:48 +00:00
|
|
|
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));
|
|
|
|
|
2009-07-19 14:48:48 +00:00
|
|
|
RawIpReceive(Interface, IPPacket);
|
|
|
|
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Checksum ICMP header and data */
|
|
|
|
if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) {
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n"));
|
|
|
|
/* Discard packet */
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ICMPHeader->Type) {
|
|
|
|
case ICMP_TYPE_ECHO_REQUEST:
|
2004-11-25 23:56:59 +00:00
|
|
|
ICMPReply( Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0 );
|
2004-09-29 05:10:48 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
case ICMP_TYPE_ECHO_REPLY:
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2005-05-08 02:16:32 +00:00
|
|
|
TI_DbgPrint(DEBUG_ICMP,
|
2004-10-03 20:38:48 +00:00
|
|
|
("Discarded ICMP datagram of unknown type %d.\n",
|
|
|
|
ICMPHeader->Type));
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Discard packet */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID ICMPTransmit(
|
2004-11-07 20:37:21 +00:00
|
|
|
PIP_PACKET IPPacket,
|
|
|
|
PIP_TRANSMIT_COMPLETE Complete,
|
|
|
|
PVOID Context)
|
2004-09-29 05:10:48 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
{
|
2004-11-30 00:10:41 +00:00
|
|
|
PNEIGHBOR_CACHE_ENTRY NCE;
|
2008-11-09 18:17:00 +00:00
|
|
|
NTSTATUS Status;
|
2004-09-29 05:10:48 +00:00
|
|
|
|
|
|
|
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 */
|
2004-11-30 00:10:41 +00:00
|
|
|
if ((NCE = RouteGetRouteToDestination(&IPPacket->DstAddr))) {
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Send the packet */
|
2008-11-09 18:17:00 +00:00
|
|
|
Status = IPSendDatagram(IPPacket, NCE, Complete, Context);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Complete(Context, IPPacket->NdisPacket, Status);
|
|
|
|
}
|
2004-09-29 05:10:48 +00:00
|
|
|
} else {
|
|
|
|
/* No route to destination (or no free resources) */
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n",
|
2004-11-30 00:10:41 +00:00
|
|
|
IPPacket->DstAddr.Address.IPv4Address));
|
2004-09-29 05:10:48 +00:00
|
|
|
/* Discard packet */
|
2004-11-07 20:37:21 +00:00
|
|
|
Complete( Context, IPPacket->NdisPacket, NDIS_STATUS_NOT_ACCEPTED );
|
2004-09-29 05:10:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID ICMPReply(
|
2004-11-25 23:56:59 +00:00
|
|
|
PIP_INTERFACE Interface,
|
2004-09-29 05:10:48 +00:00
|
|
|
PIP_PACKET IPPacket,
|
2004-10-03 20:38:48 +00:00
|
|
|
UCHAR Type,
|
|
|
|
UCHAR Code)
|
2004-09-29 05:10:48 +00:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
*/
|
|
|
|
{
|
2009-04-01 03:08:51 +00:00
|
|
|
UINT DataSize;
|
2004-11-07 20:37:21 +00:00
|
|
|
IP_PACKET NewPacket = *IPPacket;
|
2004-09-29 05:10:48 +00:00
|
|
|
|
|
|
|
TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d) Code (%d).\n", Type, Code));
|
|
|
|
|
2004-11-07 20:37:21 +00:00
|
|
|
DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
|
2005-05-08 02:16:32 +00:00
|
|
|
|
2010-01-09 16:25:11 +00:00
|
|
|
if( !PrepareICMPPacket(NULL, Interface, &NewPacket, &IPPacket->SrcAddr,
|
2004-11-07 20:37:21 +00:00
|
|
|
IPPacket->Data, DataSize) ) return;
|
2004-09-29 05:10:48 +00:00
|
|
|
|
2004-11-07 20:37:21 +00:00
|
|
|
((PICMP_HEADER)NewPacket.Data)->Type = Type;
|
|
|
|
((PICMP_HEADER)NewPacket.Data)->Code = Code;
|
|
|
|
((PICMP_HEADER)NewPacket.Data)->Checksum = 0;
|
2004-10-03 20:38:48 +00:00
|
|
|
|
2004-11-25 23:56:59 +00:00
|
|
|
ICMPTransmit(&NewPacket, SendICMPComplete, NULL);
|
2004-09-29 05:10:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|