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