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