xref: /reactos/drivers/network/tcpip/ip/network/icmp.c (revision 09dde2cf)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS TCP/IP protocol driver
4  * FILE:        network/icmp.c
5  * PURPOSE:     Internet Control Message Protocol routines
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 01/08-2000 Created
9  */
10 
11 #include "precomp.h"
12 
13 #include <icmp.h>
14 
15 NTSTATUS ICMPStartup()
16 {
17     IPRegisterProtocol(IPPROTO_ICMP, ICMPReceive);
18 
19     return STATUS_SUCCESS;
20 }
21 
22 NTSTATUS ICMPShutdown()
23 {
24     IPRegisterProtocol(IPPROTO_ICMP, NULL);
25 
26     return STATUS_SUCCESS;
27 }
28 
29 NTSTATUS ICMPSendDatagram(
30     PADDRESS_FILE AddrFile,
31     PTDI_CONNECTION_INFORMATION ConnInfo,
32     PCHAR BufferData,
33     ULONG DataSize,
34     PULONG DataUsed )
35 /*
36  * FUNCTION: Sends an ICMP datagram to a remote address
37  * ARGUMENTS:
38  *     Request   = Pointer to TDI request
39  *     ConnInfo  = Pointer to connection information
40  *     Buffer    = Pointer to NDIS buffer with data
41  *     DataSize  = Size in bytes of data to be sent
42  * RETURNS:
43  *     Status of operation
44  */
45 {
46     TI_DbgPrint(DEBUG_ICMP, ("Sending ICMP datagram (0x%x)\n", AddrFile));
47 
48     /* just forward the call to RawIP handler */
49     return RawIPSendDatagram(AddrFile, ConnInfo, BufferData, DataSize, DataUsed);
50 }
51 
52 
53 VOID ICMPReceive(
54     PIP_INTERFACE Interface,
55     PIP_PACKET IPPacket)
56 /*
57  * FUNCTION: Receives an ICMP packet
58  * ARGUMENTS:
59  *     NTE      = Pointer to net table entry which the packet was received on
60  *     IPPacket = Pointer to an IP packet that was received
61  */
62 {
63     PICMP_HEADER ICMPHeader = (PICMP_HEADER)IPPacket->Data;
64     UINT32 DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
65 
66     TI_DbgPrint(DEBUG_ICMP, ("ICMPReceive: Size (%d) HeaderSize (%d) Type (%d) Code (%d) Checksum (0x%x)\n",
67         IPPacket->TotalSize, IPPacket->HeaderSize, ICMPHeader->Type, ICMPHeader->Code, ICMPHeader->Checksum));
68 
69     /* Discard too short packets */
70     if (DataSize < sizeof(ICMP_HEADER))
71     {
72         TI_DbgPrint(DEBUG_ICMP, ("Packet doesn't fit ICMP header. Discarded\n"));
73         return;
74     }
75 
76     /* Discard packets with bad checksum */
77     if (!IPv4CorrectChecksum(IPPacket->Data, DataSize))
78     {
79         TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum. Packet discarded\n"));
80         return;
81     }
82 
83     RawIpReceive(Interface, IPPacket);
84 
85     if (ICMPHeader->Type == ICMP_TYPE_ECHO_REQUEST)
86     {
87         ICMPReply(Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0);
88     }
89 }
90 
91 VOID ICMPReply(
92     PIP_INTERFACE Interface,
93     PIP_PACKET IPPacket,
94     UCHAR Type,
95     UCHAR Code)
96 /*
97  * FUNCTION: Transmits an ICMP packet in response to an incoming packet
98  * ARGUMENTS:
99  *     NTE      = Pointer to net table entry to use
100  *     IPPacket = Pointer to IP packet that was received
101  *     Type     = ICMP message type
102  *     Code     = ICMP message code
103  * NOTES:
104  *     We have received a packet from someone and is unable to
105  *     process it due to error(s) in the packet or we have run out
106  *     of resources. We transmit an ICMP message to the host to
107  *     notify him of the problem
108  */
109 {
110     UINT DataSize;
111     IP_PACKET NewPacket;
112     ADDRESS_FILE FakeAddrFile;
113     PNEIGHBOR_CACHE_ENTRY NCE;
114 
115     TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d)  Code (%d).\n", Type, Code));
116 
117     DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
118 
119     /* First check if we have a route to sender */
120     NCE = RouteGetRouteToDestination(&IPPacket->SrcAddr);
121     if (!NCE)
122     {
123         return;
124     }
125 
126     /* This is the only data needed to generate a packet */
127     FakeAddrFile.Protocol = IPPROTO_ICMP;
128     FakeAddrFile.TTL = 128;
129 
130     if (!NT_SUCCESS(BuildRawIpPacket(
131         &FakeAddrFile, &NewPacket, &IPPacket->SrcAddr, 0, &Interface->Unicast, 0, IPPacket->Data, DataSize)))
132     {
133         return;
134     }
135 
136     ((PICMP_HEADER)NewPacket.Data)->Type     = Type;
137     ((PICMP_HEADER)NewPacket.Data)->Code     = Code;
138     ((PICMP_HEADER)NewPacket.Data)->Checksum = 0;
139     ((PICMP_HEADER)NewPacket.Data)->Checksum = (USHORT)IPv4Checksum(NewPacket.Data, DataSize, 0);
140 
141     IPSendDatagram(&NewPacket, NCE);
142 }
143 
144 /* EOF */
145