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