Home | History | Annotate | Download | only in Ip6Dxe
      1 /** @file
      2   Implementation of Neighbor Discovery support routines.
      3 
      4   Copyright (c) 2009 - 2016, 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_MAC_ADDRESS mZeroMacAddress;
     19 
     20 /**
     21   Update the ReachableTime in IP6 service binding instance data, in milliseconds.
     22 
     23   @param[in, out] IpSb     Points to the IP6_SERVICE.
     24 
     25 **/
     26 VOID
     27 Ip6UpdateReachableTime (
     28   IN OUT IP6_SERVICE  *IpSb
     29   )
     30 {
     31   UINT32              Random;
     32 
     33   Random = (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE;
     34   Random = Random + IP6_MIN_RANDOM_FACTOR_SCALED;
     35   IpSb->ReachableTime = (IpSb->BaseReachableTime * Random) / IP6_RANDOM_FACTOR_SCALE;
     36 }
     37 
     38 /**
     39   Build a array of EFI_IP6_NEIGHBOR_CACHE to be returned to the caller. The number
     40   of EFI_IP6_NEIGHBOR_CACHE is also returned.
     41 
     42   @param[in]  IpInstance        The pointer to IP6_PROTOCOL instance.
     43   @param[out] NeighborCount     The number of returned neighbor cache entries.
     44   @param[out] NeighborCache     The pointer to the array of EFI_IP6_NEIGHBOR_CACHE.
     45 
     46   @retval EFI_SUCCESS           The EFI_IP6_NEIGHBOR_CACHE successfully built.
     47   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the route table.
     48 
     49 **/
     50 EFI_STATUS
     51 Ip6BuildEfiNeighborCache (
     52   IN IP6_PROTOCOL            *IpInstance,
     53   OUT UINT32                 *NeighborCount,
     54   OUT EFI_IP6_NEIGHBOR_CACHE **NeighborCache
     55   )
     56 {
     57   IP6_NEIGHBOR_ENTRY        *Neighbor;
     58   LIST_ENTRY                *Entry;
     59   IP6_SERVICE               *IpSb;
     60   UINT32                    Count;
     61   EFI_IP6_NEIGHBOR_CACHE    *EfiNeighborCache;
     62   EFI_IP6_NEIGHBOR_CACHE    *NeighborCacheTmp;
     63 
     64   NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
     65   ASSERT (NeighborCount != NULL && NeighborCache != NULL);
     66 
     67   IpSb  = IpInstance->Service;
     68   Count = 0;
     69 
     70   NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
     71     Count++;
     72   }
     73 
     74   if (Count == 0) {
     75     return EFI_SUCCESS;
     76   }
     77 
     78   NeighborCacheTmp = AllocatePool (Count * sizeof (EFI_IP6_NEIGHBOR_CACHE));
     79   if (NeighborCacheTmp == NULL) {
     80     return EFI_OUT_OF_RESOURCES;
     81   }
     82 
     83   *NeighborCount = Count;
     84   Count          = 0;
     85 
     86   NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
     87     Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
     88 
     89     EfiNeighborCache = NeighborCacheTmp + Count;
     90 
     91    EfiNeighborCache->State = Neighbor->State;
     92     IP6_COPY_ADDRESS (&EfiNeighborCache->Neighbor, &Neighbor->Neighbor);
     93     IP6_COPY_LINK_ADDRESS (&EfiNeighborCache->LinkAddress, &Neighbor->LinkAddress);
     94 
     95     Count++;
     96   }
     97 
     98   ASSERT (*NeighborCount == Count);
     99   *NeighborCache = NeighborCacheTmp;
    100 
    101   return EFI_SUCCESS;
    102 }
    103 
    104 /**
    105   Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
    106   of prefix entries is also returned.
    107 
    108   @param[in]  IpInstance        The pointer to IP6_PROTOCOL instance.
    109   @param[out] PrefixCount       The number of returned prefix entries.
    110   @param[out] PrefixTable       The pointer to the array of PrefixTable.
    111 
    112   @retval EFI_SUCCESS           The prefix table successfully built.
    113   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory for the prefix table.
    114 
    115 **/
    116 EFI_STATUS
    117 Ip6BuildPrefixTable (
    118   IN IP6_PROTOCOL           *IpInstance,
    119   OUT UINT32                *PrefixCount,
    120   OUT EFI_IP6_ADDRESS_INFO  **PrefixTable
    121   )
    122 {
    123   LIST_ENTRY                *Entry;
    124   IP6_SERVICE               *IpSb;
    125   UINT32                    Count;
    126   IP6_PREFIX_LIST_ENTRY     *PrefixList;
    127   EFI_IP6_ADDRESS_INFO      *EfiPrefix;
    128   EFI_IP6_ADDRESS_INFO      *PrefixTableTmp;
    129 
    130   NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
    131   ASSERT (PrefixCount != NULL && PrefixTable != NULL);
    132 
    133   IpSb  = IpInstance->Service;
    134   Count = 0;
    135 
    136   NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
    137     Count++;
    138   }
    139 
    140   if (Count == 0) {
    141     return EFI_SUCCESS;
    142   }
    143 
    144   PrefixTableTmp = AllocatePool (Count * sizeof (EFI_IP6_ADDRESS_INFO));
    145   if (PrefixTableTmp == NULL) {
    146     return EFI_OUT_OF_RESOURCES;
    147   }
    148 
    149   *PrefixCount = Count;
    150   Count        = 0;
    151 
    152   NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
    153     PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
    154     EfiPrefix  = PrefixTableTmp + Count;
    155     IP6_COPY_ADDRESS (&EfiPrefix->Address, &PrefixList->Prefix);
    156     EfiPrefix->PrefixLength = PrefixList->PrefixLength;
    157 
    158     Count++;
    159   }
    160 
    161   ASSERT (*PrefixCount == Count);
    162   *PrefixTable = PrefixTableTmp;
    163 
    164   return EFI_SUCCESS;
    165 }
    166 
    167 /**
    168   Allocate and initialize a IP6 prefix list entry.
    169 
    170   @param[in]  IpSb              The pointer to IP6_SERVICE instance.
    171   @param[in]  OnLinkOrAuto      If TRUE, the entry is created for the on link prefix list.
    172                                 Otherwise, it is created for the autoconfiguration prefix list.
    173   @param[in]  ValidLifetime     The length of time in seconds that the prefix
    174                                 is valid for the purpose of on-link determination.
    175   @param[in]  PreferredLifetime The length of time in seconds that addresses
    176                                 generated from the prefix via stateless address
    177                                 autoconfiguration remain preferred.
    178   @param[in]  PrefixLength      The prefix length of the Prefix.
    179   @param[in]  Prefix            The prefix address.
    180 
    181   @return NULL if it failed to allocate memory for the prefix node. Otherwise, point
    182           to the created or existing prefix list entry.
    183 
    184 **/
    185 IP6_PREFIX_LIST_ENTRY *
    186 Ip6CreatePrefixListEntry (
    187   IN IP6_SERVICE            *IpSb,
    188   IN BOOLEAN                OnLinkOrAuto,
    189   IN UINT32                 ValidLifetime,
    190   IN UINT32                 PreferredLifetime,
    191   IN UINT8                  PrefixLength,
    192   IN EFI_IPv6_ADDRESS       *Prefix
    193   )
    194 {
    195   IP6_PREFIX_LIST_ENTRY     *PrefixEntry;
    196   IP6_ROUTE_ENTRY           *RtEntry;
    197   LIST_ENTRY                *ListHead;
    198   LIST_ENTRY                *Entry;
    199   IP6_PREFIX_LIST_ENTRY     *TmpPrefixEntry;
    200 
    201   if (Prefix == NULL || PreferredLifetime > ValidLifetime || PrefixLength > IP6_PREFIX_MAX) {
    202     return NULL;
    203   }
    204 
    205   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    206 
    207   PrefixEntry = Ip6FindPrefixListEntry (
    208                   IpSb,
    209                   OnLinkOrAuto,
    210                   PrefixLength,
    211                   Prefix
    212                   );
    213   if (PrefixEntry != NULL) {
    214     PrefixEntry->RefCnt ++;
    215     return PrefixEntry;
    216   }
    217 
    218   PrefixEntry = AllocatePool (sizeof (IP6_PREFIX_LIST_ENTRY));
    219   if (PrefixEntry == NULL) {
    220     return NULL;
    221   }
    222 
    223   PrefixEntry->RefCnt            = 1;
    224   PrefixEntry->ValidLifetime     = ValidLifetime;
    225   PrefixEntry->PreferredLifetime = PreferredLifetime;
    226   PrefixEntry->PrefixLength      = PrefixLength;
    227   IP6_COPY_ADDRESS (&PrefixEntry->Prefix, Prefix);
    228 
    229   ListHead = OnLinkOrAuto ? &IpSb->OnlinkPrefix : &IpSb->AutonomousPrefix;
    230 
    231   //
    232   // Create a direct route entry for on-link prefix and insert to route area.
    233   //
    234   if (OnLinkOrAuto) {
    235     RtEntry = Ip6CreateRouteEntry (Prefix, PrefixLength, NULL);
    236     if (RtEntry == NULL) {
    237       FreePool (PrefixEntry);
    238       return NULL;
    239     }
    240 
    241     RtEntry->Flag = IP6_DIRECT_ROUTE;
    242     InsertHeadList (&IpSb->RouteTable->RouteArea[PrefixLength], &RtEntry->Link);
    243     IpSb->RouteTable->TotalNum++;
    244   }
    245 
    246   //
    247   // Insert the prefix entry in the order that a prefix with longer prefix length
    248   // is put ahead in the list.
    249   //
    250   NET_LIST_FOR_EACH (Entry, ListHead) {
    251     TmpPrefixEntry = NET_LIST_USER_STRUCT(Entry, IP6_PREFIX_LIST_ENTRY, Link);
    252 
    253     if (TmpPrefixEntry->PrefixLength < PrefixEntry->PrefixLength) {
    254       break;
    255     }
    256   }
    257 
    258   NetListInsertBefore (Entry, &PrefixEntry->Link);
    259 
    260   return PrefixEntry;
    261 }
    262 
    263 /**
    264   Destroy a IP6 prefix list entry.
    265 
    266   @param[in]  IpSb              The pointer to IP6_SERVICE instance.
    267   @param[in]  PrefixEntry       The to be destroyed prefix list entry.
    268   @param[in]  OnLinkOrAuto      If TRUE, the entry is removed from on link prefix list.
    269                                 Otherwise remove from autoconfiguration prefix list.
    270   @param[in]  ImmediateDelete   If TRUE, remove the entry directly.
    271                                 Otherwise, check the reference count to see whether
    272                                 it should be removed.
    273 
    274 **/
    275 VOID
    276 Ip6DestroyPrefixListEntry (
    277   IN IP6_SERVICE            *IpSb,
    278   IN IP6_PREFIX_LIST_ENTRY  *PrefixEntry,
    279   IN BOOLEAN                OnLinkOrAuto,
    280   IN BOOLEAN                ImmediateDelete
    281   )
    282 {
    283   LIST_ENTRY      *Entry;
    284   IP6_INTERFACE   *IpIf;
    285   EFI_STATUS      Status;
    286 
    287   if ((!ImmediateDelete) && (PrefixEntry->RefCnt > 0) && ((--PrefixEntry->RefCnt) > 0)) {
    288     return ;
    289   }
    290 
    291   if (OnLinkOrAuto) {
    292       //
    293       // Remove the direct route for onlink prefix from route table.
    294       //
    295       do {
    296         Status = Ip6DelRoute (
    297                    IpSb->RouteTable,
    298                    &PrefixEntry->Prefix,
    299                    PrefixEntry->PrefixLength,
    300                    NULL
    301                    );
    302       } while (Status != EFI_NOT_FOUND);
    303   } else {
    304     //
    305     // Remove the corresponding addresses generated from this autonomous prefix.
    306     //
    307     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
    308       IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
    309 
    310       Ip6RemoveAddr (IpSb, &IpIf->AddressList, &IpIf->AddressCount, &PrefixEntry->Prefix, PrefixEntry->PrefixLength);
    311     }
    312   }
    313 
    314   RemoveEntryList (&PrefixEntry->Link);
    315   FreePool (PrefixEntry);
    316 }
    317 
    318 /**
    319   Search the list array to find an IP6 prefix list entry.
    320 
    321   @param[in]  IpSb              The pointer to IP6_SERVICE instance.
    322   @param[in]  OnLinkOrAuto      If TRUE, the search the link prefix list,
    323                                 Otherwise search the autoconfiguration prefix list.
    324   @param[in]  PrefixLength      The prefix length of the Prefix
    325   @param[in]  Prefix            The prefix address.
    326 
    327   @return NULL if cannot find the IP6 prefix list entry. Otherwise, return the
    328           pointer to the IP6 prefix list entry.
    329 
    330 **/
    331 IP6_PREFIX_LIST_ENTRY *
    332 Ip6FindPrefixListEntry (
    333   IN IP6_SERVICE            *IpSb,
    334   IN BOOLEAN                OnLinkOrAuto,
    335   IN UINT8                  PrefixLength,
    336   IN EFI_IPv6_ADDRESS       *Prefix
    337   )
    338 {
    339   IP6_PREFIX_LIST_ENTRY     *PrefixList;
    340   LIST_ENTRY                *Entry;
    341   LIST_ENTRY                *ListHead;
    342 
    343   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    344   ASSERT (Prefix != NULL);
    345 
    346   if (OnLinkOrAuto) {
    347     ListHead = &IpSb->OnlinkPrefix;
    348   } else {
    349     ListHead = &IpSb->AutonomousPrefix;
    350   }
    351 
    352   NET_LIST_FOR_EACH (Entry, ListHead) {
    353     PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
    354     if (PrefixLength != 255) {
    355       //
    356       // Perform exactly prefix match.
    357       //
    358       if (PrefixList->PrefixLength == PrefixLength &&
    359         NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixLength)) {
    360         return PrefixList;
    361       }
    362     } else {
    363       //
    364       // Perform the longest prefix match. The list is already sorted with
    365       // the longest length prefix put at the head of the list.
    366       //
    367       if (NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixList->PrefixLength)) {
    368         return PrefixList;
    369       }
    370     }
    371   }
    372 
    373   return NULL;
    374 }
    375 
    376 /**
    377   Release the resource in the prefix list table, and destroy the list entry and
    378   corresponding addresses or route entries.
    379 
    380   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    381   @param[in]  ListHead          The list entry head of the prefix list table.
    382 
    383 **/
    384 VOID
    385 Ip6CleanPrefixListTable (
    386   IN IP6_SERVICE            *IpSb,
    387   IN LIST_ENTRY             *ListHead
    388   )
    389 {
    390   IP6_PREFIX_LIST_ENTRY     *PrefixList;
    391   BOOLEAN                   OnLink;
    392 
    393   OnLink = (BOOLEAN) (ListHead == &IpSb->OnlinkPrefix);
    394 
    395   while (!IsListEmpty (ListHead)) {
    396     PrefixList = NET_LIST_HEAD (ListHead, IP6_PREFIX_LIST_ENTRY, Link);
    397     Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
    398   }
    399 }
    400 
    401 /**
    402   Callback function when address resolution is finished. It will cancel
    403   all the queued frames if the address resolution failed, or transmit them
    404   if the request succeeded.
    405 
    406   @param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
    407 
    408 **/
    409 VOID
    410 Ip6OnArpResolved (
    411   IN VOID                   *Context
    412   )
    413 {
    414   LIST_ENTRY                *Entry;
    415   LIST_ENTRY                *Next;
    416   IP6_NEIGHBOR_ENTRY        *ArpQue;
    417   IP6_SERVICE               *IpSb;
    418   IP6_LINK_TX_TOKEN         *Token;
    419   EFI_STATUS                Status;
    420   BOOLEAN                   Sent;
    421 
    422   ArpQue = (IP6_NEIGHBOR_ENTRY *) Context;
    423   if ((ArpQue == NULL) || (ArpQue->Interface == NULL)) {
    424     return ;
    425   }
    426 
    427   IpSb   = ArpQue->Interface->Service;
    428   if ((IpSb == NULL) || (IpSb->Signature != IP6_SERVICE_SIGNATURE)) {
    429     return ;
    430   }
    431 
    432   //
    433   // ARP resolve failed for some reason. Release all the frame
    434   // and ARP queue itself. Ip6FreeArpQue will call the frame's
    435   // owner back.
    436   //
    437   if (NET_MAC_EQUAL (&ArpQue->LinkAddress, &mZeroMacAddress, IpSb->SnpMode.HwAddressSize)) {
    438     Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, TRUE, EFI_NO_MAPPING, NULL, NULL);
    439     return ;
    440   }
    441 
    442   //
    443   // ARP resolve succeeded, Transmit all the frame.
    444   //
    445   Sent = FALSE;
    446   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
    447     RemoveEntryList (Entry);
    448 
    449     Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
    450     IP6_COPY_LINK_ADDRESS (&Token->DstMac, &ArpQue->LinkAddress);
    451 
    452     //
    453     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
    454     // may be called before Mnp->Transmit returns which will remove this tx
    455     // token from the SentFrames list. Remove it from the list if the returned
    456     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
    457     // FrameSentDpc won't be queued.
    458     //
    459     InsertTailList (&ArpQue->Interface->SentFrames, &Token->Link);
    460 
    461     Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
    462     if (EFI_ERROR (Status)) {
    463       RemoveEntryList (&Token->Link);
    464       Token->CallBack (Token->Packet, Status, 0, Token->Context);
    465 
    466       Ip6FreeLinkTxToken (Token);
    467       continue;
    468     } else {
    469       Sent = TRUE;
    470     }
    471   }
    472 
    473   //
    474   // Free the ArpQue only but not the whole neighbor entry.
    475   //
    476   Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, FALSE, EFI_SUCCESS, NULL, NULL);
    477 
    478   if (Sent && (ArpQue->State == EfiNeighborStale)) {
    479     ArpQue->State = EfiNeighborDelay;
    480     ArpQue->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
    481   }
    482 }
    483 
    484 /**
    485   Allocate and initialize an IP6 neighbor cache entry.
    486 
    487   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    488   @param[in]  CallBack          The callback function to be called when
    489                                 address resolution is finished.
    490   @param[in]  Ip6Address        Points to the IPv6 address of the neighbor.
    491   @param[in]  LinkAddress       Points to the MAC address of the neighbor.
    492                                 Ignored if NULL.
    493 
    494   @return NULL if failed to allocate memory for the neighbor cache entry.
    495           Otherwise, point to the created neighbor cache entry.
    496 
    497 **/
    498 IP6_NEIGHBOR_ENTRY *
    499 Ip6CreateNeighborEntry (
    500   IN IP6_SERVICE            *IpSb,
    501   IN IP6_ARP_CALLBACK       CallBack,
    502   IN EFI_IPv6_ADDRESS       *Ip6Address,
    503   IN EFI_MAC_ADDRESS        *LinkAddress OPTIONAL
    504   )
    505 {
    506   IP6_NEIGHBOR_ENTRY        *Entry;
    507   IP6_DEFAULT_ROUTER        *DefaultRouter;
    508 
    509   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    510   ASSERT (Ip6Address!= NULL);
    511 
    512   Entry = AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY));
    513   if (Entry == NULL) {
    514     return NULL;
    515   }
    516 
    517   Entry->RefCnt    = 1;
    518   Entry->IsRouter  = FALSE;
    519   Entry->ArpFree   = FALSE;
    520   Entry->Dynamic   = FALSE;
    521   Entry->State     = EfiNeighborInComplete;
    522   Entry->Transmit  = IP6_MAX_MULTICAST_SOLICIT + 1;
    523   Entry->CallBack  = CallBack;
    524   Entry->Interface = NULL;
    525 
    526   InitializeListHead (&Entry->Frames);
    527 
    528   IP6_COPY_ADDRESS (&Entry->Neighbor, Ip6Address);
    529 
    530   if (LinkAddress != NULL) {
    531     IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, LinkAddress);
    532   } else {
    533     IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, &mZeroMacAddress);
    534   }
    535 
    536   InsertHeadList (&IpSb->NeighborTable, &Entry->Link);
    537 
    538   //
    539   // If corresponding default router entry exists, establish the relationship.
    540   //
    541   DefaultRouter = Ip6FindDefaultRouter (IpSb, Ip6Address);
    542   if (DefaultRouter != NULL) {
    543     DefaultRouter->NeighborCache = Entry;
    544   }
    545 
    546   return Entry;
    547 }
    548 
    549 /**
    550   Search a IP6 neighbor cache entry.
    551 
    552   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    553   @param[in]  Ip6Address        Points to the IPv6 address of the neighbor.
    554 
    555   @return NULL if it failed to find the matching neighbor cache entry.
    556           Otherwise, point to the found neighbor cache entry.
    557 
    558 **/
    559 IP6_NEIGHBOR_ENTRY *
    560 Ip6FindNeighborEntry (
    561   IN IP6_SERVICE            *IpSb,
    562   IN EFI_IPv6_ADDRESS       *Ip6Address
    563   )
    564 {
    565   LIST_ENTRY                *Entry;
    566   LIST_ENTRY                *Next;
    567   IP6_NEIGHBOR_ENTRY        *Neighbor;
    568 
    569   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    570   ASSERT (Ip6Address != NULL);
    571 
    572   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
    573     Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
    574     if (EFI_IP6_EQUAL (Ip6Address, &Neighbor->Neighbor)) {
    575       RemoveEntryList (Entry);
    576       InsertHeadList (&IpSb->NeighborTable, Entry);
    577 
    578       return Neighbor;
    579     }
    580   }
    581 
    582   return NULL;
    583 }
    584 
    585 /**
    586   Free a IP6 neighbor cache entry and remove all the frames on the address
    587   resolution queue that pass the FrameToCancel. That is, either FrameToCancel
    588   is NULL, or it returns true for the frame.
    589 
    590   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    591   @param[in]  NeighborCache     The to be free neighbor cache entry.
    592   @param[in]  SendIcmpError     If TRUE, send out ICMP error.
    593   @param[in]  FullFree          If TRUE, remove the neighbor cache entry.
    594                                 Otherwise remove the pending frames.
    595   @param[in]  IoStatus          The status returned to the cancelled frames'
    596                                 callback function.
    597   @param[in]  FrameToCancel     Function to select which frame to cancel.
    598                                 This is an optional parameter that may be NULL.
    599   @param[in]  Context           Opaque parameter to the FrameToCancel.
    600                                 Ignored if FrameToCancel is NULL.
    601 
    602   @retval EFI_INVALID_PARAMETER The input parameter is invalid.
    603   @retval EFI_SUCCESS           The operation finished successfully.
    604 
    605 **/
    606 EFI_STATUS
    607 Ip6FreeNeighborEntry (
    608   IN IP6_SERVICE            *IpSb,
    609   IN IP6_NEIGHBOR_ENTRY     *NeighborCache,
    610   IN BOOLEAN                SendIcmpError,
    611   IN BOOLEAN                FullFree,
    612   IN EFI_STATUS             IoStatus,
    613   IN IP6_FRAME_TO_CANCEL    FrameToCancel OPTIONAL,
    614   IN VOID                   *Context      OPTIONAL
    615   )
    616 {
    617   IP6_LINK_TX_TOKEN         *TxToken;
    618   LIST_ENTRY                *Entry;
    619   LIST_ENTRY                *Next;
    620   IP6_DEFAULT_ROUTER        *DefaultRouter;
    621 
    622   //
    623   // If FrameToCancel fails, the token will not be released.
    624   // To avoid the memory leak, stop this usage model.
    625   //
    626   if (FullFree && FrameToCancel != NULL) {
    627     return EFI_INVALID_PARAMETER;
    628   }
    629 
    630   NET_LIST_FOR_EACH_SAFE (Entry, Next, &NeighborCache->Frames) {
    631     TxToken = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
    632 
    633     if (SendIcmpError && !IP6_IS_MULTICAST (&TxToken->Packet->Ip.Ip6->DestinationAddress)) {
    634       Ip6SendIcmpError (
    635         IpSb,
    636         TxToken->Packet,
    637         NULL,
    638         &TxToken->Packet->Ip.Ip6->SourceAddress,
    639         ICMP_V6_DEST_UNREACHABLE,
    640         ICMP_V6_ADDR_UNREACHABLE,
    641         NULL
    642         );
    643     }
    644 
    645     if ((FrameToCancel == NULL) || FrameToCancel (TxToken, Context)) {
    646       RemoveEntryList (Entry);
    647       TxToken->CallBack (TxToken->Packet, IoStatus, 0, TxToken->Context);
    648       Ip6FreeLinkTxToken (TxToken);
    649     }
    650   }
    651 
    652   if (NeighborCache->ArpFree && IsListEmpty (&NeighborCache->Frames)) {
    653     RemoveEntryList (&NeighborCache->ArpList);
    654     NeighborCache->ArpFree = FALSE;
    655   }
    656 
    657   if (FullFree) {
    658     if (NeighborCache->IsRouter) {
    659       DefaultRouter = Ip6FindDefaultRouter (IpSb, &NeighborCache->Neighbor);
    660       if (DefaultRouter != NULL) {
    661         Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
    662       }
    663     }
    664 
    665     RemoveEntryList (&NeighborCache->Link);
    666     FreePool (NeighborCache);
    667   }
    668 
    669   return EFI_SUCCESS;
    670 }
    671 
    672 /**
    673   Allocate and initialize an IP6 default router entry.
    674 
    675   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    676   @param[in]  Ip6Address        The IPv6 address of the default router.
    677   @param[in]  RouterLifetime    The lifetime associated with the default
    678                                 router, in units of seconds.
    679 
    680   @return NULL if it failed to allocate memory for the default router node.
    681           Otherwise, point to the created default router node.
    682 
    683 **/
    684 IP6_DEFAULT_ROUTER *
    685 Ip6CreateDefaultRouter (
    686   IN IP6_SERVICE            *IpSb,
    687   IN EFI_IPv6_ADDRESS       *Ip6Address,
    688   IN UINT16                 RouterLifetime
    689   )
    690 {
    691   IP6_DEFAULT_ROUTER        *Entry;
    692   IP6_ROUTE_ENTRY           *RtEntry;
    693 
    694   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    695   ASSERT (Ip6Address != NULL);
    696 
    697   Entry = AllocatePool (sizeof (IP6_DEFAULT_ROUTER));
    698   if (Entry == NULL) {
    699     return NULL;
    700   }
    701 
    702   Entry->RefCnt        = 1;
    703   Entry->Lifetime      = RouterLifetime;
    704   Entry->NeighborCache = Ip6FindNeighborEntry (IpSb, Ip6Address);
    705   IP6_COPY_ADDRESS (&Entry->Router, Ip6Address);
    706 
    707   //
    708   // Add a default route into route table with both Destination and PrefixLength set to zero.
    709   //
    710   RtEntry = Ip6CreateRouteEntry (NULL, 0, Ip6Address);
    711   if (RtEntry == NULL) {
    712     FreePool (Entry);
    713     return NULL;
    714   }
    715 
    716   InsertHeadList (&IpSb->RouteTable->RouteArea[0], &RtEntry->Link);
    717   IpSb->RouteTable->TotalNum++;
    718 
    719   InsertTailList (&IpSb->DefaultRouterList, &Entry->Link);
    720 
    721   return Entry;
    722 }
    723 
    724 /**
    725   Destroy an IP6 default router entry.
    726 
    727   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    728   @param[in]  DefaultRouter     The to be destroyed IP6_DEFAULT_ROUTER.
    729 
    730 **/
    731 VOID
    732 Ip6DestroyDefaultRouter (
    733   IN IP6_SERVICE            *IpSb,
    734   IN IP6_DEFAULT_ROUTER     *DefaultRouter
    735   )
    736 {
    737   EFI_STATUS                Status;
    738 
    739   RemoveEntryList (&DefaultRouter->Link);
    740 
    741   //
    742   // Update the Destination Cache - all entries using the time-out router as next-hop
    743   // should perform next-hop determination again.
    744   //
    745   do {
    746     Status = Ip6DelRoute (IpSb->RouteTable, NULL, 0, &DefaultRouter->Router);
    747   } while (Status != EFI_NOT_FOUND);
    748 
    749   FreePool (DefaultRouter);
    750 }
    751 
    752 /**
    753   Clean an IP6 default router list.
    754 
    755   @param[in]  IpSb              The pointer to the IP6_SERVICE instance.
    756 
    757 **/
    758 VOID
    759 Ip6CleanDefaultRouterList (
    760   IN IP6_SERVICE            *IpSb
    761   )
    762 {
    763   IP6_DEFAULT_ROUTER        *DefaultRouter;
    764 
    765   while (!IsListEmpty (&IpSb->DefaultRouterList)) {
    766     DefaultRouter = NET_LIST_HEAD (&IpSb->DefaultRouterList, IP6_DEFAULT_ROUTER, Link);
    767     Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
    768   }
    769 }
    770 
    771 /**
    772   Search a default router node from an IP6 default router list.
    773 
    774   @param[in]  IpSb          The pointer to the IP6_SERVICE instance.
    775   @param[in]  Ip6Address    The IPv6 address of the to be searched default router node.
    776 
    777   @return NULL if it failed to find the matching default router node.
    778           Otherwise, point to the found default router node.
    779 
    780 **/
    781 IP6_DEFAULT_ROUTER *
    782 Ip6FindDefaultRouter (
    783   IN IP6_SERVICE            *IpSb,
    784   IN EFI_IPv6_ADDRESS       *Ip6Address
    785   )
    786 {
    787   LIST_ENTRY                *Entry;
    788   IP6_DEFAULT_ROUTER        *DefaultRouter;
    789 
    790   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
    791   ASSERT (Ip6Address != NULL);
    792 
    793   NET_LIST_FOR_EACH (Entry, &IpSb->DefaultRouterList) {
    794     DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
    795     if (EFI_IP6_EQUAL (Ip6Address, &DefaultRouter->Router)) {
    796       return DefaultRouter;
    797     }
    798   }
    799 
    800   return NULL;
    801 }
    802 
    803 /**
    804   The function to be called after DAD (Duplicate Address Detection) is performed.
    805 
    806   @param[in]  IsDadPassed   If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
    807   @param[in]  IpIf          Points to the IP6_INTERFACE.
    808   @param[in]  DadEntry      The DAD entry which already performed DAD.
    809 
    810 **/
    811 VOID
    812 Ip6OnDADFinished (
    813   IN BOOLEAN        IsDadPassed,
    814   IN IP6_INTERFACE  *IpIf,
    815   IN IP6_DAD_ENTRY  *DadEntry
    816   )
    817 {
    818   IP6_SERVICE               *IpSb;
    819   IP6_ADDRESS_INFO          *AddrInfo;
    820   EFI_DHCP6_PROTOCOL        *Dhcp6;
    821   UINT16                    OptBuf[4];
    822   EFI_DHCP6_PACKET_OPTION   *Oro;
    823   EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;
    824   EFI_IPv6_ADDRESS          AllNodes;
    825 
    826   IpSb     = IpIf->Service;
    827   AddrInfo = DadEntry->AddressInfo;
    828 
    829   if (IsDadPassed) {
    830     //
    831     // DAD succeed.
    832     //
    833     if (NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
    834       ASSERT (!IpSb->LinkLocalOk);
    835 
    836       IP6_COPY_ADDRESS (&IpSb->LinkLocalAddr, &AddrInfo->Address);
    837       IpSb->LinkLocalOk = TRUE;
    838       IpIf->Configured  = TRUE;
    839 
    840       //
    841       // Check whether DHCP6 need to be started.
    842       //
    843       Dhcp6 = IpSb->Ip6ConfigInstance.Dhcp6;
    844 
    845       if (IpSb->Dhcp6NeedStart) {
    846         Dhcp6->Start (Dhcp6);
    847         IpSb->Dhcp6NeedStart = FALSE;
    848       }
    849 
    850       if (IpSb->Dhcp6NeedInfoRequest) {
    851         //
    852         // Set the exta options to send. Here we only want the option request option
    853         // with DNS SERVERS.
    854         //
    855         Oro         = (EFI_DHCP6_PACKET_OPTION *) OptBuf;
    856         Oro->OpCode = HTONS (DHCP6_OPT_ORO);
    857         Oro->OpLen  = HTONS (2);
    858         *((UINT16 *) &Oro->Data[0]) = HTONS (DHCP6_OPT_DNS_SERVERS);
    859 
    860         InfoReqReXmit.Irt = 4;
    861         InfoReqReXmit.Mrc = 64;
    862         InfoReqReXmit.Mrt = 60;
    863         InfoReqReXmit.Mrd = 0;
    864 
    865         Dhcp6->InfoRequest (
    866                  Dhcp6,
    867                  TRUE,
    868                  Oro,
    869                  0,
    870                  NULL,
    871                  &InfoReqReXmit,
    872                  IpSb->Ip6ConfigInstance.Dhcp6Event,
    873                  Ip6ConfigOnDhcp6Reply,
    874                  &IpSb->Ip6ConfigInstance
    875                  );
    876       }
    877 
    878       //
    879       // Add an on-link prefix for link-local address.
    880       //
    881       Ip6CreatePrefixListEntry (
    882         IpSb,
    883         TRUE,
    884         (UINT32) IP6_INFINIT_LIFETIME,
    885         (UINT32) IP6_INFINIT_LIFETIME,
    886         IP6_LINK_LOCAL_PREFIX_LENGTH,
    887         &IpSb->LinkLocalAddr
    888         );
    889 
    890     } else {
    891       //
    892       // Global scope unicast address.
    893       //
    894       Ip6AddAddr (IpIf, AddrInfo);
    895 
    896       //
    897       // Add an on-link prefix for this address.
    898       //
    899       Ip6CreatePrefixListEntry (
    900         IpSb,
    901         TRUE,
    902         AddrInfo->ValidLifetime,
    903         AddrInfo->PreferredLifetime,
    904         AddrInfo->PrefixLength,
    905         &AddrInfo->Address
    906         );
    907 
    908       IpIf->Configured = TRUE;
    909     }
    910   } else {
    911     //
    912     // Leave the group we joined before.
    913     //
    914     Ip6LeaveGroup (IpSb, &DadEntry->Destination);
    915   }
    916 
    917   if (DadEntry->Callback != NULL) {
    918     DadEntry->Callback (IsDadPassed, &AddrInfo->Address, DadEntry->Context);
    919   }
    920 
    921   if (!IsDadPassed && NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
    922     FreePool (AddrInfo);
    923     RemoveEntryList (&DadEntry->Link);
    924     FreePool (DadEntry);
    925     //
    926     // Leave link-scope all-nodes multicast address (FF02::1)
    927     //
    928     Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &AllNodes);
    929     Ip6LeaveGroup (IpSb, &AllNodes);
    930     //
    931     // Disable IP operation since link-local address is a duplicate address.
    932     //
    933     IpSb->LinkLocalDadFail = TRUE;
    934     IpSb->Mnp->Configure (IpSb->Mnp, NULL);
    935     gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
    936     gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);
    937     return ;
    938   }
    939 
    940   if (!IsDadPassed || NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
    941     //
    942     // Free the AddressInfo we hold if DAD fails or it is a link-local address.
    943     //
    944     FreePool (AddrInfo);
    945   }
    946 
    947   RemoveEntryList (&DadEntry->Link);
    948   FreePool (DadEntry);
    949 }
    950 
    951 /**
    952   Create a DAD (Duplicate Address Detection) entry and queue it to be performed.
    953 
    954   @param[in]  IpIf          Points to the IP6_INTERFACE.
    955   @param[in]  AddressInfo   The address information which needs DAD performed.
    956   @param[in]  Callback      The callback routine that will be called after DAD
    957                             is performed. This is an optional parameter that
    958                             may be NULL.
    959   @param[in]  Context       The opaque parameter for a DAD callback routine.
    960                             This is an optional parameter that may be NULL.
    961 
    962   @retval EFI_SUCCESS           The DAD entry was created and queued.
    963   @retval EFI_OUT_OF_RESOURCES  Failed to allocate the memory to complete the
    964                                 operation.
    965 
    966 
    967 **/
    968 EFI_STATUS
    969 Ip6InitDADProcess (
    970   IN IP6_INTERFACE          *IpIf,
    971   IN IP6_ADDRESS_INFO       *AddressInfo,
    972   IN IP6_DAD_CALLBACK       Callback  OPTIONAL,
    973   IN VOID                   *Context  OPTIONAL
    974   )
    975 {
    976   IP6_DAD_ENTRY                             *Entry;
    977   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS  *DadXmits;
    978   IP6_SERVICE                               *IpSb;
    979   EFI_STATUS                                Status;
    980   UINT32                                    MaxDelayTick;
    981 
    982   NET_CHECK_SIGNATURE (IpIf, IP6_INTERFACE_SIGNATURE);
    983   ASSERT (AddressInfo != NULL);
    984 
    985   //
    986   // Do nothing if we have already started DAD on the address.
    987   //
    988   if (Ip6FindDADEntry (IpIf->Service, &AddressInfo->Address, NULL) != NULL) {
    989     return EFI_SUCCESS;
    990   }
    991 
    992   Status   = EFI_SUCCESS;
    993   IpSb     = IpIf->Service;
    994   DadXmits = &IpSb->Ip6ConfigInstance.DadXmits;
    995 
    996   //
    997   // Allocate the resources and insert info
    998   //
    999   Entry = AllocatePool (sizeof (IP6_DAD_ENTRY));
   1000   if (Entry == NULL) {
   1001     return EFI_OUT_OF_RESOURCES;
   1002   }
   1003 
   1004   //
   1005   // Map the incoming unicast address to solicited-node multicast address
   1006   //
   1007   Ip6CreateSNMulticastAddr (&AddressInfo->Address, &Entry->Destination);
   1008 
   1009   //
   1010   // Join in the solicited-node multicast address.
   1011   //
   1012   Status = Ip6JoinGroup (IpSb, IpIf, &Entry->Destination);
   1013   if (EFI_ERROR (Status)) {
   1014     FreePool (Entry);
   1015     return Status;
   1016   }
   1017 
   1018   Entry->Signature    = IP6_DAD_ENTRY_SIGNATURE;
   1019   Entry->MaxTransmit  = DadXmits->DupAddrDetectTransmits;
   1020   Entry->Transmit     = 0;
   1021   Entry->Receive      = 0;
   1022   MaxDelayTick        = IP6_MAX_RTR_SOLICITATION_DELAY / IP6_TIMER_INTERVAL_IN_MS;
   1023   Entry->RetransTick  = (MaxDelayTick * ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5;
   1024   Entry->AddressInfo  = AddressInfo;
   1025   Entry->Callback     = Callback;
   1026   Entry->Context      = Context;
   1027   InsertTailList (&IpIf->DupAddrDetectList, &Entry->Link);
   1028 
   1029   if (Entry->MaxTransmit == 0) {
   1030     //
   1031     // DAD is disabled on this interface, immediately mark this DAD successful.
   1032     //
   1033     Ip6OnDADFinished (TRUE, IpIf, Entry);
   1034   }
   1035 
   1036   return EFI_SUCCESS;
   1037 }
   1038 
   1039 /**
   1040   Search IP6_DAD_ENTRY from the Duplicate Address Detection List.
   1041 
   1042   @param[in]  IpSb          The pointer to the IP6_SERVICE instance.
   1043   @param[in]  Target        The address information which needs DAD performed .
   1044   @param[out] Interface     If not NULL, output the IP6 interface that configures
   1045                             the tentative address.
   1046 
   1047   @return NULL if failed to find the matching DAD entry.
   1048           Otherwise, point to the found DAD entry.
   1049 
   1050 **/
   1051 IP6_DAD_ENTRY *
   1052 Ip6FindDADEntry (
   1053   IN  IP6_SERVICE      *IpSb,
   1054   IN  EFI_IPv6_ADDRESS *Target,
   1055   OUT IP6_INTERFACE    **Interface OPTIONAL
   1056   )
   1057 {
   1058   LIST_ENTRY                *Entry;
   1059   LIST_ENTRY                *Entry2;
   1060   IP6_INTERFACE             *IpIf;
   1061   IP6_DAD_ENTRY             *DupAddrDetect;
   1062   IP6_ADDRESS_INFO          *AddrInfo;
   1063 
   1064   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
   1065     IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
   1066 
   1067     NET_LIST_FOR_EACH (Entry2, &IpIf->DupAddrDetectList) {
   1068       DupAddrDetect = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
   1069       AddrInfo      = DupAddrDetect->AddressInfo;
   1070       if (EFI_IP6_EQUAL (&AddrInfo->Address, Target)) {
   1071         if (Interface != NULL) {
   1072           *Interface = IpIf;
   1073         }
   1074         return DupAddrDetect;
   1075       }
   1076     }
   1077   }
   1078 
   1079   return NULL;
   1080 }
   1081 
   1082 /**
   1083   Generate router solicit message and send it out to Destination Address or
   1084   All Router Link Local scope multicast address.
   1085 
   1086   @param[in]  IpSb               The IP service to send the packet.
   1087   @param[in]  Interface          If not NULL, points to the IP6 interface to send
   1088                                  the packet.
   1089   @param[in]  SourceAddress      If not NULL, the source address of the message.
   1090   @param[in]  DestinationAddress If not NULL, the destination address of the message.
   1091   @param[in]  SourceLinkAddress  If not NULL, the MAC address of the source.
   1092                                  A source link-layer address option will be appended
   1093                                  to the message.
   1094 
   1095   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to complete the
   1096                                  operation.
   1097   @retval EFI_SUCCESS            The router solicit message was successfully sent.
   1098 
   1099 **/
   1100 EFI_STATUS
   1101 Ip6SendRouterSolicit (
   1102   IN IP6_SERVICE            *IpSb,
   1103   IN IP6_INTERFACE          *Interface          OPTIONAL,
   1104   IN EFI_IPv6_ADDRESS       *SourceAddress      OPTIONAL,
   1105   IN EFI_IPv6_ADDRESS       *DestinationAddress OPTIONAL,
   1106   IN EFI_MAC_ADDRESS        *SourceLinkAddress  OPTIONAL
   1107   )
   1108 {
   1109   NET_BUF                   *Packet;
   1110   EFI_IP6_HEADER            Head;
   1111   IP6_ICMP_INFORMATION_HEAD *IcmpHead;
   1112   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
   1113   UINT16                    PayloadLen;
   1114   IP6_INTERFACE             *IpIf;
   1115 
   1116   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
   1117 
   1118   IpIf = Interface;
   1119   if (IpIf == NULL && IpSb->DefaultInterface != NULL) {
   1120     IpIf = IpSb->DefaultInterface;
   1121   }
   1122 
   1123   //
   1124   // Generate the packet to be sent
   1125   //
   1126 
   1127   PayloadLen = (UINT16) sizeof (IP6_ICMP_INFORMATION_HEAD);
   1128   if (SourceLinkAddress != NULL) {
   1129     PayloadLen += sizeof (IP6_ETHER_ADDR_OPTION);
   1130   }
   1131 
   1132   Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
   1133   if (Packet == NULL) {
   1134     return EFI_OUT_OF_RESOURCES;
   1135   }
   1136 
   1137   //
   1138   // Create the basic IPv6 header.
   1139   //
   1140   Head.FlowLabelL     = 0;
   1141   Head.FlowLabelH     = 0;
   1142   Head.PayloadLength  = HTONS (PayloadLen);
   1143   Head.NextHeader     = IP6_ICMP;
   1144   Head.HopLimit       = IP6_HOP_LIMIT;
   1145 
   1146   if (SourceAddress != NULL) {
   1147     IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
   1148   } else {
   1149     ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
   1150   }
   1151 
   1152 
   1153   if (DestinationAddress != NULL) {
   1154     IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
   1155   } else {
   1156     Ip6SetToAllNodeMulticast (TRUE, IP6_LINK_LOCAL_SCOPE, &Head.DestinationAddress);
   1157   }
   1158 
   1159   NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
   1160 
   1161   //
   1162   // Fill in the ICMP header, and Source link-layer address if contained.
   1163   //
   1164 
   1165   IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
   1166   ASSERT (IcmpHead != NULL);
   1167   ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
   1168   IcmpHead->Head.Type = ICMP_V6_ROUTER_SOLICIT;
   1169   IcmpHead->Head.Code = 0;
   1170 
   1171   LinkLayerOption = NULL;
   1172   if (SourceLinkAddress != NULL) {
   1173     LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
   1174                                                   Packet,
   1175                                                   sizeof (IP6_ETHER_ADDR_OPTION),
   1176                                                   FALSE
   1177                                                   );
   1178     ASSERT (LinkLayerOption != NULL);
   1179     LinkLayerOption->Type   = Ip6OptionEtherSource;
   1180     LinkLayerOption->Length = (UINT8) sizeof (IP6_ETHER_ADDR_OPTION);
   1181     CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
   1182   }
   1183 
   1184   //
   1185   // Transmit the packet
   1186   //
   1187   return Ip6Output (IpSb, IpIf, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
   1188 }
   1189 
   1190 /**
   1191   Generate a Neighbor Advertisement message and send it out to Destination Address.
   1192 
   1193   @param[in]  IpSb               The IP service to send the packet.
   1194   @param[in]  SourceAddress      The source address of the message.
   1195   @param[in]  DestinationAddress The destination address of the message.
   1196   @param[in]  TargetIp6Address   The target address field in the Neighbor Solicitation
   1197                                  message that prompted this advertisement.
   1198   @param[in]  TargetLinkAddress  The MAC address for the target, i.e. the sender
   1199                                  of the advertisement.
   1200   @param[in]  IsRouter           If TRUE, indicates the sender is a router.
   1201   @param[in]  Override           If TRUE, indicates the advertisement should override
   1202                                  an existing cache entry and update the MAC address.
   1203   @param[in]  Solicited          If TRUE, indicates the advertisement was sent
   1204                                  in response to a Neighbor Solicitation from
   1205                                  the Destination address.
   1206 
   1207   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to complete the
   1208                                  operation.
   1209   @retval EFI_SUCCESS            The Neighbor Advertise message was successfully sent.
   1210 
   1211 **/
   1212 EFI_STATUS
   1213 Ip6SendNeighborAdvertise (
   1214   IN IP6_SERVICE            *IpSb,
   1215   IN EFI_IPv6_ADDRESS       *SourceAddress,
   1216   IN EFI_IPv6_ADDRESS       *DestinationAddress,
   1217   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
   1218   IN EFI_MAC_ADDRESS        *TargetLinkAddress,
   1219   IN BOOLEAN                IsRouter,
   1220   IN BOOLEAN                Override,
   1221   IN BOOLEAN                Solicited
   1222   )
   1223 {
   1224   NET_BUF                   *Packet;
   1225   EFI_IP6_HEADER            Head;
   1226   IP6_ICMP_INFORMATION_HEAD *IcmpHead;
   1227   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
   1228   EFI_IPv6_ADDRESS          *Target;
   1229   UINT16                    PayloadLen;
   1230 
   1231   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
   1232 
   1233   //
   1234   // The Neighbor Advertisement message must include a Target link-layer address option
   1235   // when responding to multicast solicitation and should include such option when
   1236   // responding to unicast solicitation. It also must include such option as unsolicited
   1237   // advertisement.
   1238   //
   1239   ASSERT (DestinationAddress != NULL && TargetIp6Address != NULL && TargetLinkAddress != NULL);
   1240 
   1241   PayloadLen = (UINT16) (sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS) + sizeof (IP6_ETHER_ADDR_OPTION));
   1242 
   1243   //
   1244   // Generate the packet to be sent
   1245   //
   1246 
   1247   Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
   1248   if (Packet == NULL) {
   1249     return EFI_OUT_OF_RESOURCES;
   1250   }
   1251 
   1252   //
   1253   // Create the basic IPv6 header.
   1254   //
   1255   Head.FlowLabelL     = 0;
   1256   Head.FlowLabelH     = 0;
   1257   Head.PayloadLength  = HTONS (PayloadLen);
   1258   Head.NextHeader     = IP6_ICMP;
   1259   Head.HopLimit       = IP6_HOP_LIMIT;
   1260 
   1261   IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
   1262   IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
   1263 
   1264   NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
   1265 
   1266   //
   1267   // Fill in the ICMP header, Target address, and Target link-layer address.
   1268   // Set the Router flag, Solicited flag and Override flag.
   1269   //
   1270 
   1271   IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
   1272   ASSERT (IcmpHead != NULL);
   1273   ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
   1274   IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_ADVERTISE;
   1275   IcmpHead->Head.Code = 0;
   1276 
   1277   if (IsRouter) {
   1278     IcmpHead->Fourth |= IP6_IS_ROUTER_FLAG;
   1279   }
   1280 
   1281   if (Solicited) {
   1282     IcmpHead->Fourth |= IP6_SOLICITED_FLAG;
   1283   }
   1284 
   1285   if (Override) {
   1286     IcmpHead->Fourth |= IP6_OVERRIDE_FLAG;
   1287   }
   1288 
   1289   Target = (EFI_IPv6_ADDRESS *) NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
   1290   ASSERT (Target != NULL);
   1291   IP6_COPY_ADDRESS (Target, TargetIp6Address);
   1292 
   1293   LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
   1294                                                 Packet,
   1295                                                 sizeof (IP6_ETHER_ADDR_OPTION),
   1296                                                 FALSE
   1297                                                 );
   1298   ASSERT (LinkLayerOption != NULL);
   1299   LinkLayerOption->Type   = Ip6OptionEtherTarget;
   1300   LinkLayerOption->Length = 1;
   1301   CopyMem (LinkLayerOption->EtherAddr, TargetLinkAddress, 6);
   1302 
   1303   //
   1304   // Transmit the packet
   1305   //
   1306   return Ip6Output (IpSb, NULL, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
   1307 }
   1308 
   1309 /**
   1310   Generate the Neighbor Solicitation message and send it to the Destination Address.
   1311 
   1312   @param[in]  IpSb               The IP service to send the packet
   1313   @param[in]  SourceAddress      The source address of the message.
   1314   @param[in]  DestinationAddress The destination address of the message.
   1315   @param[in]  TargetIp6Address   The IP address of the target of the solicitation.
   1316                                  It must not be a multicast address.
   1317   @param[in]  SourceLinkAddress  The MAC address for the sender. If not NULL,
   1318                                  a source link-layer address option will be appended
   1319                                  to the message.
   1320 
   1321   @retval EFI_INVALID_PARAMETER  Any input parameter is invalid.
   1322   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to complete the
   1323                                  operation.
   1324   @retval EFI_SUCCESS            The Neighbor Advertise message was successfully sent.
   1325 
   1326 **/
   1327 EFI_STATUS
   1328 Ip6SendNeighborSolicit (
   1329   IN IP6_SERVICE            *IpSb,
   1330   IN EFI_IPv6_ADDRESS       *SourceAddress,
   1331   IN EFI_IPv6_ADDRESS       *DestinationAddress,
   1332   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
   1333   IN EFI_MAC_ADDRESS        *SourceLinkAddress OPTIONAL
   1334   )
   1335 {
   1336   NET_BUF                   *Packet;
   1337   EFI_IP6_HEADER            Head;
   1338   IP6_ICMP_INFORMATION_HEAD *IcmpHead;
   1339   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
   1340   EFI_IPv6_ADDRESS          *Target;
   1341   BOOLEAN                   IsDAD;
   1342   UINT16                    PayloadLen;
   1343   IP6_NEIGHBOR_ENTRY        *Neighbor;
   1344 
   1345   //
   1346   // Check input parameters
   1347   //
   1348   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
   1349   if (DestinationAddress == NULL || TargetIp6Address == NULL) {
   1350     return EFI_INVALID_PARAMETER;
   1351   }
   1352 
   1353   IsDAD = FALSE;
   1354 
   1355   if (SourceAddress == NULL || (SourceAddress != NULL && NetIp6IsUnspecifiedAddr (SourceAddress))) {
   1356     IsDAD = TRUE;
   1357   }
   1358 
   1359   //
   1360   // The Neighbor Solicitation message should include a source link-layer address option
   1361   // if the solicitation is not sent by performing DAD - Duplicate Address Detection.
   1362   // Otherwise must not include it.
   1363   //
   1364   PayloadLen = (UINT16) (sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS));
   1365 
   1366   if (!IsDAD) {
   1367     if (SourceLinkAddress == NULL) {
   1368       return EFI_INVALID_PARAMETER;
   1369     }
   1370 
   1371     PayloadLen = (UINT16) (PayloadLen + sizeof (IP6_ETHER_ADDR_OPTION));
   1372   }
   1373 
   1374   //
   1375   // Generate the packet to be sent
   1376   //
   1377 
   1378   Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
   1379   if (Packet == NULL) {
   1380     return EFI_OUT_OF_RESOURCES;
   1381   }
   1382 
   1383   //
   1384   // Create the basic IPv6 header
   1385   //
   1386   Head.FlowLabelL     = 0;
   1387   Head.FlowLabelH     = 0;
   1388   Head.PayloadLength  = HTONS (PayloadLen);
   1389   Head.NextHeader     = IP6_ICMP;
   1390   Head.HopLimit       = IP6_HOP_LIMIT;
   1391 
   1392   if (SourceAddress != NULL) {
   1393     IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
   1394   } else {
   1395     ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
   1396   }
   1397 
   1398   IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
   1399 
   1400   NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
   1401 
   1402   //
   1403   // Fill in the ICMP header, Target address, and Source link-layer address.
   1404   //
   1405   IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
   1406   ASSERT (IcmpHead != NULL);
   1407   ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
   1408   IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_SOLICIT;
   1409   IcmpHead->Head.Code = 0;
   1410 
   1411   Target = (EFI_IPv6_ADDRESS *) NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
   1412   ASSERT (Target != NULL);
   1413   IP6_COPY_ADDRESS (Target, TargetIp6Address);
   1414 
   1415   LinkLayerOption = NULL;
   1416   if (!IsDAD) {
   1417 
   1418     //
   1419     // Fill in the source link-layer address option
   1420     //
   1421     LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
   1422                                                   Packet,
   1423                                                   sizeof (IP6_ETHER_ADDR_OPTION),
   1424                                                   FALSE
   1425                                                   );
   1426     ASSERT (LinkLayerOption != NULL);
   1427     LinkLayerOption->Type   = Ip6OptionEtherSource;
   1428     LinkLayerOption->Length = 1;
   1429     CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
   1430   }
   1431 
   1432   //
   1433   // Create a Neighbor Cache entry in the INCOMPLETE state when performing
   1434   // address resolution.
   1435   //
   1436   if (!IsDAD && Ip6IsSNMulticastAddr (DestinationAddress)) {
   1437     Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
   1438     if (Neighbor == NULL) {
   1439       Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, NULL);
   1440       ASSERT (Neighbor != NULL);
   1441     }
   1442   }
   1443 
   1444   //
   1445   // Transmit the packet
   1446   //
   1447   return Ip6Output (IpSb, IpSb->DefaultInterface, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
   1448 }
   1449 
   1450 /**
   1451   Process the Neighbor Solicitation message. The message may be sent for Duplicate
   1452   Address Detection or Address Resolution.
   1453 
   1454   @param[in]  IpSb               The IP service that received the packet.
   1455   @param[in]  Head               The IP head of the message.
   1456   @param[in]  Packet             The content of the message with IP head removed.
   1457 
   1458   @retval EFI_SUCCESS            The packet processed successfully.
   1459   @retval EFI_INVALID_PARAMETER  The packet is invalid.
   1460   @retval EFI_ICMP_ERROR         The packet indicates that DAD is failed.
   1461   @retval Others                 Failed to process the packet.
   1462 
   1463 **/
   1464 EFI_STATUS
   1465 Ip6ProcessNeighborSolicit (
   1466   IN IP6_SERVICE            *IpSb,
   1467   IN EFI_IP6_HEADER         *Head,
   1468   IN NET_BUF                *Packet
   1469   )
   1470 {
   1471   IP6_ICMP_INFORMATION_HEAD Icmp;
   1472   EFI_IPv6_ADDRESS          Target;
   1473   IP6_ETHER_ADDR_OPTION     LinkLayerOption;
   1474   BOOLEAN                   IsDAD;
   1475   BOOLEAN                   IsUnicast;
   1476   BOOLEAN                   IsMaintained;
   1477   IP6_DAD_ENTRY             *DupAddrDetect;
   1478   IP6_INTERFACE             *IpIf;
   1479   IP6_NEIGHBOR_ENTRY        *Neighbor;
   1480   BOOLEAN                   Solicited;
   1481   BOOLEAN                   UpdateCache;
   1482   EFI_IPv6_ADDRESS          Dest;
   1483   UINT16                    OptionLen;
   1484   UINT8                     *Option;
   1485   BOOLEAN                   Provided;
   1486   EFI_STATUS                Status;
   1487   VOID                      *MacAddress;
   1488 
   1489   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
   1490   NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
   1491 
   1492   //
   1493   // Perform Message Validation:
   1494   // The IP Hop Limit field has a value of 255, i.e., the packet
   1495   // could not possibly have been forwarded by a router.
   1496   // ICMP Code is 0.
   1497   // Target Address is not a multicast address.
   1498   //
   1499   Status = EFI_INVALID_PARAMETER;
   1500 
   1501   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 || !NetIp6IsValidUnicast (&Target)) {
   1502     goto Exit;
   1503   }
   1504 
   1505   //
   1506   // ICMP length is 24 or more octets.
   1507   //
   1508   OptionLen = 0;
   1509   if (Head->PayloadLength < IP6_ND_LENGTH) {
   1510     goto Exit;
   1511   } else {
   1512     OptionLen = (UINT16) (Head->PayloadLength - IP6_ND_LENGTH);
   1513     if (OptionLen != 0) {
   1514       Option    = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
   1515       ASSERT (Option != NULL);
   1516 
   1517       //
   1518       // All included options should have a length that is greater than zero.
   1519       //
   1520       if (!Ip6IsNDOptionValid (Option, OptionLen)) {
   1521         goto Exit;
   1522       }
   1523     }
   1524   }
   1525 
   1526   IsDAD        = NetIp6IsUnspecifiedAddr (&Head->SourceAddress);
   1527   IsUnicast    = (BOOLEAN) !Ip6IsSNMulticastAddr (&Head->DestinationAddress);
   1528   IsMaintained = Ip6IsOneOfSetAddress (IpSb, &Target, &IpIf, NULL);
   1529 
   1530   Provided = FALSE;
   1531   if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
   1532     NetbufCopy (
   1533       Packet,
   1534       IP6_ND_LENGTH,
   1535       sizeof (IP6_ETHER_ADDR_OPTION),
   1536       (UINT8 *) &LinkLayerOption
   1537       );
   1538     //
   1539     // The solicitation for neighbor discovery should include a source link-layer
   1540     // address option. If the option is not recognized, silently ignore it.
   1541     //
   1542     if (LinkLayerOption.Type == Ip6OptionEtherSource) {
   1543       if (IsDAD) {
   1544         //
   1545         // If the IP source address is the unspecified address, the source
   1546         // link-layer address option must not be included in the message.
   1547         //
   1548         goto Exit;
   1549       }
   1550 
   1551       Provided = TRUE;
   1552     }
   1553   }
   1554 
   1555   //
   1556   // If the IP source address is the unspecified address, the IP
   1557   // destination address is a solicited-node multicast address.
   1558   //
   1559   if (IsDAD && IsUnicast) {
   1560     goto Exit;
   1561   }
   1562 
   1563   //
   1564   // If the target address is tentative, and the source address is a unicast address,
   1565   // the solicitation's sender is performing address resolution on the target;
   1566   //  the solicitation should be silently ignored.
   1567   //
   1568   if (!IsDAD && !IsMaintained) {
   1569     goto Exit;
   1570   }
   1571 
   1572   //
   1573   // If received unicast neighbor solicitation but destination is not this node,
   1574   // drop the packet.
   1575   //
   1576   if (IsUnicast && !IsMaintained) {
   1577     goto Exit;
   1578   }
   1579 
   1580   //
   1581   // In DAD, when target address is a tentative address,
   1582   // process the received neighbor solicitation message but not send out response.
   1583   //
   1584   if (IsDAD && !IsMaintained) {
   1585     DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
   1586     if (DupAddrDetect != NULL) {
   1587       //
   1588       // Check the MAC address of the incoming packet.
   1589       //
   1590       if (IpSb->RecvRequest.MnpToken.Packet.RxData == NULL) {
   1591         goto Exit;
   1592       }
   1593 
   1594       MacAddress = IpSb->RecvRequest.MnpToken.Packet.RxData->SourceAddress;
   1595       if (MacAddress != NULL) {
   1596         if (CompareMem (
   1597               MacAddress,
   1598               &IpSb->SnpMode.CurrentAddress,
   1599               IpSb->SnpMode.HwAddressSize
   1600               ) != 0) {
   1601           //
   1602           // The NS is from another node to performing DAD on the same address.
   1603           // Fail DAD for the tentative address.
   1604           //
   1605           Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
   1606           Status = EFI_ICMP_ERROR;
   1607         } else {
   1608           //
   1609           // The below layer loopback the NS we sent. Record it and wait for more.
   1610           //
   1611           DupAddrDetect->Receive++;
   1612           Status = EFI_SUCCESS;
   1613         }
   1614       }
   1615     }
   1616     goto Exit;
   1617   }
   1618 
   1619   //
   1620   // If the solicitation does not contain a link-layer address, DO NOT create or
   1621   // update the neighbor cache entries.
   1622   //
   1623   if (Provided) {
   1624     Neighbor    = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
   1625     UpdateCache = FALSE;
   1626 
   1627     if (Neighbor == NULL) {
   1628       Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &Head->SourceAddress, NULL);
   1629       if (Neighbor == NULL) {
   1630         Status = EFI_OUT_OF_RESOURCES;
   1631         goto Exit;
   1632       }
   1633       UpdateCache = TRUE;
   1634     } else {
   1635       if (CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6) != 0) {
   1636         UpdateCache = TRUE;
   1637       }
   1638     }
   1639 
   1640     if (UpdateCache) {
   1641       Neighbor->State = EfiNeighborStale;
   1642       Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   1643       CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
   1644       //
   1645       // Send queued packets if exist.
   1646       //
   1647       Neighbor->CallBack ((VOID *) Neighbor);
   1648     }
   1649   }
   1650 
   1651   //
   1652   // Sends a Neighbor Advertisement as response.
   1653   // Set the Router flag to zero since the node is a host.
   1654   // If the source address of the solicitation is unspeicifed, and target address
   1655   // is one of the maintained address, reply a unsolicited multicast advertisement.
   1656   //
   1657   if (IsDAD && IsMaintained) {
   1658     Solicited = FALSE;
   1659     Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &Dest);
   1660   } else {
   1661     Solicited = TRUE;
   1662     IP6_COPY_ADDRESS (&Dest, &Head->SourceAddress);
   1663   }
   1664 
   1665   Status = Ip6SendNeighborAdvertise (
   1666              IpSb,
   1667              &Target,
   1668              &Dest,
   1669              &Target,
   1670              &IpSb->SnpMode.CurrentAddress,
   1671              FALSE,
   1672              TRUE,
   1673              Solicited
   1674              );
   1675 Exit:
   1676   NetbufFree (Packet);
   1677   return Status;
   1678 }
   1679 
   1680 /**
   1681   Process the Neighbor Advertisement message.
   1682 
   1683   @param[in]  IpSb               The IP service that received the packet.
   1684   @param[in]  Head               The IP head of the message.
   1685   @param[in]  Packet             The content of the message with IP head removed.
   1686 
   1687   @retval EFI_SUCCESS            The packet processed successfully.
   1688   @retval EFI_INVALID_PARAMETER  The packet is invalid.
   1689   @retval EFI_ICMP_ERROR         The packet indicates that DAD is failed.
   1690   @retval Others                 Failed to process the packet.
   1691 
   1692 **/
   1693 EFI_STATUS
   1694 Ip6ProcessNeighborAdvertise (
   1695   IN IP6_SERVICE            *IpSb,
   1696   IN EFI_IP6_HEADER         *Head,
   1697   IN NET_BUF                *Packet
   1698   )
   1699 {
   1700   IP6_ICMP_INFORMATION_HEAD Icmp;
   1701   EFI_IPv6_ADDRESS          Target;
   1702   IP6_ETHER_ADDR_OPTION     LinkLayerOption;
   1703   BOOLEAN                   Provided;
   1704   INTN                      Compare;
   1705   IP6_NEIGHBOR_ENTRY        *Neighbor;
   1706   IP6_DEFAULT_ROUTER        *DefaultRouter;
   1707   BOOLEAN                   Solicited;
   1708   BOOLEAN                   IsRouter;
   1709   BOOLEAN                   Override;
   1710   IP6_DAD_ENTRY             *DupAddrDetect;
   1711   IP6_INTERFACE             *IpIf;
   1712   UINT16                    OptionLen;
   1713   UINT8                     *Option;
   1714   EFI_STATUS                Status;
   1715 
   1716   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
   1717   NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
   1718 
   1719   //
   1720   // Validate the incoming Neighbor Advertisement
   1721   //
   1722   Status = EFI_INVALID_PARAMETER;
   1723   //
   1724   // The IP Hop Limit field has a value of 255, i.e., the packet
   1725   // could not possibly have been forwarded by a router.
   1726   // ICMP Code is 0.
   1727   // Target Address is not a multicast address.
   1728   //
   1729   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 || !NetIp6IsValidUnicast (&Target)) {
   1730     goto Exit;
   1731   }
   1732 
   1733   //
   1734   // ICMP length is 24 or more octets.
   1735   //
   1736   Provided  = FALSE;
   1737   OptionLen = 0;
   1738   if (Head->PayloadLength < IP6_ND_LENGTH) {
   1739     goto Exit;
   1740   } else {
   1741     OptionLen = (UINT16) (Head->PayloadLength - IP6_ND_LENGTH);
   1742     if (OptionLen != 0) {
   1743       Option    = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
   1744       ASSERT (Option != NULL);
   1745 
   1746       //
   1747       // All included options should have a length that is greater than zero.
   1748       //
   1749       if (!Ip6IsNDOptionValid (Option, OptionLen)) {
   1750         goto Exit;
   1751       }
   1752     }
   1753   }
   1754 
   1755   //
   1756   // If the IP destination address is a multicast address, Solicited Flag is ZERO.
   1757   //
   1758   Solicited = FALSE;
   1759   if ((Icmp.Fourth & IP6_SOLICITED_FLAG) == IP6_SOLICITED_FLAG) {
   1760     Solicited = TRUE;
   1761   }
   1762   if (IP6_IS_MULTICAST (&Head->DestinationAddress) && Solicited) {
   1763     goto Exit;
   1764   }
   1765 
   1766   //
   1767   // DAD - Check whether the Target is one of our tentative address.
   1768   //
   1769   DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
   1770   if (DupAddrDetect != NULL) {
   1771     //
   1772     // DAD fails, some other node is using this address.
   1773     //
   1774     NetbufFree (Packet);
   1775     Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
   1776     return EFI_ICMP_ERROR;
   1777   }
   1778 
   1779   //
   1780   // Search the Neighbor Cache for the target's entry. If no entry exists,
   1781   // the advertisement should be silently discarded.
   1782   //
   1783   Neighbor = Ip6FindNeighborEntry (IpSb, &Target);
   1784   if (Neighbor == NULL) {
   1785     goto Exit;
   1786   }
   1787 
   1788   //
   1789   // Get IsRouter Flag and Override Flag
   1790   //
   1791   IsRouter = FALSE;
   1792   Override = FALSE;
   1793   if ((Icmp.Fourth & IP6_IS_ROUTER_FLAG) == IP6_IS_ROUTER_FLAG) {
   1794     IsRouter = TRUE;
   1795   }
   1796   if ((Icmp.Fourth & IP6_OVERRIDE_FLAG) == IP6_OVERRIDE_FLAG) {
   1797     Override = TRUE;
   1798   }
   1799 
   1800   //
   1801   // Check whether link layer option is included.
   1802   //
   1803   if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
   1804     NetbufCopy (
   1805       Packet,
   1806       IP6_ND_LENGTH,
   1807       sizeof (IP6_ETHER_ADDR_OPTION),
   1808       (UINT8 *) &LinkLayerOption
   1809       );
   1810 
   1811     if (LinkLayerOption.Type == Ip6OptionEtherTarget) {
   1812       Provided = TRUE;
   1813     }
   1814   }
   1815 
   1816   Compare = 0;
   1817   if (Provided) {
   1818     Compare = CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
   1819   }
   1820 
   1821   if (!Neighbor->IsRouter && IsRouter) {
   1822     DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
   1823     if (DefaultRouter != NULL) {
   1824       DefaultRouter->NeighborCache = Neighbor;
   1825     }
   1826   }
   1827 
   1828   if (Neighbor->State == EfiNeighborInComplete) {
   1829     //
   1830     // If the target's Neighbor Cache entry is in INCOMPLETE state and no
   1831     // Target Link-Layer address option is included while link layer has
   1832     // address, the message should be silently discarded.
   1833     //
   1834     if (!Provided) {
   1835       goto Exit;
   1836     }
   1837     //
   1838     // Update the Neighbor Cache
   1839     //
   1840     CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
   1841     if (Solicited) {
   1842       Neighbor->State = EfiNeighborReachable;
   1843       Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
   1844     } else {
   1845       Neighbor->State = EfiNeighborStale;
   1846       Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   1847       //
   1848       // Send any packets queued for the neighbor awaiting address resolution.
   1849       //
   1850       Neighbor->CallBack ((VOID *) Neighbor);
   1851     }
   1852 
   1853     Neighbor->IsRouter = IsRouter;
   1854 
   1855   } else {
   1856     if (!Override && Compare != 0) {
   1857       //
   1858       // When the Override Flag is clear and supplied link-layer address differs from
   1859       // that in the cache, if the state of the entry is not REACHABLE, ignore the
   1860       // message. Otherwise set it to STALE but do not update the entry in any
   1861       // other way.
   1862       //
   1863       if (Neighbor->State == EfiNeighborReachable) {
   1864         Neighbor->State = EfiNeighborStale;
   1865         Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   1866       }
   1867     } else {
   1868       if (Compare != 0) {
   1869         CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
   1870       }
   1871       //
   1872       // Update the entry's state
   1873       //
   1874       if (Solicited) {
   1875         Neighbor->State = EfiNeighborReachable;
   1876         Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
   1877       } else {
   1878         if (Compare != 0) {
   1879           Neighbor->State = EfiNeighborStale;
   1880           Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   1881         }
   1882       }
   1883 
   1884       //
   1885       // When IsRouter is changed from TRUE to FALSE, remove the router from the
   1886       // Default Router List and remove the Destination Cache entries for all destinations
   1887       // using the neighbor as a router.
   1888       //
   1889       if (Neighbor->IsRouter && !IsRouter) {
   1890         DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
   1891         if (DefaultRouter != NULL) {
   1892           Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
   1893         }
   1894       }
   1895 
   1896       Neighbor->IsRouter = IsRouter;
   1897     }
   1898   }
   1899 
   1900   if (Neighbor->State == EfiNeighborReachable) {
   1901     Neighbor->CallBack ((VOID *) Neighbor);
   1902   }
   1903 
   1904   Status = EFI_SUCCESS;
   1905 
   1906 Exit:
   1907   NetbufFree (Packet);
   1908   return Status;
   1909 }
   1910 
   1911 /**
   1912   Process the Router Advertisement message according to RFC4861.
   1913 
   1914   @param[in]  IpSb               The IP service that received the packet.
   1915   @param[in]  Head               The IP head of the message.
   1916   @param[in]  Packet             The content of the message with the IP head removed.
   1917 
   1918   @retval EFI_SUCCESS            The packet processed successfully.
   1919   @retval EFI_INVALID_PARAMETER  The packet is invalid.
   1920   @retval EFI_OUT_OF_RESOURCES   Insufficient resources to complete the
   1921                                  operation.
   1922   @retval Others                 Failed to process the packet.
   1923 
   1924 **/
   1925 EFI_STATUS
   1926 Ip6ProcessRouterAdvertise (
   1927   IN IP6_SERVICE            *IpSb,
   1928   IN EFI_IP6_HEADER         *Head,
   1929   IN NET_BUF                *Packet
   1930   )
   1931 {
   1932   IP6_ICMP_INFORMATION_HEAD Icmp;
   1933   UINT32                    ReachableTime;
   1934   UINT32                    RetransTimer;
   1935   UINT16                    RouterLifetime;
   1936   UINT16                    Offset;
   1937   UINT8                     Type;
   1938   UINT8                     Length;
   1939   IP6_ETHER_ADDR_OPTION     LinkLayerOption;
   1940   UINT32                    Fourth;
   1941   UINT8                     CurHopLimit;
   1942   BOOLEAN                   Mflag;
   1943   BOOLEAN                   Oflag;
   1944   IP6_DEFAULT_ROUTER        *DefaultRouter;
   1945   IP6_NEIGHBOR_ENTRY        *NeighborCache;
   1946   EFI_MAC_ADDRESS           LinkLayerAddress;
   1947   IP6_MTU_OPTION            MTUOption;
   1948   IP6_PREFIX_INFO_OPTION    PrefixOption;
   1949   IP6_PREFIX_LIST_ENTRY     *PrefixList;
   1950   BOOLEAN                   OnLink;
   1951   BOOLEAN                   Autonomous;
   1952   EFI_IPv6_ADDRESS          StatelessAddress;
   1953   EFI_STATUS                Status;
   1954   UINT16                    OptionLen;
   1955   UINT8                     *Option;
   1956   INTN                      Result;
   1957 
   1958   Status = EFI_INVALID_PARAMETER;
   1959 
   1960   if (IpSb->Ip6ConfigInstance.Policy != Ip6ConfigPolicyAutomatic) {
   1961     //
   1962     // Skip the process below as it's not required under the current policy.
   1963     //
   1964     goto Exit;
   1965   }
   1966 
   1967   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
   1968 
   1969   //
   1970   // Validate the incoming Router Advertisement
   1971   //
   1972 
   1973   //
   1974   // The IP source address must be a link-local address
   1975   //
   1976   if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
   1977     goto Exit;
   1978   }
   1979   //
   1980   // The IP Hop Limit field has a value of 255, i.e. the packet
   1981   // could not possibly have been forwarded by a router.
   1982   // ICMP Code is 0.
   1983   // ICMP length (derived from the IP length) is 16 or more octets.
   1984   //
   1985   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 ||
   1986       Head->PayloadLength < IP6_RA_LENGTH) {
   1987     goto Exit;
   1988   }
   1989 
   1990   //
   1991   // All included options have a length that is greater than zero.
   1992   //
   1993   OptionLen = (UINT16) (Head->PayloadLength - IP6_RA_LENGTH);
   1994   if (OptionLen != 0) {
   1995     Option    = NetbufGetByte (Packet, IP6_RA_LENGTH, NULL);
   1996     ASSERT (Option != NULL);
   1997 
   1998     if (!Ip6IsNDOptionValid (Option, OptionLen)) {
   1999       goto Exit;
   2000     }
   2001   }
   2002 
   2003   //
   2004   // Process Fourth field.
   2005   // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
   2006   // and Router Lifetime (16 bit).
   2007   //
   2008 
   2009   Fourth = NTOHL (Icmp.Fourth);
   2010   CopyMem (&RouterLifetime, &Fourth, sizeof (UINT16));
   2011 
   2012   //
   2013   // If the source address already in the default router list, update it.
   2014   // Otherwise create a new entry.
   2015   // A Lifetime of zero indicates that the router is not a default router.
   2016   //
   2017   DefaultRouter = Ip6FindDefaultRouter (IpSb, &Head->SourceAddress);
   2018   if (DefaultRouter == NULL) {
   2019     if (RouterLifetime != 0) {
   2020       DefaultRouter = Ip6CreateDefaultRouter (IpSb, &Head->SourceAddress, RouterLifetime);
   2021       if (DefaultRouter == NULL) {
   2022         Status = EFI_OUT_OF_RESOURCES;
   2023         goto Exit;
   2024       }
   2025     }
   2026   } else {
   2027     if (RouterLifetime != 0) {
   2028       DefaultRouter->Lifetime = RouterLifetime;
   2029       //
   2030       // Check the corresponding neighbor cache entry here.
   2031       //
   2032       if (DefaultRouter->NeighborCache == NULL) {
   2033         DefaultRouter->NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
   2034       }
   2035     } else {
   2036       //
   2037       // If the address is in the host's default router list and the router lifetime is zero,
   2038       // immediately time-out the entry.
   2039       //
   2040       Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
   2041     }
   2042   }
   2043 
   2044   CurHopLimit = *((UINT8 *) &Fourth + 3);
   2045   if (CurHopLimit != 0) {
   2046     IpSb->CurHopLimit = CurHopLimit;
   2047   }
   2048 
   2049   Mflag = FALSE;
   2050   Oflag = FALSE;
   2051   if ((*((UINT8 *) &Fourth + 2) & IP6_M_ADDR_CONFIG_FLAG) == IP6_M_ADDR_CONFIG_FLAG) {
   2052     Mflag = TRUE;
   2053   } else {
   2054     if ((*((UINT8 *) &Fourth + 2) & IP6_O_CONFIG_FLAG) == IP6_O_CONFIG_FLAG) {
   2055       Oflag = TRUE;
   2056     }
   2057   }
   2058 
   2059   if (Mflag || Oflag) {
   2060     //
   2061     // Use Ip6Config to get available addresses or other configuration from DHCP.
   2062     //
   2063     Ip6ConfigStartStatefulAutoConfig (&IpSb->Ip6ConfigInstance, Oflag);
   2064   }
   2065 
   2066   //
   2067   // Process Reachable Time and Retrans Timer fields.
   2068   //
   2069   NetbufCopy (Packet, sizeof (Icmp), sizeof (UINT32), (UINT8 *) &ReachableTime);
   2070   NetbufCopy (Packet, sizeof (Icmp) + sizeof (UINT32), sizeof (UINT32), (UINT8 *) &RetransTimer);
   2071   ReachableTime = NTOHL (ReachableTime);
   2072   RetransTimer  = NTOHL (RetransTimer);
   2073 
   2074   if (ReachableTime != 0 && ReachableTime != IpSb->BaseReachableTime) {
   2075     //
   2076     // If new value is not unspecified and differs from the previous one, record it
   2077     // in BaseReachableTime and recompute a ReachableTime.
   2078     //
   2079     IpSb->BaseReachableTime = ReachableTime;
   2080     Ip6UpdateReachableTime (IpSb);
   2081   }
   2082 
   2083   if (RetransTimer != 0) {
   2084     IpSb->RetransTimer = RetransTimer;
   2085   }
   2086 
   2087   //
   2088   // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
   2089   //
   2090   NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
   2091   if (NeighborCache != NULL) {
   2092     NeighborCache->IsRouter = TRUE;
   2093   }
   2094 
   2095   //
   2096   // If an valid router advertisment is received, stops router solicitation.
   2097   //
   2098   IpSb->RouterAdvertiseReceived = TRUE;
   2099 
   2100   //
   2101   // The only defined options that may appear are the Source
   2102   // Link-Layer Address, Prefix information and MTU options.
   2103   // All included options have a length that is greater than zero.
   2104   //
   2105   Offset = 16;
   2106   while (Offset < Head->PayloadLength) {
   2107     NetbufCopy (Packet, Offset, sizeof (UINT8), &Type);
   2108     switch (Type) {
   2109     case Ip6OptionEtherSource:
   2110       //
   2111       // Update the neighbor cache
   2112       //
   2113       NetbufCopy (Packet, Offset, sizeof (IP6_ETHER_ADDR_OPTION), (UINT8 *) &LinkLayerOption);
   2114       if (LinkLayerOption.Length <= 0) {
   2115         goto Exit;
   2116       }
   2117 
   2118       ZeroMem (&LinkLayerAddress, sizeof (EFI_MAC_ADDRESS));
   2119       CopyMem (&LinkLayerAddress, LinkLayerOption.EtherAddr, 6);
   2120 
   2121       if (NeighborCache == NULL) {
   2122         NeighborCache = Ip6CreateNeighborEntry (
   2123                           IpSb,
   2124                           Ip6OnArpResolved,
   2125                           &Head->SourceAddress,
   2126                           &LinkLayerAddress
   2127                           );
   2128         if (NeighborCache == NULL) {
   2129           Status = EFI_OUT_OF_RESOURCES;
   2130           goto Exit;
   2131         }
   2132         NeighborCache->IsRouter = TRUE;
   2133         NeighborCache->State    = EfiNeighborStale;
   2134         NeighborCache->Ticks    = (UINT32) IP6_INFINIT_LIFETIME;
   2135       } else {
   2136         Result = CompareMem (&LinkLayerAddress, &NeighborCache->LinkAddress, 6);
   2137 
   2138         //
   2139         // If the link-local address is the same as that already in the cache,
   2140         // the cache entry's state remains unchanged. Otherwise update the
   2141         // reachability state to STALE.
   2142         //
   2143         if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
   2144           CopyMem (&NeighborCache->LinkAddress, &LinkLayerAddress, 6);
   2145 
   2146           NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   2147 
   2148           if (NeighborCache->State == EfiNeighborInComplete) {
   2149             //
   2150             // Send queued packets if exist.
   2151             //
   2152             NeighborCache->State = EfiNeighborStale;
   2153             NeighborCache->CallBack ((VOID *) NeighborCache);
   2154           } else {
   2155             NeighborCache->State = EfiNeighborStale;
   2156           }
   2157         }
   2158       }
   2159 
   2160       Offset = (UINT16) (Offset + (UINT16) LinkLayerOption.Length * 8);
   2161       break;
   2162     case Ip6OptionPrefixInfo:
   2163       NetbufCopy (Packet, Offset, sizeof (IP6_PREFIX_INFO_OPTION), (UINT8 *) &PrefixOption);
   2164       if (PrefixOption.Length != 4) {
   2165         goto Exit;
   2166       }
   2167       PrefixOption.ValidLifetime     = NTOHL (PrefixOption.ValidLifetime);
   2168       PrefixOption.PreferredLifetime = NTOHL (PrefixOption.PreferredLifetime);
   2169 
   2170       //
   2171       // Get L and A flag, recorded in the lower 2 bits of Reserved1
   2172       //
   2173       OnLink = FALSE;
   2174       if ((PrefixOption.Reserved1 & IP6_ON_LINK_FLAG) == IP6_ON_LINK_FLAG) {
   2175         OnLink = TRUE;
   2176       }
   2177       Autonomous = FALSE;
   2178       if ((PrefixOption.Reserved1 & IP6_AUTO_CONFIG_FLAG) == IP6_AUTO_CONFIG_FLAG) {
   2179         Autonomous = TRUE;
   2180       }
   2181 
   2182       //
   2183       // If the prefix is the link-local prefix, silently ignore the prefix option.
   2184       //
   2185       if (PrefixOption.PrefixLength == IP6_LINK_LOCAL_PREFIX_LENGTH &&
   2186           NetIp6IsLinkLocalAddr (&PrefixOption.Prefix)
   2187           ) {
   2188         Offset += sizeof (IP6_PREFIX_INFO_OPTION);
   2189         break;
   2190       }
   2191       //
   2192       // Do following if on-link flag is set according to RFC4861.
   2193       //
   2194       if (OnLink) {
   2195         PrefixList = Ip6FindPrefixListEntry (
   2196                        IpSb,
   2197                        TRUE,
   2198                        PrefixOption.PrefixLength,
   2199                        &PrefixOption.Prefix
   2200                        );
   2201         //
   2202         // Create a new entry for the prefix, if the ValidLifetime is zero,
   2203         // silently ignore the prefix option.
   2204         //
   2205         if (PrefixList == NULL && PrefixOption.ValidLifetime != 0) {
   2206           PrefixList = Ip6CreatePrefixListEntry (
   2207                          IpSb,
   2208                          TRUE,
   2209                          PrefixOption.ValidLifetime,
   2210                          PrefixOption.PreferredLifetime,
   2211                          PrefixOption.PrefixLength,
   2212                          &PrefixOption.Prefix
   2213                          );
   2214           if (PrefixList == NULL) {
   2215             Status = EFI_OUT_OF_RESOURCES;
   2216             goto Exit;
   2217           }
   2218         } else if (PrefixList != NULL) {
   2219           if (PrefixOption.ValidLifetime != 0) {
   2220             PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
   2221           } else {
   2222             //
   2223             // If the prefix exists and incoming ValidLifetime is zero, immediately
   2224             // remove the prefix.
   2225             Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
   2226           }
   2227         }
   2228       }
   2229 
   2230       //
   2231       // Do following if Autonomous flag is set according to RFC4862.
   2232       //
   2233       if (Autonomous && PrefixOption.PreferredLifetime <= PrefixOption.ValidLifetime) {
   2234         PrefixList = Ip6FindPrefixListEntry (
   2235                        IpSb,
   2236                        FALSE,
   2237                        PrefixOption.PrefixLength,
   2238                        &PrefixOption.Prefix
   2239                        );
   2240         //
   2241         // Create a new entry for the prefix, and form an address by prefix + interface id
   2242         // If the sum of the prefix length and interface identifier length
   2243         // does not equal 128 bits, the Prefix Information option MUST be ignored.
   2244         //
   2245         if (PrefixList == NULL &&
   2246             PrefixOption.ValidLifetime != 0 &&
   2247             PrefixOption.PrefixLength + IpSb->InterfaceIdLen * 8 == 128
   2248             ) {
   2249           //
   2250           // Form the address in network order.
   2251           //
   2252           CopyMem (&StatelessAddress, &PrefixOption.Prefix, sizeof (UINT64));
   2253           CopyMem (&StatelessAddress.Addr[8], IpSb->InterfaceId, sizeof (UINT64));
   2254 
   2255           //
   2256           // If the address is not yet in the assigned address list, adds it into.
   2257           //
   2258           if (!Ip6IsOneOfSetAddress (IpSb, &StatelessAddress, NULL, NULL)) {
   2259             //
   2260             // And also not in the DAD process, check its uniqeness firstly.
   2261             //
   2262             if (Ip6FindDADEntry (IpSb, &StatelessAddress, NULL) == NULL) {
   2263               Status = Ip6SetAddress (
   2264                          IpSb->DefaultInterface,
   2265                          &StatelessAddress,
   2266                          FALSE,
   2267                          PrefixOption.PrefixLength,
   2268                          PrefixOption.ValidLifetime,
   2269                          PrefixOption.PreferredLifetime,
   2270                          NULL,
   2271                          NULL
   2272                          );
   2273               if (EFI_ERROR (Status)) {
   2274                 goto Exit;
   2275               }
   2276             }
   2277           }
   2278 
   2279           //
   2280           // Adds the prefix option to stateless prefix option list.
   2281           //
   2282           PrefixList = Ip6CreatePrefixListEntry (
   2283                          IpSb,
   2284                          FALSE,
   2285                          PrefixOption.ValidLifetime,
   2286                          PrefixOption.PreferredLifetime,
   2287                          PrefixOption.PrefixLength,
   2288                          &PrefixOption.Prefix
   2289                          );
   2290           if (PrefixList == NULL) {
   2291             Status = EFI_OUT_OF_RESOURCES;
   2292             goto Exit;
   2293           }
   2294         } else if (PrefixList != NULL) {
   2295 
   2296           //
   2297           // Reset the preferred lifetime of the address if the advertised prefix exists.
   2298           // Perform specific action to valid lifetime together.
   2299           //
   2300           PrefixList->PreferredLifetime = PrefixOption.PreferredLifetime;
   2301           if ((PrefixOption.ValidLifetime > 7200) ||
   2302               (PrefixOption.ValidLifetime > PrefixList->ValidLifetime)) {
   2303             //
   2304             // If the received Valid Lifetime is greater than 2 hours or
   2305             // greater than RemainingLifetime, set the valid lifetime of the
   2306             // corresponding address to the advertised Valid Lifetime.
   2307             //
   2308             PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
   2309 
   2310           } else if (PrefixList->ValidLifetime <= 7200) {
   2311             //
   2312             // If RemainingLifetime is less than or equls to 2 hours, ignore the
   2313             // Prefix Information option with regards to the valid lifetime.
   2314             // TODO: If this option has been authenticated, set the valid lifetime.
   2315             //
   2316           } else {
   2317             //
   2318             // Otherwise, reset the valid lifetime of the corresponding
   2319             // address to 2 hours.
   2320             //
   2321             PrefixList->ValidLifetime = 7200;
   2322           }
   2323         }
   2324       }
   2325 
   2326       Offset += sizeof (IP6_PREFIX_INFO_OPTION);
   2327       break;
   2328     case Ip6OptionMtu:
   2329       NetbufCopy (Packet, Offset, sizeof (IP6_MTU_OPTION), (UINT8 *) &MTUOption);
   2330       if (MTUOption.Length != 1) {
   2331         goto Exit;
   2332       }
   2333 
   2334       //
   2335       // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
   2336       // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
   2337       // in Router Advertisement.
   2338       //
   2339 
   2340       Offset += sizeof (IP6_MTU_OPTION);
   2341       break;
   2342     default:
   2343       //
   2344       // Silently ignore unrecognized options
   2345       //
   2346       NetbufCopy (Packet, Offset + sizeof (UINT8), sizeof (UINT8), &Length);
   2347       if (Length <= 0) {
   2348         goto Exit;
   2349       }
   2350 
   2351       Offset = (UINT16) (Offset + (UINT16) Length * 8);
   2352       break;
   2353     }
   2354   }
   2355 
   2356   Status = EFI_SUCCESS;
   2357 
   2358 Exit:
   2359   NetbufFree (Packet);
   2360   return Status;
   2361 }
   2362 
   2363 /**
   2364   Process the ICMPv6 redirect message. Find the instance, then update
   2365   its route cache.
   2366 
   2367   @param[in]  IpSb               The IP6 service binding instance that received
   2368                                  the packet.
   2369   @param[in]  Head               The IP head of the received ICMPv6 packet.
   2370   @param[in]  Packet             The content of the ICMPv6 redirect packet with
   2371                                  the IP head removed.
   2372 
   2373   @retval EFI_INVALID_PARAMETER  The parameter is invalid.
   2374   @retval EFI_OUT_OF_RESOURCES   Insuffcient resources to complete the
   2375                                  operation.
   2376   @retval EFI_SUCCESS            Successfully updated the route caches.
   2377 
   2378 **/
   2379 EFI_STATUS
   2380 Ip6ProcessRedirect (
   2381   IN IP6_SERVICE            *IpSb,
   2382   IN EFI_IP6_HEADER         *Head,
   2383   IN NET_BUF                *Packet
   2384   )
   2385 {
   2386   IP6_ICMP_INFORMATION_HEAD *Icmp;
   2387   EFI_IPv6_ADDRESS          *Target;
   2388   EFI_IPv6_ADDRESS          *IcmpDest;
   2389   UINT8                     *Option;
   2390   UINT16                    OptionLen;
   2391   IP6_ROUTE_ENTRY           *RouteEntry;
   2392   IP6_ROUTE_CACHE_ENTRY     *RouteCache;
   2393   IP6_NEIGHBOR_ENTRY        *NeighborCache;
   2394   INT32                     Length;
   2395   UINT8                     OptLen;
   2396   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
   2397   EFI_MAC_ADDRESS           Mac;
   2398   UINT32                    Index;
   2399   BOOLEAN                   IsRouter;
   2400   EFI_STATUS                Status;
   2401   INTN                      Result;
   2402 
   2403   Status = EFI_INVALID_PARAMETER;
   2404 
   2405   Icmp = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Packet, 0, NULL);
   2406   if (Icmp == NULL) {
   2407     goto Exit;
   2408   }
   2409 
   2410   //
   2411   // Validate the incoming Redirect message
   2412   //
   2413 
   2414   //
   2415   // The IP Hop Limit field has a value of 255, i.e. the packet
   2416   // could not possibly have been forwarded by a router.
   2417   // ICMP Code is 0.
   2418   // ICMP length (derived from the IP length) is 40 or more octets.
   2419   //
   2420   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp->Head.Code != 0 ||
   2421       Head->PayloadLength < IP6_REDITECT_LENGTH) {
   2422     goto Exit;
   2423   }
   2424 
   2425   //
   2426   // The IP source address must be a link-local address
   2427   //
   2428   if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
   2429     goto Exit;
   2430   }
   2431 
   2432   //
   2433   // The dest of this ICMP redirect message is not us.
   2434   //
   2435   if (!Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
   2436     goto Exit;
   2437   }
   2438 
   2439   //
   2440   // All included options have a length that is greater than zero.
   2441   //
   2442   OptionLen = (UINT16) (Head->PayloadLength - IP6_REDITECT_LENGTH);
   2443   if (OptionLen != 0) {
   2444     Option    = NetbufGetByte (Packet, IP6_REDITECT_LENGTH, NULL);
   2445     ASSERT (Option != NULL);
   2446 
   2447     if (!Ip6IsNDOptionValid (Option, OptionLen)) {
   2448       goto Exit;
   2449     }
   2450   }
   2451 
   2452   Target   = (EFI_IPv6_ADDRESS *) (Icmp + 1);
   2453   IcmpDest = Target + 1;
   2454 
   2455   //
   2456   // The ICMP Destination Address field in the redirect message does not contain
   2457   // a multicast address.
   2458   //
   2459   if (IP6_IS_MULTICAST (IcmpDest)) {
   2460     goto Exit;
   2461   }
   2462 
   2463   //
   2464   // The ICMP Target Address is either a link-local address (when redirected to
   2465   // a router) or the same as the ICMP Destination Address (when redirected to
   2466   // the on-link destination).
   2467   //
   2468   IsRouter = (BOOLEAN) !EFI_IP6_EQUAL (Target, IcmpDest);
   2469   if (!NetIp6IsLinkLocalAddr (Target) && IsRouter) {
   2470     goto Exit;
   2471   }
   2472 
   2473   //
   2474   // Check the options. The only interested option here is the target-link layer
   2475   // address option.
   2476   //
   2477   Length          = Packet->TotalSize - 40;
   2478   Option          = (UINT8 *) (IcmpDest + 1);
   2479   LinkLayerOption = NULL;
   2480   while (Length > 0) {
   2481     switch (*Option) {
   2482     case Ip6OptionEtherTarget:
   2483 
   2484       LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) Option;
   2485       OptLen          = LinkLayerOption->Length;
   2486       if (OptLen != 1) {
   2487         //
   2488         // For ethernet, the length must be 1.
   2489         //
   2490         goto Exit;
   2491       }
   2492       break;
   2493 
   2494     default:
   2495 
   2496       OptLen = *(Option + 1);
   2497       if (OptLen == 0) {
   2498         //
   2499         // A length of 0 is invalid.
   2500         //
   2501         goto Exit;
   2502       }
   2503       break;
   2504     }
   2505 
   2506     Length -= 8 * OptLen;
   2507     Option += 8 * OptLen;
   2508   }
   2509 
   2510   if (Length != 0) {
   2511     goto Exit;
   2512   }
   2513 
   2514   //
   2515   // The IP source address of the Redirect is the same as the current
   2516   // first-hop router for the specified ICMP Destination Address.
   2517   //
   2518   RouteCache = Ip6FindRouteCache (IpSb->RouteTable, IcmpDest, &Head->DestinationAddress);
   2519   if (RouteCache != NULL) {
   2520     if (!EFI_IP6_EQUAL (&RouteCache->NextHop, &Head->SourceAddress)) {
   2521       //
   2522       // The source of this Redirect message must match the NextHop of the
   2523       // corresponding route cache entry.
   2524       //
   2525       goto Exit;
   2526     }
   2527 
   2528     //
   2529     // Update the NextHop.
   2530     //
   2531     IP6_COPY_ADDRESS (&RouteCache->NextHop, Target);
   2532 
   2533     if (!IsRouter) {
   2534       RouteEntry = (IP6_ROUTE_ENTRY *) RouteCache->Tag;
   2535       RouteEntry->Flag = RouteEntry->Flag | IP6_DIRECT_ROUTE;
   2536     }
   2537 
   2538   } else {
   2539     //
   2540     // Get the Route Entry.
   2541     //
   2542     RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, IcmpDest, NULL);
   2543     if (RouteEntry == NULL) {
   2544       RouteEntry = Ip6CreateRouteEntry (IcmpDest, 0, NULL);
   2545       if (RouteEntry == NULL) {
   2546         Status = EFI_OUT_OF_RESOURCES;
   2547         goto Exit;
   2548       }
   2549     }
   2550 
   2551     if (!IsRouter) {
   2552       RouteEntry->Flag = IP6_DIRECT_ROUTE;
   2553     }
   2554 
   2555     //
   2556     // Create a route cache for this.
   2557     //
   2558     RouteCache = Ip6CreateRouteCacheEntry (
   2559                    IcmpDest,
   2560                    &Head->DestinationAddress,
   2561                    Target,
   2562                    (UINTN) RouteEntry
   2563                    );
   2564     if (RouteCache == NULL) {
   2565       Status = EFI_OUT_OF_RESOURCES;
   2566       goto Exit;
   2567     }
   2568 
   2569     //
   2570     // Insert the newly created route cache entry.
   2571     //
   2572     Index = IP6_ROUTE_CACHE_HASH (IcmpDest, &Head->DestinationAddress);
   2573     InsertHeadList (&IpSb->RouteTable->Cache.CacheBucket[Index], &RouteCache->Link);
   2574   }
   2575 
   2576   //
   2577   // Try to locate the neighbor cache for the Target.
   2578   //
   2579   NeighborCache = Ip6FindNeighborEntry (IpSb, Target);
   2580 
   2581   if (LinkLayerOption != NULL) {
   2582     if (NeighborCache == NULL) {
   2583       //
   2584       // Create a neighbor cache for the Target.
   2585       //
   2586       ZeroMem (&Mac, sizeof (EFI_MAC_ADDRESS));
   2587       CopyMem (&Mac, LinkLayerOption->EtherAddr, 6);
   2588       NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, Target, &Mac);
   2589       if (NeighborCache == NULL) {
   2590         //
   2591         // Just report a success here. The neighbor cache can be created in
   2592         // some other place.
   2593         //
   2594         Status = EFI_SUCCESS;
   2595         goto Exit;
   2596       }
   2597 
   2598       NeighborCache->State = EfiNeighborStale;
   2599       NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   2600     } else {
   2601       Result = CompareMem (LinkLayerOption->EtherAddr, &NeighborCache->LinkAddress, 6);
   2602 
   2603       //
   2604       // If the link-local address is the same as that already in the cache,
   2605       // the cache entry's state remains unchanged. Otherwise update the
   2606       // reachability state to STALE.
   2607       //
   2608       if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
   2609         CopyMem (&NeighborCache->LinkAddress, LinkLayerOption->EtherAddr, 6);
   2610 
   2611         NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   2612 
   2613         if (NeighborCache->State == EfiNeighborInComplete) {
   2614           //
   2615           // Send queued packets if exist.
   2616           //
   2617           NeighborCache->State = EfiNeighborStale;
   2618           NeighborCache->CallBack ((VOID *) NeighborCache);
   2619         } else {
   2620           NeighborCache->State = EfiNeighborStale;
   2621         }
   2622       }
   2623     }
   2624   }
   2625 
   2626   if (NeighborCache != NULL && IsRouter) {
   2627     //
   2628     // The Target is a router, set IsRouter to TRUE.
   2629     //
   2630     NeighborCache->IsRouter = TRUE;
   2631   }
   2632 
   2633   Status = EFI_SUCCESS;
   2634 
   2635 Exit:
   2636   NetbufFree (Packet);
   2637   return Status;
   2638 }
   2639 
   2640 /**
   2641   Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
   2642 
   2643   @param[in]  IpSb               The IP6 service binding instance.
   2644   @param[in]  TargetIp6Address   Pointer to Target IPv6 address.
   2645   @param[in]  TargetLinkAddress  Pointer to link-layer address of the target. Ignored if NULL.
   2646   @param[in]  Timeout            Time in 100-ns units that this entry will remain in the neighbor
   2647                                  cache. It will be deleted after Timeout. A value of zero means that
   2648                                  the entry is permanent. A non-zero value means that the entry is
   2649                                  dynamic.
   2650   @param[in]  Override           If TRUE, the cached link-layer address of the matching entry will
   2651                                  be overridden and updated; if FALSE, and if a
   2652                                  corresponding cache entry already existed, EFI_ACCESS_DENIED
   2653                                  will be returned.
   2654 
   2655   @retval  EFI_SUCCESS           The neighbor cache entry has been added.
   2656   @retval  EFI_OUT_OF_RESOURCES  Could not add the entry to the neighbor cache
   2657                                  due to insufficient resources.
   2658   @retval  EFI_NOT_FOUND         TargetLinkAddress is NULL.
   2659   @retval  EFI_ACCESS_DENIED     The to-be-added entry is already defined in the neighbor cache,
   2660                                  and that entry is tagged as un-overridden (when DeleteFlag
   2661                                  is FALSE).
   2662 
   2663 **/
   2664 EFI_STATUS
   2665 Ip6AddNeighbor (
   2666   IN IP6_SERVICE            *IpSb,
   2667   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
   2668   IN EFI_MAC_ADDRESS        *TargetLinkAddress OPTIONAL,
   2669   IN UINT32                 Timeout,
   2670   IN BOOLEAN                Override
   2671   )
   2672 {
   2673   IP6_NEIGHBOR_ENTRY        *Neighbor;
   2674 
   2675   Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
   2676   if (Neighbor != NULL) {
   2677     if (!Override) {
   2678       return EFI_ACCESS_DENIED;
   2679     } else {
   2680       if (TargetLinkAddress != NULL) {
   2681         IP6_COPY_LINK_ADDRESS (&Neighbor->LinkAddress, TargetLinkAddress);
   2682       }
   2683     }
   2684   } else {
   2685     if (TargetLinkAddress == NULL) {
   2686       return EFI_NOT_FOUND;
   2687     }
   2688 
   2689     Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, TargetLinkAddress);
   2690     if (Neighbor == NULL) {
   2691       return EFI_OUT_OF_RESOURCES;
   2692     }
   2693   }
   2694 
   2695   Neighbor->State = EfiNeighborReachable;
   2696 
   2697   if (Timeout != 0) {
   2698     Neighbor->Ticks   = IP6_GET_TICKS (Timeout / TICKS_PER_MS);
   2699     Neighbor->Dynamic = TRUE;
   2700   } else {
   2701     Neighbor->Ticks   = (UINT32) IP6_INFINIT_LIFETIME;
   2702   }
   2703 
   2704   return EFI_SUCCESS;
   2705 }
   2706 
   2707 /**
   2708   Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
   2709 
   2710   @param[in]  IpSb               The IP6 service binding instance.
   2711   @param[in]  TargetIp6Address   Pointer to Target IPv6 address.
   2712   @param[in]  TargetLinkAddress  Pointer to link-layer address of the target. Ignored if NULL.
   2713   @param[in]  Timeout            Time in 100-ns units that this entry will remain in the neighbor
   2714                                  cache. It will be deleted after Timeout. A value of zero means that
   2715                                  the entry is permanent. A non-zero value means that the entry is
   2716                                  dynamic.
   2717   @param[in]  Override           If TRUE, the cached link-layer address of the matching entry will
   2718                                  be overridden and updated; if FALSE, and if a
   2719                                  corresponding cache entry already existed, EFI_ACCESS_DENIED
   2720                                  will be returned.
   2721 
   2722   @retval  EFI_SUCCESS           The neighbor cache entry has been updated or deleted.
   2723   @retval  EFI_NOT_FOUND         This entry is not in the neighbor cache.
   2724 
   2725 **/
   2726 EFI_STATUS
   2727 Ip6DelNeighbor (
   2728   IN IP6_SERVICE            *IpSb,
   2729   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
   2730   IN EFI_MAC_ADDRESS        *TargetLinkAddress OPTIONAL,
   2731   IN UINT32                 Timeout,
   2732   IN BOOLEAN                Override
   2733   )
   2734 {
   2735   IP6_NEIGHBOR_ENTRY        *Neighbor;
   2736 
   2737   Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
   2738   if (Neighbor == NULL) {
   2739     return EFI_NOT_FOUND;
   2740   }
   2741 
   2742   RemoveEntryList (&Neighbor->Link);
   2743   FreePool (Neighbor);
   2744 
   2745   return EFI_SUCCESS;
   2746 }
   2747 
   2748 /**
   2749   The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
   2750   This time routine handles DAD module and neighbor state transition.
   2751   It is also responsible for sending out router solicitations.
   2752 
   2753   @param[in]  Event                 The IP6 service instance's heartbeat timer.
   2754   @param[in]  Context               The IP6 service instance.
   2755 
   2756 **/
   2757 VOID
   2758 EFIAPI
   2759 Ip6NdFasterTimerTicking (
   2760   IN EFI_EVENT              Event,
   2761   IN VOID                   *Context
   2762   )
   2763 {
   2764   LIST_ENTRY                *Entry;
   2765   LIST_ENTRY                *Next;
   2766   LIST_ENTRY                *Entry2;
   2767   IP6_INTERFACE             *IpIf;
   2768   IP6_DELAY_JOIN_LIST       *DelayNode;
   2769   EFI_IPv6_ADDRESS          Source;
   2770   IP6_DAD_ENTRY             *DupAddrDetect;
   2771   EFI_STATUS                Status;
   2772   IP6_NEIGHBOR_ENTRY        *NeighborCache;
   2773   EFI_IPv6_ADDRESS          Destination;
   2774   IP6_SERVICE               *IpSb;
   2775   BOOLEAN                   Flag;
   2776 
   2777   IpSb = (IP6_SERVICE *) Context;
   2778   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
   2779 
   2780   ZeroMem (&Source, sizeof (EFI_IPv6_ADDRESS));
   2781 
   2782   //
   2783   // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
   2784   // Solicitation messages, each separated by at least
   2785   // RTR_SOLICITATION_INTERVAL (4) seconds.
   2786   //
   2787   if ((IpSb->Ip6ConfigInstance.Policy == Ip6ConfigPolicyAutomatic) &&
   2788       !IpSb->RouterAdvertiseReceived &&
   2789       IpSb->SolicitTimer > 0
   2790       ) {
   2791     if ((IpSb->Ticks == 0) || (--IpSb->Ticks == 0)) {
   2792       Status = Ip6SendRouterSolicit (IpSb, NULL, NULL, NULL, NULL);
   2793       if (!EFI_ERROR (Status)) {
   2794         IpSb->SolicitTimer--;
   2795         IpSb->Ticks = (UINT32) IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL);
   2796       }
   2797     }
   2798   }
   2799 
   2800   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
   2801     IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
   2802 
   2803     //
   2804     // Process the delay list to join the solicited-node multicast address.
   2805     //
   2806     NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
   2807       DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
   2808       if ((DelayNode->DelayTime == 0) || (--DelayNode->DelayTime == 0)) {
   2809         //
   2810         // The timer expires, init the duplicate address detection.
   2811         //
   2812         Ip6InitDADProcess (
   2813           DelayNode->Interface,
   2814           DelayNode->AddressInfo,
   2815           DelayNode->DadCallback,
   2816           DelayNode->Context
   2817           );
   2818 
   2819         //
   2820         // Remove the delay node
   2821         //
   2822         RemoveEntryList (&DelayNode->Link);
   2823         FreePool (DelayNode);
   2824       }
   2825     }
   2826 
   2827     //
   2828     // Process the duplicate address detection list.
   2829     //
   2830     NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
   2831       DupAddrDetect = NET_LIST_USER_STRUCT (Entry2, IP6_DAD_ENTRY, Link);
   2832 
   2833       if ((DupAddrDetect->RetransTick == 0) || (--DupAddrDetect->RetransTick == 0)) {
   2834         //
   2835         // The timer expires, check the remaining transmit counts.
   2836         //
   2837         if (DupAddrDetect->Transmit < DupAddrDetect->MaxTransmit) {
   2838           //
   2839           // Send the Neighbor Solicitation message with
   2840           // Source - unspecified address, destination - solicited-node multicast address
   2841           // Target - the address to be validated
   2842           //
   2843           Status = Ip6SendNeighborSolicit (
   2844                      IpSb,
   2845                      NULL,
   2846                      &DupAddrDetect->Destination,
   2847                      &DupAddrDetect->AddressInfo->Address,
   2848                      NULL
   2849                      );
   2850           if (EFI_ERROR (Status)) {
   2851             return;
   2852           }
   2853 
   2854           DupAddrDetect->Transmit++;
   2855           DupAddrDetect->RetransTick = IP6_GET_TICKS (IpSb->RetransTimer);
   2856         } else {
   2857           //
   2858           // All required solicitation has been sent out, and the RetransTime after the last
   2859           // Neighbor Solicit is elapsed, finish the DAD process.
   2860           //
   2861           Flag = FALSE;
   2862           if ((DupAddrDetect->Receive == 0) ||
   2863               (DupAddrDetect->Transmit <= DupAddrDetect->Receive)) {
   2864             Flag = TRUE;
   2865           }
   2866 
   2867           Ip6OnDADFinished (Flag, IpIf, DupAddrDetect);
   2868         }
   2869       }
   2870     }
   2871   }
   2872 
   2873   //
   2874   // Polling the state of Neighbor cache
   2875   //
   2876   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
   2877     NeighborCache = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
   2878 
   2879     switch (NeighborCache->State) {
   2880     case EfiNeighborInComplete:
   2881       if (NeighborCache->Ticks > 0) {
   2882         --NeighborCache->Ticks;
   2883       }
   2884 
   2885       //
   2886       // Retransmit Neighbor Solicitation messages approximately every
   2887       // RetransTimer milliseconds while awaiting a response.
   2888       //
   2889       if (NeighborCache->Ticks == 0) {
   2890         if (NeighborCache->Transmit > 1) {
   2891           //
   2892           // Send out multicast neighbor solicitation for address resolution.
   2893           // After last neighbor solicitation message has been sent out, wait
   2894           // for RetransTimer and then remove entry if no response is received.
   2895           //
   2896           Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
   2897           Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
   2898           if (EFI_ERROR (Status)) {
   2899             return;
   2900           }
   2901 
   2902           Status = Ip6SendNeighborSolicit (
   2903                      IpSb,
   2904                      &Source,
   2905                      &Destination,
   2906                      &NeighborCache->Neighbor,
   2907                      &IpSb->SnpMode.CurrentAddress
   2908                      );
   2909           if (EFI_ERROR (Status)) {
   2910             return;
   2911           }
   2912         }
   2913 
   2914         //
   2915         // Update the retransmit times.
   2916         //
   2917         if (NeighborCache->Transmit > 0) {
   2918           --NeighborCache->Transmit;
   2919           NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
   2920         }
   2921       }
   2922 
   2923       if (NeighborCache->Transmit == 0) {
   2924         //
   2925         // Timeout, send ICMP destination unreachable packet and then remove entry
   2926         //
   2927         Status = Ip6FreeNeighborEntry (
   2928                    IpSb,
   2929                    NeighborCache,
   2930                    TRUE,
   2931                    TRUE,
   2932                    EFI_ICMP_ERROR,
   2933                    NULL,
   2934                    NULL
   2935                    );
   2936         if (EFI_ERROR (Status)) {
   2937           return;
   2938         }
   2939       }
   2940 
   2941       break;
   2942 
   2943     case EfiNeighborReachable:
   2944       //
   2945       // This entry is inserted by EfiIp6Neighbors() as static entry
   2946       // and will not timeout.
   2947       //
   2948       if (!NeighborCache->Dynamic && (NeighborCache->Ticks == IP6_INFINIT_LIFETIME)) {
   2949         break;
   2950       }
   2951 
   2952       if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
   2953         if (NeighborCache->Dynamic) {
   2954           //
   2955           // This entry is inserted by EfiIp6Neighbors() as dynamic entry
   2956           // and will be deleted after timeout.
   2957           //
   2958           Status = Ip6FreeNeighborEntry (
   2959                      IpSb,
   2960                      NeighborCache,
   2961                      FALSE,
   2962                      TRUE,
   2963                      EFI_TIMEOUT,
   2964                      NULL,
   2965                      NULL
   2966                      );
   2967           if (EFI_ERROR (Status)) {
   2968             return;
   2969           }
   2970         } else {
   2971           NeighborCache->State = EfiNeighborStale;
   2972           NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
   2973         }
   2974       }
   2975 
   2976       break;
   2977 
   2978     case EfiNeighborDelay:
   2979       if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
   2980 
   2981         NeighborCache->State    = EfiNeighborProbe;
   2982         NeighborCache->Ticks    = IP6_GET_TICKS (IpSb->RetransTimer);
   2983         NeighborCache->Transmit = IP6_MAX_UNICAST_SOLICIT + 1;
   2984         //
   2985         // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
   2986         //
   2987         Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
   2988         if (EFI_ERROR (Status)) {
   2989           return;
   2990         }
   2991 
   2992         Status = Ip6SendNeighborSolicit (
   2993                    IpSb,
   2994                    &Source,
   2995                    &NeighborCache->Neighbor,
   2996                    &NeighborCache->Neighbor,
   2997                    &IpSb->SnpMode.CurrentAddress
   2998                    );
   2999         if (EFI_ERROR (Status)) {
   3000           return;
   3001         }
   3002 
   3003         NeighborCache->Transmit--;
   3004       }
   3005 
   3006       break;
   3007 
   3008     case EfiNeighborProbe:
   3009       if (NeighborCache->Ticks > 0) {
   3010         --NeighborCache->Ticks;
   3011       }
   3012 
   3013       //
   3014       // Retransmit Neighbor Solicitation messages approximately every
   3015       // RetransTimer milliseconds while awaiting a response.
   3016       //
   3017       if (NeighborCache->Ticks == 0) {
   3018         if (NeighborCache->Transmit > 1) {
   3019           //
   3020           // Send out unicast neighbor solicitation for Neighbor Unreachability
   3021           // Detection. After last neighbor solicitation message has been sent out,
   3022           // wait for RetransTimer and then remove entry if no response is received.
   3023           //
   3024           Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
   3025           if (EFI_ERROR (Status)) {
   3026             return;
   3027           }
   3028 
   3029           Status = Ip6SendNeighborSolicit (
   3030                      IpSb,
   3031                      &Source,
   3032                      &NeighborCache->Neighbor,
   3033                      &NeighborCache->Neighbor,
   3034                      &IpSb->SnpMode.CurrentAddress
   3035                      );
   3036           if (EFI_ERROR (Status)) {
   3037             return;
   3038           }
   3039         }
   3040 
   3041         //
   3042         // Update the retransmit times.
   3043         //
   3044         if (NeighborCache->Transmit > 0) {
   3045           --NeighborCache->Transmit;
   3046           NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
   3047         }
   3048       }
   3049 
   3050       if (NeighborCache->Transmit == 0) {
   3051         //
   3052         // Delete the neighbor entry.
   3053         //
   3054         Status = Ip6FreeNeighborEntry (
   3055                    IpSb,
   3056                    NeighborCache,
   3057                    FALSE,
   3058                    TRUE,
   3059                    EFI_TIMEOUT,
   3060                    NULL,
   3061                    NULL
   3062                    );
   3063         if (EFI_ERROR (Status)) {
   3064           return;
   3065         }
   3066       }
   3067 
   3068       break;
   3069 
   3070     default:
   3071       break;
   3072     }
   3073   }
   3074 }
   3075 
   3076 /**
   3077   The heartbeat timer of ND module in 1 second. This time routine handles following
   3078   things: 1) maitain default router list; 2) maintain prefix options;
   3079   3) maintain route caches.
   3080 
   3081   @param[in]  IpSb              The IP6 service binding instance.
   3082 
   3083 **/
   3084 VOID
   3085 Ip6NdTimerTicking (
   3086   IN IP6_SERVICE            *IpSb
   3087   )
   3088 {
   3089   LIST_ENTRY                *Entry;
   3090   LIST_ENTRY                *Next;
   3091   IP6_DEFAULT_ROUTER        *DefaultRouter;
   3092   IP6_PREFIX_LIST_ENTRY     *PrefixOption;
   3093   UINT8                     Index;
   3094   IP6_ROUTE_CACHE_ENTRY     *RouteCache;
   3095 
   3096   //
   3097   // Decrease the lifetime of default router, if expires remove it from default router list.
   3098   //
   3099   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->DefaultRouterList) {
   3100     DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
   3101     if (DefaultRouter->Lifetime != IP6_INF_ROUTER_LIFETIME) {
   3102       if ((DefaultRouter->Lifetime == 0) || (--DefaultRouter->Lifetime == 0)) {
   3103         Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
   3104       }
   3105     }
   3106   }
   3107 
   3108   //
   3109   // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
   3110   //
   3111   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->AutonomousPrefix) {
   3112     PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
   3113     if (PrefixOption->ValidLifetime != (UINT32) IP6_INFINIT_LIFETIME) {
   3114       if ((PrefixOption->ValidLifetime > 0) && (--PrefixOption->ValidLifetime > 0)) {
   3115         if ((PrefixOption->PreferredLifetime != (UINT32) IP6_INFINIT_LIFETIME) &&
   3116             (PrefixOption->PreferredLifetime > 0)
   3117             ) {
   3118           --PrefixOption->PreferredLifetime;
   3119         }
   3120       } else {
   3121         Ip6DestroyPrefixListEntry (IpSb, PrefixOption, FALSE, TRUE);
   3122       }
   3123     }
   3124   }
   3125 
   3126   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->OnlinkPrefix) {
   3127     PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
   3128     if (PrefixOption->ValidLifetime != (UINT32) IP6_INFINIT_LIFETIME) {
   3129       if ((PrefixOption->ValidLifetime == 0) || (--PrefixOption->ValidLifetime == 0)) {
   3130         Ip6DestroyPrefixListEntry (IpSb, PrefixOption, TRUE, TRUE);
   3131       }
   3132     }
   3133   }
   3134 
   3135   //
   3136   // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
   3137   // Remove the entries at the tail of the bucket. These entries
   3138   // are likely to be used least.
   3139   // Reclaim frequency is set to 1 second.
   3140   //
   3141   for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
   3142     while (IpSb->RouteTable->Cache.CacheNum[Index] > IP6_ROUTE_CACHE_MAX) {
   3143       Entry = NetListRemoveTail (&IpSb->RouteTable->Cache.CacheBucket[Index]);
   3144       if (Entry == NULL) {
   3145         break;
   3146       }
   3147 
   3148       RouteCache = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
   3149       Ip6FreeRouteCacheEntry (RouteCache);
   3150       ASSERT (IpSb->RouteTable->Cache.CacheNum[Index] > 0);
   3151       IpSb->RouteTable->Cache.CacheNum[Index]--;
   3152     }
   3153   }
   3154 }
   3155 
   3156