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