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