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
18 VOID
SendICMPComplete(
21 NDIS_STATUS NdisStatus
)
23 * FUNCTION: ICMP datagram transmit completion handler
25 * Context = Pointer to context infomation (IP_PACKET)
26 * Packet = Pointer to NDIS packet
27 * NdisStatus = Status of transmit operation
29 * This routine is called by IP when a ICMP send completes
32 PIP_PACKET IPPacket
= (PIP_PACKET
)Context
;
34 TI_DbgPrint(MAX_TRACE
, ("Called.\n"));
36 TI_DbgPrint(MAX_TRACE
, ("Freeing NDIS packet (%X).\n", Packet
));
39 FreeNdisPacket(Packet
);
41 TI_DbgPrint(MAX_TRACE
, ("Freeing IP packet at %X.\n", IPPacket
));
43 PoolFreeBuffer(IPPacket
);
47 PIP_PACKET
PrepareICMPPacket(
49 PIP_ADDRESS Destination
,
52 * FUNCTION: Prepares an ICMP packet
54 * NTE = Pointer to net table entry to use
55 * Destination = Pointer to destination address
56 * DataSize = Size of dataarea
58 * Pointer to IP packet, NULL if there is not enough free resources
62 PNDIS_PACKET NdisPacket
;
63 PNDIS_BUFFER NdisBuffer
;
64 NDIS_STATUS NdisStatus
;
65 PIPv4_HEADER IPHeader
;
69 TI_DbgPrint(MAX_TRACE
, ("Called. DataSize = %d.\n", DataSize
));
71 /* Prepare ICMP packet */
72 IPPacket
= PoolAllocateBuffer(sizeof(IP_PACKET
));
76 TI_DbgPrint(MAX_TRACE
, ("IPPacket at %X.\n", IPPacket
));
78 Size
= MaxLLHeaderSize
+ sizeof(IPv4_HEADER
) +
79 sizeof(ICMP_HEADER
) + DataSize
;
80 DataBuffer
= ExAllocatePool(NonPagedPool
, Size
);
82 PoolFreeBuffer(IPPacket
);
86 TI_DbgPrint(MAX_TRACE
, ("Size = %d, Data at %X.\n", Size
, DataBuffer
));
88 /* Allocate NDIS packet */
89 NdisAllocatePacket(&NdisStatus
, &NdisPacket
, GlobalPacketPool
);
90 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
91 PoolFreeBuffer(IPPacket
);
92 ExFreePool(DataBuffer
);
96 TI_DbgPrint(MAX_TRACE
, ("NdisPacket at %X.\n", NdisPacket
));
98 /* Allocate NDIS buffer for maximum link level header and ICMP packet */
99 NdisAllocateBuffer(&NdisStatus
, &NdisBuffer
, GlobalBufferPool
,
101 if (NdisStatus
!= NDIS_STATUS_SUCCESS
) {
102 PoolFreeBuffer(IPPacket
);
103 NdisFreePacket(NdisPacket
);
104 ExFreePool(DataBuffer
);
108 TI_DbgPrint(MAX_TRACE
, ("NdisBuffer at %X.\n", NdisBuffer
));
110 /* Link NDIS buffer into packet */
111 NdisChainBufferAtFront(NdisPacket
, NdisBuffer
);
112 IPPacket
->NdisPacket
= NdisPacket
;
113 IPPacket
->Header
= (PVOID
)((ULONG_PTR
)DataBuffer
+ MaxLLHeaderSize
);
114 IPPacket
->Data
= (PVOID
)((ULONG_PTR
)DataBuffer
+ MaxLLHeaderSize
+ sizeof(IPv4_HEADER
));
116 IPPacket
->HeaderSize
= sizeof(IPv4_HEADER
);
117 IPPacket
->TotalSize
= Size
- MaxLLHeaderSize
;
118 RtlCopyMemory(&IPPacket
->DstAddr
, Destination
, sizeof(IP_ADDRESS
));
120 /* Build IPv4 header. FIXME: IPv4 only */
122 IPHeader
= (PIPv4_HEADER
)IPPacket
->Header
;
124 /* Version = 4, Length = 5 DWORDs */
125 IPHeader
->VerIHL
= 0x45;
126 /* Normal Type-of-Service */
128 /* Length of data and header */
129 IPHeader
->TotalLength
= WH2N((USHORT
)DataSize
+
130 sizeof(IPv4_HEADER
) + sizeof(ICMP_HEADER
));
132 IPHeader
->Id
= (USHORT
)Random();
133 /* One fragment at offset 0 */
134 IPHeader
->FlagsFragOfs
= 0;
135 /* Time-to-Live is 128 */
137 /* Internet Control Message Protocol */
138 IPHeader
->Protocol
= IPPROTO_ICMP
;
139 /* Checksum is 0 (for later calculation of this) */
140 IPHeader
->Checksum
= 0;
142 IPHeader
->SrcAddr
= NTE
->Address
->Address
.IPv4Address
;
143 /* Destination address */
144 IPHeader
->DstAddr
= Destination
->Address
.IPv4Address
;
146 /* Completion handler */
147 PC(NdisPacket
)->Complete
= SendICMPComplete
;
148 PC(NdisPacket
)->Context
= IPPacket
;
155 PNET_TABLE_ENTRY NTE
,
158 * FUNCTION: Receives an ICMP packet
160 * NTE = Pointer to net table entry which the packet was received on
161 * IPPacket = Pointer to an IP packet that was received
164 PICMP_HEADER ICMPHeader
;
165 PIP_PACKET NewPacket
;
169 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
171 ICMPHeader
= (PICMP_HEADER
)IPPacket
->Data
;
173 TI_DbgPrint(MID_TRACE
, ("Size = %d.\n", IPPacket
->TotalSize
));
175 TI_DbgPrint(MID_TRACE
, ("HeaderSize = %d.\n", IPPacket
->HeaderSize
));
177 TI_DbgPrint(MID_TRACE
, ("Type = %d.\n", ICMPHeader
->Type
));
179 TI_DbgPrint(MID_TRACE
, ("Code = %d.\n", ICMPHeader
->Code
));
181 TI_DbgPrint(MID_TRACE
, ("Checksum = %X.\n", ICMPHeader
->Checksum
));
183 /* Checksum ICMP header and data and compare */
184 Checksum
= DN2H(IPv4Checksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
, 0));
185 if (Checksum
!= 0xFFFF) {
186 TI_DbgPrint(MIN_TRACE
, ("Bad ICMP checksum (0x%X).\n", Checksum
));
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(MID_TRACE
, ("Echo reply sent.\n"));
211 TI_DbgPrint(MID_TRACE
, ("Discarded ICMP datagram of unknown type.\n"));
219 PNET_TABLE_ENTRY NTE
,
222 * FUNCTION: Transmits an ICMP packet
224 * NTE = Pointer to net table entry to use (NULL if don't care)
225 * IPPacket = Pointer to IP packet to transmit
228 PROUTE_CACHE_NODE RCN
;
230 TI_DbgPrint(MID_TRACE
, ("Called.\n"));
232 /* Calculate checksum of ICMP header and data */
233 ((PICMP_HEADER
)IPPacket
->Data
)->Checksum
= (USHORT
)
234 IPv4Checksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
, 0);
236 /* Get a route to the destination address */
237 if (RouteGetRouteToDestination(&IPPacket
->DstAddr
, NTE
, &RCN
) == IP_SUCCESS
) {
238 /* Send the packet */
239 if (IPSendDatagram(IPPacket
, RCN
) != STATUS_SUCCESS
) {
240 FreeNdisPacket(IPPacket
->NdisPacket
);
241 PoolFreeBuffer(IPPacket
);
243 /* We're done with the RCN */
244 DereferenceObject(RCN
);
246 TI_DbgPrint(MIN_TRACE
, ("RCN at 0x%X.\n", RCN
));
248 /* No route to destination (or no free resources) */
249 TI_DbgPrint(MIN_TRACE
, ("No route to destination address 0x%X.\n",
250 IPPacket
->DstAddr
.Address
.IPv4Address
));
252 FreeNdisPacket(IPPacket
->NdisPacket
);
253 PoolFreeBuffer(IPPacket
);
259 PNET_TABLE_ENTRY NTE
,
264 * FUNCTION: Transmits an ICMP packet in response to an incoming packet
266 * NTE = Pointer to net table entry to use
267 * IPPacket = Pointer to IP packet that was received
268 * Type = ICMP message type
269 * Code = ICMP message code
271 * We have received a packet from someone and is unable to
272 * process it due to error(s) in the packet or we have run out
273 * of resources. We transmit an ICMP message to the host to
274 * notify him of the problem
278 PIP_PACKET NewPacket
;
280 TI_DbgPrint(MID_TRACE
, ("Called (Type=%d, Code=%d).\n", Type
, Code
));
282 DataSize
= IPPacket
->TotalSize
;
283 if ((DataSize
) > (576 - sizeof(IPv4_HEADER
) - sizeof(ICMP_HEADER
)))
286 NewPacket
= PrepareICMPPacket(NTE
, &IPPacket
->SrcAddr
, DataSize
);
290 RtlCopyMemory((PVOID
)((ULONG_PTR
)NewPacket
->Data
+ sizeof(ICMP_HEADER
)),
291 IPPacket
->Header
, DataSize
);
292 ((PICMP_HEADER
)NewPacket
->Data
)->Type
= Type
;
293 ((PICMP_HEADER
)NewPacket
->Data
)->Code
= Code
;
294 ((PICMP_HEADER
)NewPacket
->Data
)->Checksum
= 0;
296 ICMPTransmit(NTE
, NewPacket
);