2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
5 * PURPOSE: Internet Control Message Protocol routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 01/08-2000 Created
19 VOID
SendICMPComplete(
22 NDIS_STATUS NdisStatus
)
24 * FUNCTION: ICMP datagram transmit completion handler
26 * Context = Pointer to context infomation (IP_PACKET)
27 * Packet = Pointer to NDIS packet
28 * NdisStatus = Status of transmit operation
30 * This routine is called by IP when a ICMP send completes
33 PIP_PACKET IPPacket
= (PIP_PACKET
)Context
;
35 TI_DbgPrint(DEBUG_ICMP
, ("Freeing NDIS packet (%X).\n", Packet
));
38 FreeNdisPacket(Packet
);
40 TI_DbgPrint(DEBUG_ICMP
, ("Freeing IP packet at %X.\n", IPPacket
));
42 PoolFreeBuffer(IPPacket
);
46 PIP_PACKET
PrepareICMPPacket(
48 PIP_ADDRESS Destination
,
51 * FUNCTION: Prepares an ICMP packet
53 * NTE = Pointer to net table entry to use
54 * Destination = Pointer to destination address
55 * DataSize = Size of dataarea
57 * Pointer to IP packet, NULL if there is not enough free resources
61 PNDIS_PACKET NdisPacket
;
62 PNDIS_BUFFER NdisBuffer
;
63 NDIS_STATUS NdisStatus
;
64 PIPv4_HEADER IPHeader
;
68 TI_DbgPrint(DEBUG_ICMP
, ("Called. DataSize (%d).\n", DataSize
));
70 /* Prepare ICMP packet */
71 IPPacket
= PoolAllocateBuffer(sizeof(IP_PACKET
));
75 TI_DbgPrint(DEBUG_ICMP
, ("IPPacket at (0x%X).\n", IPPacket
));
77 /* No special flags */
80 Size
= MaxLLHeaderSize
+ sizeof(IPv4_HEADER
) +
81 sizeof(ICMP_HEADER
) + DataSize
;
82 DataBuffer
= ExAllocatePool(NonPagedPool
, Size
);
84 PoolFreeBuffer(IPPacket
);
88 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d). Data at (0x%X).\n", Size
, DataBuffer
));
90 /* Allocate NDIS packet */
91 NdisAllocatePacket(&NdisStatus
, &NdisPacket
, GlobalPacketPool
);
92 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
93 PoolFreeBuffer(IPPacket
);
94 ExFreePool(DataBuffer
);
98 TI_DbgPrint(MAX_TRACE
, ("NdisPacket at (0x%X).\n", NdisPacket
));
100 /* Allocate NDIS buffer for maximum link level header and ICMP packet */
101 NdisAllocateBuffer(&NdisStatus
, &NdisBuffer
, GlobalBufferPool
,
103 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
104 PoolFreeBuffer(IPPacket
);
105 NdisFreePacket(NdisPacket
);
106 ExFreePool(DataBuffer
);
110 TI_DbgPrint(MAX_TRACE
, ("NdisBuffer at (0x%X).\n", NdisBuffer
));
112 /* Link NDIS buffer into packet */
113 NdisChainBufferAtFront(NdisPacket
, NdisBuffer
);
114 IPPacket
->NdisPacket
= NdisPacket
;
115 IPPacket
->Header
= (PVOID
)((ULONG_PTR
)DataBuffer
+ MaxLLHeaderSize
);
116 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)DataBuffer
+ MaxLLHeaderSize
+ sizeof(IPv4_HEADER
));
118 IPPacket
->HeaderSize
= sizeof(IPv4_HEADER
);
119 IPPacket
->TotalSize
= Size
- MaxLLHeaderSize
;
120 RtlCopyMemory(&IPPacket
->DstAddr
, Destination
, sizeof(IP_ADDRESS
));
122 /* Build IPv4 header. FIXME: IPv4 only */
124 IPHeader
= (PIPv4_HEADER
)IPPacket
->Header
;
126 /* Version = 4, Length = 5 DWORDs */
127 IPHeader
->VerIHL
= 0x45;
128 /* Normal Type-of-Service */
130 /* Length of data and header */
131 IPHeader
->TotalLength
= WH2N((USHORT
)DataSize
+
132 sizeof(IPv4_HEADER
) + sizeof(ICMP_HEADER
));
134 IPHeader
->Id
= (USHORT
)Random();
135 /* One fragment at offset 0 */
136 IPHeader
->FlagsFragOfs
= 0;
137 /* Time-to-Live is 128 */
139 /* Internet Control Message Protocol */
140 IPHeader
->Protocol
= IPPROTO_ICMP
;
141 /* Checksum is 0 (for later calculation of this) */
142 IPHeader
->Checksum
= 0;
144 IPHeader
->SrcAddr
= NTE
->Address
->Address
.IPv4Address
;
145 /* Destination address */
146 IPHeader
->DstAddr
= Destination
->Address
.IPv4Address
;
148 /* Completion handler */
149 PC(NdisPacket
)->Complete
= SendICMPComplete
;
150 PC(NdisPacket
)->Context
= IPPacket
;
157 PNET_TABLE_ENTRY NTE
,
160 * FUNCTION: Receives an ICMP packet
162 * NTE = Pointer to net table entry which the packet was received on
163 * IPPacket = Pointer to an IP packet that was received
166 PICMP_HEADER ICMPHeader
;
167 PIP_PACKET NewPacket
;
170 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
172 ICMPHeader
= (PICMP_HEADER
)IPPacket
->Data
;
174 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d).\n", IPPacket
->TotalSize
));
176 TI_DbgPrint(DEBUG_ICMP
, ("HeaderSize (%d).\n", IPPacket
->HeaderSize
));
178 TI_DbgPrint(DEBUG_ICMP
, ("Type (%d).\n", ICMPHeader
->Type
));
180 TI_DbgPrint(DEBUG_ICMP
, ("Code (%d).\n", ICMPHeader
->Code
));
182 TI_DbgPrint(DEBUG_ICMP
, ("Checksum (0x%X).\n", ICMPHeader
->Checksum
));
184 /* Checksum ICMP header and data */
185 if (!CorrectChecksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
)) {
186 TI_DbgPrint(DEBUG_ICMP
, ("Bad ICMP checksum.\n"));
191 switch (ICMPHeader
->Type
) {
192 case ICMP_TYPE_ECHO_REQUEST
:
193 /* Reply with an ICMP echo reply message */
194 DataSize
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
- sizeof(ICMP_HEADER
);
195 NewPacket
= PrepareICMPPacket(NTE
, &IPPacket
->SrcAddr
, DataSize
);
199 /* Copy ICMP header and data into new packet */
200 RtlCopyMemory(NewPacket
->Data
, IPPacket
->Data
, DataSize
+ sizeof(ICMP_HEADER
));
201 ((PICMP_HEADER
)NewPacket
->Data
)->Type
= ICMP_TYPE_ECHO_REPLY
;
202 ((PICMP_HEADER
)NewPacket
->Data
)->Code
= 0;
203 ((PICMP_HEADER
)NewPacket
->Data
)->Checksum
= 0;
205 ICMPTransmit(NTE
, NewPacket
);
207 TI_DbgPrint(DEBUG_ICMP
, ("Echo reply sent.\n"));
210 case ICMP_TYPE_ECHO_REPLY
:
214 TI_DbgPrint(DEBUG_ICMP
, ("Discarded ICMP datagram of unknown type %d.\n",
220 /* Send datagram up the protocol stack */
221 RawIPReceive(NTE
, IPPacket
);
226 PNET_TABLE_ENTRY NTE
,
229 * FUNCTION: Transmits an ICMP packet
231 * NTE = Pointer to net table entry to use (NULL if don't care)
232 * IPPacket = Pointer to IP packet to transmit
235 PROUTE_CACHE_NODE RCN
;
237 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
239 /* Calculate checksum of ICMP header and data */
240 ((PICMP_HEADER
)IPPacket
->Data
)->Checksum
= (USHORT
)
241 IPv4Checksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
, 0);
243 /* Get a route to the destination address */
244 if (RouteGetRouteToDestination(&IPPacket
->DstAddr
, NTE
, &RCN
) == IP_SUCCESS
) {
245 /* Send the packet */
246 if (IPSendDatagram(IPPacket
, RCN
) != STATUS_SUCCESS
) {
247 FreeNdisPacket(IPPacket
->NdisPacket
);
248 PoolFreeBuffer(IPPacket
);
250 /* We're done with the RCN */
251 DereferenceObject(RCN
);
253 TI_DbgPrint(MIN_TRACE
, ("RCN at (0x%X).\n", RCN
));
255 /* No route to destination (or no free resources) */
256 TI_DbgPrint(DEBUG_ICMP
, ("No route to destination address 0x%X.\n",
257 IPPacket
->DstAddr
.Address
.IPv4Address
));
259 FreeNdisPacket(IPPacket
->NdisPacket
);
260 PoolFreeBuffer(IPPacket
);
266 PNET_TABLE_ENTRY NTE
,
271 * FUNCTION: Transmits an ICMP packet in response to an incoming packet
273 * NTE = Pointer to net table entry to use
274 * IPPacket = Pointer to IP packet that was received
275 * Type = ICMP message type
276 * Code = ICMP message code
278 * We have received a packet from someone and is unable to
279 * process it due to error(s) in the packet or we have run out
280 * of resources. We transmit an ICMP message to the host to
281 * notify him of the problem
285 PIP_PACKET NewPacket
;
287 TI_DbgPrint(DEBUG_ICMP
, ("Called. Type (%d) Code (%d).\n", Type
, Code
));
289 DataSize
= IPPacket
->TotalSize
;
290 if ((DataSize
) > (576 - sizeof(IPv4_HEADER
) - sizeof(ICMP_HEADER
)))
293 NewPacket
= PrepareICMPPacket(NTE
, &IPPacket
->SrcAddr
, DataSize
);
295 TI_DbgPrint(MIN_TRACE
, ("Insufficient resources.\n"));
299 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewPacket
->Data
+ sizeof(ICMP_HEADER
)),
300 IPPacket
->Header
, DataSize
);
301 ((PICMP_HEADER
)NewPacket
->Data
)->Type
= Type
;
302 ((PICMP_HEADER
)NewPacket
->Data
)->Code
= Code
;
303 ((PICMP_HEADER
)NewPacket
->Data
)->Checksum
= 0;
305 ICMPTransmit(NTE
, NewPacket
);