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