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 BOOLEAN
PrepareICMPPacket(
28 PADDRESS_FILE AddrFile
,
29 PIP_INTERFACE Interface
,
31 PIP_ADDRESS Destination
,
35 * FUNCTION: Prepares an ICMP packet
37 * NTE = Pointer to net table entry to use
38 * Destination = Pointer to destination address
39 * DataSize = Size of dataarea
41 * Pointer to IP packet, NULL if there is not enough free resources
44 PNDIS_PACKET NdisPacket
;
45 NDIS_STATUS NdisStatus
;
46 PIPv4_HEADER IPHeader
;
49 TI_DbgPrint(DEBUG_ICMP
, ("Called. DataSize (%d).\n", DataSize
));
51 IPInitializePacket(IPPacket
, IP_ADDRESS_V4
);
53 /* No special flags */
56 Size
= sizeof(IPv4_HEADER
) + DataSize
;
58 /* Allocate NDIS packet */
59 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
, Size
);
61 if( !NT_SUCCESS(NdisStatus
) ) return FALSE
;
63 IPPacket
->NdisPacket
= NdisPacket
;
64 IPPacket
->MappedHeader
= TRUE
;
66 GetDataPtr( IPPacket
->NdisPacket
, 0,
67 (PCHAR
*)&IPPacket
->Header
, &IPPacket
->TotalSize
);
68 ASSERT(IPPacket
->TotalSize
== Size
);
70 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d). Data at (0x%X).\n", Size
, Data
));
71 TI_DbgPrint(DEBUG_ICMP
, ("NdisPacket at (0x%X).\n", NdisPacket
));
73 IPPacket
->HeaderSize
= sizeof(IPv4_HEADER
);
74 IPPacket
->Data
= ((PCHAR
)IPPacket
->Header
) + IPPacket
->HeaderSize
;
76 TI_DbgPrint(DEBUG_ICMP
, ("Copying Address: %x -> %x\n",
77 &IPPacket
->DstAddr
, Destination
));
79 RtlCopyMemory(&IPPacket
->DstAddr
, Destination
, sizeof(IP_ADDRESS
));
80 RtlCopyMemory(IPPacket
->Data
, Data
, DataSize
);
82 /* Build IPv4 header. FIXME: IPv4 only */
84 IPHeader
= (PIPv4_HEADER
)IPPacket
->Header
;
86 /* Version = 4, Length = 5 DWORDs */
87 IPHeader
->VerIHL
= 0x45;
88 /* Normal Type-of-Service */
90 /* Length of data and header */
91 IPHeader
->TotalLength
= WH2N((USHORT
)DataSize
+ sizeof(IPv4_HEADER
));
93 IPHeader
->Id
= (USHORT
)Random();
94 /* One fragment at offset 0 */
95 IPHeader
->FlagsFragOfs
= 0;
98 IPHeader
->Ttl
= AddrFile
->TTL
;
101 /* Internet Control Message Protocol */
102 IPHeader
->Protocol
= IPPROTO_ICMP
;
103 /* Checksum is 0 (for later calculation of this) */
104 IPHeader
->Checksum
= 0;
106 IPHeader
->SrcAddr
= Interface
->Unicast
.Address
.IPv4Address
;
107 /* Destination address */
108 IPHeader
->DstAddr
= Destination
->Address
.IPv4Address
;
111 TI_DbgPrint(MID_TRACE
,("Leaving\n"));
116 NTSTATUS
ICMPSendDatagram(
117 PADDRESS_FILE AddrFile
,
118 PTDI_CONNECTION_INFORMATION ConnInfo
,
123 * FUNCTION: Sends an ICMP datagram to a remote address
125 * Request = Pointer to TDI request
126 * ConnInfo = Pointer to connection information
127 * Buffer = Pointer to NDIS buffer with data
128 * DataSize = Size in bytes of data to be sent
130 * Status of operation
134 PTA_IP_ADDRESS RemoteAddressTa
= (PTA_IP_ADDRESS
)ConnInfo
->RemoteAddress
;
135 IP_ADDRESS RemoteAddress
, LocalAddress
;
137 PNEIGHBOR_CACHE_ENTRY NCE
;
140 TI_DbgPrint(MID_TRACE
,("Sending Datagram(%x %x %x %d)\n",
141 AddrFile
, ConnInfo
, BufferData
, DataSize
));
142 TI_DbgPrint(MID_TRACE
,("RemoteAddressTa: %x\n", RemoteAddressTa
));
144 switch( RemoteAddressTa
->Address
[0].AddressType
) {
145 case TDI_ADDRESS_TYPE_IP
:
146 RemoteAddress
.Type
= IP_ADDRESS_V4
;
147 RemoteAddress
.Address
.IPv4Address
=
148 RemoteAddressTa
->Address
[0].Address
[0].in_addr
;
152 return STATUS_UNSUCCESSFUL
;
155 TI_DbgPrint(MID_TRACE
,("About to get route to destination\n"));
157 LockObject(AddrFile
, &OldIrql
);
159 LocalAddress
= AddrFile
->Address
;
160 if (AddrIsUnspecified(&LocalAddress
))
162 /* If the local address is unspecified (0),
163 * then use the unicast address of the
164 * interface we're sending over
166 if(!(NCE
= RouteGetRouteToDestination( &RemoteAddress
)))
168 UnlockObject(AddrFile
, OldIrql
);
169 return STATUS_NETWORK_UNREACHABLE
;
172 LocalAddress
= NCE
->Interface
->Unicast
;
176 if(!(NCE
= NBLocateNeighbor( &LocalAddress
)))
178 UnlockObject(AddrFile
, OldIrql
);
179 return STATUS_INVALID_PARAMETER
;
183 Status
= PrepareICMPPacket( AddrFile
,
190 UnlockObject(AddrFile
, OldIrql
);
192 if( !NT_SUCCESS(Status
) )
195 TI_DbgPrint(MID_TRACE
,("About to send datagram\n"));
197 Status
= IPSendDatagram(&Packet
, NCE
);
198 if (!NT_SUCCESS(Status
))
201 *DataUsed
= DataSize
;
203 TI_DbgPrint(MID_TRACE
,("Leaving\n"));
205 return STATUS_SUCCESS
;
210 PIP_INTERFACE Interface
,
213 * FUNCTION: Receives an ICMP packet
215 * NTE = Pointer to net table entry which the packet was received on
216 * IPPacket = Pointer to an IP packet that was received
219 PICMP_HEADER ICMPHeader
;
221 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
223 ICMPHeader
= (PICMP_HEADER
)IPPacket
->Data
;
225 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d).\n", IPPacket
->TotalSize
));
227 TI_DbgPrint(DEBUG_ICMP
, ("HeaderSize (%d).\n", IPPacket
->HeaderSize
));
229 TI_DbgPrint(DEBUG_ICMP
, ("Type (%d).\n", ICMPHeader
->Type
));
231 TI_DbgPrint(DEBUG_ICMP
, ("Code (%d).\n", ICMPHeader
->Code
));
233 TI_DbgPrint(DEBUG_ICMP
, ("Checksum (0x%X).\n", ICMPHeader
->Checksum
));
235 /* Checksum ICMP header and data */
236 if (!IPv4CorrectChecksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
)) {
237 TI_DbgPrint(DEBUG_ICMP
, ("Bad ICMP checksum.\n"));
242 RawIpReceive(Interface
, IPPacket
);
244 switch (ICMPHeader
->Type
) {
245 case ICMP_TYPE_ECHO_REQUEST
:
246 ICMPReply( Interface
, IPPacket
, ICMP_TYPE_ECHO_REPLY
, 0 );
249 case ICMP_TYPE_ECHO_REPLY
:
253 TI_DbgPrint(DEBUG_ICMP
,
254 ("Discarded ICMP datagram of unknown type %d.\n",
264 PIP_TRANSMIT_COMPLETE Complete
,
267 * FUNCTION: Transmits an ICMP packet
269 * NTE = Pointer to net table entry to use (NULL if don't care)
270 * IPPacket = Pointer to IP packet to transmit
273 PNEIGHBOR_CACHE_ENTRY NCE
;
275 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
277 /* Calculate checksum of ICMP header and data */
278 ((PICMP_HEADER
)IPPacket
->Data
)->Checksum
= (USHORT
)
279 IPv4Checksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
, 0);
281 /* Get a route to the destination address */
282 if ((NCE
= RouteGetRouteToDestination(&IPPacket
->DstAddr
))) {
283 /* Send the packet */
284 IPSendDatagram(IPPacket
, NCE
);
286 /* No route to destination (or no free resources) */
287 TI_DbgPrint(DEBUG_ICMP
, ("No route to destination address 0x%X.\n",
288 IPPacket
->DstAddr
.Address
.IPv4Address
));
289 IPPacket
->Free(IPPacket
);
295 PIP_INTERFACE Interface
,
300 * FUNCTION: Transmits an ICMP packet in response to an incoming packet
302 * NTE = Pointer to net table entry to use
303 * IPPacket = Pointer to IP packet that was received
304 * Type = ICMP message type
305 * Code = ICMP message code
307 * We have received a packet from someone and is unable to
308 * process it due to error(s) in the packet or we have run out
309 * of resources. We transmit an ICMP message to the host to
310 * notify him of the problem
316 TI_DbgPrint(DEBUG_ICMP
, ("Called. Type (%d) Code (%d).\n", Type
, Code
));
318 DataSize
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
;
320 if( !PrepareICMPPacket(NULL
, Interface
, &NewPacket
, &IPPacket
->SrcAddr
,
321 IPPacket
->Data
, DataSize
) ) return;
323 ((PICMP_HEADER
)NewPacket
.Data
)->Type
= Type
;
324 ((PICMP_HEADER
)NewPacket
.Data
)->Code
= Code
;
325 ((PICMP_HEADER
)NewPacket
.Data
)->Checksum
= 0;
327 ICMPTransmit(&NewPacket
, NULL
, NULL
);