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
14 VOID
SendICMPComplete(
17 NDIS_STATUS NdisStatus
)
19 * FUNCTION: ICMP datagram transmit completion handler
21 * Context = Pointer to context infomation (IP_PACKET)
22 * Packet = Pointer to NDIS packet
23 * NdisStatus = Status of transmit operation
25 * This routine is called by IP when a ICMP send completes
28 TI_DbgPrint(DEBUG_ICMP
, ("Freeing NDIS packet (%X).\n", Packet
));
31 FreeNdisPacket(Packet
);
33 TI_DbgPrint(DEBUG_ICMP
, ("Done\n"));
37 PIP_PACKET
PrepareICMPPacket(
38 PIP_INTERFACE Interface
,
40 PIP_ADDRESS Destination
,
44 * FUNCTION: Prepares an ICMP packet
46 * NTE = Pointer to net table entry to use
47 * Destination = Pointer to destination address
48 * DataSize = Size of dataarea
50 * Pointer to IP packet, NULL if there is not enough free resources
53 PNDIS_PACKET NdisPacket
;
54 NDIS_STATUS NdisStatus
;
55 PIPv4_HEADER IPHeader
;
58 TI_DbgPrint(DEBUG_ICMP
, ("Called. DataSize (%d).\n", DataSize
));
60 /* No special flags */
63 Size
= MaxLLHeaderSize
+ sizeof(IPv4_HEADER
) + DataSize
;
65 /* Allocate NDIS packet */
66 NdisStatus
= AllocatePacketWithBuffer( &NdisPacket
, NULL
, Size
);
68 if( !NT_SUCCESS(NdisStatus
) ) return NULL
;
70 IPPacket
->NdisPacket
= NdisPacket
;
72 GetDataPtr( IPPacket
->NdisPacket
, MaxLLHeaderSize
,
73 (PCHAR
*)&IPPacket
->Header
, &IPPacket
->ContigSize
);
75 IPPacket
->Data
= ((PCHAR
)IPPacket
->Header
) + IPPacket
->HeaderSize
;
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
));
80 IPPacket
->HeaderSize
= sizeof(IPv4_HEADER
);
81 IPPacket
->TotalSize
= Size
- MaxLLHeaderSize
;
83 TI_DbgPrint(DEBUG_ICMP
, ("Copying Address: %x -> %x\n",
84 &IPPacket
->DstAddr
, Destination
));
86 RtlCopyMemory(&IPPacket
->DstAddr
, Destination
, sizeof(IP_ADDRESS
));
87 RtlCopyMemory(IPPacket
->Data
, Data
, DataSize
);
89 /* Build IPv4 header. FIXME: IPv4 only */
91 IPHeader
= (PIPv4_HEADER
)IPPacket
->Header
;
93 /* Version = 4, Length = 5 DWORDs */
94 IPHeader
->VerIHL
= 0x45;
95 /* Normal Type-of-Service */
97 /* Length of data and header */
98 IPHeader
->TotalLength
= WH2N((USHORT
)DataSize
+ sizeof(IPv4_HEADER
));
100 IPHeader
->Id
= (USHORT
)Random();
101 /* One fragment at offset 0 */
102 IPHeader
->FlagsFragOfs
= 0;
103 /* Time-to-Live is 128 */
105 /* Internet Control Message Protocol */
106 IPHeader
->Protocol
= IPPROTO_ICMP
;
107 /* Checksum is 0 (for later calculation of this) */
108 IPHeader
->Checksum
= 0;
110 IPHeader
->SrcAddr
= Interface
->Unicast
.Address
.IPv4Address
;
111 /* Destination address */
112 IPHeader
->DstAddr
= Destination
->Address
.IPv4Address
;
115 TI_DbgPrint(MID_TRACE
,("Leaving\n"));
122 PIP_INTERFACE Interface
,
125 * FUNCTION: Receives an ICMP packet
127 * NTE = Pointer to net table entry which the packet was received on
128 * IPPacket = Pointer to an IP packet that was received
131 PICMP_HEADER ICMPHeader
;
133 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
135 ICMPHeader
= (PICMP_HEADER
)IPPacket
->Data
;
137 TI_DbgPrint(DEBUG_ICMP
, ("Size (%d).\n", IPPacket
->TotalSize
));
139 TI_DbgPrint(DEBUG_ICMP
, ("HeaderSize (%d).\n", IPPacket
->HeaderSize
));
141 TI_DbgPrint(DEBUG_ICMP
, ("Type (%d).\n", ICMPHeader
->Type
));
143 TI_DbgPrint(DEBUG_ICMP
, ("Code (%d).\n", ICMPHeader
->Code
));
145 TI_DbgPrint(DEBUG_ICMP
, ("Checksum (0x%X).\n", ICMPHeader
->Checksum
));
147 /* Checksum ICMP header and data */
148 if (!IPv4CorrectChecksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
)) {
149 TI_DbgPrint(DEBUG_ICMP
, ("Bad ICMP checksum.\n"));
154 switch (ICMPHeader
->Type
) {
155 case ICMP_TYPE_ECHO_REQUEST
:
156 ICMPReply( Interface
, IPPacket
, ICMP_TYPE_ECHO_REPLY
, 0 );
159 case ICMP_TYPE_ECHO_REPLY
:
163 TI_DbgPrint(DEBUG_ICMP
,
164 ("Discarded ICMP datagram of unknown type %d.\n",
174 PIP_TRANSMIT_COMPLETE Complete
,
177 * FUNCTION: Transmits an ICMP packet
179 * NTE = Pointer to net table entry to use (NULL if don't care)
180 * IPPacket = Pointer to IP packet to transmit
183 PNEIGHBOR_CACHE_ENTRY NCE
;
185 TI_DbgPrint(DEBUG_ICMP
, ("Called.\n"));
187 /* Calculate checksum of ICMP header and data */
188 ((PICMP_HEADER
)IPPacket
->Data
)->Checksum
= (USHORT
)
189 IPv4Checksum(IPPacket
->Data
, IPPacket
->TotalSize
- IPPacket
->HeaderSize
, 0);
191 /* Get a route to the destination address */
192 if ((NCE
= RouteGetRouteToDestination(&IPPacket
->DstAddr
))) {
193 /* Send the packet */
194 IPSendDatagram(IPPacket
, NCE
, Complete
, Context
);
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
));
200 Complete( Context
, IPPacket
->NdisPacket
, NDIS_STATUS_NOT_ACCEPTED
);
206 PIP_INTERFACE Interface
,
211 * FUNCTION: Transmits an ICMP packet in response to an incoming packet
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
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
224 UINT DataSize
, PayloadSize
;
225 IP_PACKET NewPacket
= *IPPacket
;
227 TI_DbgPrint(DEBUG_ICMP
, ("Called. Type (%d) Code (%d).\n", Type
, Code
));
229 DataSize
= IPPacket
->TotalSize
- IPPacket
->HeaderSize
;
230 PayloadSize
= DataSize
- sizeof(ICMP_HEADER
);
231 if ((PayloadSize
) > 576) {
233 DataSize
= PayloadSize
+ sizeof(ICMP_HEADER
);
236 if( !PrepareICMPPacket(Interface
, &NewPacket
, &IPPacket
->SrcAddr
,
237 IPPacket
->Data
, DataSize
) ) return;
239 ((PICMP_HEADER
)NewPacket
.Data
)->Type
= Type
;
240 ((PICMP_HEADER
)NewPacket
.Data
)->Code
= Code
;
241 ((PICMP_HEADER
)NewPacket
.Data
)->Checksum
= 0;
243 ICMPTransmit(&NewPacket
, SendICMPComplete
, NULL
);