]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/Ip6Dxe/Ip6Icmp.c
Nt32Pkg: Convert to build FatPkg from source
[mirror_edk2.git] / NetworkPkg / Ip6Dxe / Ip6Icmp.c
CommitLineData
a3bcde70
HT
1/** @file\r
2 The ICMPv6 handle routines to process the ICMPv6 control messages.\r
3\r
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
40696972
SEHM
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6 \r
a3bcde70
HT
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "Ip6Impl.h"\r
18\r
19EFI_IP6_ICMP_TYPE mIp6SupportedIcmp[23] = {\r
20\r
21 {\r
22 ICMP_V6_DEST_UNREACHABLE,\r
23 ICMP_V6_NO_ROUTE_TO_DEST\r
24 },\r
25 {\r
26 ICMP_V6_DEST_UNREACHABLE,\r
27 ICMP_V6_COMM_PROHIBITED\r
28 },\r
29 {\r
30 ICMP_V6_DEST_UNREACHABLE,\r
31 ICMP_V6_BEYOND_SCOPE\r
32 },\r
33 {\r
34 ICMP_V6_DEST_UNREACHABLE,\r
35 ICMP_V6_ADDR_UNREACHABLE\r
36 },\r
37 {\r
38 ICMP_V6_DEST_UNREACHABLE,\r
39 ICMP_V6_PORT_UNREACHABLE\r
40 },\r
41 {\r
42 ICMP_V6_DEST_UNREACHABLE,\r
43 ICMP_V6_SOURCE_ADDR_FAILED\r
44 },\r
45 {\r
46 ICMP_V6_DEST_UNREACHABLE,\r
47 ICMP_V6_ROUTE_REJECTED\r
48 },\r
49\r
50 {\r
51 ICMP_V6_PACKET_TOO_BIG,\r
52 ICMP_V6_DEFAULT_CODE\r
53 },\r
54\r
55 {\r
56 ICMP_V6_TIME_EXCEEDED,\r
57 ICMP_V6_TIMEOUT_HOP_LIMIT\r
58 },\r
59 {\r
60 ICMP_V6_TIME_EXCEEDED,\r
61 ICMP_V6_TIMEOUT_REASSEMBLE\r
62 },\r
63\r
64 {\r
65 ICMP_V6_PARAMETER_PROBLEM,\r
66 ICMP_V6_ERRONEOUS_HEADER\r
67 },\r
68 {\r
69 ICMP_V6_PARAMETER_PROBLEM,\r
70 ICMP_V6_UNRECOGNIZE_NEXT_HDR\r
71 },\r
72 {\r
73 ICMP_V6_PARAMETER_PROBLEM,\r
74 ICMP_V6_UNRECOGNIZE_OPTION\r
75 },\r
76\r
77 {\r
78 ICMP_V6_ECHO_REQUEST,\r
79 ICMP_V6_DEFAULT_CODE\r
80 },\r
81 {\r
82 ICMP_V6_ECHO_REPLY,\r
83 ICMP_V6_DEFAULT_CODE\r
84 },\r
85\r
86 {\r
87 ICMP_V6_LISTENER_QUERY,\r
88 ICMP_V6_DEFAULT_CODE\r
89 },\r
90 {\r
91 ICMP_V6_LISTENER_REPORT,\r
92 ICMP_V6_DEFAULT_CODE\r
93 },\r
94 {\r
95 ICMP_V6_LISTENER_REPORT_2,\r
96 ICMP_V6_DEFAULT_CODE\r
97 },\r
98 {\r
99 ICMP_V6_LISTENER_DONE,\r
100 ICMP_V6_DEFAULT_CODE\r
101 },\r
102\r
103 {\r
104 ICMP_V6_ROUTER_SOLICIT,\r
105 ICMP_V6_DEFAULT_CODE\r
106 },\r
107 {\r
108 ICMP_V6_ROUTER_ADVERTISE,\r
109 ICMP_V6_DEFAULT_CODE\r
110 },\r
111 {\r
112 ICMP_V6_NEIGHBOR_SOLICIT,\r
113 ICMP_V6_DEFAULT_CODE\r
114 },\r
115 {\r
116 ICMP_V6_NEIGHBOR_ADVERTISE,\r
117 ICMP_V6_DEFAULT_CODE\r
118 },\r
119};\r
120\r
121/**\r
122 Reply an ICMPv6 echo request.\r
123\r
124 @param[in] IpSb The IP service that received the packet.\r
125 @param[in] Head The IP head of the ICMPv6 informational message.\r
126 @param[in] Packet The content of the ICMPv6 message with the IP head\r
127 removed.\r
128\r
129 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.\r
130 @retval EFI_SUCCESS Successfully answered the ICMPv6 Echo request.\r
131 @retval Others Failed to answer the ICMPv6 Echo request.\r
132\r
133**/\r
134EFI_STATUS\r
135Ip6IcmpReplyEcho (\r
136 IN IP6_SERVICE *IpSb,\r
137 IN EFI_IP6_HEADER *Head,\r
138 IN NET_BUF *Packet\r
139 )\r
140{\r
141 IP6_ICMP_INFORMATION_HEAD *Icmp;\r
142 NET_BUF *Data;\r
143 EFI_STATUS Status;\r
144 EFI_IP6_HEADER ReplyHead;\r
145\r
146 Status = EFI_OUT_OF_RESOURCES;\r
147 //\r
148 // make a copy the packet, it is really a bad idea to\r
149 // send the MNP's buffer back to MNP.\r
150 //\r
151 Data = NetbufDuplicate (Packet, NULL, IP6_MAX_HEADLEN);\r
152 if (Data == NULL) {\r
153 goto Exit;\r
154 }\r
155\r
156 //\r
157 // Change the ICMP type to echo reply, exchange the source\r
158 // and destination, then send it. The source is updated to\r
159 // use specific destination. See RFC1122. SRR/RR option\r
160 // update is omitted.\r
161 //\r
162 Icmp = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Data, 0, NULL);\r
163 if (Icmp == NULL) {\r
164 NetbufFree (Data);\r
165 goto Exit;\r
166 }\r
167\r
168 Icmp->Head.Type = ICMP_V6_ECHO_REPLY;\r
169 Icmp->Head.Checksum = 0;\r
170\r
171 //\r
172 // Generate the IPv6 basic header\r
173 // If the Echo Reply is a response to a Echo Request sent to one of the node's unicast address,\r
174 // the Source address of the Echo Reply must be the same address.\r
175 //\r
176 ZeroMem (&ReplyHead, sizeof (EFI_IP6_HEADER));\r
177\r
178 ReplyHead.PayloadLength = HTONS ((UINT16) (Packet->TotalSize));\r
179 ReplyHead.NextHeader = IP6_ICMP;\r
180 ReplyHead.HopLimit = IpSb->CurHopLimit;\r
181 IP6_COPY_ADDRESS (&ReplyHead.DestinationAddress, &Head->SourceAddress);\r
182\r
183 if (Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {\r
184 IP6_COPY_ADDRESS (&ReplyHead.SourceAddress, &Head->DestinationAddress);\r
185 }\r
186\r
187 //\r
188 // If source is unspecified, Ip6Output will select a source for us\r
189 //\r
190 Status = Ip6Output (\r
191 IpSb,\r
192 NULL,\r
193 NULL,\r
194 Data,\r
195 &ReplyHead,\r
196 NULL,\r
197 0,\r
198 Ip6SysPacketSent,\r
199 NULL\r
200 );\r
201\r
202Exit:\r
203 NetbufFree (Packet);\r
204 return Status;\r
205}\r
206\r
207/**\r
208 Process Packet Too Big message sent by a router in response to a packet that\r
209 it cannot forward because the packet is larger than the MTU of outgoing link.\r
210 Since this driver already uses IPv6 minimum link MTU as the maximum packet size,\r
211 if Packet Too Big message is still received, do not reduce the packet size, but\r
212 rather include a Fragment header in the subsequent packets.\r
213\r
214 @param[in] IpSb The IP service that received the packet.\r
215 @param[in] Head The IP head of the ICMPv6 error packet.\r
216 @param[in] Packet The content of the ICMPv6 error with the IP head\r
217 removed.\r
218\r
219 @retval EFI_SUCCESS The ICMPv6 error processed successfully.\r
220 @retval EFI_OUT_OF_RESOURCES Failed to finish the operation due to lack of\r
221 resource.\r
222 @retval EFI_NOT_FOUND The packet too big message is not sent to us.\r
223\r
224**/\r
225EFI_STATUS\r
226Ip6ProcessPacketTooBig (\r
227 IN IP6_SERVICE *IpSb,\r
228 IN EFI_IP6_HEADER *Head,\r
229 IN NET_BUF *Packet\r
230 )\r
231{\r
232 IP6_ICMP_ERROR_HEAD Icmp;\r
233 UINT32 Mtu;\r
234 IP6_ROUTE_ENTRY *RouteEntry;\r
235 EFI_IPv6_ADDRESS *DestAddress;\r
236\r
237 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
238 Mtu = NTOHL (Icmp.Fourth);\r
239 DestAddress = &Icmp.IpHead.DestinationAddress;\r
240\r
241 if (Mtu < IP6_MIN_LINK_MTU) {\r
242 //\r
243 // Normally the multicast address is considered to be on-link and not recorded\r
244 // in route table. Here it is added into the table since the MTU information\r
245 // need be recorded.\r
246 //\r
247 if (IP6_IS_MULTICAST (DestAddress)) {\r
248 RouteEntry = Ip6CreateRouteEntry (DestAddress, 128, NULL);\r
249 if (RouteEntry == NULL) {\r
250 NetbufFree (Packet);\r
251 return EFI_OUT_OF_RESOURCES;\r
252 }\r
253\r
254 RouteEntry->Flag = IP6_DIRECT_ROUTE | IP6_PACKET_TOO_BIG;\r
255 InsertHeadList (&IpSb->RouteTable->RouteArea[128], &RouteEntry->Link);\r
256 IpSb->RouteTable->TotalNum++;\r
257 } else {\r
258 RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, DestAddress, NULL);\r
259 if (RouteEntry == NULL) {\r
260 NetbufFree (Packet);\r
261 return EFI_NOT_FOUND;\r
262 }\r
263\r
264 RouteEntry->Flag = RouteEntry->Flag | IP6_PACKET_TOO_BIG;\r
265\r
266 Ip6FreeRouteEntry (RouteEntry);\r
267 }\r
268 }\r
269\r
270 NetbufFree (Packet);\r
271 return EFI_SUCCESS;\r
272}\r
273\r
274/**\r
275 Process the ICMPv6 error packet, and deliver the packet to upper layer.\r
276\r
277 @param[in] IpSb The IP service that received the packet.\r
278 @param[in] Head The IP head of the ICMPv6 error packet.\r
279 @param[in] Packet The content of the ICMPv6 error with the IP head\r
280 removed.\r
281\r
282 @retval EFI_SUCCESS The ICMPv6 error processed successfully.\r
283 @retval EFI_INVALID_PARAMETER The packet is invalid.\r
284 @retval Others Failed to process the packet.\r
285\r
286**/\r
287EFI_STATUS\r
288Ip6ProcessIcmpError (\r
289 IN IP6_SERVICE *IpSb,\r
290 IN EFI_IP6_HEADER *Head,\r
291 IN NET_BUF *Packet\r
292 )\r
293{\r
294 IP6_ICMP_ERROR_HEAD Icmp;\r
295\r
296 //\r
297 // Check the validity of the packet\r
298 //\r
299 if (Packet->TotalSize < sizeof (Icmp)) {\r
300 goto DROP;\r
301 }\r
302\r
303 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
304 if (Icmp.Head.Type == ICMP_V6_PACKET_TOO_BIG) {\r
305 return Ip6ProcessPacketTooBig (IpSb, Head, Packet);\r
306 }\r
307\r
308 //\r
309 // Notify the upper-layer process that an ICMPv6 eror message is received.\r
310 //\r
311 IP6_GET_CLIP_INFO (Packet)->Status = EFI_ICMP_ERROR;\r
312 return Ip6Demultiplex (IpSb, Head, Packet);\r
313\r
314DROP:\r
315 NetbufFree (Packet);\r
316 Packet = NULL;\r
317 return EFI_INVALID_PARAMETER;\r
318}\r
319\r
320/**\r
321 Process the ICMPv6 informational messages. If it is an ICMPv6 echo\r
322 request, answer it. If it is a MLD message, trigger MLD routines to\r
323 process it. If it is a ND message, trigger ND routines to process it.\r
324 Otherwise, deliver it to upper layer.\r
325\r
326 @param[in] IpSb The IP service that receivd the packet.\r
327 @param[in] Head The IP head of the ICMPv6 informational packet.\r
328 @param[in] Packet The content of the ICMPv6 informational packet\r
329 with IP head removed.\r
330\r
331 @retval EFI_INVALID_PARAMETER The packet is invalid.\r
332 @retval EFI_SUCCESS The ICMPv6 informational message processed.\r
333 @retval Others Failed to process ICMPv6 informational message.\r
334\r
335**/\r
336EFI_STATUS\r
337Ip6ProcessIcmpInformation (\r
338 IN IP6_SERVICE *IpSb,\r
339 IN EFI_IP6_HEADER *Head,\r
340 IN NET_BUF *Packet\r
341 )\r
342{\r
343 IP6_ICMP_INFORMATION_HEAD Icmp;\r
344 EFI_STATUS Status;\r
345\r
346 NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);\r
347 NET_CHECK_SIGNATURE (Packet, NET_BUF_SIGNATURE);\r
348 ASSERT (Head != NULL);\r
349\r
350 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
351 Status = EFI_INVALID_PARAMETER;\r
352\r
353 switch (Icmp.Head.Type) {\r
354 case ICMP_V6_ECHO_REQUEST:\r
355 //\r
356 // If ICMPv6 echo, reply it\r
357 //\r
358 if (Icmp.Head.Code == 0) {\r
359 Status = Ip6IcmpReplyEcho (IpSb, Head, Packet);\r
360 }\r
361 break;\r
362 case ICMP_V6_LISTENER_QUERY:\r
363 Status = Ip6ProcessMldQuery (IpSb, Head, Packet);\r
364 break;\r
365 case ICMP_V6_LISTENER_REPORT:\r
366 case ICMP_V6_LISTENER_REPORT_2:\r
367 Status = Ip6ProcessMldReport (IpSb, Head, Packet);\r
368 break;\r
369 case ICMP_V6_NEIGHBOR_SOLICIT:\r
370 Status = Ip6ProcessNeighborSolicit (IpSb, Head, Packet);\r
371 break;\r
372 case ICMP_V6_NEIGHBOR_ADVERTISE:\r
373 Status = Ip6ProcessNeighborAdvertise (IpSb, Head, Packet);\r
374 break;\r
375 case ICMP_V6_ROUTER_ADVERTISE:\r
376 Status = Ip6ProcessRouterAdvertise (IpSb, Head, Packet);\r
377 break;\r
378 case ICMP_V6_REDIRECT:\r
379 Status = Ip6ProcessRedirect (IpSb, Head, Packet);\r
380 break;\r
381 case ICMP_V6_ECHO_REPLY:\r
382 Status = Ip6Demultiplex (IpSb, Head, Packet);\r
383 break;\r
384 default:\r
385 Status = EFI_INVALID_PARAMETER;\r
386 break;\r
387 }\r
388\r
389 return Status;\r
390}\r
391\r
392/**\r
393 Handle the ICMPv6 packet. First validate the message format,\r
394 then, according to the message types, process it as an informational packet or\r
395 an error packet.\r
396\r
397 @param[in] IpSb The IP service that received the packet.\r
398 @param[in] Head The IP head of the ICMPv6 packet.\r
399 @param[in] Packet The content of the ICMPv6 packet with IP head\r
400 removed.\r
401\r
402 @retval EFI_INVALID_PARAMETER The packet is malformated.\r
403 @retval EFI_SUCCESS The ICMPv6 message successfully processed.\r
404 @retval Others Failed to handle the ICMPv6 packet.\r
405\r
406**/\r
407EFI_STATUS\r
408Ip6IcmpHandle (\r
409 IN IP6_SERVICE *IpSb,\r
410 IN EFI_IP6_HEADER *Head,\r
411 IN NET_BUF *Packet\r
412 )\r
413{\r
414 IP6_ICMP_HEAD Icmp;\r
415 UINT16 PseudoCheckSum;\r
416 UINT16 CheckSum;\r
417\r
418 //\r
419 // Check the validity of the incoming packet.\r
420 //\r
421 if (Packet->TotalSize < sizeof (Icmp)) {\r
422 goto DROP;\r
423 }\r
424\r
425 NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);\r
426\r
427 //\r
428 // Make sure checksum is valid.\r
429 //\r
430 PseudoCheckSum = NetIp6PseudoHeadChecksum (\r
431 &Head->SourceAddress,\r
432 &Head->DestinationAddress,\r
433 IP6_ICMP,\r
434 Packet->TotalSize\r
435 );\r
436 CheckSum = (UINT16) ~NetAddChecksum (PseudoCheckSum, NetbufChecksum (Packet));\r
437 if (CheckSum != 0) {\r
438 goto DROP;\r
439 }\r
440\r
441 //\r
442 // According to the packet type, call corresponding process\r
443 //\r
444 if (Icmp.Type <= ICMP_V6_ERROR_MAX) {\r
445 return Ip6ProcessIcmpError (IpSb, Head, Packet);\r
446 } else {\r
447 return Ip6ProcessIcmpInformation (IpSb, Head, Packet);\r
448 }\r
449\r
450DROP:\r
451 NetbufFree (Packet);\r
452 return EFI_INVALID_PARAMETER;\r
453}\r
454\r
455/**\r
456 Retrieve the Prefix address according to the PrefixLength by clear the useless\r
457 bits.\r
458\r
459 @param[in] PrefixLength The prefix length of the prefix.\r
460 @param[in, out] Prefix On input, points to the original prefix address\r
461 with dirty bits; on output, points to the updated\r
462 address with useless bit clear.\r
463\r
464**/\r
465VOID\r
466Ip6GetPrefix (\r
467 IN UINT8 PrefixLength,\r
468 IN OUT EFI_IPv6_ADDRESS *Prefix\r
469 )\r
470{\r
471 UINT8 Byte;\r
472 UINT8 Bit;\r
473 UINT8 Mask;\r
474 UINT8 Value;\r
475\r
476 ASSERT ((Prefix != NULL) && (PrefixLength < IP6_PREFIX_NUM));\r
477\r
478 if (PrefixLength == 0) {\r
479 ZeroMem (Prefix, sizeof (EFI_IPv6_ADDRESS));\r
480 return ;\r
481 }\r
482\r
40696972 483 if (PrefixLength >= IP6_PREFIX_NUM - 1) {\r
a3bcde70
HT
484 return ;\r
485 }\r
486\r
487 Byte = (UINT8) (PrefixLength / 8);\r
488 Bit = (UINT8) (PrefixLength % 8);\r
489 Value = Prefix->Addr[Byte];\r
490\r
40696972 491 if (Byte > 0) {\r
a3bcde70
HT
492 ZeroMem (Prefix->Addr + Byte, 16 - Byte);\r
493 }\r
494\r
495 if (Bit > 0) {\r
496 Mask = (UINT8) (0xFF << (8 - Bit));\r
497 Prefix->Addr[Byte] = (UINT8) (Value & Mask);\r
498 }\r
499\r
500}\r
501\r
502/**\r
503 Check whether the DestinationAddress is an anycast address.\r
504\r
505 @param[in] IpSb The IP service that received the packet.\r
506 @param[in] DestinationAddress Points to the Destination Address of the packet.\r
507\r
508 @retval TRUE The DestinationAddress is anycast address.\r
509 @retval FALSE The DestinationAddress is not anycast address.\r
510\r
511**/\r
512BOOLEAN\r
513Ip6IsAnycast (\r
514 IN IP6_SERVICE *IpSb,\r
515 IN EFI_IPv6_ADDRESS *DestinationAddress\r
516 )\r
517{\r
518 IP6_PREFIX_LIST_ENTRY *PrefixEntry;\r
519 EFI_IPv6_ADDRESS Prefix;\r
520 BOOLEAN Flag;\r
521\r
522 ZeroMem (&Prefix, sizeof (EFI_IPv6_ADDRESS));\r
523\r
524 Flag = FALSE;\r
525\r
526 //\r
527 // If the address is known as on-link or autonomous prefix, record it as\r
528 // anycast address.\r
529 //\r
530 do {\r
531 PrefixEntry = Ip6FindPrefixListEntry (IpSb, Flag, 255, DestinationAddress);\r
532 if (PrefixEntry != NULL) {\r
533 IP6_COPY_ADDRESS (&Prefix, &PrefixEntry->Prefix);\r
534 Ip6GetPrefix (PrefixEntry->PrefixLength, &Prefix);\r
535 if (EFI_IP6_EQUAL (&Prefix, DestinationAddress)) {\r
536 return TRUE;\r
537 }\r
538 }\r
539\r
540 Flag = (BOOLEAN) !Flag;\r
541 } while (Flag);\r
542\r
543 return FALSE;\r
544}\r
545\r
546/**\r
547 Generate ICMPv6 error message and send it out to DestinationAddress. Currently\r
548 Destination Unreachable message, Time Exceeded message and Parameter Problem\r
549 message are supported.\r
550\r
551 @param[in] IpSb The IP service that received the packet.\r
552 @param[in] Packet The packet which invoking ICMPv6 error.\r
553 @param[in] SourceAddress If not NULL, points to the SourceAddress.\r
554 Otherwise, the IP layer will select a source address\r
555 according to the DestinationAddress.\r
556 @param[in] DestinationAddress Points to the Destination Address of the ICMPv6\r
557 error message.\r
558 @param[in] Type The type of the ICMPv6 message.\r
559 @param[in] Code The additional level of the ICMPv6 message.\r
560 @param[in] Pointer If not NULL, identifies the octet offset within\r
561 the invoking packet where the error was detected.\r
562\r
563 @retval EFI_INVALID_PARAMETER The packet is malformated.\r
564 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to complete the\r
565 operation.\r
566 @retval EFI_SUCCESS The ICMPv6 message was successfully sent out.\r
567 @retval Others Failed to generate the ICMPv6 packet.\r
568\r
569**/\r
570EFI_STATUS\r
571Ip6SendIcmpError (\r
572 IN IP6_SERVICE *IpSb,\r
573 IN NET_BUF *Packet,\r
574 IN EFI_IPv6_ADDRESS *SourceAddress OPTIONAL,\r
575 IN EFI_IPv6_ADDRESS *DestinationAddress,\r
576 IN UINT8 Type,\r
577 IN UINT8 Code,\r
578 IN UINT32 *Pointer OPTIONAL\r
579 )\r
580{\r
581 UINT32 PacketLen;\r
582 NET_BUF *ErrorMsg;\r
583 UINT16 PayloadLen;\r
584 EFI_IP6_HEADER Head;\r
585 IP6_ICMP_INFORMATION_HEAD *IcmpHead;\r
586 UINT8 *ErrorBody;\r
587\r
588 if (DestinationAddress == NULL) {\r
589 return EFI_INVALID_PARAMETER;\r
590 }\r
591\r
592 //\r
593 // An ICMPv6 error message must not be originated as a result of receiving\r
594 // a packet whose source address does not uniquely identify a single node --\r
595 // e.g., the IPv6 Unspecified Address, an IPv6 multicast address, or an address\r
596 // known by the ICMP message originator to be an IPv6 anycast address.\r
597 //\r
598 if (NetIp6IsUnspecifiedAddr (DestinationAddress) ||\r
599 IP6_IS_MULTICAST (DestinationAddress) ||\r
600 Ip6IsAnycast (IpSb, DestinationAddress)\r
601 ) {\r
602 return EFI_INVALID_PARAMETER;\r
603 }\r
604\r
605 switch (Type) {\r
606 case ICMP_V6_DEST_UNREACHABLE:\r
607 case ICMP_V6_TIME_EXCEEDED:\r
608 break;\r
609\r
610 case ICMP_V6_PARAMETER_PROBLEM:\r
611 if (Pointer == NULL) {\r
612 return EFI_INVALID_PARAMETER;\r
613 }\r
614\r
615 break;\r
616\r
617 default:\r
618 return EFI_INVALID_PARAMETER;\r
619 }\r
620\r
621 PacketLen = sizeof (IP6_ICMP_ERROR_HEAD) + Packet->TotalSize;\r
622\r
623 if (PacketLen > IpSb->MaxPacketSize) {\r
624 PacketLen = IpSb->MaxPacketSize;\r
625 }\r
626\r
627 ErrorMsg = NetbufAlloc (PacketLen);\r
628 if (ErrorMsg == NULL) {\r
629 return EFI_OUT_OF_RESOURCES;\r
630 }\r
631\r
632 PayloadLen = (UINT16) (PacketLen - sizeof (EFI_IP6_HEADER));\r
633\r
634 //\r
635 // Create the basic IPv6 header.\r
636 //\r
637 ZeroMem (&Head, sizeof (EFI_IP6_HEADER));\r
638\r
639 Head.PayloadLength = HTONS (PayloadLen);\r
640 Head.NextHeader = IP6_ICMP;\r
641 Head.HopLimit = IpSb->CurHopLimit;\r
642\r
643 if (SourceAddress != NULL) {\r
644 IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);\r
645 } else {\r
646 ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));\r
647 }\r
648\r
649 IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);\r
650\r
651 NetbufReserve (ErrorMsg, sizeof (EFI_IP6_HEADER));\r
652\r
653 //\r
654 // Fill in the ICMP error message head\r
655 //\r
656 IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (ErrorMsg, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);\r
657 if (IcmpHead == NULL) {\r
658 NetbufFree (ErrorMsg);\r
659 return EFI_OUT_OF_RESOURCES;\r
660 }\r
661\r
662 ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));\r
663 IcmpHead->Head.Type = Type;\r
664 IcmpHead->Head.Code = Code;\r
665\r
666 if (Pointer != NULL) {\r
667 IcmpHead->Fourth = HTONL (*Pointer);\r
668 }\r
669\r
670 //\r
671 // Fill in the ICMP error message body\r
672 //\r
673 PayloadLen -= sizeof (IP6_ICMP_INFORMATION_HEAD);\r
674 ErrorBody = NetbufAllocSpace (ErrorMsg, PayloadLen, FALSE);\r
675 if (ErrorBody != NULL) {\r
676 ZeroMem (ErrorBody, PayloadLen);\r
677 NetbufCopy (Packet, 0, PayloadLen, ErrorBody);\r
678 }\r
679\r
680 //\r
681 // Transmit the packet\r
682 //\r
683 return Ip6Output (IpSb, NULL, NULL, ErrorMsg, &Head, NULL, 0, Ip6SysPacketSent, NULL);\r
684}\r
685\r