EDK2 doxygen online documents - Firmware Encoding Index 1
EDK2 doxygen online documents - Firmware Encoding Index

NetworkPkg/Ip6Dxe/Ip6Nd.c

Go to the documentation of this file.
00001 
00016 #include "Ip6Impl.h"
00017 
00018 EFI_MAC_ADDRESS mZeroMacAddress;
00019 
00026 VOID
00027 Ip6UpdateReachableTime (
00028   IN OUT IP6_SERVICE  *IpSb
00029   )
00030 {
00031   UINT32              Random;
00032 
00033   Random = (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE;
00034   Random = Random + IP6_MIN_RANDOM_FACTOR_SCALED;
00035   IpSb->ReachableTime = (IpSb->BaseReachableTime * Random) / IP6_RANDOM_FACTOR_SCALE;
00036 }
00037 
00050 EFI_STATUS
00051 Ip6BuildEfiNeighborCache (
00052   IN IP6_PROTOCOL            *IpInstance,
00053   OUT UINT32                 *NeighborCount,
00054   OUT EFI_IP6_NEIGHBOR_CACHE **NeighborCache
00055   )
00056 {
00057   IP6_NEIGHBOR_ENTRY        *Neighbor;
00058   LIST_ENTRY                *Entry;
00059   IP6_SERVICE               *IpSb;
00060   UINT32                    Count;
00061   EFI_IP6_NEIGHBOR_CACHE    *EfiNeighborCache;
00062   EFI_IP6_NEIGHBOR_CACHE    *NeighborCacheTmp;
00063 
00064   NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
00065   ASSERT (NeighborCount != NULL && NeighborCache != NULL);
00066 
00067   IpSb  = IpInstance->Service;
00068   Count = 0;
00069 
00070   NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
00071     Count++;
00072   }
00073 
00074   if (Count == 0) {
00075     return EFI_SUCCESS;
00076   }
00077 
00078   NeighborCacheTmp = AllocatePool (Count * sizeof (EFI_IP6_NEIGHBOR_CACHE));
00079   if (NeighborCacheTmp == NULL) {
00080     return EFI_OUT_OF_RESOURCES;
00081   }
00082 
00083   *NeighborCount = Count;
00084   Count          = 0;
00085 
00086   NET_LIST_FOR_EACH (Entry, &IpSb->NeighborTable) {
00087     Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
00088 
00089     EfiNeighborCache = NeighborCacheTmp + Count;
00090 
00091    EfiNeighborCache->State = Neighbor->State;
00092     IP6_COPY_ADDRESS (&EfiNeighborCache->Neighbor, &Neighbor->Neighbor);
00093     IP6_COPY_LINK_ADDRESS (&EfiNeighborCache->LinkAddress, &Neighbor->LinkAddress);
00094 
00095     Count++;
00096   }
00097 
00098   ASSERT (*NeighborCount == Count);
00099   *NeighborCache = NeighborCacheTmp;
00100 
00101   return EFI_SUCCESS;
00102 }
00103 
00116 EFI_STATUS
00117 Ip6BuildPrefixTable (
00118   IN IP6_PROTOCOL           *IpInstance,
00119   OUT UINT32                *PrefixCount,
00120   OUT EFI_IP6_ADDRESS_INFO  **PrefixTable
00121   )
00122 {
00123   LIST_ENTRY                *Entry;
00124   IP6_SERVICE               *IpSb;
00125   UINT32                    Count;
00126   IP6_PREFIX_LIST_ENTRY     *PrefixList;
00127   EFI_IP6_ADDRESS_INFO      *EfiPrefix;
00128   EFI_IP6_ADDRESS_INFO      *PrefixTableTmp;
00129 
00130   NET_CHECK_SIGNATURE (IpInstance, IP6_PROTOCOL_SIGNATURE);
00131   ASSERT (PrefixCount != NULL && PrefixTable != NULL);
00132 
00133   IpSb  = IpInstance->Service;
00134   Count = 0;
00135 
00136   NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
00137     Count++;
00138   }
00139 
00140   if (Count == 0) {
00141     return EFI_SUCCESS;
00142   }
00143 
00144   PrefixTableTmp = AllocatePool (Count * sizeof (EFI_IP6_ADDRESS_INFO));
00145   if (PrefixTableTmp == NULL) {
00146     return EFI_OUT_OF_RESOURCES;
00147   }
00148 
00149   *PrefixCount = Count;
00150   Count        = 0;
00151 
00152   NET_LIST_FOR_EACH (Entry, &IpSb->OnlinkPrefix) {
00153     PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
00154     EfiPrefix  = PrefixTableTmp + Count;
00155     IP6_COPY_ADDRESS (&EfiPrefix->Address, &PrefixList->Prefix);
00156     EfiPrefix->PrefixLength = PrefixList->PrefixLength;
00157 
00158     Count++;
00159   }
00160 
00161   ASSERT (*PrefixCount == Count);
00162   *PrefixTable = PrefixTableTmp;
00163 
00164   return EFI_SUCCESS;
00165 }
00166 
00185 IP6_PREFIX_LIST_ENTRY *
00186 Ip6CreatePrefixListEntry (
00187   IN IP6_SERVICE            *IpSb,
00188   IN BOOLEAN                OnLinkOrAuto,
00189   IN UINT32                 ValidLifetime,
00190   IN UINT32                 PreferredLifetime,
00191   IN UINT8                  PrefixLength,
00192   IN EFI_IPv6_ADDRESS       *Prefix
00193   )
00194 {
00195   IP6_PREFIX_LIST_ENTRY     *PrefixEntry;
00196   IP6_ROUTE_ENTRY           *RtEntry;
00197   LIST_ENTRY                *ListHead;
00198   LIST_ENTRY                *Entry;
00199   IP6_PREFIX_LIST_ENTRY     *TmpPrefixEntry;
00200 
00201   if (Prefix == NULL || PreferredLifetime > ValidLifetime || PrefixLength >= IP6_PREFIX_NUM) {
00202     return NULL;
00203   }
00204 
00205   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
00206 
00207   PrefixEntry = Ip6FindPrefixListEntry (
00208                   IpSb,
00209                   OnLinkOrAuto,
00210                   PrefixLength,
00211                   Prefix
00212                   );
00213   if (PrefixEntry != NULL) {
00214     PrefixEntry->RefCnt ++;
00215     return PrefixEntry;
00216   }
00217 
00218   PrefixEntry = AllocatePool (sizeof (IP6_PREFIX_LIST_ENTRY));
00219   if (PrefixEntry == NULL) {
00220     return NULL;
00221   }
00222 
00223   PrefixEntry->RefCnt            = 1;
00224   PrefixEntry->ValidLifetime     = ValidLifetime;
00225   PrefixEntry->PreferredLifetime = PreferredLifetime;
00226   PrefixEntry->PrefixLength      = PrefixLength;
00227   IP6_COPY_ADDRESS (&PrefixEntry->Prefix, Prefix);
00228 
00229   ListHead = OnLinkOrAuto ? &IpSb->OnlinkPrefix : &IpSb->AutonomousPrefix;
00230 
00231   //
00232   // Create a direct route entry for on-link prefix and insert to route area.
00233   //
00234   if (OnLinkOrAuto) {
00235     RtEntry = Ip6CreateRouteEntry (Prefix, PrefixLength, NULL);
00236     if (RtEntry == NULL) {
00237       FreePool (PrefixEntry);
00238       return NULL;
00239     }
00240 
00241     RtEntry->Flag = IP6_DIRECT_ROUTE;
00242     InsertHeadList (&IpSb->RouteTable->RouteArea[PrefixLength], &RtEntry->Link);
00243     IpSb->RouteTable->TotalNum++;
00244   }
00245 
00246   //
00247   // Insert the prefix entry in the order that a prefix with longer prefix length
00248   // is put ahead in the list.
00249   //
00250   NET_LIST_FOR_EACH (Entry, ListHead) {
00251     TmpPrefixEntry = NET_LIST_USER_STRUCT(Entry, IP6_PREFIX_LIST_ENTRY, Link);
00252 
00253     if (TmpPrefixEntry->PrefixLength < PrefixEntry->PrefixLength) {
00254       break;
00255     }
00256   }
00257 
00258   NetListInsertBefore (Entry, &PrefixEntry->Link);
00259 
00260   return PrefixEntry;
00261 }
00262 
00275 VOID
00276 Ip6DestroyPrefixListEntry (
00277   IN IP6_SERVICE            *IpSb,
00278   IN IP6_PREFIX_LIST_ENTRY  *PrefixEntry,
00279   IN BOOLEAN                OnLinkOrAuto,
00280   IN BOOLEAN                ImmediateDelete
00281   )
00282 {
00283   LIST_ENTRY      *Entry;
00284   IP6_INTERFACE   *IpIf;
00285   EFI_STATUS      Status;
00286 
00287   if ((!ImmediateDelete) && (PrefixEntry->RefCnt > 0) && ((--PrefixEntry->RefCnt) > 0)) {
00288     return ;
00289   }
00290 
00291   if (OnLinkOrAuto) {
00292       //
00293       // Remove the direct route for onlink prefix from route table.
00294       //
00295       do {
00296         Status = Ip6DelRoute (
00297                    IpSb->RouteTable,
00298                    &PrefixEntry->Prefix,
00299                    PrefixEntry->PrefixLength,
00300                    NULL
00301                    );
00302       } while (Status != EFI_NOT_FOUND);
00303   } else {
00304     //
00305     // Remove the corresponding addresses generated from this autonomous prefix.
00306     //
00307     NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
00308       IpIf = NET_LIST_USER_STRUCT_S (Entry, IP6_INTERFACE, Link, IP6_INTERFACE_SIGNATURE);
00309 
00310       Ip6RemoveAddr (IpSb, &IpIf->AddressList, &IpIf->AddressCount, &PrefixEntry->Prefix, PrefixEntry->PrefixLength);
00311     }
00312   }
00313 
00314   RemoveEntryList (&PrefixEntry->Link);
00315   FreePool (PrefixEntry);
00316 }
00317 
00331 IP6_PREFIX_LIST_ENTRY *
00332 Ip6FindPrefixListEntry (
00333   IN IP6_SERVICE            *IpSb,
00334   IN BOOLEAN                OnLinkOrAuto,
00335   IN UINT8                  PrefixLength,
00336   IN EFI_IPv6_ADDRESS       *Prefix
00337   )
00338 {
00339   IP6_PREFIX_LIST_ENTRY     *PrefixList;
00340   LIST_ENTRY                *Entry;
00341   LIST_ENTRY                *ListHead;
00342 
00343   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
00344   ASSERT (Prefix != NULL);
00345 
00346   if (OnLinkOrAuto) {
00347     ListHead = &IpSb->OnlinkPrefix;
00348   } else {
00349     ListHead = &IpSb->AutonomousPrefix;
00350   }
00351 
00352   NET_LIST_FOR_EACH (Entry, ListHead) {
00353     PrefixList = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
00354     if (PrefixLength != 255) {
00355       //
00356       // Perform exactly prefix match.
00357       //
00358       if (PrefixList->PrefixLength == PrefixLength &&
00359         NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixLength)) {
00360         return PrefixList;
00361       }
00362     } else {
00363       //
00364       // Perform the longest prefix match. The list is already sorted with
00365       // the longest length prefix put at the head of the list.
00366       //
00367       if (NetIp6IsNetEqual (&PrefixList->Prefix, Prefix, PrefixList->PrefixLength)) {
00368         return PrefixList;
00369       }
00370     }
00371   }
00372 
00373   return NULL;
00374 }
00375 
00384 VOID
00385 Ip6CleanPrefixListTable (
00386   IN IP6_SERVICE            *IpSb,
00387   IN LIST_ENTRY             *ListHead
00388   )
00389 {
00390   IP6_PREFIX_LIST_ENTRY     *PrefixList;
00391   BOOLEAN                   OnLink;
00392 
00393   OnLink = (BOOLEAN) (ListHead == &IpSb->OnlinkPrefix);
00394 
00395   while (!IsListEmpty (ListHead)) {
00396     PrefixList = NET_LIST_HEAD (ListHead, IP6_PREFIX_LIST_ENTRY, Link);
00397     Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
00398   }
00399 }
00400 
00409 VOID
00410 Ip6OnArpResolved (
00411   IN VOID                   *Context
00412   )
00413 {
00414   LIST_ENTRY                *Entry;
00415   LIST_ENTRY                *Next;
00416   IP6_NEIGHBOR_ENTRY        *ArpQue;
00417   IP6_SERVICE               *IpSb;
00418   IP6_LINK_TX_TOKEN         *Token;
00419   EFI_STATUS                Status;
00420   BOOLEAN                   Sent;
00421 
00422   ArpQue = (IP6_NEIGHBOR_ENTRY *) Context;
00423   if ((ArpQue == NULL) || (ArpQue->Interface == NULL)) {
00424     return ;
00425   }
00426 
00427   IpSb   = ArpQue->Interface->Service;
00428   if ((IpSb == NULL) || (IpSb->Signature != IP6_SERVICE_SIGNATURE)) {
00429     return ;
00430   }
00431 
00432   //
00433   // ARP resolve failed for some reason. Release all the frame
00434   // and ARP queue itself. Ip6FreeArpQue will call the frame's
00435   // owner back.
00436   //
00437   if (NET_MAC_EQUAL (&ArpQue->LinkAddress, &mZeroMacAddress, IpSb->SnpMode.HwAddressSize)) {
00438     Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, TRUE, EFI_NO_MAPPING, NULL, NULL);
00439     return ;
00440   }
00441 
00442   //
00443   // ARP resolve succeeded, Transmit all the frame.
00444   //
00445   Sent = FALSE;
00446   NET_LIST_FOR_EACH_SAFE (Entry, Next, &ArpQue->Frames) {
00447     RemoveEntryList (Entry);
00448 
00449     Token = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
00450     IP6_COPY_LINK_ADDRESS (&Token->DstMac, &ArpQue->LinkAddress);
00451 
00452     //
00453     // Insert the tx token before transmitting it via MNP as the FrameSentDpc
00454     // may be called before Mnp->Transmit returns which will remove this tx
00455     // token from the SentFrames list. Remove it from the list if the returned
00456     // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
00457     // FrameSentDpc won't be queued.
00458     //
00459     InsertTailList (&ArpQue->Interface->SentFrames, &Token->Link);
00460 
00461     Status = IpSb->Mnp->Transmit (IpSb->Mnp, &Token->MnpToken);
00462     if (EFI_ERROR (Status)) {
00463       RemoveEntryList (&Token->Link);
00464       Token->CallBack (Token->Packet, Status, 0, Token->Context);
00465 
00466       Ip6FreeLinkTxToken (Token);
00467       continue;
00468     } else {
00469       Sent = TRUE;
00470     }
00471   }
00472 
00473   //
00474   // Free the ArpQue only but not the whole neighbor entry.
00475   //
00476   Ip6FreeNeighborEntry (IpSb, ArpQue, FALSE, FALSE, EFI_SUCCESS, NULL, NULL);
00477 
00478   if (Sent && (ArpQue->State == EfiNeighborStale)) {
00479     ArpQue->State = EfiNeighborDelay;
00480     ArpQue->Ticks = (UINT32) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME);
00481   }
00482 }
00483 
00498 IP6_NEIGHBOR_ENTRY *
00499 Ip6CreateNeighborEntry (
00500   IN IP6_SERVICE            *IpSb,
00501   IN IP6_ARP_CALLBACK       CallBack,
00502   IN EFI_IPv6_ADDRESS       *Ip6Address,
00503   IN EFI_MAC_ADDRESS        *LinkAddress OPTIONAL
00504   )
00505 {
00506   IP6_NEIGHBOR_ENTRY        *Entry;
00507   IP6_DEFAULT_ROUTER        *DefaultRouter;
00508 
00509   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
00510   ASSERT (Ip6Address!= NULL);
00511 
00512   Entry = AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY));
00513   if (Entry == NULL) {
00514     return NULL;
00515   }
00516 
00517   Entry->RefCnt    = 1;
00518   Entry->IsRouter  = FALSE;
00519   Entry->ArpFree   = FALSE;
00520   Entry->Dynamic   = FALSE;
00521   Entry->State     = EfiNeighborInComplete;
00522   Entry->Transmit  = IP6_MAX_MULTICAST_SOLICIT + 1;
00523   Entry->CallBack  = CallBack;
00524   Entry->Interface = NULL;
00525 
00526   InitializeListHead (&Entry->Frames);
00527 
00528   IP6_COPY_ADDRESS (&Entry->Neighbor, Ip6Address);
00529 
00530   if (LinkAddress != NULL) {
00531     IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, LinkAddress);
00532   } else {
00533     IP6_COPY_LINK_ADDRESS (&Entry->LinkAddress, &mZeroMacAddress);
00534   }
00535 
00536   InsertHeadList (&IpSb->NeighborTable, &Entry->Link);
00537 
00538   //
00539   // If corresponding default router entry exists, establish the relationship.
00540   //
00541   DefaultRouter = Ip6FindDefaultRouter (IpSb, Ip6Address);
00542   if (DefaultRouter != NULL) {
00543     DefaultRouter->NeighborCache = Entry;
00544   }
00545 
00546   return Entry;
00547 }
00548 
00559 IP6_NEIGHBOR_ENTRY *
00560 Ip6FindNeighborEntry (
00561   IN IP6_SERVICE            *IpSb,
00562   IN EFI_IPv6_ADDRESS       *Ip6Address
00563   )
00564 {
00565   LIST_ENTRY                *Entry;
00566   LIST_ENTRY                *Next;
00567   IP6_NEIGHBOR_ENTRY        *Neighbor;
00568 
00569   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
00570   ASSERT (Ip6Address != NULL);
00571 
00572   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
00573     Neighbor = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
00574     if (EFI_IP6_EQUAL (Ip6Address, &Neighbor->Neighbor)) {
00575       RemoveEntryList (Entry);
00576       InsertHeadList (&IpSb->NeighborTable, Entry);
00577 
00578       return Neighbor;
00579     }
00580   }
00581 
00582   return NULL;
00583 }
00584 
00606 EFI_STATUS
00607 Ip6FreeNeighborEntry (
00608   IN IP6_SERVICE            *IpSb,
00609   IN IP6_NEIGHBOR_ENTRY     *NeighborCache,
00610   IN BOOLEAN                SendIcmpError,
00611   IN BOOLEAN                FullFree,
00612   IN EFI_STATUS             IoStatus,
00613   IN IP6_FRAME_TO_CANCEL    FrameToCancel OPTIONAL,
00614   IN VOID                   *Context      OPTIONAL
00615   )
00616 {
00617   IP6_LINK_TX_TOKEN         *TxToken;
00618   LIST_ENTRY                *Entry;
00619   LIST_ENTRY                *Next;
00620   IP6_DEFAULT_ROUTER        *DefaultRouter;
00621 
00622   //
00623   // If FrameToCancel fails, the token will not be released.
00624   // To avoid the memory leak, stop this usage model.
00625   //
00626   if (FullFree && FrameToCancel != NULL) {
00627     return EFI_INVALID_PARAMETER;
00628   }
00629 
00630   NET_LIST_FOR_EACH_SAFE (Entry, Next, &NeighborCache->Frames) {
00631     TxToken = NET_LIST_USER_STRUCT (Entry, IP6_LINK_TX_TOKEN, Link);
00632 
00633     if (SendIcmpError && !IP6_IS_MULTICAST (&TxToken->Packet->Ip.Ip6->DestinationAddress)) {
00634       Ip6SendIcmpError (
00635         IpSb,
00636         TxToken->Packet,
00637         NULL,
00638         &TxToken->Packet->Ip.Ip6->SourceAddress,
00639         ICMP_V6_DEST_UNREACHABLE,
00640         ICMP_V6_ADDR_UNREACHABLE,
00641         NULL
00642         );
00643     }
00644 
00645     if ((FrameToCancel == NULL) || FrameToCancel (TxToken, Context)) {
00646       RemoveEntryList (Entry);
00647       TxToken->CallBack (TxToken->Packet, IoStatus, 0, TxToken->Context);
00648       Ip6FreeLinkTxToken (TxToken);
00649     }
00650   }
00651 
00652   if (NeighborCache->ArpFree && IsListEmpty (&NeighborCache->Frames)) {
00653     RemoveEntryList (&NeighborCache->ArpList);
00654     NeighborCache->ArpFree = FALSE;
00655   }
00656 
00657   if (FullFree) {
00658     if (NeighborCache->IsRouter) {
00659       DefaultRouter = Ip6FindDefaultRouter (IpSb, &NeighborCache->Neighbor);
00660       if (DefaultRouter != NULL) {
00661         Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
00662       }
00663     }
00664 
00665     RemoveEntryList (&NeighborCache->Link);
00666     FreePool (NeighborCache);
00667   }
00668 
00669   return EFI_SUCCESS;
00670 }
00671 
00684 IP6_DEFAULT_ROUTER *
00685 Ip6CreateDefaultRouter (
00686   IN IP6_SERVICE            *IpSb,
00687   IN EFI_IPv6_ADDRESS       *Ip6Address,
00688   IN UINT16                 RouterLifetime
00689   )
00690 {
00691   IP6_DEFAULT_ROUTER        *Entry;
00692   IP6_ROUTE_ENTRY           *RtEntry;
00693 
00694   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
00695   ASSERT (Ip6Address != NULL);
00696 
00697   Entry = AllocatePool (sizeof (IP6_DEFAULT_ROUTER));
00698   if (Entry == NULL) {
00699     return NULL;
00700   }
00701 
00702   Entry->RefCnt        = 1;
00703   Entry->Lifetime      = RouterLifetime;
00704   Entry->NeighborCache = Ip6FindNeighborEntry (IpSb, Ip6Address);
00705   IP6_COPY_ADDRESS (&Entry->Router, Ip6Address);
00706 
00707   //
00708   // Add a default route into route table with both Destination and PrefixLength set to zero.
00709   //
00710   RtEntry = Ip6CreateRouteEntry (NULL, 0, Ip6Address);
00711   if (RtEntry == NULL) {
00712     FreePool (Entry);
00713     return NULL;
00714   }
00715 
00716   InsertHeadList (&IpSb->RouteTable->RouteArea[0], &RtEntry->Link);
00717   IpSb->RouteTable->TotalNum++;
00718 
00719   InsertTailList (&IpSb->DefaultRouterList, &Entry->Link);
00720 
00721   return Entry;
00722 }
00723 
00731 VOID
00732 Ip6DestroyDefaultRouter (
00733   IN IP6_SERVICE            *IpSb,
00734   IN IP6_DEFAULT_ROUTER     *DefaultRouter
00735   )
00736 {
00737   EFI_STATUS                Status;
00738 
00739   RemoveEntryList (&DefaultRouter->Link);
00740 
00741   //
00742   // Update the Destination Cache - all entries using the time-out router as next-hop
00743   // should perform next-hop determination again.
00744   //
00745   do {
00746     Status = Ip6DelRoute (IpSb->RouteTable, NULL, 0, &DefaultRouter->Router);
00747   } while (Status != EFI_NOT_FOUND);
00748 
00749   FreePool (DefaultRouter);
00750 }
00751 
00758 VOID
00759 Ip6CleanDefaultRouterList (
00760   IN IP6_SERVICE            *IpSb
00761   )
00762 {
00763   IP6_DEFAULT_ROUTER        *DefaultRouter;
00764 
00765   while (!IsListEmpty (&IpSb->DefaultRouterList)) {
00766     DefaultRouter = NET_LIST_HEAD (&IpSb->DefaultRouterList, IP6_DEFAULT_ROUTER, Link);
00767     Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
00768   }
00769 }
00770 
00781 IP6_DEFAULT_ROUTER *
00782 Ip6FindDefaultRouter (
00783   IN IP6_SERVICE            *IpSb,
00784   IN EFI_IPv6_ADDRESS       *Ip6Address
00785   )
00786 {
00787   LIST_ENTRY                *Entry;
00788   IP6_DEFAULT_ROUTER        *DefaultRouter;
00789 
00790   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
00791   ASSERT (Ip6Address != NULL);
00792 
00793   NET_LIST_FOR_EACH (Entry, &IpSb->DefaultRouterList) {
00794     DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
00795     if (EFI_IP6_EQUAL (Ip6Address, &DefaultRouter->Router)) {
00796       return DefaultRouter;
00797     }
00798   }
00799 
00800   return NULL;
00801 }
00802 
00811 VOID
00812 Ip6OnDADFinished (
00813   IN BOOLEAN        IsDadPassed,
00814   IN IP6_INTERFACE  *IpIf,
00815   IN IP6_DAD_ENTRY  *DadEntry
00816   )
00817 {
00818   IP6_SERVICE               *IpSb;
00819   IP6_ADDRESS_INFO          *AddrInfo;
00820   EFI_DHCP6_PROTOCOL        *Dhcp6;
00821   UINT16                    OptBuf[4];
00822   EFI_DHCP6_PACKET_OPTION   *Oro;
00823   EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;
00824 
00825   IpSb     = IpIf->Service;
00826   AddrInfo = DadEntry->AddressInfo;
00827 
00828   if (IsDadPassed) {
00829     //
00830     // DAD succeed.
00831     //
00832     if (NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
00833       ASSERT (!IpSb->LinkLocalOk);
00834 
00835       IP6_COPY_ADDRESS (&IpSb->LinkLocalAddr, &AddrInfo->Address);
00836       IpSb->LinkLocalOk = TRUE;
00837       IpIf->Configured  = TRUE;
00838 
00839       //
00840       // Check whether DHCP6 need to be started.
00841       //
00842       Dhcp6 = IpSb->Ip6ConfigInstance.Dhcp6;
00843 
00844       if (IpSb->Dhcp6NeedStart) {
00845         Dhcp6->Start (Dhcp6);
00846         IpSb->Dhcp6NeedStart = FALSE;
00847       }
00848 
00849       if (IpSb->Dhcp6NeedInfoRequest) {
00850         //
00851         // Set the exta options to send. Here we only want the option request option
00852         // with DNS SERVERS.
00853         //
00854         Oro         = (EFI_DHCP6_PACKET_OPTION *) OptBuf;
00855         Oro->OpCode = HTONS (IP6_CONFIG_DHCP6_OPTION_ORO);
00856         Oro->OpLen  = HTONS (2);
00857         *((UINT16 *) &Oro->Data[0]) = HTONS (IP6_CONFIG_DHCP6_OPTION_DNS_SERVERS);
00858 
00859         InfoReqReXmit.Irt = 4;
00860         InfoReqReXmit.Mrc = 64;
00861         InfoReqReXmit.Mrt = 60;
00862         InfoReqReXmit.Mrd = 0;
00863 
00864         Dhcp6->InfoRequest (
00865                  Dhcp6,
00866                  TRUE,
00867                  Oro,
00868                  0,
00869                  NULL,
00870                  &InfoReqReXmit,
00871                  IpSb->Ip6ConfigInstance.Dhcp6Event,
00872                  Ip6ConfigOnDhcp6Reply,
00873                  &IpSb->Ip6ConfigInstance
00874                  );
00875       }
00876 
00877       //
00878       // Add an on-link prefix for link-local address.
00879       //
00880       Ip6CreatePrefixListEntry (
00881         IpSb,
00882         TRUE,
00883         (UINT32) IP6_INFINIT_LIFETIME,
00884         (UINT32) IP6_INFINIT_LIFETIME,
00885         IP6_LINK_LOCAL_PREFIX_LENGTH,
00886         &IpSb->LinkLocalAddr
00887         );
00888 
00889     } else {
00890       //
00891       // Global scope unicast address.
00892       //
00893       Ip6AddAddr (IpIf, AddrInfo);
00894 
00895       //
00896       // Add an on-link prefix for this address.
00897       //
00898       Ip6CreatePrefixListEntry (
00899         IpSb,
00900         TRUE,
00901         AddrInfo->ValidLifetime,
00902         AddrInfo->PreferredLifetime,
00903         AddrInfo->PrefixLength,
00904         &AddrInfo->Address
00905         );
00906 
00907       IpIf->Configured = TRUE;
00908     }
00909   } else {
00910     //
00911     // Leave the group we joined before.
00912     //
00913     Ip6LeaveGroup (IpSb, &DadEntry->Destination);
00914   }
00915 
00916   if (DadEntry->Callback != NULL) {
00917     DadEntry->Callback (IsDadPassed, &AddrInfo->Address, DadEntry->Context);
00918   }
00919 
00920   if (!IsDadPassed && NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
00921     FreePool (AddrInfo);
00922     RemoveEntryList (&DadEntry->Link);
00923     FreePool (DadEntry);
00924     //
00925     // Disable IP operation since link-local address is a duplicate address.
00926     //
00927     IpSb->LinkLocalDadFail = TRUE;
00928     IpSb->Mnp->Configure (IpSb->Mnp, NULL);
00929     gBS->SetTimer (IpSb->Timer, TimerCancel, 0);
00930     gBS->SetTimer (IpSb->FasterTimer, TimerCancel, 0);
00931     return ;
00932   }
00933 
00934   if (!IsDadPassed || NetIp6IsLinkLocalAddr (&AddrInfo->Address)) {
00935     //
00936     // Free the AddressInfo we hold if DAD fails or it is a link-local address.
00937     //
00938     FreePool (AddrInfo);
00939   }
00940 
00941   RemoveEntryList (&DadEntry->Link);
00942   FreePool (DadEntry);
00943 }
00944 
00962 EFI_STATUS
00963 Ip6InitDADProcess (
00964   IN IP6_INTERFACE          *IpIf,
00965   IN IP6_ADDRESS_INFO       *AddressInfo,
00966   IN IP6_DAD_CALLBACK       Callback  OPTIONAL,
00967   IN VOID                   *Context  OPTIONAL
00968   )
00969 {
00970   IP6_DAD_ENTRY                             *Entry;
00971   EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS  *DadXmits;
00972   IP6_SERVICE                               *IpSb;
00973   EFI_STATUS                                Status;
00974   UINT32                                    MaxDelayTick;
00975 
00976   NET_CHECK_SIGNATURE (IpIf, IP6_INTERFACE_SIGNATURE);
00977   ASSERT (AddressInfo != NULL);
00978 
00979   Status   = EFI_SUCCESS;
00980   IpSb     = IpIf->Service;
00981   DadXmits = &IpSb->Ip6ConfigInstance.DadXmits;
00982 
00983   //
00984   // Allocate the resources and insert info
00985   //
00986   Entry = AllocatePool (sizeof (IP6_DAD_ENTRY));
00987   if (Entry == NULL) {
00988     return EFI_OUT_OF_RESOURCES;
00989   }
00990 
00991   //
00992   // Map the incoming unicast address to solicited-node multicast address
00993   //
00994   Ip6CreateSNMulticastAddr (&AddressInfo->Address, &Entry->Destination);
00995 
00996   //
00997   // Join in the solicited-node multicast address.
00998   //
00999   Status = Ip6JoinGroup (IpSb, IpIf, &Entry->Destination);
01000   if (EFI_ERROR (Status)) {
01001     FreePool (Entry);
01002     return Status;
01003   }
01004 
01005   Entry->Signature    = IP6_DAD_ENTRY_SIGNATURE;
01006   Entry->MaxTransmit  = DadXmits->DupAddrDetectTransmits;
01007   Entry->Transmit     = 0;
01008   Entry->Receive      = 0;
01009   MaxDelayTick        = IP6_MAX_RTR_SOLICITATION_DELAY / IP6_TIMER_INTERVAL_IN_MS;
01010   Entry->RetransTick  = (MaxDelayTick * ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5;
01011   Entry->AddressInfo  = AddressInfo;
01012   Entry->Callback     = Callback;
01013   Entry->Context      = Context;
01014   InsertTailList (&IpIf->DupAddrDetectList, &Entry->Link);
01015 
01016   if (Entry->MaxTransmit == 0) {
01017     //
01018     // DAD is disabled on this interface, immediately mark this DAD successful.
01019     //
01020     Ip6OnDADFinished (TRUE, IpIf, Entry);
01021   }
01022 
01023   return EFI_SUCCESS;
01024 }
01025 
01038 IP6_DAD_ENTRY *
01039 Ip6FindDADEntry (
01040   IN  IP6_SERVICE      *IpSb,
01041   IN  EFI_IPv6_ADDRESS *Target,
01042   OUT IP6_INTERFACE    **Interface OPTIONAL
01043   )
01044 {
01045   LIST_ENTRY                *Entry;
01046   LIST_ENTRY                *Entry2;
01047   IP6_INTERFACE             *IpIf;
01048   IP6_DAD_ENTRY             *DupAddrDetect;
01049   IP6_ADDRESS_INFO          *AddrInfo;
01050 
01051   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
01052     IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
01053 
01054     NET_LIST_FOR_EACH (Entry2, &IpIf->DupAddrDetectList) {
01055       DupAddrDetect = NET_LIST_USER_STRUCT_S (Entry2, IP6_DAD_ENTRY, Link, IP6_DAD_ENTRY_SIGNATURE);
01056       AddrInfo      = DupAddrDetect->AddressInfo;
01057       if (EFI_IP6_EQUAL (&AddrInfo->Address, Target)) {
01058         if (Interface != NULL) {
01059           *Interface = IpIf;
01060         }
01061         return DupAddrDetect;
01062       }
01063     }
01064   }
01065 
01066   return NULL;
01067 }
01068 
01087 EFI_STATUS
01088 Ip6SendRouterSolicit (
01089   IN IP6_SERVICE            *IpSb,
01090   IN IP6_INTERFACE          *Interface          OPTIONAL,
01091   IN EFI_IPv6_ADDRESS       *SourceAddress      OPTIONAL,
01092   IN EFI_IPv6_ADDRESS       *DestinationAddress OPTIONAL,
01093   IN EFI_MAC_ADDRESS        *SourceLinkAddress  OPTIONAL
01094   )
01095 {
01096   NET_BUF                   *Packet;
01097   EFI_IP6_HEADER            Head;
01098   IP6_ICMP_INFORMATION_HEAD *IcmpHead;
01099   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
01100   UINT16                    PayloadLen;
01101   IP6_INTERFACE             *IpIf;
01102 
01103   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
01104 
01105   IpIf = Interface;
01106   if (IpIf == NULL && IpSb->DefaultInterface != NULL) {
01107     IpIf = IpSb->DefaultInterface;
01108   }
01109 
01110   //
01111   // Generate the packet to be sent
01112   //
01113 
01114   PayloadLen = (UINT16) sizeof (IP6_ICMP_INFORMATION_HEAD);
01115   if (SourceLinkAddress != NULL) {
01116     PayloadLen += sizeof (IP6_ETHER_ADDR_OPTION);
01117   }
01118 
01119   Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
01120   if (Packet == NULL) {
01121     return EFI_OUT_OF_RESOURCES;
01122   }
01123 
01124   //
01125   // Create the basic IPv6 header.
01126   //
01127   Head.FlowLabelL     = 0;
01128   Head.FlowLabelH     = 0;
01129   Head.PayloadLength  = HTONS (PayloadLen);
01130   Head.NextHeader     = IP6_ICMP;
01131   Head.HopLimit       = IP6_HOP_LIMIT;
01132 
01133   if (SourceAddress != NULL) {
01134     IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
01135   } else {
01136     ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
01137   }
01138 
01139 
01140   if (DestinationAddress != NULL) {
01141     IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
01142   } else {
01143     Ip6SetToAllNodeMulticast (TRUE, IP6_LINK_LOCAL_SCOPE, &Head.DestinationAddress);
01144   }
01145 
01146   NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
01147 
01148   //
01149   // Fill in the ICMP header, and Source link-layer address if contained.
01150   //
01151 
01152   IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
01153   ASSERT (IcmpHead != NULL);
01154   ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
01155   IcmpHead->Head.Type = ICMP_V6_ROUTER_SOLICIT;
01156   IcmpHead->Head.Code = 0;
01157 
01158   LinkLayerOption = NULL;
01159   if (SourceLinkAddress != NULL) {
01160     LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
01161                                                   Packet,
01162                                                   sizeof (IP6_ETHER_ADDR_OPTION),
01163                                                   FALSE
01164                                                   );
01165     ASSERT (LinkLayerOption != NULL);
01166     LinkLayerOption->Type   = Ip6OptionEtherSource;
01167     LinkLayerOption->Length = (UINT8) sizeof (IP6_ETHER_ADDR_OPTION);
01168     CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
01169   }
01170 
01171   //
01172   // Transmit the packet
01173   //
01174   return Ip6Output (IpSb, IpIf, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
01175 }
01176 
01199 EFI_STATUS
01200 Ip6SendNeighborAdvertise (
01201   IN IP6_SERVICE            *IpSb,
01202   IN EFI_IPv6_ADDRESS       *SourceAddress,
01203   IN EFI_IPv6_ADDRESS       *DestinationAddress,
01204   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
01205   IN EFI_MAC_ADDRESS        *TargetLinkAddress,
01206   IN BOOLEAN                IsRouter,
01207   IN BOOLEAN                Override,
01208   IN BOOLEAN                Solicited
01209   )
01210 {
01211   NET_BUF                   *Packet;
01212   EFI_IP6_HEADER            Head;
01213   IP6_ICMP_INFORMATION_HEAD *IcmpHead;
01214   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
01215   EFI_IPv6_ADDRESS          *Target;
01216   UINT16                    PayloadLen;
01217 
01218   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
01219 
01220   //
01221   // The Neighbor Advertisement message must include a Target link-layer address option
01222   // when responding to multicast solicitation and should include such option when
01223   // responding to unicast solicitation. It also must include such option as unsolicited
01224   // advertisement.
01225   //
01226   ASSERT (DestinationAddress != NULL && TargetIp6Address != NULL && TargetLinkAddress != NULL);
01227 
01228   PayloadLen = (UINT16) (sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS) + sizeof (IP6_ETHER_ADDR_OPTION));
01229 
01230   //
01231   // Generate the packet to be sent
01232   //
01233 
01234   Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
01235   if (Packet == NULL) {
01236     return EFI_OUT_OF_RESOURCES;
01237   }
01238 
01239   //
01240   // Create the basic IPv6 header.
01241   //
01242   Head.FlowLabelL     = 0;
01243   Head.FlowLabelH     = 0;
01244   Head.PayloadLength  = HTONS (PayloadLen);
01245   Head.NextHeader     = IP6_ICMP;
01246   Head.HopLimit       = IP6_HOP_LIMIT;
01247 
01248   IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
01249   IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
01250 
01251   NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
01252 
01253   //
01254   // Fill in the ICMP header, Target address, and Target link-layer address.
01255   // Set the Router flag, Solicited flag and Override flag.
01256   //
01257 
01258   IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
01259   ASSERT (IcmpHead != NULL);
01260   ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
01261   IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_ADVERTISE;
01262   IcmpHead->Head.Code = 0;
01263 
01264   if (IsRouter) {
01265     IcmpHead->Fourth |= IP6_IS_ROUTER_FLAG;
01266   }
01267 
01268   if (Solicited) {
01269     IcmpHead->Fourth |= IP6_SOLICITED_FLAG;
01270   }
01271 
01272   if (Override) {
01273     IcmpHead->Fourth |= IP6_OVERRIDE_FLAG;
01274   }
01275 
01276   Target = (EFI_IPv6_ADDRESS *) NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
01277   ASSERT (Target != NULL);
01278   IP6_COPY_ADDRESS (Target, TargetIp6Address);
01279 
01280   LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
01281                                                 Packet,
01282                                                 sizeof (IP6_ETHER_ADDR_OPTION),
01283                                                 FALSE
01284                                                 );
01285   ASSERT (LinkLayerOption != NULL);
01286   LinkLayerOption->Type   = Ip6OptionEtherTarget;
01287   LinkLayerOption->Length = 1;
01288   CopyMem (LinkLayerOption->EtherAddr, TargetLinkAddress, 6);
01289 
01290   //
01291   // Transmit the packet
01292   //
01293   return Ip6Output (IpSb, NULL, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
01294 }
01295 
01314 EFI_STATUS
01315 Ip6SendNeighborSolicit (
01316   IN IP6_SERVICE            *IpSb,
01317   IN EFI_IPv6_ADDRESS       *SourceAddress,
01318   IN EFI_IPv6_ADDRESS       *DestinationAddress,
01319   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
01320   IN EFI_MAC_ADDRESS        *SourceLinkAddress OPTIONAL
01321   )
01322 {
01323   NET_BUF                   *Packet;
01324   EFI_IP6_HEADER            Head;
01325   IP6_ICMP_INFORMATION_HEAD *IcmpHead;
01326   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
01327   EFI_IPv6_ADDRESS          *Target;
01328   BOOLEAN                   IsDAD;
01329   UINT16                    PayloadLen;
01330   IP6_NEIGHBOR_ENTRY        *Neighbor;
01331 
01332   //
01333   // Check input parameters
01334   //
01335   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
01336   if (DestinationAddress == NULL || TargetIp6Address == NULL) {
01337     return EFI_INVALID_PARAMETER;
01338   }
01339 
01340   IsDAD = FALSE;
01341 
01342   if (SourceAddress == NULL || (SourceAddress != NULL && NetIp6IsUnspecifiedAddr (SourceAddress))) {
01343     IsDAD = TRUE;
01344   }
01345 
01346   //
01347   // The Neighbor Solicitation message should include a source link-layer address option
01348   // if the solicitation is not sent by performing DAD - Duplicate Address Detection.
01349   // Otherwise must not include it.
01350   //
01351   PayloadLen = (UINT16) (sizeof (IP6_ICMP_INFORMATION_HEAD) + sizeof (EFI_IPv6_ADDRESS));
01352 
01353   if (!IsDAD) {
01354     if (SourceLinkAddress == NULL) {
01355       return EFI_INVALID_PARAMETER;
01356     }
01357 
01358     PayloadLen = (UINT16) (PayloadLen + sizeof (IP6_ETHER_ADDR_OPTION));
01359   }
01360 
01361   //
01362   // Generate the packet to be sent
01363   //
01364 
01365   Packet = NetbufAlloc (sizeof (EFI_IP6_HEADER) + (UINT32) PayloadLen);
01366   if (Packet == NULL) {
01367     return EFI_OUT_OF_RESOURCES;
01368   }
01369 
01370   //
01371   // Create the basic IPv6 header
01372   //
01373   Head.FlowLabelL     = 0;
01374   Head.FlowLabelH     = 0;
01375   Head.PayloadLength  = HTONS (PayloadLen);
01376   Head.NextHeader     = IP6_ICMP;
01377   Head.HopLimit       = IP6_HOP_LIMIT;
01378 
01379   if (SourceAddress != NULL) {
01380     IP6_COPY_ADDRESS (&Head.SourceAddress, SourceAddress);
01381   } else {
01382     ZeroMem (&Head.SourceAddress, sizeof (EFI_IPv6_ADDRESS));
01383   }
01384 
01385   IP6_COPY_ADDRESS (&Head.DestinationAddress, DestinationAddress);
01386 
01387   NetbufReserve (Packet, sizeof (EFI_IP6_HEADER));
01388 
01389   //
01390   // Fill in the ICMP header, Target address, and Source link-layer address.
01391   //
01392   IcmpHead = (IP6_ICMP_INFORMATION_HEAD *) NetbufAllocSpace (Packet, sizeof (IP6_ICMP_INFORMATION_HEAD), FALSE);
01393   ASSERT (IcmpHead != NULL);
01394   ZeroMem (IcmpHead, sizeof (IP6_ICMP_INFORMATION_HEAD));
01395   IcmpHead->Head.Type = ICMP_V6_NEIGHBOR_SOLICIT;
01396   IcmpHead->Head.Code = 0;
01397 
01398   Target = (EFI_IPv6_ADDRESS *) NetbufAllocSpace (Packet, sizeof (EFI_IPv6_ADDRESS), FALSE);
01399   ASSERT (Target != NULL);
01400   IP6_COPY_ADDRESS (Target, TargetIp6Address);
01401 
01402   LinkLayerOption = NULL;
01403   if (!IsDAD) {
01404 
01405     //
01406     // Fill in the source link-layer address option
01407     //
01408     LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) NetbufAllocSpace (
01409                                                   Packet,
01410                                                   sizeof (IP6_ETHER_ADDR_OPTION),
01411                                                   FALSE
01412                                                   );
01413     ASSERT (LinkLayerOption != NULL);
01414     LinkLayerOption->Type   = Ip6OptionEtherSource;
01415     LinkLayerOption->Length = 1;
01416     CopyMem (LinkLayerOption->EtherAddr, SourceLinkAddress, 6);
01417   }
01418 
01419   //
01420   // Create a Neighbor Cache entry in the INCOMPLETE state when performing
01421   // address resolution.
01422   //
01423   if (!IsDAD && Ip6IsSNMulticastAddr (DestinationAddress)) {
01424     Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
01425     if (Neighbor == NULL) {
01426       Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, NULL);
01427       ASSERT (Neighbor != NULL);
01428     }
01429   }
01430 
01431   //
01432   // Transmit the packet
01433   //
01434   return Ip6Output (IpSb, IpSb->DefaultInterface, NULL, Packet, &Head, NULL, 0, Ip6SysPacketSent, NULL);
01435 }
01436 
01451 EFI_STATUS
01452 Ip6ProcessNeighborSolicit (
01453   IN IP6_SERVICE            *IpSb,
01454   IN EFI_IP6_HEADER         *Head,
01455   IN NET_BUF                *Packet
01456   )
01457 {
01458   IP6_ICMP_INFORMATION_HEAD Icmp;
01459   EFI_IPv6_ADDRESS          Target;
01460   IP6_ETHER_ADDR_OPTION     LinkLayerOption;
01461   BOOLEAN                   IsDAD;
01462   BOOLEAN                   IsUnicast;
01463   BOOLEAN                   IsMaintained;
01464   IP6_DAD_ENTRY             *DupAddrDetect;
01465   IP6_INTERFACE             *IpIf;
01466   IP6_NEIGHBOR_ENTRY        *Neighbor;
01467   BOOLEAN                   Solicited;
01468   BOOLEAN                   UpdateCache;
01469   EFI_IPv6_ADDRESS          Dest;
01470   UINT16                    OptionLen;
01471   UINT8                     *Option;
01472   BOOLEAN                   Provided;
01473   EFI_STATUS                Status;
01474   VOID                      *MacAddress;
01475 
01476   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
01477   NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
01478 
01479   //
01480   // Perform Message Validation:
01481   // The IP Hop Limit field has a value of 255, i.e., the packet
01482   // could not possibly have been forwarded by a router.
01483   // ICMP Code is 0.
01484   // Target Address is not a multicast address.
01485   //
01486   Status = EFI_INVALID_PARAMETER;
01487 
01488   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 || !NetIp6IsValidUnicast (&Target)) {
01489     goto Exit;
01490   }
01491 
01492   //
01493   // ICMP length is 24 or more octets.
01494   //
01495   OptionLen = 0;
01496   if (Head->PayloadLength < IP6_ND_LENGTH) {
01497     goto Exit;
01498   } else {
01499     OptionLen = (UINT16) (Head->PayloadLength - IP6_ND_LENGTH);
01500     if (OptionLen != 0) {
01501       Option    = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
01502       ASSERT (Option != NULL);
01503 
01504       //
01505       // All included options should have a length that is greater than zero.
01506       //
01507       if (!Ip6IsNDOptionValid (Option, OptionLen)) {
01508         goto Exit;
01509       }
01510     }
01511   }
01512 
01513   IsDAD        = NetIp6IsUnspecifiedAddr (&Head->SourceAddress);
01514   IsUnicast    = (BOOLEAN) !Ip6IsSNMulticastAddr (&Head->DestinationAddress);
01515   IsMaintained = Ip6IsOneOfSetAddress (IpSb, &Target, &IpIf, NULL);
01516 
01517   Provided = FALSE;
01518   if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
01519     NetbufCopy (
01520       Packet,
01521       IP6_ND_LENGTH,
01522       sizeof (IP6_ETHER_ADDR_OPTION),
01523       (UINT8 *) &LinkLayerOption
01524       );
01525     //
01526     // The solicitation for neighbor discovery should include a source link-layer
01527     // address option. If the option is not recognized, silently ignore it.
01528     //
01529     if (LinkLayerOption.Type == Ip6OptionEtherSource) {
01530       if (IsDAD) {
01531         //
01532         // If the IP source address is the unspecified address, the source
01533         // link-layer address option must not be included in the message.
01534         //
01535         goto Exit;
01536       }
01537 
01538       Provided = TRUE;
01539     }
01540   }
01541 
01542   //
01543   // If the IP source address is the unspecified address, the IP
01544   // destination address is a solicited-node multicast address.
01545   //
01546   if (IsDAD && IsUnicast) {
01547     goto Exit;
01548   }
01549 
01550   //
01551   // If the target address is tentative, and the source address is a unicast address,
01552   // the solicitation's sender is performing address resolution on the target;
01553   //  the solicitation should be silently ignored.
01554   //
01555   if (!IsDAD && !IsMaintained) {
01556     goto Exit;
01557   }
01558 
01559   //
01560   // If received unicast neighbor solicitation but destination is not this node,
01561   // drop the packet.
01562   //
01563   if (IsUnicast && !IsMaintained) {
01564     goto Exit;
01565   }
01566 
01567   //
01568   // In DAD, when target address is a tentative address,
01569   // process the received neighbor solicitation message but not send out response.
01570   //
01571   if (IsDAD && !IsMaintained) {
01572     DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
01573     if (DupAddrDetect != NULL) {
01574       if (DupAddrDetect->Transmit == 0) {
01575         //
01576         // The NS is from another node to performing DAD on the same address since
01577         // we haven't send out any NS yet. Fail DAD for the tentative address.
01578         //
01579         Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
01580         Status = EFI_ICMP_ERROR;
01581         goto Exit;
01582       }
01583 
01584       //
01585       // Check the MAC address of the incoming packet.
01586       //
01587       if (IpSb->RecvRequest.MnpToken.Packet.RxData == NULL) {
01588         goto Exit;
01589       }
01590 
01591       MacAddress = IpSb->RecvRequest.MnpToken.Packet.RxData->SourceAddress;
01592       if (MacAddress != NULL) {
01593         if (CompareMem (
01594               MacAddress,
01595               &IpSb->SnpMode.CurrentAddress,
01596               IpSb->SnpMode.HwAddressSize
01597               ) != 0) {
01598           //
01599           // The NS is from another node to performing DAD on the same address.
01600           // Fail DAD for the tentative address.
01601           //
01602           Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
01603           Status = EFI_ICMP_ERROR;
01604         } else {
01605           //
01606           // The below layer loopback the NS we sent. Record it and wait for more.
01607           //
01608           DupAddrDetect->Receive++;
01609           Status = EFI_SUCCESS;
01610         }
01611       }
01612     }
01613     goto Exit;
01614   }
01615 
01616   //
01617   // If the solicitation does not contain a link-layer address, DO NOT create or
01618   // update the neighbor cache entries.
01619   //
01620   if (Provided) {
01621     Neighbor    = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
01622     UpdateCache = FALSE;
01623 
01624     if (Neighbor == NULL) {
01625       Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, &Head->SourceAddress, NULL);
01626       if (Neighbor == NULL) {
01627         Status = EFI_OUT_OF_RESOURCES;
01628         goto Exit;
01629       }
01630       UpdateCache = TRUE;
01631     } else {
01632       if (CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6) != 0) {
01633         UpdateCache = TRUE;
01634       }
01635     }
01636 
01637     if (UpdateCache) {
01638       Neighbor->State = EfiNeighborStale;
01639       Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
01640       CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
01641       //
01642       // Send queued packets if exist.
01643       //
01644       Neighbor->CallBack ((VOID *) Neighbor);
01645     }
01646   }
01647 
01648   //
01649   // Sends a Neighbor Advertisement as response.
01650   // Set the Router flag to zero since the node is a host.
01651   // If the source address of the solicitation is unspeicifed, and target address
01652   // is one of the maintained address, reply a unsolicited multicast advertisement.
01653   //
01654   if (IsDAD && IsMaintained) {
01655     Solicited = FALSE;
01656     Ip6SetToAllNodeMulticast (FALSE, IP6_LINK_LOCAL_SCOPE, &Dest);
01657   } else {
01658     Solicited = TRUE;
01659     IP6_COPY_ADDRESS (&Dest, &Head->SourceAddress);
01660   }
01661 
01662   Status = Ip6SendNeighborAdvertise (
01663              IpSb,
01664              &Target,
01665              &Dest,
01666              &Target,
01667              &IpSb->SnpMode.CurrentAddress,
01668              FALSE,
01669              TRUE,
01670              Solicited
01671              );
01672 Exit:
01673   NetbufFree (Packet);
01674   return Status;
01675 }
01676 
01690 EFI_STATUS
01691 Ip6ProcessNeighborAdvertise (
01692   IN IP6_SERVICE            *IpSb,
01693   IN EFI_IP6_HEADER         *Head,
01694   IN NET_BUF                *Packet
01695   )
01696 {
01697   IP6_ICMP_INFORMATION_HEAD Icmp;
01698   EFI_IPv6_ADDRESS          Target;
01699   IP6_ETHER_ADDR_OPTION     LinkLayerOption;
01700   BOOLEAN                   Provided;
01701   INTN                      Compare;
01702   IP6_NEIGHBOR_ENTRY        *Neighbor;
01703   IP6_DEFAULT_ROUTER        *DefaultRouter;
01704   BOOLEAN                   Solicited;
01705   BOOLEAN                   IsRouter;
01706   BOOLEAN                   Override;
01707   IP6_DAD_ENTRY             *DupAddrDetect;
01708   IP6_INTERFACE             *IpIf;
01709   UINT16                    OptionLen;
01710   UINT8                     *Option;
01711   EFI_STATUS                Status;
01712 
01713   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
01714   NetbufCopy (Packet, sizeof (Icmp), sizeof (Target), Target.Addr);
01715 
01716   //
01717   // Validate the incoming Neighbor Advertisement
01718   //
01719   Status = EFI_INVALID_PARAMETER;
01720   //
01721   // The IP Hop Limit field has a value of 255, i.e., the packet
01722   // could not possibly have been forwarded by a router.
01723   // ICMP Code is 0.
01724   // Target Address is not a multicast address.
01725   //
01726   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 || !NetIp6IsValidUnicast (&Target)) {
01727     goto Exit;
01728   }
01729 
01730   //
01731   // ICMP length is 24 or more octets.
01732   //
01733   Provided  = FALSE;
01734   OptionLen = 0;
01735   if (Head->PayloadLength < IP6_ND_LENGTH) {
01736     goto Exit;
01737   } else {
01738     OptionLen = (UINT16) (Head->PayloadLength - IP6_ND_LENGTH);
01739     if (OptionLen != 0) {
01740       Option    = NetbufGetByte (Packet, IP6_ND_LENGTH, NULL);
01741       ASSERT (Option != NULL);
01742 
01743       //
01744       // All included options should have a length that is greater than zero.
01745       //
01746       if (!Ip6IsNDOptionValid (Option, OptionLen)) {
01747         goto Exit;
01748       }
01749     }
01750   }
01751 
01752   //
01753   // If the IP destination address is a multicast address, Solicited Flag is ZERO.
01754   //
01755   Solicited = FALSE;
01756   if ((Icmp.Fourth & IP6_SOLICITED_FLAG) == IP6_SOLICITED_FLAG) {
01757     Solicited = TRUE;
01758   }
01759   if (IP6_IS_MULTICAST (&Head->DestinationAddress) && Solicited) {
01760     goto Exit;
01761   }
01762 
01763   //
01764   // DAD - Check whether the Target is one of our tentative address.
01765   //
01766   DupAddrDetect = Ip6FindDADEntry (IpSb, &Target, &IpIf);
01767   if (DupAddrDetect != NULL) {
01768     //
01769     // DAD fails, some other node is using this address.
01770     //
01771     NetbufFree (Packet);
01772     Ip6OnDADFinished (FALSE, IpIf, DupAddrDetect);
01773     return EFI_ICMP_ERROR;
01774   }
01775 
01776   //
01777   // Search the Neighbor Cache for the target's entry. If no entry exists,
01778   // the advertisement should be silently discarded.
01779   //
01780   Neighbor = Ip6FindNeighborEntry (IpSb, &Target);
01781   if (Neighbor == NULL) {
01782     goto Exit;
01783   }
01784 
01785   //
01786   // Get IsRouter Flag and Override Flag
01787   //
01788   IsRouter = FALSE;
01789   Override = FALSE;
01790   if ((Icmp.Fourth & IP6_IS_ROUTER_FLAG) == IP6_IS_ROUTER_FLAG) {
01791     IsRouter = TRUE;
01792   }
01793   if ((Icmp.Fourth & IP6_OVERRIDE_FLAG) == IP6_OVERRIDE_FLAG) {
01794     Override = TRUE;
01795   }
01796 
01797   //
01798   // Check whether link layer option is included.
01799   //
01800   if (OptionLen >= sizeof (IP6_ETHER_ADDR_OPTION)) {
01801     NetbufCopy (
01802       Packet,
01803       IP6_ND_LENGTH,
01804       sizeof (IP6_ETHER_ADDR_OPTION),
01805       (UINT8 *) &LinkLayerOption
01806       );
01807 
01808     if (LinkLayerOption.Type == Ip6OptionEtherTarget) {
01809       Provided = TRUE;
01810     }
01811   }
01812 
01813   Compare = 0;
01814   if (Provided) {
01815     Compare = CompareMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
01816   }
01817 
01818   if (!Neighbor->IsRouter && IsRouter) {
01819     DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
01820     if (DefaultRouter != NULL) {
01821       DefaultRouter->NeighborCache = Neighbor;
01822     }
01823   }
01824 
01825   if (Neighbor->State == EfiNeighborInComplete) {
01826     //
01827     // If the target's Neighbor Cache entry is in INCOMPLETE state and no
01828     // Target Link-Layer address option is included while link layer has
01829     // address, the message should be silently discarded.
01830     //
01831     if (!Provided) {
01832       goto Exit;
01833     }
01834     //
01835     // Update the Neighbor Cache
01836     //
01837     CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
01838     if (Solicited) {
01839       Neighbor->State = EfiNeighborReachable;
01840       Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
01841     } else {
01842       Neighbor->State = EfiNeighborStale;
01843       Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
01844       //
01845       // Send any packets queued for the neighbor awaiting address resolution.
01846       //
01847       Neighbor->CallBack ((VOID *) Neighbor);
01848     }
01849 
01850     Neighbor->IsRouter = IsRouter;
01851 
01852   } else {
01853     if (!Override && Compare != 0) {
01854       //
01855       // When the Override Flag is clear and supplied link-layer address differs from
01856       // that in the cache, if the state of the entry is not REACHABLE, ignore the
01857       // message. Otherwise set it to STALE but do not update the entry in any
01858       // other way.
01859       //
01860       if (Neighbor->State == EfiNeighborReachable) {
01861         Neighbor->State = EfiNeighborStale;
01862         Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
01863       }
01864     } else {
01865       if (Compare != 0) {
01866         CopyMem (Neighbor->LinkAddress.Addr, LinkLayerOption.EtherAddr, 6);
01867       }
01868       //
01869       // Update the entry's state
01870       //
01871       if (Solicited) {
01872         Neighbor->State = EfiNeighborReachable;
01873         Neighbor->Ticks = IP6_GET_TICKS (IpSb->ReachableTime);
01874       } else {
01875         if (Compare != 0) {
01876           Neighbor->State = EfiNeighborStale;
01877           Neighbor->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
01878         }
01879       }
01880 
01881       //
01882       // When IsRouter is changed from TRUE to FALSE, remove the router from the
01883       // Default Router List and remove the Destination Cache entries for all destinations
01884       // using the neighbor as a router.
01885       //
01886       if (Neighbor->IsRouter && !IsRouter) {
01887         DefaultRouter = Ip6FindDefaultRouter (IpSb, &Target);
01888         if (DefaultRouter != NULL) {
01889           Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
01890         }
01891       }
01892 
01893       Neighbor->IsRouter = IsRouter;
01894     }
01895   }
01896 
01897   if (Neighbor->State == EfiNeighborReachable) {
01898     Neighbor->CallBack ((VOID *) Neighbor);
01899   }
01900 
01901   Status = EFI_SUCCESS;
01902 
01903 Exit:
01904   NetbufFree (Packet);
01905   return Status;
01906 }
01907 
01922 EFI_STATUS
01923 Ip6ProcessRouterAdvertise (
01924   IN IP6_SERVICE            *IpSb,
01925   IN EFI_IP6_HEADER         *Head,
01926   IN NET_BUF                *Packet
01927   )
01928 {
01929   IP6_ICMP_INFORMATION_HEAD Icmp;
01930   UINT32                    ReachableTime;
01931   UINT32                    RetransTimer;
01932   UINT16                    RouterLifetime;
01933   UINT16                    Offset;
01934   UINT8                     Type;
01935   UINT8                     Length;
01936   IP6_ETHER_ADDR_OPTION     LinkLayerOption;
01937   UINT32                    Fourth;
01938   UINT8                     CurHopLimit;
01939   BOOLEAN                   Mflag;
01940   BOOLEAN                   Oflag;
01941   IP6_DEFAULT_ROUTER        *DefaultRouter;
01942   IP6_NEIGHBOR_ENTRY        *NeighborCache;
01943   EFI_MAC_ADDRESS           LinkLayerAddress;
01944   IP6_MTU_OPTION            MTUOption;
01945   IP6_PREFIX_INFO_OPTION    PrefixOption;
01946   IP6_PREFIX_LIST_ENTRY     *PrefixList;
01947   BOOLEAN                   OnLink;
01948   BOOLEAN                   Autonomous;
01949   EFI_IPv6_ADDRESS          StatelessAddress;
01950   EFI_STATUS                Status;
01951   UINT16                    OptionLen;
01952   UINT8                     *Option;
01953   INTN                      Result;
01954 
01955   Status = EFI_INVALID_PARAMETER;
01956 
01957   if (IpSb->Ip6ConfigInstance.Policy != Ip6ConfigPolicyAutomatic) {
01958     //
01959     // Skip the process below as it's not required under the current policy.
01960     //
01961     goto Exit;
01962   }
01963 
01964   NetbufCopy (Packet, 0, sizeof (Icmp), (UINT8 *) &Icmp);
01965 
01966   //
01967   // Validate the incoming Router Advertisement
01968   //
01969 
01970   //
01971   // The IP source address must be a link-local address
01972   //
01973   if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
01974     goto Exit;
01975   }
01976   //
01977   // The IP Hop Limit field has a value of 255, i.e. the packet
01978   // could not possibly have been forwarded by a router.
01979   // ICMP Code is 0.
01980   // ICMP length (derived from the IP length) is 16 or more octets.
01981   //
01982   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp.Head.Code != 0 ||
01983       Head->PayloadLength < IP6_RA_LENGTH) {
01984     goto Exit;
01985   }
01986 
01987   //
01988   // All included options have a length that is greater than zero.
01989   //
01990   OptionLen = (UINT16) (Head->PayloadLength - IP6_RA_LENGTH);
01991   if (OptionLen != 0) {
01992     Option    = NetbufGetByte (Packet, IP6_RA_LENGTH, NULL);
01993     ASSERT (Option != NULL);
01994 
01995     if (!Ip6IsNDOptionValid (Option, OptionLen)) {
01996       goto Exit;
01997     }
01998   }
01999 
02000   //
02001   // Process Fourth field.
02002   // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
02003   // and Router Lifetime (16 bit).
02004   //
02005 
02006   Fourth = NTOHL (Icmp.Fourth);
02007   CopyMem (&RouterLifetime, &Fourth, sizeof (UINT16));
02008 
02009   //
02010   // If the source address already in the default router list, update it.
02011   // Otherwise create a new entry.
02012   // A Lifetime of zero indicates that the router is not a default router.
02013   //
02014   DefaultRouter = Ip6FindDefaultRouter (IpSb, &Head->SourceAddress);
02015   if (DefaultRouter == NULL) {
02016     if (RouterLifetime != 0) {
02017       DefaultRouter = Ip6CreateDefaultRouter (IpSb, &Head->SourceAddress, RouterLifetime);
02018       if (DefaultRouter == NULL) {
02019         Status = EFI_OUT_OF_RESOURCES;
02020         goto Exit;
02021       }
02022     }
02023   } else {
02024     if (RouterLifetime != 0) {
02025       DefaultRouter->Lifetime = RouterLifetime;
02026       //
02027       // Check the corresponding neighbor cache entry here.
02028       //
02029       if (DefaultRouter->NeighborCache == NULL) {
02030         DefaultRouter->NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
02031       }
02032     } else {
02033       //
02034       // If the address is in the host's default router list and the router lifetime is zero,
02035       // immediately time-out the entry.
02036       //
02037       Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
02038     }
02039   }
02040 
02041   CurHopLimit = *((UINT8 *) &Fourth + 3);
02042   if (CurHopLimit != 0) {
02043     IpSb->CurHopLimit = CurHopLimit;
02044   }
02045 
02046   Mflag = FALSE;
02047   Oflag = FALSE;
02048   if ((*((UINT8 *) &Fourth + 2) & IP6_M_ADDR_CONFIG_FLAG) == IP6_M_ADDR_CONFIG_FLAG) {
02049     Mflag = TRUE;
02050   } else {
02051     if ((*((UINT8 *) &Fourth + 2) & IP6_O_CONFIG_FLAG) == IP6_O_CONFIG_FLAG) {
02052       Oflag = TRUE;
02053     }
02054   }
02055 
02056   if (Mflag || Oflag) {
02057     //
02058     // Use Ip6Config to get available addresses or other configuration from DHCP.
02059     //
02060     Ip6ConfigStartStatefulAutoConfig (&IpSb->Ip6ConfigInstance, Oflag);
02061   }
02062 
02063   //
02064   // Process Reachable Time and Retrans Timer fields.
02065   //
02066   NetbufCopy (Packet, sizeof (Icmp), sizeof (UINT32), (UINT8 *) &ReachableTime);
02067   NetbufCopy (Packet, sizeof (Icmp) + sizeof (UINT32), sizeof (UINT32), (UINT8 *) &RetransTimer);
02068   ReachableTime = NTOHL (ReachableTime);
02069   RetransTimer  = NTOHL (RetransTimer);
02070 
02071   if (ReachableTime != 0 && ReachableTime != IpSb->BaseReachableTime) {
02072     //
02073     // If new value is not unspecified and differs from the previous one, record it
02074     // in BaseReachableTime and recompute a ReachableTime.
02075     //
02076     IpSb->BaseReachableTime = ReachableTime;
02077     Ip6UpdateReachableTime (IpSb);
02078   }
02079 
02080   if (RetransTimer != 0) {
02081     IpSb->RetransTimer = RetransTimer;
02082   }
02083 
02084   //
02085   // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
02086   //
02087   NeighborCache = Ip6FindNeighborEntry (IpSb, &Head->SourceAddress);
02088   if (NeighborCache != NULL) {
02089     NeighborCache->IsRouter = TRUE;
02090   }
02091 
02092   //
02093   // If an valid router advertisment is received, stops router solicitation.
02094   //
02095   IpSb->RouterAdvertiseReceived = TRUE;
02096 
02097   //
02098   // The only defined options that may appear are the Source
02099   // Link-Layer Address, Prefix information and MTU options.
02100   // All included options have a length that is greater than zero.
02101   //
02102   Offset = 16;
02103   while (Offset < Head->PayloadLength) {
02104     NetbufCopy (Packet, Offset, sizeof (UINT8), &Type);
02105     switch (Type) {
02106     case Ip6OptionEtherSource:
02107       //
02108       // Update the neighbor cache
02109       //
02110       NetbufCopy (Packet, Offset, sizeof (IP6_ETHER_ADDR_OPTION), (UINT8 *) &LinkLayerOption);
02111       if (LinkLayerOption.Length <= 0) {
02112         goto Exit;
02113       }
02114 
02115       ZeroMem (&LinkLayerAddress, sizeof (EFI_MAC_ADDRESS));
02116       CopyMem (&LinkLayerAddress, LinkLayerOption.EtherAddr, 6);
02117 
02118       if (NeighborCache == NULL) {
02119         NeighborCache = Ip6CreateNeighborEntry (
02120                           IpSb,
02121                           Ip6OnArpResolved,
02122                           &Head->SourceAddress,
02123                           &LinkLayerAddress
02124                           );
02125         if (NeighborCache == NULL) {
02126           Status = EFI_OUT_OF_RESOURCES;
02127           goto Exit;
02128         }
02129         NeighborCache->IsRouter = TRUE;
02130         NeighborCache->State    = EfiNeighborStale;
02131         NeighborCache->Ticks    = (UINT32) IP6_INFINIT_LIFETIME;
02132       } else {
02133         Result = CompareMem (&LinkLayerAddress, &NeighborCache->LinkAddress, 6);
02134 
02135         //
02136         // If the link-local address is the same as that already in the cache,
02137         // the cache entry's state remains unchanged. Otherwise update the
02138         // reachability state to STALE.
02139         //
02140         if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
02141           CopyMem (&NeighborCache->LinkAddress, &LinkLayerAddress, 6);
02142 
02143           NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
02144 
02145           if (NeighborCache->State == EfiNeighborInComplete) {
02146             //
02147             // Send queued packets if exist.
02148             //
02149             NeighborCache->State = EfiNeighborStale;
02150             NeighborCache->CallBack ((VOID *) NeighborCache);
02151           } else {
02152             NeighborCache->State = EfiNeighborStale;
02153           }
02154         }
02155       }
02156 
02157       Offset = (UINT16) (Offset + (UINT16) LinkLayerOption.Length * 8);
02158       break;
02159     case Ip6OptionPrefixInfo:
02160       NetbufCopy (Packet, Offset, sizeof (IP6_PREFIX_INFO_OPTION), (UINT8 *) &PrefixOption);
02161       if (PrefixOption.Length != 4) {
02162         goto Exit;
02163       }
02164       PrefixOption.ValidLifetime     = NTOHL (PrefixOption.ValidLifetime);
02165       PrefixOption.PreferredLifetime = NTOHL (PrefixOption.PreferredLifetime);
02166 
02167       //
02168       // Get L and A flag, recorded in the lower 2 bits of Reserved1
02169       //
02170       OnLink = FALSE;
02171       if ((PrefixOption.Reserved1 & IP6_ON_LINK_FLAG) == IP6_ON_LINK_FLAG) {
02172         OnLink = TRUE;
02173       }
02174       Autonomous = FALSE;
02175       if ((PrefixOption.Reserved1 & IP6_AUTO_CONFIG_FLAG) == IP6_AUTO_CONFIG_FLAG) {
02176         Autonomous = TRUE;
02177       }
02178 
02179       //
02180       // If the prefix is the link-local prefix, silently ignore the prefix option.
02181       //
02182       if (PrefixOption.PrefixLength == IP6_LINK_LOCAL_PREFIX_LENGTH &&
02183           NetIp6IsLinkLocalAddr (&PrefixOption.Prefix)
02184           ) {
02185         Offset += sizeof (IP6_PREFIX_INFO_OPTION);
02186         break;
02187       }
02188       //
02189       // Do following if on-link flag is set according to RFC4861.
02190       //
02191       if (OnLink) {
02192         PrefixList = Ip6FindPrefixListEntry (
02193                        IpSb,
02194                        TRUE,
02195                        PrefixOption.PrefixLength,
02196                        &PrefixOption.Prefix
02197                        );
02198         //
02199         // Create a new entry for the prefix, if the ValidLifetime is zero,
02200         // silently ignore the prefix option.
02201         //
02202         if (PrefixList == NULL && PrefixOption.ValidLifetime != 0) {
02203           PrefixList = Ip6CreatePrefixListEntry (
02204                          IpSb,
02205                          TRUE,
02206                          PrefixOption.ValidLifetime,
02207                          PrefixOption.PreferredLifetime,
02208                          PrefixOption.PrefixLength,
02209                          &PrefixOption.Prefix
02210                          );
02211           if (PrefixList == NULL) {
02212             Status = EFI_OUT_OF_RESOURCES;
02213             goto Exit;
02214           }
02215         } else if (PrefixList != NULL) {
02216           if (PrefixOption.ValidLifetime != 0) {
02217             PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
02218           } else {
02219             //
02220             // If the prefix exists and incoming ValidLifetime is zero, immediately
02221             // remove the prefix.
02222             Ip6DestroyPrefixListEntry (IpSb, PrefixList, OnLink, TRUE);
02223           }
02224         }
02225       }
02226 
02227       //
02228       // Do following if Autonomous flag is set according to RFC4862.
02229       //
02230       if (Autonomous && PrefixOption.PreferredLifetime <= PrefixOption.ValidLifetime) {
02231         PrefixList = Ip6FindPrefixListEntry (
02232                        IpSb,
02233                        FALSE,
02234                        PrefixOption.PrefixLength,
02235                        &PrefixOption.Prefix
02236                        );
02237         //
02238         // Create a new entry for the prefix, and form an address by prefix + interface id
02239         // If the sum of the prefix length and interface identifier length
02240         // does not equal 128 bits, the Prefix Information option MUST be ignored.
02241         //
02242         if (PrefixList == NULL &&
02243             PrefixOption.ValidLifetime != 0 &&
02244             PrefixOption.PrefixLength + IpSb->InterfaceIdLen * 8 == 128
02245             ) {
02246           //
02247           // Form the address in network order.
02248           //
02249           CopyMem (&StatelessAddress, &PrefixOption.Prefix, sizeof (UINT64));
02250           CopyMem (&StatelessAddress.Addr[8], IpSb->InterfaceId, sizeof (UINT64));
02251 
02252           //
02253           // If the address is not yet in the assigned address list, adds it into.
02254           //
02255           if (!Ip6IsOneOfSetAddress (IpSb, &StatelessAddress, NULL, NULL)) {
02256             //
02257             // And also not in the DAD process, check its uniqeness firstly.
02258             //
02259             if (Ip6FindDADEntry (IpSb, &StatelessAddress, NULL) == NULL) {
02260               Status = Ip6SetAddress (
02261                          IpSb->DefaultInterface,
02262                          &StatelessAddress,
02263                          FALSE,
02264                          PrefixOption.PrefixLength,
02265                          PrefixOption.ValidLifetime,
02266                          PrefixOption.PreferredLifetime,
02267                          NULL,
02268                          NULL
02269                          );
02270               if (EFI_ERROR (Status)) {
02271                 goto Exit;
02272               }
02273             }
02274           }
02275 
02276           //
02277           // Adds the prefix option to stateless prefix option list.
02278           //
02279           PrefixList = Ip6CreatePrefixListEntry (
02280                          IpSb,
02281                          FALSE,
02282                          PrefixOption.ValidLifetime,
02283                          PrefixOption.PreferredLifetime,
02284                          PrefixOption.PrefixLength,
02285                          &PrefixOption.Prefix
02286                          );
02287           if (PrefixList == NULL) {
02288             Status = EFI_OUT_OF_RESOURCES;
02289             goto Exit;
02290           }
02291         } else if (PrefixList != NULL) {
02292 
02293           //
02294           // Reset the preferred lifetime of the address if the advertised prefix exists.
02295           // Perform specific action to valid lifetime together.
02296           //
02297           PrefixList->PreferredLifetime = PrefixOption.PreferredLifetime;
02298           if ((PrefixOption.ValidLifetime > 7200) ||
02299               (PrefixOption.ValidLifetime > PrefixList->ValidLifetime)) {
02300             //
02301             // If the received Valid Lifetime is greater than 2 hours or
02302             // greater than RemainingLifetime, set the valid lifetime of the
02303             // corresponding address to the advertised Valid Lifetime.
02304             //
02305             PrefixList->ValidLifetime = PrefixOption.ValidLifetime;
02306 
02307           } else if (PrefixList->ValidLifetime <= 7200) {
02308             //
02309             // If RemainingLifetime is less than or equls to 2 hours, ignore the
02310             // Prefix Information option with regards to the valid lifetime.
02311             // TODO: If this option has been authenticated, set the valid lifetime.
02312             //
02313           } else {
02314             //
02315             // Otherwise, reset the valid lifetime of the corresponding
02316             // address to 2 hours.
02317             //
02318             PrefixList->ValidLifetime = 7200;
02319           }
02320         }
02321       }
02322 
02323       Offset += sizeof (IP6_PREFIX_INFO_OPTION);
02324       break;
02325     case Ip6OptionMtu:
02326       NetbufCopy (Packet, Offset, sizeof (IP6_MTU_OPTION), (UINT8 *) &MTUOption);
02327       if (MTUOption.Length != 1) {
02328         goto Exit;
02329       }
02330 
02331       //
02332       // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
02333       // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
02334       // in Router Advertisement.
02335       //
02336 
02337       Offset += sizeof (IP6_MTU_OPTION);
02338       break;
02339     default:
02340       //
02341       // Silently ignore unrecognized options
02342       //
02343       NetbufCopy (Packet, Offset + sizeof (UINT8), sizeof (UINT8), &Length);
02344       if (Length <= 0) {
02345         goto Exit;
02346       }
02347 
02348       Offset = (UINT16) (Offset + (UINT16) Length * 8);
02349       break;
02350     }
02351   }
02352 
02353   Status = EFI_SUCCESS;
02354 
02355 Exit:
02356   NetbufFree (Packet);
02357   return Status;
02358 }
02359 
02376 EFI_STATUS
02377 Ip6ProcessRedirect (
02378   IN IP6_SERVICE            *IpSb,
02379   IN EFI_IP6_HEADER         *Head,
02380   IN NET_BUF                *Packet
02381   )
02382 {
02383   IP6_ICMP_INFORMATION_HEAD *Icmp;
02384   EFI_IPv6_ADDRESS          *Target;
02385   EFI_IPv6_ADDRESS          *IcmpDest;
02386   UINT8                     *Option;
02387   UINT16                    OptionLen;
02388   IP6_ROUTE_ENTRY           *RouteEntry;
02389   IP6_ROUTE_CACHE_ENTRY     *RouteCache;
02390   IP6_NEIGHBOR_ENTRY        *NeighborCache;
02391   INT32                     Length;
02392   UINT8                     OptLen;
02393   IP6_ETHER_ADDR_OPTION     *LinkLayerOption;
02394   EFI_MAC_ADDRESS           Mac;
02395   UINT32                    Index;
02396   BOOLEAN                   IsRouter;
02397   EFI_STATUS                Status;
02398   INTN                      Result;
02399 
02400   Status = EFI_INVALID_PARAMETER;
02401 
02402   Icmp = (IP6_ICMP_INFORMATION_HEAD *) NetbufGetByte (Packet, 0, NULL);
02403   if (Icmp == NULL) {
02404     goto Exit;
02405   }
02406 
02407   //
02408   // Validate the incoming Redirect message
02409   //
02410 
02411   //
02412   // The IP Hop Limit field has a value of 255, i.e. the packet
02413   // could not possibly have been forwarded by a router.
02414   // ICMP Code is 0.
02415   // ICMP length (derived from the IP length) is 40 or more octets.
02416   //
02417   if (Head->HopLimit != IP6_HOP_LIMIT || Icmp->Head.Code != 0 ||
02418       Head->PayloadLength < IP6_REDITECT_LENGTH) {
02419     goto Exit;
02420   }
02421 
02422   //
02423   // The IP source address must be a link-local address
02424   //
02425   if (!NetIp6IsLinkLocalAddr (&Head->SourceAddress)) {
02426     goto Exit;
02427   }
02428 
02429   //
02430   // The dest of this ICMP redirect message is not us.
02431   //
02432   if (!Ip6IsOneOfSetAddress (IpSb, &Head->DestinationAddress, NULL, NULL)) {
02433     goto Exit;
02434   }
02435 
02436   //
02437   // All included options have a length that is greater than zero.
02438   //
02439   OptionLen = (UINT16) (Head->PayloadLength - IP6_REDITECT_LENGTH);
02440   if (OptionLen != 0) {
02441     Option    = NetbufGetByte (Packet, IP6_REDITECT_LENGTH, NULL);
02442     ASSERT (Option != NULL);
02443 
02444     if (!Ip6IsNDOptionValid (Option, OptionLen)) {
02445       goto Exit;
02446     }
02447   }
02448 
02449   Target   = (EFI_IPv6_ADDRESS *) (Icmp + 1);
02450   IcmpDest = Target + 1;
02451 
02452   //
02453   // The ICMP Destination Address field in the redirect message does not contain
02454   // a multicast address.
02455   //
02456   if (IP6_IS_MULTICAST (IcmpDest)) {
02457     goto Exit;
02458   }
02459 
02460   //
02461   // The ICMP Target Address is either a link-local address (when redirected to
02462   // a router) or the same as the ICMP Destination Address (when redirected to
02463   // the on-link destination).
02464   //
02465   IsRouter = (BOOLEAN) !EFI_IP6_EQUAL (Target, IcmpDest);
02466   if (!NetIp6IsLinkLocalAddr (Target) && IsRouter) {
02467     goto Exit;
02468   }
02469 
02470   //
02471   // Check the options. The only interested option here is the target-link layer
02472   // address option.
02473   //
02474   Length          = Packet->TotalSize - 40;
02475   Option          = (UINT8 *) (IcmpDest + 1);
02476   LinkLayerOption = NULL;
02477   while (Length > 0) {
02478     switch (*Option) {
02479     case Ip6OptionEtherTarget:
02480 
02481       LinkLayerOption = (IP6_ETHER_ADDR_OPTION *) Option;
02482       OptLen          = LinkLayerOption->Length;
02483       if (OptLen != 1) {
02484         //
02485         // For ethernet, the length must be 1.
02486         //
02487         goto Exit;
02488       }
02489       break;
02490 
02491     default:
02492 
02493       OptLen = *(Option + 1);
02494       if (OptLen == 0) {
02495         //
02496         // A length of 0 is invalid.
02497         //
02498         goto Exit;
02499       }
02500       break;
02501     }
02502 
02503     Length -= 8 * OptLen;
02504     Option += 8 * OptLen;
02505   }
02506 
02507   if (Length != 0) {
02508     goto Exit;
02509   }
02510 
02511   //
02512   // The IP source address of the Redirect is the same as the current
02513   // first-hop router for the specified ICMP Destination Address.
02514   //
02515   RouteCache = Ip6FindRouteCache (IpSb->RouteTable, IcmpDest, &Head->DestinationAddress);
02516   if (RouteCache != NULL) {
02517     if (!EFI_IP6_EQUAL (&RouteCache->NextHop, &Head->SourceAddress)) {
02518       //
02519       // The source of this Redirect message must match the NextHop of the
02520       // corresponding route cache entry.
02521       //
02522       goto Exit;
02523     }
02524 
02525     //
02526     // Update the NextHop.
02527     //
02528     IP6_COPY_ADDRESS (&RouteCache->NextHop, Target);
02529 
02530     if (!IsRouter) {
02531       RouteEntry = (IP6_ROUTE_ENTRY *) RouteCache->Tag;
02532       RouteEntry->Flag = RouteEntry->Flag | IP6_DIRECT_ROUTE;
02533     }
02534 
02535   } else {
02536     //
02537     // Get the Route Entry.
02538     //
02539     RouteEntry = Ip6FindRouteEntry (IpSb->RouteTable, IcmpDest, NULL);
02540     if (RouteEntry == NULL) {
02541       RouteEntry = Ip6CreateRouteEntry (IcmpDest, 0, NULL);
02542       if (RouteEntry == NULL) {
02543         Status = EFI_OUT_OF_RESOURCES;
02544         goto Exit;
02545       }
02546     }
02547 
02548     if (!IsRouter) {
02549       RouteEntry->Flag = IP6_DIRECT_ROUTE;
02550     }
02551 
02552     //
02553     // Create a route cache for this.
02554     //
02555     RouteCache = Ip6CreateRouteCacheEntry (
02556                    IcmpDest,
02557                    &Head->DestinationAddress,
02558                    Target,
02559                    (UINTN) RouteEntry
02560                    );
02561     if (RouteCache == NULL) {
02562       Status = EFI_OUT_OF_RESOURCES;
02563       goto Exit;
02564     }
02565 
02566     //
02567     // Insert the newly created route cache entry.
02568     //
02569     Index = IP6_ROUTE_CACHE_HASH (IcmpDest, &Head->DestinationAddress);
02570     InsertHeadList (&IpSb->RouteTable->Cache.CacheBucket[Index], &RouteCache->Link);
02571   }
02572 
02573   //
02574   // Try to locate the neighbor cache for the Target.
02575   //
02576   NeighborCache = Ip6FindNeighborEntry (IpSb, Target);
02577 
02578   if (LinkLayerOption != NULL) {
02579     if (NeighborCache == NULL) {
02580       //
02581       // Create a neighbor cache for the Target.
02582       //
02583       ZeroMem (&Mac, sizeof (EFI_MAC_ADDRESS));
02584       CopyMem (&Mac, LinkLayerOption->EtherAddr, 6);
02585       NeighborCache = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, Target, &Mac);
02586       if (NeighborCache == NULL) {
02587         //
02588         // Just report a success here. The neighbor cache can be created in
02589         // some other place.
02590         //
02591         Status = EFI_SUCCESS;
02592         goto Exit;
02593       }
02594 
02595       NeighborCache->State = EfiNeighborStale;
02596       NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
02597     } else {
02598       Result = CompareMem (LinkLayerOption->EtherAddr, &NeighborCache->LinkAddress, 6);
02599 
02600       //
02601       // If the link-local address is the same as that already in the cache,
02602       // the cache entry's state remains unchanged. Otherwise update the
02603       // reachability state to STALE.
02604       //
02605       if ((NeighborCache->State == EfiNeighborInComplete) || (Result != 0)) {
02606         CopyMem (&NeighborCache->LinkAddress, LinkLayerOption->EtherAddr, 6);
02607 
02608         NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
02609 
02610         if (NeighborCache->State == EfiNeighborInComplete) {
02611           //
02612           // Send queued packets if exist.
02613           //
02614           NeighborCache->State = EfiNeighborStale;
02615           NeighborCache->CallBack ((VOID *) NeighborCache);
02616         } else {
02617           NeighborCache->State = EfiNeighborStale;
02618         }
02619       }
02620     }
02621   }
02622 
02623   if (NeighborCache != NULL && IsRouter) {
02624     //
02625     // The Target is a router, set IsRouter to TRUE.
02626     //
02627     NeighborCache->IsRouter = TRUE;
02628   }
02629 
02630   Status = EFI_SUCCESS;
02631 
02632 Exit:
02633   NetbufFree (Packet);
02634   return Status;
02635 }
02636 
02661 EFI_STATUS
02662 Ip6AddNeighbor (
02663   IN IP6_SERVICE            *IpSb,
02664   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
02665   IN EFI_MAC_ADDRESS        *TargetLinkAddress OPTIONAL,
02666   IN UINT32                 Timeout,
02667   IN BOOLEAN                Override
02668   )
02669 {
02670   IP6_NEIGHBOR_ENTRY        *Neighbor;
02671 
02672   Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
02673   if (Neighbor != NULL) {
02674     if (!Override) {
02675       return EFI_ACCESS_DENIED;
02676     } else {
02677       if (TargetLinkAddress != NULL) {
02678         IP6_COPY_LINK_ADDRESS (&Neighbor->LinkAddress, TargetLinkAddress);
02679       }
02680     }
02681   } else {
02682     if (TargetLinkAddress == NULL) {
02683       return EFI_NOT_FOUND;
02684     }
02685 
02686     Neighbor = Ip6CreateNeighborEntry (IpSb, Ip6OnArpResolved, TargetIp6Address, TargetLinkAddress);
02687     if (Neighbor == NULL) {
02688       return EFI_OUT_OF_RESOURCES;
02689     }
02690   }
02691 
02692   Neighbor->State = EfiNeighborReachable;
02693 
02694   if (Timeout != 0) {
02695     Neighbor->Ticks   = IP6_GET_TICKS (Timeout / TICKS_PER_MS);
02696     Neighbor->Dynamic = TRUE;
02697   } else {
02698     Neighbor->Ticks   = (UINT32) IP6_INFINIT_LIFETIME;
02699   }
02700 
02701   return EFI_SUCCESS;
02702 }
02703 
02723 EFI_STATUS
02724 Ip6DelNeighbor (
02725   IN IP6_SERVICE            *IpSb,
02726   IN EFI_IPv6_ADDRESS       *TargetIp6Address,
02727   IN EFI_MAC_ADDRESS        *TargetLinkAddress OPTIONAL,
02728   IN UINT32                 Timeout,
02729   IN BOOLEAN                Override
02730   )
02731 {
02732   IP6_NEIGHBOR_ENTRY        *Neighbor;
02733 
02734   Neighbor = Ip6FindNeighborEntry (IpSb, TargetIp6Address);
02735   if (Neighbor == NULL) {
02736     return EFI_NOT_FOUND;
02737   }
02738 
02739   RemoveEntryList (&Neighbor->Link);
02740   FreePool (Neighbor);
02741 
02742   return EFI_SUCCESS;
02743 }
02744 
02754 VOID
02755 EFIAPI
02756 Ip6NdFasterTimerTicking (
02757   IN EFI_EVENT              Event,
02758   IN VOID                   *Context
02759   )
02760 {
02761   LIST_ENTRY                *Entry;
02762   LIST_ENTRY                *Next;
02763   LIST_ENTRY                *Entry2;
02764   IP6_INTERFACE             *IpIf;
02765   IP6_DELAY_JOIN_LIST       *DelayNode;
02766   EFI_IPv6_ADDRESS          Source;
02767   IP6_DAD_ENTRY             *DupAddrDetect;
02768   EFI_STATUS                Status;
02769   IP6_NEIGHBOR_ENTRY        *NeighborCache;
02770   EFI_IPv6_ADDRESS          Destination;
02771   IP6_SERVICE               *IpSb;
02772   BOOLEAN                   Flag;
02773 
02774   IpSb = (IP6_SERVICE *) Context;
02775   NET_CHECK_SIGNATURE (IpSb, IP6_SERVICE_SIGNATURE);
02776 
02777   ZeroMem (&Source, sizeof (EFI_IPv6_ADDRESS));
02778 
02779   //
02780   // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
02781   // Solicitation messages, each separated by at least
02782   // RTR_SOLICITATION_INTERVAL (4) seconds.
02783   //
02784   if ((IpSb->Ip6ConfigInstance.Policy == Ip6ConfigPolicyAutomatic) &&
02785       !IpSb->RouterAdvertiseReceived &&
02786       IpSb->SolicitTimer > 0
02787       ) {
02788     if ((IpSb->Ticks == 0) || (--IpSb->Ticks == 0)) {
02789       Status = Ip6SendRouterSolicit (IpSb, NULL, NULL, NULL, NULL);
02790       if (!EFI_ERROR (Status)) {
02791         IpSb->SolicitTimer--;
02792         IpSb->Ticks = (UINT32) IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL);
02793       }
02794     }
02795   }
02796 
02797   NET_LIST_FOR_EACH (Entry, &IpSb->Interfaces) {
02798     IpIf = NET_LIST_USER_STRUCT (Entry, IP6_INTERFACE, Link);
02799 
02800     //
02801     // Process the delay list to join the solicited-node multicast address.
02802     //
02803     NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DelayJoinList) {
02804       DelayNode = NET_LIST_USER_STRUCT (Entry2, IP6_DELAY_JOIN_LIST, Link);
02805       if ((DelayNode->DelayTime == 0) || (--DelayNode->DelayTime == 0)) {
02806         //
02807         // The timer expires, init the duplicate address detection.
02808         //
02809         Ip6InitDADProcess (
02810           DelayNode->Interface,
02811           DelayNode->AddressInfo,
02812           DelayNode->DadCallback,
02813           DelayNode->Context
02814           );
02815 
02816         //
02817         // Remove the delay node
02818         //
02819         RemoveEntryList (&DelayNode->Link);
02820         FreePool (DelayNode);
02821       }
02822     }
02823 
02824     //
02825     // Process the duplicate address detection list.
02826     //
02827     NET_LIST_FOR_EACH_SAFE (Entry2, Next, &IpIf->DupAddrDetectList) {
02828       DupAddrDetect = NET_LIST_USER_STRUCT (Entry2, IP6_DAD_ENTRY, Link);
02829 
02830       if ((DupAddrDetect->RetransTick == 0) || (--DupAddrDetect->RetransTick == 0)) {
02831         //
02832         // The timer expires, check the remaining transmit counts.
02833         //
02834         if (DupAddrDetect->Transmit < DupAddrDetect->MaxTransmit) {
02835           //
02836           // Send the Neighbor Solicitation message with
02837           // Source - unspecified address, destination - solicited-node multicast address
02838           // Target - the address to be validated
02839           //
02840           Status = Ip6SendNeighborSolicit (
02841                      IpSb,
02842                      NULL,
02843                      &DupAddrDetect->Destination,
02844                      &DupAddrDetect->AddressInfo->Address,
02845                      NULL
02846                      );
02847           if (EFI_ERROR (Status)) {
02848             return;
02849           }
02850 
02851           DupAddrDetect->Transmit++;
02852           DupAddrDetect->RetransTick = IP6_GET_TICKS (IpSb->RetransTimer);
02853         } else {
02854           //
02855           // All required solicitation has been sent out, and the RetransTime after the last
02856           // Neighbor Solicit is elapsed, finish the DAD process.
02857           //
02858           Flag = FALSE;
02859           if ((DupAddrDetect->Receive == 0) ||
02860               (DupAddrDetect->Transmit == DupAddrDetect->Receive)) {
02861             Flag = TRUE;
02862           }
02863 
02864           Ip6OnDADFinished (Flag, IpIf, DupAddrDetect);
02865         }
02866       }
02867     }
02868   }
02869 
02870   //
02871   // Polling the state of Neighbor cache
02872   //
02873   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->NeighborTable) {
02874     NeighborCache = NET_LIST_USER_STRUCT (Entry, IP6_NEIGHBOR_ENTRY, Link);
02875 
02876     switch (NeighborCache->State) {
02877     case EfiNeighborInComplete:
02878       if (NeighborCache->Ticks > 0) {
02879         --NeighborCache->Ticks;
02880       }
02881 
02882       //
02883       // Retransmit Neighbor Solicitation messages approximately every
02884       // RetransTimer milliseconds while awaiting a response.
02885       //
02886       if (NeighborCache->Ticks == 0) {
02887         if (NeighborCache->Transmit > 1) {
02888           //
02889           // Send out multicast neighbor solicitation for address resolution.
02890           // After last neighbor solicitation message has been sent out, wait
02891           // for RetransTimer and then remove entry if no response is received.
02892           //
02893           Ip6CreateSNMulticastAddr (&NeighborCache->Neighbor, &Destination);
02894           Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
02895           if (EFI_ERROR (Status)) {
02896             return;
02897           }
02898 
02899           Status = Ip6SendNeighborSolicit (
02900                      IpSb,
02901                      &Source,
02902                      &Destination,
02903                      &NeighborCache->Neighbor,
02904                      &IpSb->SnpMode.CurrentAddress
02905                      );
02906           if (EFI_ERROR (Status)) {
02907             return;
02908           }
02909         }
02910 
02911         //
02912         // Update the retransmit times.
02913         //
02914         if (NeighborCache->Transmit > 0) {
02915           --NeighborCache->Transmit;
02916           NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
02917         }
02918       }
02919 
02920       if (NeighborCache->Transmit == 0) {
02921         //
02922         // Timeout, send ICMP destination unreachable packet and then remove entry
02923         //
02924         Status = Ip6FreeNeighborEntry (
02925                    IpSb,
02926                    NeighborCache,
02927                    TRUE,
02928                    TRUE,
02929                    EFI_ICMP_ERROR,
02930                    NULL,
02931                    NULL
02932                    );
02933         if (EFI_ERROR (Status)) {
02934           return;
02935         }
02936       }
02937 
02938       break;
02939 
02940     case EfiNeighborReachable:
02941       //
02942       // This entry is inserted by EfiIp6Neighbors() as static entry
02943       // and will not timeout.
02944       //
02945       if (!NeighborCache->Dynamic && (NeighborCache->Ticks == IP6_INFINIT_LIFETIME)) {
02946         break;
02947       }
02948 
02949       if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
02950         if (NeighborCache->Dynamic) {
02951           //
02952           // This entry is inserted by EfiIp6Neighbors() as dynamic entry
02953           // and will be deleted after timeout.
02954           //
02955           Status = Ip6FreeNeighborEntry (
02956                      IpSb,
02957                      NeighborCache,
02958                      FALSE,
02959                      TRUE,
02960                      EFI_TIMEOUT,
02961                      NULL,
02962                      NULL
02963                      );
02964           if (EFI_ERROR (Status)) {
02965             return;
02966           }
02967         } else {
02968           NeighborCache->State = EfiNeighborStale;
02969           NeighborCache->Ticks = (UINT32) IP6_INFINIT_LIFETIME;
02970         }
02971       }
02972 
02973       break;
02974 
02975     case EfiNeighborDelay:
02976       if ((NeighborCache->Ticks == 0) || (--NeighborCache->Ticks == 0)) {
02977 
02978         NeighborCache->State    = EfiNeighborProbe;
02979         NeighborCache->Ticks    = IP6_GET_TICKS (IpSb->RetransTimer);
02980         NeighborCache->Transmit = IP6_MAX_UNICAST_SOLICIT + 1;
02981         //
02982         // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
02983         //
02984         Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
02985         if (EFI_ERROR (Status)) {
02986           return;
02987         }
02988 
02989         Status = Ip6SendNeighborSolicit (
02990                    IpSb,
02991                    &Source,
02992                    &NeighborCache->Neighbor,
02993                    &NeighborCache->Neighbor,
02994                    &IpSb->SnpMode.CurrentAddress
02995                    );
02996         if (EFI_ERROR (Status)) {
02997           return;
02998         }
02999 
03000         NeighborCache->Transmit--;
03001       }
03002 
03003       break;
03004 
03005     case EfiNeighborProbe:
03006       if (NeighborCache->Ticks > 0) {
03007         --NeighborCache->Ticks;
03008       }
03009 
03010       //
03011       // Retransmit Neighbor Solicitation messages approximately every
03012       // RetransTimer milliseconds while awaiting a response.
03013       //
03014       if (NeighborCache->Ticks == 0) {
03015         if (NeighborCache->Transmit > 1) {
03016           //
03017           // Send out unicast neighbor solicitation for Neighbor Unreachability
03018           // Detection. After last neighbor solicitation message has been sent out,
03019           // wait for RetransTimer and then remove entry if no response is received.
03020           //
03021           Status = Ip6SelectSourceAddress (IpSb, &NeighborCache->Neighbor, &Source);
03022           if (EFI_ERROR (Status)) {
03023             return;
03024           }
03025 
03026           Status = Ip6SendNeighborSolicit (
03027                      IpSb,
03028                      &Source,
03029                      &NeighborCache->Neighbor,
03030                      &NeighborCache->Neighbor,
03031                      &IpSb->SnpMode.CurrentAddress
03032                      );
03033           if (EFI_ERROR (Status)) {
03034             return;
03035           }
03036         }
03037 
03038         //
03039         // Update the retransmit times.
03040         //
03041         if (NeighborCache->Transmit > 0) {
03042           --NeighborCache->Transmit;
03043           NeighborCache->Ticks = IP6_GET_TICKS (IpSb->RetransTimer);
03044         }
03045       }
03046 
03047       if (NeighborCache->Transmit == 0) {
03048         //
03049         // Delete the neighbor entry.
03050         //
03051         Status = Ip6FreeNeighborEntry (
03052                    IpSb,
03053                    NeighborCache,
03054                    FALSE,
03055                    TRUE,
03056                    EFI_TIMEOUT,
03057                    NULL,
03058                    NULL
03059                    );
03060         if (EFI_ERROR (Status)) {
03061           return;
03062         }
03063       }
03064 
03065       break;
03066 
03067     default:
03068       break;
03069     }
03070   }
03071 }
03072 
03081 VOID
03082 Ip6NdTimerTicking (
03083   IN IP6_SERVICE            *IpSb
03084   )
03085 {
03086   LIST_ENTRY                *Entry;
03087   LIST_ENTRY                *Next;
03088   IP6_DEFAULT_ROUTER        *DefaultRouter;
03089   IP6_PREFIX_LIST_ENTRY     *PrefixOption;
03090   UINT8                     Index;
03091   IP6_ROUTE_CACHE_ENTRY     *RouteCache;
03092 
03093   //
03094   // Decrease the lifetime of default router, if expires remove it from default router list.
03095   //
03096   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->DefaultRouterList) {
03097     DefaultRouter = NET_LIST_USER_STRUCT (Entry, IP6_DEFAULT_ROUTER, Link);
03098     if (DefaultRouter->Lifetime != IP6_INF_ROUTER_LIFETIME) {
03099       if ((DefaultRouter->Lifetime == 0) || (--DefaultRouter->Lifetime == 0)) {
03100         Ip6DestroyDefaultRouter (IpSb, DefaultRouter);
03101       }
03102     }
03103   }
03104 
03105   //
03106   // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
03107   //
03108   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->AutonomousPrefix) {
03109     PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
03110     if (PrefixOption->ValidLifetime != (UINT32) IP6_INFINIT_LIFETIME) {
03111       if ((PrefixOption->ValidLifetime > 0) && (--PrefixOption->ValidLifetime > 0)) {
03112         if ((PrefixOption->PreferredLifetime != (UINT32) IP6_INFINIT_LIFETIME) &&
03113             (PrefixOption->PreferredLifetime > 0)
03114             ) {
03115           --PrefixOption->PreferredLifetime;
03116         }
03117       } else {
03118         Ip6DestroyPrefixListEntry (IpSb, PrefixOption, FALSE, TRUE);
03119       }
03120     }
03121   }
03122 
03123   NET_LIST_FOR_EACH_SAFE (Entry, Next, &IpSb->OnlinkPrefix) {
03124     PrefixOption = NET_LIST_USER_STRUCT (Entry, IP6_PREFIX_LIST_ENTRY, Link);
03125     if (PrefixOption->ValidLifetime != (UINT32) IP6_INFINIT_LIFETIME) {
03126       if ((PrefixOption->ValidLifetime == 0) || (--PrefixOption->ValidLifetime == 0)) {
03127         Ip6DestroyPrefixListEntry (IpSb, PrefixOption, TRUE, TRUE);
03128       }
03129     }
03130   }
03131 
03132   //
03133   // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
03134   // Remove the entries at the tail of the bucket. These entries
03135   // are likely to be used least.
03136   // Reclaim frequency is set to 1 second.
03137   //
03138   for (Index = 0; Index < IP6_ROUTE_CACHE_HASH_SIZE; Index++) {
03139     while (IpSb->RouteTable->Cache.CacheNum[Index] > IP6_ROUTE_CACHE_MAX) {
03140       Entry = NetListRemoveTail (&IpSb->RouteTable->Cache.CacheBucket[Index]);
03141       if (Entry == NULL) {
03142         break;
03143       }
03144 
03145       RouteCache = NET_LIST_USER_STRUCT (Entry, IP6_ROUTE_CACHE_ENTRY, Link);
03146       Ip6FreeRouteCacheEntry (RouteCache);
03147       ASSERT (IpSb->RouteTable->Cache.CacheNum[Index] > 0);
03148       IpSb->RouteTable->Cache.CacheNum[Index]--;
03149     }
03150   }
03151 }
03152 
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Defines