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