]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Ip4Dxe/Ip4Icmp.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Ip4Dxe / Ip4Icmp.c
CommitLineData
772db4bb 1/** @file\r
2\r
d1102dba 3Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 4SPDX-License-Identifier: BSD-2-Clause-Patent\r
772db4bb 5\r
772db4bb 6**/\r
7\r
8#include "Ip4Impl.h"\r
9\r
10IP4_ICMP_CLASS\r
11mIcmpClass[] = {\r
12 {ICMP_ECHO_REPLY, ICMP_QUERY_MESSAGE },\r
13 {1, ICMP_INVALID_MESSAGE},\r
14 {2, ICMP_INVALID_MESSAGE},\r
15 {ICMP_DEST_UNREACHABLE, ICMP_ERROR_MESSAGE },\r
16 {ICMP_SOURCE_QUENCH, ICMP_ERROR_MESSAGE },\r
17 {ICMP_REDIRECT, ICMP_ERROR_MESSAGE },\r
18 {6, ICMP_INVALID_MESSAGE},\r
19 {7, ICMP_INVALID_MESSAGE},\r
20 {ICMP_ECHO_REQUEST, ICMP_QUERY_MESSAGE },\r
21 {9, ICMP_INVALID_MESSAGE},\r
22 {10, ICMP_INVALID_MESSAGE},\r
23 {ICMP_TIME_EXCEEDED, ICMP_ERROR_MESSAGE },\r
24 {ICMP_PARAMETER_PROBLEM, ICMP_ERROR_MESSAGE },\r
25 {ICMP_TIMESTAMP , ICMP_QUERY_MESSAGE },\r
26 {14, ICMP_INVALID_MESSAGE},\r
27 {ICMP_INFO_REQUEST , ICMP_QUERY_MESSAGE },\r
28 {ICMP_INFO_REPLY , ICMP_QUERY_MESSAGE },\r
29};\r
30\r
31EFI_IP4_ICMP_TYPE\r
5405e9a6 32mIp4SupportedIcmp[23] = {\r
33 {ICMP_ECHO_REPLY, ICMP_DEFAULT_CODE },\r
34\r
35 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE },\r
36 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE },\r
37 {ICMP_DEST_UNREACHABLE, ICMP_PROTO_UNREACHABLE },\r
38 {ICMP_DEST_UNREACHABLE, ICMP_PORT_UNREACHABLE },\r
39 {ICMP_DEST_UNREACHABLE, ICMP_FRAGMENT_FAILED },\r
40 {ICMP_DEST_UNREACHABLE, ICMP_SOURCEROUTE_FAILED },\r
41 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNKNOWN },\r
42 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNKNOWN },\r
43 {ICMP_DEST_UNREACHABLE, ICMP_SOURCE_ISOLATED },\r
44 {ICMP_DEST_UNREACHABLE, ICMP_NET_PROHIBITED },\r
45 {ICMP_DEST_UNREACHABLE, ICMP_HOST_PROHIBITED },\r
772db4bb 46 {ICMP_DEST_UNREACHABLE, ICMP_NET_UNREACHABLE_TOS },\r
47 {ICMP_DEST_UNREACHABLE, ICMP_HOST_UNREACHABLE_TOS},\r
48\r
5405e9a6 49 {ICMP_SOURCE_QUENCH, ICMP_DEFAULT_CODE },\r
772db4bb 50\r
5405e9a6 51 {ICMP_REDIRECT, ICMP_NET_REDIRECT },\r
52 {ICMP_REDIRECT, ICMP_HOST_REDIRECT },\r
53 {ICMP_REDIRECT, ICMP_NET_TOS_REDIRECT },\r
54 {ICMP_REDIRECT, ICMP_HOST_TOS_REDIRECT },\r
772db4bb 55\r
5405e9a6 56 {ICMP_ECHO_REQUEST, ICMP_DEFAULT_CODE },\r
772db4bb 57\r
5405e9a6 58 {ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_IN_TRANSIT },\r
f6b7393c 59 {ICMP_TIME_EXCEEDED, ICMP_TIMEOUT_REASSEMBLE },\r
772db4bb 60\r
5405e9a6 61 {ICMP_PARAMETER_PROBLEM, ICMP_DEFAULT_CODE },\r
772db4bb 62};\r
63\r
64\r
65\r
66/**\r
67 Process the ICMP redirect. Find the instance then update\r
68 its route cache.\r
d1102dba 69\r
772db4bb 70 All kinds of redirect is treated as host redirect as\r
71 specified by RFC1122 3.3.1.2:\r
72 "Since the subnet mask appropriate to the destination\r
73 address is generally not known, a Network Redirect\r
74 message SHOULD be treated identically to a Host Redirect\r
75 message;"\r
76\r
d1102dba 77 @param[in] IpSb The IP4 service binding instance that received\r
3e8c18da 78 the packet.\r
79 @param[in] Head The IP head of the received ICMPpacket.\r
80 @param[in] Packet The content of the ICMP redirect packet with IP\r
772db4bb 81 head removed.\r
3e8c18da 82 @param[in] Icmp The buffer to store the ICMP error message if\r
772db4bb 83 something is wrong.\r
84\r
85 @retval EFI_INVALID_PARAMETER The parameter is invalid\r
86 @retval EFI_SUCCESS Successfully updated the route caches\r
87\r
88**/\r
772db4bb 89EFI_STATUS\r
90Ip4ProcessIcmpRedirect (\r
91 IN IP4_SERVICE *IpSb,\r
92 IN IP4_HEAD *Head,\r
93 IN NET_BUF *Packet,\r
94 IN IP4_ICMP_ERROR_HEAD *Icmp\r
95 )\r
96{\r
e48e37fc 97 LIST_ENTRY *Entry;\r
772db4bb 98 IP4_PROTOCOL *Ip4Instance;\r
99 IP4_ROUTE_CACHE_ENTRY *CacheEntry;\r
100 IP4_INTERFACE *IpIf;\r
101 IP4_ADDR Gateway;\r
1204fe83 102 IP4_ADDR Src;\r
103 IP4_ADDR Dst;\r
772db4bb 104\r
105 //\r
106 // Find the interface whose IP address is the source of the\r
107 // orgianl IP packet.\r
108 //\r
109 IpIf = Ip4FindInterface (IpSb, NTOHL (Icmp->IpHead.Src));\r
110 Gateway = NTOHL (Icmp->Fourth);\r
111\r
112 //\r
113 // discard the packet if the new gateway address it specifies\r
114 // is not on the same connected net through which the Redirect\r
115 // arrived. (RFC1122 3.2.2.2).\r
116 //\r
117 if ((IpIf == NULL) || !IP4_NET_EQUAL (Gateway, IpIf->Ip, IpIf->SubnetMask)) {\r
118 NetbufFree (Packet);\r
119 return EFI_INVALID_PARAMETER;\r
120 }\r
121\r
122 //\r
123 // Update each IP child's route cache on the interface.\r
124 //\r
125 NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
126 Ip4Instance = NET_LIST_USER_STRUCT (Entry, IP4_PROTOCOL, AddrLink);\r
127\r
128 if (Ip4Instance->RouteTable == NULL) {\r
129 continue;\r
130 }\r
131\r
1204fe83 132 Dst = NTOHL (Icmp->IpHead.Dst);\r
133 Src = NTOHL (Icmp->IpHead.Src);\r
134 CacheEntry = Ip4FindRouteCache (Ip4Instance->RouteTable, Dst, Src);\r
772db4bb 135\r
136 //\r
137 // Only update the route cache's gateway if the source of the\r
138 // Redirect is the current first-hop gateway\r
139 //\r
140 if ((CacheEntry != NULL) && (NTOHL (Head->Src) == CacheEntry->NextHop)) {\r
141 CacheEntry->NextHop = Gateway;\r
142 }\r
143 }\r
144\r
145 NetbufFree (Packet);\r
146 return EFI_SUCCESS;\r
147}\r
148\r
149\r
150/**\r
151 Process the ICMP error packet. If it is an ICMP redirect packet,\r
152 update call Ip4ProcessIcmpRedirect to update the IP instance's\r
153 route cache, otherwise, deliver the packet to upper layer.\r
154\r
1f6729ff 155 @param[in] IpSb The IP4 service that received the packet.\r
156 @param[in] Head The IP4 head of the ICMP error packet\r
157 @param[in] Packet The content of the ICMP error with IP4 head\r
772db4bb 158 removed.\r
159\r
5405e9a6 160 @retval EFI_SUCCESS The ICMP error is processed successfully.\r
772db4bb 161 @retval EFI_INVALID_PARAMETER The packet is invalid\r
162 @retval Others Failed to process the packet.\r
d1102dba 163\r
772db4bb 164**/\r
772db4bb 165EFI_STATUS\r
166Ip4ProcessIcmpError (\r
167 IN IP4_SERVICE *IpSb,\r
168 IN IP4_HEAD *Head,\r
169 IN NET_BUF *Packet\r
170 )\r
171{\r
172 IP4_ICMP_ERROR_HEAD Icmp;\r
173\r
174 if (Packet->TotalSize < sizeof (Icmp)) {\r
175 NetbufFree (Packet);\r
176 return EFI_INVALID_PARAMETER;\r
177 }\r
178\r
179 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
180\r
181 //\r
182 // If it is an ICMP redirect error, update the route cache\r
183 // as RFC1122. Otherwise, demultiplex it to IP instances.\r
184 //\r
185 if (Icmp.Head.Type == ICMP_REDIRECT) {\r
186 return Ip4ProcessIcmpRedirect (IpSb, Head, Packet, &Icmp);\r
187 }\r
188\r
189 IP4_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;\r
216f7970 190 return Ip4Demultiplex (IpSb, Head, Packet, NULL, 0);\r
772db4bb 191}\r
192\r
193\r
194/**\r
195 Replay an ICMP echo request.\r
196\r
1f6729ff 197 @param[in] IpSb The IP4 service that receivd the packet\r
198 @param[in] Head The IP4 head of the ICMP error packet\r
199 @param[in] Packet The content of the ICMP error with IP4 head\r
772db4bb 200 removed.\r
201\r
202 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource.\r
203 @retval EFI_SUCCESS The ICMP Echo request is successfully answered.\r
204 @retval Others Failed to answer the ICMP echo request.\r
205\r
206**/\r
207EFI_STATUS\r
208Ip4IcmpReplyEcho (\r
209 IN IP4_SERVICE *IpSb,\r
210 IN IP4_HEAD *Head,\r
211 IN NET_BUF *Packet\r
212 )\r
213{\r
214 IP4_ICMP_QUERY_HEAD *Icmp;\r
215 NET_BUF *Data;\r
216 EFI_STATUS Status;\r
217 IP4_HEAD ReplyHead;\r
218\r
219 //\r
220 // make a copy the packet, it is really a bad idea to\r
221 // send the MNP's buffer back to MNP.\r
222 //\r
223 Data = NetbufDuplicate (Packet, NULL, IP4_MAX_HEADLEN);\r
224\r
225 if (Data == NULL) {\r
226 Status = EFI_OUT_OF_RESOURCES;\r
227 goto ON_EXIT;\r
228 }\r
229\r
230 //\r
231 // Change the ICMP type to echo reply, exchange the source\r
232 // and destination, then send it. The source is updated to\r
233 // use specific destination. See RFC1122. SRR/RR option\r
234 // update is omitted.\r
235 //\r
236 Icmp = (IP4_ICMP_QUERY_HEAD *) NetbufGetByte (Data, 0, NULL);\r
a56b6e03 237 ASSERT (Icmp != NULL);\r
772db4bb 238 Icmp->Head.Type = ICMP_ECHO_REPLY;\r
239 Icmp->Head.Checksum = 0;\r
687a2e5f 240 Icmp->Head.Checksum = (UINT16) (~NetblockChecksum ((UINT8 *) Icmp, Data->TotalSize));\r
772db4bb 241\r
242 ReplyHead.Tos = 0;\r
243 ReplyHead.Fragment = 0;\r
244 ReplyHead.Ttl = 64;\r
f6b7393c 245 ReplyHead.Protocol = EFI_IP_PROTO_ICMP;\r
772db4bb 246 ReplyHead.Src = 0;\r
247\r
248 //\r
249 // Ip4Output will select a source for us\r
250 //\r
251 ReplyHead.Dst = Head->Src;\r
252\r
253 Status = Ip4Output (\r
254 IpSb,\r
255 NULL,\r
256 Data,\r
257 &ReplyHead,\r
258 NULL,\r
259 0,\r
260 IP4_ALLZERO_ADDRESS,\r
261 Ip4SysPacketSent,\r
262 NULL\r
263 );\r
764c9d95
HG
264 if (EFI_ERROR (Status)) {\r
265 NetbufFree (Data);\r
266 }\r
772db4bb 267\r
268ON_EXIT:\r
269 NetbufFree (Packet);\r
270 return Status;\r
271}\r
272\r
273\r
274/**\r
275 Process the ICMP query message. If it is an ICMP echo\r
276 request, answer it. Otherwise deliver it to upper layer.\r
277\r
1f6729ff 278 @param[in] IpSb The IP4 service that receivd the packet\r
279 @param[in] Head The IP4 head of the ICMP query packet\r
280 @param[in] Packet The content of the ICMP query with IP4 head\r
772db4bb 281 removed.\r
282\r
283 @retval EFI_INVALID_PARAMETER The packet is invalid\r
284 @retval EFI_SUCCESS The ICMP query message is processed\r
5405e9a6 285 @retval Others Failed to process ICMP query.\r
772db4bb 286\r
287**/\r
288EFI_STATUS\r
289Ip4ProcessIcmpQuery (\r
290 IN IP4_SERVICE *IpSb,\r
291 IN IP4_HEAD *Head,\r
292 IN NET_BUF *Packet\r
293 )\r
294{\r
295 IP4_ICMP_QUERY_HEAD Icmp;\r
296\r
297 if (Packet->TotalSize < sizeof (Icmp)) {\r
298 NetbufFree (Packet);\r
299 return EFI_INVALID_PARAMETER;\r
300 }\r
301\r
302 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
303\r
304 if (Icmp.Head.Type == ICMP_ECHO_REQUEST) {\r
305 return Ip4IcmpReplyEcho (IpSb, Head, Packet);\r
306 }\r
307\r
216f7970 308 return Ip4Demultiplex (IpSb, Head, Packet, NULL, 0);\r
772db4bb 309}\r
310\r
311\r
312/**\r
313 Handle the ICMP packet. First validate the message format,\r
314 then according to the message types, process it as query or\r
315 error packet.\r
316\r
1f6729ff 317 @param[in] IpSb The IP4 service that receivd the packet.\r
318 @param[in] Head The IP4 head of the ICMP query packet.\r
319 @param[in] Packet The content of the ICMP query with IP4 head\r
772db4bb 320 removed.\r
321\r
322 @retval EFI_INVALID_PARAMETER The packet is malformated.\r
323 @retval EFI_SUCCESS The ICMP message is successfully processed.\r
5405e9a6 324 @retval Others Failed to handle ICMP packet.\r
772db4bb 325\r
326**/\r
327EFI_STATUS\r
328Ip4IcmpHandle (\r
329 IN IP4_SERVICE *IpSb,\r
330 IN IP4_HEAD *Head,\r
331 IN NET_BUF *Packet\r
332 )\r
333{\r
334 IP4_ICMP_HEAD Icmp;\r
335 UINT16 Checksum;\r
336\r
337 if (Packet->TotalSize < sizeof (Icmp)) {\r
338 goto DROP;\r
339 }\r
340\r
341 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
342\r
343 if (Icmp.Type > ICMP_TYPE_MAX) {\r
344 goto DROP;\r
345 }\r
346\r
687a2e5f 347 Checksum = (UINT16) (~NetbufChecksum (Packet));\r
772db4bb 348 if ((Icmp.Checksum != 0) && (Checksum != 0)) {\r
349 goto DROP;\r
350 }\r
351\r
352 if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_ERROR_MESSAGE) {\r
353 return Ip4ProcessIcmpError (IpSb, Head, Packet);\r
354\r
355 } else if (mIcmpClass[Icmp.Type].IcmpClass == ICMP_QUERY_MESSAGE) {\r
356 return Ip4ProcessIcmpQuery (IpSb, Head, Packet);\r
357\r
358 }\r
359\r
360DROP:\r
361 NetbufFree (Packet);\r
362 return EFI_INVALID_PARAMETER;\r
363}\r