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
13 NTSTATUS
ICMPStartup()
15 IPRegisterProtocol(IPPROTO_ICMP
, ICMPReceive
);
17 return STATUS_SUCCESS
;
20 NTSTATUS
ICMPShutdown()
22 IPRegisterProtocol(IPPROTO_ICMP
, NULL
);
24 return STATUS_SUCCESS
;
27 VOID
SendICMPComplete(
30 NDIS_STATUS NdisStatus
)
32 * FUNCTION: ICMP datagram transmit completion handler
34 * Context = Pointer to context infomation (IP_PACKET)
35 * Packet = Pointer to NDIS packet
36 * NdisStatus = Status of transmit operation
38 * This routine is called by IP when a ICMP send completes
41 TI_DbgPrint(DEBUG_ICMP
, ("Freeing NDIS packet (%X).\n", Packet
));
44 FreeNdisPacket(Packet
);
46 TI_DbgPrint(DEBUG_ICMP
, ("Done\n"));
50 BOOLEAN
PrepareICMPPacket(
51 PIP_INTERFACE Interface
,
53 PIP_ADDRESS Destination
,
57 * FUNCTION: Prepares an ICMP packet
59 * NTE = Pointer to net table entry to use
60 * Destination = Pointer to destination address
61 * DataSize = Size of dataarea
63 * Pointer to IP packet, NULL if there is not enough free resources
66 PNDIS_PACKET NdisPacket
;
67 NDIS_STATUS NdisStatus
;
68 PIPv4_HEADER IPHeader
;
71 TI_DbgPrint(DEBUG_ICMP
, ("Called. DataSize (%d).\n", DataSize
));
73 IPInitializePacket(IPPacket
, IP_ADDRESS_V4
);
75 /* No special flags */
78 Size
= sizeof(IPv4_HEADER
) + DataSize
;
80 /* Allocate NDIS packet */
81 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
, Size
);
83 if( !NT_SUCCESS(NdisStatus
) ) return FALSE
;
85 IPPacket
->NdisPacket
= NdisPacket
;
87 GetDataPtr( IPPacket
->NdisPacket
, 0,
88 (PCHAR
*)&IPPacket
->Header
, &IPPacket
->ContigSize
);
90 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d). Data at (0x%X).\n", Size
, Data
));
91 TI_DbgPrint(DEBUG_ICMP
, ("NdisPacket at (0x%X).\n", NdisPacket
));
93 IPPacket
->HeaderSize
= sizeof(IPv4_HEADER
);
94 IPPacket
->TotalSize
= Size
;
95 IPPacket
->Data
= ((PCHAR
)IPPacket
->Header
) + IPPacket
->HeaderSize
;
97 TI_DbgPrint(DEBUG_ICMP
, ("Copying Address: %x -> %x\n",
98 &IPPacket
->DstAddr
, Destination
));
100 RtlCopyMemory(&IPPacket
->DstAddr
, Destination
, sizeof(IP_ADDRESS
));
101 RtlCopyMemory(IPPacket
->Data
, Data
, DataSize
);
103 /* Build IPv4 header. FIXME: IPv4 only */
105 IPHeader
= (PIPv4_HEADER
)IPPacket
->Header
;
107 /* Version = 4, Length = 5 DWORDs */
108 IPHeader
->VerIHL
= 0x45;
109 /* Normal Type-of-Service */
111 /* Length of data and header */
112 IPHeader
->TotalLength
= WH2N((USHORT
)DataSize
+ sizeof(IPv4_HEADER
));
114 IPHeader
->Id
= (USHORT
)Random();
115 /* One fragment at offset 0 */
116 IPHeader
->FlagsFragOfs
= 0;
117 /* Time-to-Live is 128 */
119 /* Internet Control Message Protocol */
120 IPHeader
->Protocol
= IPPROTO_ICMP
;
121 /* Checksum is 0 (for later calculation of this) */
122 IPHeader
->Checksum
= 0;
124 IPHeader
->SrcAddr
= Interface
->Unicast
.Address
.IPv4Address
;
125 /* Destination address */
126 IPHeader
->DstAddr
= Destination
->Address
.IPv4Address
;
129 TI_DbgPrint(MID_TRACE
,("Leaving\n"));
134 VOID ICMPSendPacketComplete
135 ( PVOID Context
, PNDIS_PACKET Packet
, NDIS_STATUS Status
) {
136 FreeNdisPacket( Packet
);
139 NTSTATUS
ICMPSendDatagram(
140 PADDRESS_FILE AddrFile
,
141 PTDI_CONNECTION_INFORMATION ConnInfo
,
146 * FUNCTION: Sends an ICMP datagram to a remote address
148 * Request = Pointer to TDI request
149 * ConnInfo = Pointer to connection information
150 * Buffer = Pointer to NDIS buffer with data
151 * DataSize = Size in bytes of data to be sent
153 * Status of operation
157 PTA_IP_ADDRESS RemoteAddressTa
= (PTA_IP_ADDRESS
)ConnInfo
->RemoteAddress
;
158 IP_ADDRESS RemoteAddress
, LocalAddress
;
161 PNEIGHBOR_CACHE_ENTRY NCE
;
164 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
165 AddrFile
, ConnInfo
, BufferData
, DataSize
));
166 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
168 switch( RemoteAddressTa
->Address
[0].AddressType
) {
169 case TDI_ADDRESS_TYPE_IP
:
170 RemoteAddress
.Type
= IP_ADDRESS_V4
;
171 RemoteAddress
.Address
.IPv4Address
=
172 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
173 RemotePort
= RemoteAddressTa
->Address
[0].Address
[0].sin_port
;
177 return STATUS_UNSUCCESSFUL
;
180 TI_DbgPrint(MID_TRACE
,("About to get route to destination\n"));
182 LockObject(AddrFile
, &OldIrql
);
184 LocalAddress
= AddrFile
->Address
;
185 if (AddrIsUnspecified(&LocalAddress
))
187 /* If the local address is unspecified (0),
188 * then use the unicast address of the
189 * interface we're sending over
191 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
)))
193 UnlockObject(AddrFile
, OldIrql
);
194 return STATUS_NETWORK_UNREACHABLE
;
197 LocalAddress
= NCE
->Interface
->Unicast
;
201 if(!(NCE
= NBLocateNeighbor( &LocalAddress
)))
203 UnlockObject(AddrFile
, OldIrql
);
204 return STATUS_INVALID_PARAMETER
;
208 Status
= PrepareICMPPacket( NCE
->Interface
,
214 if( !NT_SUCCESS(Status
) )
216 UnlockObject(AddrFile
, OldIrql
);
220 TI_DbgPrint(MID_TRACE
,("About to send datagram\n"));
222 if (!NT_SUCCESS(Status
= IPSendDatagram( &Packet
, NCE
, ICMPSendPacketComplete
, NULL
)))
224 UnlockObject(AddrFile
, OldIrql
);
225 FreeNdisPacket(Packet
.NdisPacket
);
229 TI_DbgPrint(MID_TRACE
,("Leaving\n"));
231 UnlockObject(AddrFile
, OldIrql
);
233 return STATUS_SUCCESS
;
239 PIP_INTERFACE Interface
,
242 * FUNCTION: Receives an ICMP packet
244 * NTE = Pointer to net table entry which the packet was received on
245 * IPPacket = Pointer to an IP packet that was received
248 PICMP_HEADER ICMPHeader
;
250 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
252 ICMPHeader
= (PICMP_HEADER
)IPPacket
->Data
;
254 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d).\n", IPPacket
->TotalSize
));
256 TI_DbgPrint(DEBUG_ICMP
, ("HeaderSize (%d).\n", IPPacket
->HeaderSize
));
258 TI_DbgPrint(DEBUG_ICMP
, ("Type (%d).\n", ICMPHeader
->Type
));
260 TI_DbgPrint(DEBUG_ICMP
, ("Code (%d).\n", ICMPHeader
->Code
));
262 TI_DbgPrint(DEBUG_ICMP
, ("Checksum (0x%X).\n", ICMPHeader
->Checksum
));
264 RawIpReceive(Interface
, IPPacket
);
266 /* Checksum ICMP header and data */
267 if (!IPv4CorrectChecksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
)) {
268 TI_DbgPrint(DEBUG_ICMP
, ("Bad ICMP checksum.\n"));
273 switch (ICMPHeader
->Type
) {
274 case ICMP_TYPE_ECHO_REQUEST
:
275 ICMPReply( Interface
, IPPacket
, ICMP_TYPE_ECHO_REPLY
, 0 );
278 case ICMP_TYPE_ECHO_REPLY
:
282 TI_DbgPrint(DEBUG_ICMP
,
283 ("Discarded ICMP datagram of unknown type %d.\n",
293 PIP_TRANSMIT_COMPLETE Complete
,
296 * FUNCTION: Transmits an ICMP packet
298 * NTE = Pointer to net table entry to use (NULL if don't care)
299 * IPPacket = Pointer to IP packet to transmit
302 PNEIGHBOR_CACHE_ENTRY NCE
;
305 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
307 /* Calculate checksum of ICMP header and data */
308 ((PICMP_HEADER
)IPPacket
->Data
)->Checksum
= (USHORT
)
309 IPv4Checksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
, 0);
311 /* Get a route to the destination address */
312 if ((NCE
= RouteGetRouteToDestination(&IPPacket
->DstAddr
))) {
313 /* Send the packet */
314 Status
= IPSendDatagram(IPPacket
, NCE
, Complete
, Context
);
315 if (!NT_SUCCESS(Status
))
317 Complete(Context
, IPPacket
->NdisPacket
, Status
);
320 /* No route to destination (or no free resources) */
321 TI_DbgPrint(DEBUG_ICMP
, ("No route to destination address 0x%X.\n",
322 IPPacket
->DstAddr
.Address
.IPv4Address
));
324 Complete( Context
, IPPacket
->NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
330 PIP_INTERFACE Interface
,
335 * FUNCTION: Transmits an ICMP packet in response to an incoming packet
337 * NTE = Pointer to net table entry to use
338 * IPPacket = Pointer to IP packet that was received
339 * Type = ICMP message type
340 * Code = ICMP message code
342 * We have received a packet from someone and is unable to
343 * process it due to error(s) in the packet or we have run out
344 * of resources. We transmit an ICMP message to the host to
345 * notify him of the problem
349 IP_PACKET NewPacket
= *IPPacket
;
351 TI_DbgPrint(DEBUG_ICMP
, ("Called. Type (%d) Code (%d).\n", Type
, Code
));
353 DataSize
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
;
355 if( !PrepareICMPPacket(Interface
, &NewPacket
, &IPPacket
->SrcAddr
,
356 IPPacket
->Data
, DataSize
) ) return;
358 ((PICMP_HEADER
)NewPacket
.Data
)->Type
= Type
;
359 ((PICMP_HEADER
)NewPacket
.Data
)->Code
= Code
;
360 ((PICMP_HEADER
)NewPacket
.Data
)->Checksum
= 0;
362 ICMPTransmit(&NewPacket
, SendICMPComplete
, NULL
);