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