merge ROS Shell without integrated explorer part into trunk
[reactos.git] / reactos / drivers / lib / ip / network / icmp.c
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
14 VOID SendICMPComplete(
15 PVOID Context,
16 PNDIS_PACKET Packet,
17 NDIS_STATUS NdisStatus)
18 /*
19 * FUNCTION: ICMP datagram transmit completion handler
20 * ARGUMENTS:
21 * Context = Pointer to context infomation (IP_PACKET)
22 * Packet = Pointer to NDIS packet
23 * NdisStatus = Status of transmit operation
24 * NOTES:
25 * This routine is called by IP when a ICMP send completes
26 */
27 {
28 TI_DbgPrint(DEBUG_ICMP, ("Freeing NDIS packet (%X).\n", Packet));
29
30 /* Free packet */
31 FreeNdisPacket(Packet);
32
33 TI_DbgPrint(DEBUG_ICMP, ("Done\n"));
34 }
35
36
37 PIP_PACKET PrepareICMPPacket(
38 PIP_INTERFACE Interface,
39 PIP_PACKET IPPacket,
40 PIP_ADDRESS Destination,
41 PCHAR Data,
42 UINT DataSize)
43 /*
44 * FUNCTION: Prepares an ICMP packet
45 * ARGUMENTS:
46 * NTE = Pointer to net table entry to use
47 * Destination = Pointer to destination address
48 * DataSize = Size of dataarea
49 * RETURNS:
50 * Pointer to IP packet, NULL if there is not enough free resources
51 */
52 {
53 PNDIS_PACKET NdisPacket;
54 NDIS_STATUS NdisStatus;
55 PIPv4_HEADER IPHeader;
56 ULONG Size;
57
58 TI_DbgPrint(DEBUG_ICMP, ("Called. DataSize (%d).\n", DataSize));
59
60 /* No special flags */
61 IPPacket->Flags = 0;
62
63 Size = MaxLLHeaderSize + sizeof(IPv4_HEADER) + DataSize;
64
65 /* Allocate NDIS packet */
66 NdisStatus = AllocatePacketWithBuffer( &NdisPacket, NULL, Size );
67
68 if( !NT_SUCCESS(NdisStatus) ) return NULL;
69
70 IPPacket->NdisPacket = NdisPacket;
71
72 GetDataPtr( IPPacket->NdisPacket, MaxLLHeaderSize,
73 (PCHAR *)&IPPacket->Header, &IPPacket->ContigSize );
74
75 IPPacket->Data = ((PCHAR)IPPacket->Header) + IPPacket->HeaderSize;
76
77 TI_DbgPrint(DEBUG_ICMP, ("Size (%d). Data at (0x%X).\n", Size, Data));
78 TI_DbgPrint(DEBUG_ICMP, ("NdisPacket at (0x%X).\n", NdisPacket));
79
80 IPPacket->HeaderSize = sizeof(IPv4_HEADER);
81 IPPacket->TotalSize = Size - MaxLLHeaderSize;
82
83 TI_DbgPrint(DEBUG_ICMP, ("Copying Address: %x -> %x\n",
84 &IPPacket->DstAddr, Destination));
85
86 RtlCopyMemory(&IPPacket->DstAddr, Destination, sizeof(IP_ADDRESS));
87 RtlCopyMemory(IPPacket->Data, Data, DataSize);
88
89 /* Build IPv4 header. FIXME: IPv4 only */
90
91 IPHeader = (PIPv4_HEADER)IPPacket->Header;
92
93 /* Version = 4, Length = 5 DWORDs */
94 IPHeader->VerIHL = 0x45;
95 /* Normal Type-of-Service */
96 IPHeader->Tos = 0;
97 /* Length of data and header */
98 IPHeader->TotalLength = WH2N((USHORT)DataSize + sizeof(IPv4_HEADER));
99 /* Identification */
100 IPHeader->Id = (USHORT)Random();
101 /* One fragment at offset 0 */
102 IPHeader->FlagsFragOfs = 0;
103 /* Time-to-Live is 128 */
104 IPHeader->Ttl = 128;
105 /* Internet Control Message Protocol */
106 IPHeader->Protocol = IPPROTO_ICMP;
107 /* Checksum is 0 (for later calculation of this) */
108 IPHeader->Checksum = 0;
109 /* Source address */
110 IPHeader->SrcAddr = Interface->Unicast.Address.IPv4Address;
111 /* Destination address */
112 IPHeader->DstAddr = Destination->Address.IPv4Address;
113
114
115 TI_DbgPrint(MID_TRACE,("Leaving\n"));
116
117 return IPPacket;
118 }
119
120
121 VOID ICMPReceive(
122 PIP_INTERFACE Interface,
123 PIP_PACKET IPPacket)
124 /*
125 * FUNCTION: Receives an ICMP packet
126 * ARGUMENTS:
127 * NTE = Pointer to net table entry which the packet was received on
128 * IPPacket = Pointer to an IP packet that was received
129 */
130 {
131 PICMP_HEADER ICMPHeader;
132
133 TI_DbgPrint(DEBUG_ICMP, ("Called.\n"));
134
135 ICMPHeader = (PICMP_HEADER)IPPacket->Data;
136
137 TI_DbgPrint(DEBUG_ICMP, ("Size (%d).\n", IPPacket->TotalSize));
138
139 TI_DbgPrint(DEBUG_ICMP, ("HeaderSize (%d).\n", IPPacket->HeaderSize));
140
141 TI_DbgPrint(DEBUG_ICMP, ("Type (%d).\n", ICMPHeader->Type));
142
143 TI_DbgPrint(DEBUG_ICMP, ("Code (%d).\n", ICMPHeader->Code));
144
145 TI_DbgPrint(DEBUG_ICMP, ("Checksum (0x%X).\n", ICMPHeader->Checksum));
146
147 /* Checksum ICMP header and data */
148 if (!IPv4CorrectChecksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize)) {
149 TI_DbgPrint(DEBUG_ICMP, ("Bad ICMP checksum.\n"));
150 /* Discard packet */
151 return;
152 }
153
154 switch (ICMPHeader->Type) {
155 case ICMP_TYPE_ECHO_REQUEST:
156 ICMPReply( Interface, IPPacket, ICMP_TYPE_ECHO_REPLY, 0 );
157 return;
158
159 case ICMP_TYPE_ECHO_REPLY:
160 break;
161
162 default:
163 TI_DbgPrint(DEBUG_ICMP,
164 ("Discarded ICMP datagram of unknown type %d.\n",
165 ICMPHeader->Type));
166 /* Discard packet */
167 break;
168 }
169 }
170
171
172 VOID ICMPTransmit(
173 PIP_PACKET IPPacket,
174 PIP_TRANSMIT_COMPLETE Complete,
175 PVOID Context)
176 /*
177 * FUNCTION: Transmits an ICMP packet
178 * ARGUMENTS:
179 * NTE = Pointer to net table entry to use (NULL if don't care)
180 * IPPacket = Pointer to IP packet to transmit
181 */
182 {
183 PNEIGHBOR_CACHE_ENTRY NCE;
184
185 TI_DbgPrint(DEBUG_ICMP, ("Called.\n"));
186
187 /* Calculate checksum of ICMP header and data */
188 ((PICMP_HEADER)IPPacket->Data)->Checksum = (USHORT)
189 IPv4Checksum(IPPacket->Data, IPPacket->TotalSize - IPPacket->HeaderSize, 0);
190
191 /* Get a route to the destination address */
192 if ((NCE = RouteGetRouteToDestination(&IPPacket->DstAddr))) {
193 /* Send the packet */
194 IPSendDatagram(IPPacket, NCE, Complete, Context);
195 } else {
196 /* No route to destination (or no free resources) */
197 TI_DbgPrint(DEBUG_ICMP, ("No route to destination address 0x%X.\n",
198 IPPacket->DstAddr.Address.IPv4Address));
199 /* Discard packet */
200 Complete( Context, IPPacket->NdisPacket, NDIS_STATUS_NOT_ACCEPTED );
201 }
202 }
203
204
205 VOID ICMPReply(
206 PIP_INTERFACE Interface,
207 PIP_PACKET IPPacket,
208 UCHAR Type,
209 UCHAR Code)
210 /*
211 * FUNCTION: Transmits an ICMP packet in response to an incoming packet
212 * ARGUMENTS:
213 * NTE = Pointer to net table entry to use
214 * IPPacket = Pointer to IP packet that was received
215 * Type = ICMP message type
216 * Code = ICMP message code
217 * NOTES:
218 * We have received a packet from someone and is unable to
219 * process it due to error(s) in the packet or we have run out
220 * of resources. We transmit an ICMP message to the host to
221 * notify him of the problem
222 */
223 {
224 UINT DataSize, PayloadSize;
225 IP_PACKET NewPacket = *IPPacket;
226
227 TI_DbgPrint(DEBUG_ICMP, ("Called. Type (%d) Code (%d).\n", Type, Code));
228
229 DataSize = IPPacket->TotalSize - IPPacket->HeaderSize;
230 PayloadSize = DataSize - sizeof(ICMP_HEADER);
231 if ((PayloadSize) > 576) {
232 PayloadSize = 576;
233 DataSize = PayloadSize + sizeof(ICMP_HEADER);
234 }
235
236 if( !PrepareICMPPacket(Interface, &NewPacket, &IPPacket->SrcAddr,
237 IPPacket->Data, DataSize) ) return;
238
239 ((PICMP_HEADER)NewPacket.Data)->Type = Type;
240 ((PICMP_HEADER)NewPacket.Data)->Code = Code;
241 ((PICMP_HEADER)NewPacket.Data)->Checksum = 0;
242
243 ICMPTransmit(&NewPacket, SendICMPComplete, NULL);
244 }
245
246 /* EOF */