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