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