Home | History | Annotate | Download | only in Ip6Dxe
      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
    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
    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
    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
    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
    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
    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
    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
    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