2 Implementation of Neighbor Discovery support routines.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
12 EFI_MAC_ADDRESS mZeroMacAddress
;
15 Update the ReachableTime in IP6 service binding instance data, in milliseconds.
17 @param[in, out] IpSb Points to the IP6_SERVICE.
21 Ip6UpdateReachableTime (
22 IN OUT IP6_SERVICE
*IpSb
27 Random
= (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE
;
28 Random
= Random
+ IP6_MIN_RANDOM_FACTOR_SCALED
;
29 IpSb
->ReachableTime
= (IpSb
->BaseReachableTime
* Random
) / IP6_RANDOM_FACTOR_SCALE
;
33 Build a array of EFI_IP6_NEIGHBOR_CACHE to be returned to the caller. The number
34 of EFI_IP6_NEIGHBOR_CACHE is also returned.
36 @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
37 @param[out] NeighborCount The number of returned neighbor cache entries.
38 @param[out] NeighborCache The pointer to the array of EFI_IP6_NEIGHBOR_CACHE.
40 @retval EFI_SUCCESS The EFI_IP6_NEIGHBOR_CACHE successfully built.
41 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
45 Ip6BuildEfiNeighborCache (
46 IN IP6_PROTOCOL
*IpInstance
,
47 OUT UINT32
*NeighborCount
,
48 OUT EFI_IP6_NEIGHBOR_CACHE
**NeighborCache
51 IP6_NEIGHBOR_ENTRY
*Neighbor
;
55 EFI_IP6_NEIGHBOR_CACHE
*EfiNeighborCache
;
56 EFI_IP6_NEIGHBOR_CACHE
*NeighborCacheTmp
;
58 NET_CHECK_SIGNATURE (IpInstance
, IP6_PROTOCOL_SIGNATURE
);
59 ASSERT (NeighborCount
!= NULL
&& NeighborCache
!= NULL
);
61 IpSb
= IpInstance
->Service
;
64 NET_LIST_FOR_EACH (Entry
, &IpSb
->NeighborTable
) {
72 NeighborCacheTmp
= AllocatePool (Count
* sizeof (EFI_IP6_NEIGHBOR_CACHE
));
73 if (NeighborCacheTmp
== NULL
) {
74 return EFI_OUT_OF_RESOURCES
;
77 *NeighborCount
= Count
;
80 NET_LIST_FOR_EACH (Entry
, &IpSb
->NeighborTable
) {
81 Neighbor
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, Link
);
83 EfiNeighborCache
= NeighborCacheTmp
+ Count
;
85 EfiNeighborCache
->State
= Neighbor
->State
;
86 IP6_COPY_ADDRESS (&EfiNeighborCache
->Neighbor
, &Neighbor
->Neighbor
);
87 IP6_COPY_LINK_ADDRESS (&EfiNeighborCache
->LinkAddress
, &Neighbor
->LinkAddress
);
92 ASSERT (*NeighborCount
== Count
);
93 *NeighborCache
= NeighborCacheTmp
;
99 Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
100 of prefix entries is also returned.
102 @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
103 @param[out] PrefixCount The number of returned prefix entries.
104 @param[out] PrefixTable The pointer to the array of PrefixTable.
106 @retval EFI_SUCCESS The prefix table successfully built.
107 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the prefix table.
111 Ip6BuildPrefixTable (
112 IN IP6_PROTOCOL
*IpInstance
,
113 OUT UINT32
*PrefixCount
,
114 OUT EFI_IP6_ADDRESS_INFO
**PrefixTable
120 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
121 EFI_IP6_ADDRESS_INFO
*EfiPrefix
;
122 EFI_IP6_ADDRESS_INFO
*PrefixTableTmp
;
124 NET_CHECK_SIGNATURE (IpInstance
, IP6_PROTOCOL_SIGNATURE
);
125 ASSERT (PrefixCount
!= NULL
&& PrefixTable
!= NULL
);
127 IpSb
= IpInstance
->Service
;
130 NET_LIST_FOR_EACH (Entry
, &IpSb
->OnlinkPrefix
) {
138 PrefixTableTmp
= AllocatePool (Count
* sizeof (EFI_IP6_ADDRESS_INFO
));
139 if (PrefixTableTmp
== NULL
) {
140 return EFI_OUT_OF_RESOURCES
;
143 *PrefixCount
= Count
;
146 NET_LIST_FOR_EACH (Entry
, &IpSb
->OnlinkPrefix
) {
147 PrefixList
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
148 EfiPrefix
= PrefixTableTmp
+ Count
;
149 IP6_COPY_ADDRESS (&EfiPrefix
->Address
, &PrefixList
->Prefix
);
150 EfiPrefix
->PrefixLength
= PrefixList
->PrefixLength
;
155 ASSERT (*PrefixCount
== Count
);
156 *PrefixTable
= PrefixTableTmp
;
162 Allocate and initialize a IP6 prefix list entry.
164 @param[in] IpSb The pointer to IP6_SERVICE instance.
165 @param[in] OnLinkOrAuto If TRUE, the entry is created for the on link prefix list.
166 Otherwise, it is created for the autoconfiguration prefix list.
167 @param[in] ValidLifetime The length of time in seconds that the prefix
168 is valid for the purpose of on-link determination.
169 @param[in] PreferredLifetime The length of time in seconds that addresses
170 generated from the prefix via stateless address
171 autoconfiguration remain preferred.
172 @param[in] PrefixLength The prefix length of the Prefix.
173 @param[in] Prefix The prefix address.
175 @return NULL if it failed to allocate memory for the prefix node. Otherwise, point
176 to the created or existing prefix list entry.
179 IP6_PREFIX_LIST_ENTRY
*
180 Ip6CreatePrefixListEntry (
181 IN IP6_SERVICE
*IpSb
,
182 IN BOOLEAN OnLinkOrAuto
,
183 IN UINT32 ValidLifetime
,
184 IN UINT32 PreferredLifetime
,
185 IN UINT8 PrefixLength
,
186 IN EFI_IPv6_ADDRESS
*Prefix
189 IP6_PREFIX_LIST_ENTRY
*PrefixEntry
;
190 IP6_ROUTE_ENTRY
*RtEntry
;
191 LIST_ENTRY
*ListHead
;
193 IP6_PREFIX_LIST_ENTRY
*TmpPrefixEntry
;
195 if ((Prefix
== NULL
) || (PreferredLifetime
> ValidLifetime
) || (PrefixLength
> IP6_PREFIX_MAX
)) {
199 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
201 PrefixEntry
= Ip6FindPrefixListEntry (
207 if (PrefixEntry
!= NULL
) {
208 PrefixEntry
->RefCnt
++;
212 PrefixEntry
= AllocatePool (sizeof (IP6_PREFIX_LIST_ENTRY
));
213 if (PrefixEntry
== NULL
) {
217 PrefixEntry
->RefCnt
= 1;
218 PrefixEntry
->ValidLifetime
= ValidLifetime
;
219 PrefixEntry
->PreferredLifetime
= PreferredLifetime
;
220 PrefixEntry
->PrefixLength
= PrefixLength
;
221 IP6_COPY_ADDRESS (&PrefixEntry
->Prefix
, Prefix
);
223 ListHead
= OnLinkOrAuto
? &IpSb
->OnlinkPrefix
: &IpSb
->AutonomousPrefix
;
226 // Create a direct route entry for on-link prefix and insert to route area.
229 RtEntry
= Ip6CreateRouteEntry (Prefix
, PrefixLength
, NULL
);
230 if (RtEntry
== NULL
) {
231 FreePool (PrefixEntry
);
235 RtEntry
->Flag
= IP6_DIRECT_ROUTE
;
236 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[PrefixLength
], &RtEntry
->Link
);
237 IpSb
->RouteTable
->TotalNum
++;
241 // Insert the prefix entry in the order that a prefix with longer prefix length
242 // is put ahead in the list.
244 NET_LIST_FOR_EACH (Entry
, ListHead
) {
245 TmpPrefixEntry
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
247 if (TmpPrefixEntry
->PrefixLength
< PrefixEntry
->PrefixLength
) {
252 NetListInsertBefore (Entry
, &PrefixEntry
->Link
);
258 Destroy a IP6 prefix list entry.
260 @param[in] IpSb The pointer to IP6_SERVICE instance.
261 @param[in] PrefixEntry The to be destroyed prefix list entry.
262 @param[in] OnLinkOrAuto If TRUE, the entry is removed from on link prefix list.
263 Otherwise remove from autoconfiguration prefix list.
264 @param[in] ImmediateDelete If TRUE, remove the entry directly.
265 Otherwise, check the reference count to see whether
266 it should be removed.
270 Ip6DestroyPrefixListEntry (
271 IN IP6_SERVICE
*IpSb
,
272 IN IP6_PREFIX_LIST_ENTRY
*PrefixEntry
,
273 IN BOOLEAN OnLinkOrAuto
,
274 IN BOOLEAN ImmediateDelete
281 if ((!ImmediateDelete
) && (PrefixEntry
->RefCnt
> 0) && ((--PrefixEntry
->RefCnt
) > 0)) {
287 // Remove the direct route for onlink prefix from route table.
290 Status
= Ip6DelRoute (
292 &PrefixEntry
->Prefix
,
293 PrefixEntry
->PrefixLength
,
296 } while (Status
!= EFI_NOT_FOUND
);
299 // Remove the corresponding addresses generated from this autonomous prefix.
301 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
302 IpIf
= NET_LIST_USER_STRUCT_S (Entry
, IP6_INTERFACE
, Link
, IP6_INTERFACE_SIGNATURE
);
304 Ip6RemoveAddr (IpSb
, &IpIf
->AddressList
, &IpIf
->AddressCount
, &PrefixEntry
->Prefix
, PrefixEntry
->PrefixLength
);
308 RemoveEntryList (&PrefixEntry
->Link
);
309 FreePool (PrefixEntry
);
313 Search the list array to find an IP6 prefix list entry.
315 @param[in] IpSb The pointer to IP6_SERVICE instance.
316 @param[in] OnLinkOrAuto If TRUE, the search the link prefix list,
317 Otherwise search the autoconfiguration prefix list.
318 @param[in] PrefixLength The prefix length of the Prefix
319 @param[in] Prefix The prefix address.
321 @return NULL if cannot find the IP6 prefix list entry. Otherwise, return the
322 pointer to the IP6 prefix list entry.
325 IP6_PREFIX_LIST_ENTRY
*
326 Ip6FindPrefixListEntry (
327 IN IP6_SERVICE
*IpSb
,
328 IN BOOLEAN OnLinkOrAuto
,
329 IN UINT8 PrefixLength
,
330 IN EFI_IPv6_ADDRESS
*Prefix
333 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
335 LIST_ENTRY
*ListHead
;
337 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
338 ASSERT (Prefix
!= NULL
);
341 ListHead
= &IpSb
->OnlinkPrefix
;
343 ListHead
= &IpSb
->AutonomousPrefix
;
346 NET_LIST_FOR_EACH (Entry
, ListHead
) {
347 PrefixList
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
348 if (PrefixLength
!= 255) {
350 // Perform exactly prefix match.
352 if ((PrefixList
->PrefixLength
== PrefixLength
) &&
353 NetIp6IsNetEqual (&PrefixList
->Prefix
, Prefix
, PrefixLength
))
359 // Perform the longest prefix match. The list is already sorted with
360 // the longest length prefix put at the head of the list.
362 if (NetIp6IsNetEqual (&PrefixList
->Prefix
, Prefix
, PrefixList
->PrefixLength
)) {
372 Release the resource in the prefix list table, and destroy the list entry and
373 corresponding addresses or route entries.
375 @param[in] IpSb The pointer to the IP6_SERVICE instance.
376 @param[in] ListHead The list entry head of the prefix list table.
380 Ip6CleanPrefixListTable (
381 IN IP6_SERVICE
*IpSb
,
382 IN LIST_ENTRY
*ListHead
385 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
388 OnLink
= (BOOLEAN
)(ListHead
== &IpSb
->OnlinkPrefix
);
390 while (!IsListEmpty (ListHead
)) {
391 PrefixList
= NET_LIST_HEAD (ListHead
, IP6_PREFIX_LIST_ENTRY
, Link
);
392 Ip6DestroyPrefixListEntry (IpSb
, PrefixList
, OnLink
, TRUE
);
397 Callback function when address resolution is finished. It will cancel
398 all the queued frames if the address resolution failed, or transmit them
399 if the request succeeded.
401 @param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
411 IP6_NEIGHBOR_ENTRY
*ArpQue
;
413 IP6_LINK_TX_TOKEN
*Token
;
417 ArpQue
= (IP6_NEIGHBOR_ENTRY
*)Context
;
418 if ((ArpQue
== NULL
) || (ArpQue
->Interface
== NULL
)) {
422 IpSb
= ArpQue
->Interface
->Service
;
423 if ((IpSb
== NULL
) || (IpSb
->Signature
!= IP6_SERVICE_SIGNATURE
)) {
428 // ARP resolve failed for some reason. Release all the frame
429 // and ARP queue itself. Ip6FreeArpQue will call the frame's
432 if (NET_MAC_EQUAL (&ArpQue
->LinkAddress
, &mZeroMacAddress
, IpSb
->SnpMode
.HwAddressSize
)) {
433 Ip6FreeNeighborEntry (IpSb
, ArpQue
, FALSE
, TRUE
, EFI_NO_MAPPING
, NULL
, NULL
);
438 // ARP resolve succeeded, Transmit all the frame.
441 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &ArpQue
->Frames
) {
442 RemoveEntryList (Entry
);
444 Token
= NET_LIST_USER_STRUCT (Entry
, IP6_LINK_TX_TOKEN
, Link
);
445 IP6_COPY_LINK_ADDRESS (&Token
->DstMac
, &ArpQue
->LinkAddress
);
448 // Insert the tx token before transmitting it via MNP as the FrameSentDpc
449 // may be called before Mnp->Transmit returns which will remove this tx
450 // token from the SentFrames list. Remove it from the list if the returned
451 // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
452 // FrameSentDpc won't be queued.
454 InsertTailList (&ArpQue
->Interface
->SentFrames
, &Token
->Link
);
456 Status
= IpSb
->Mnp
->Transmit (IpSb
->Mnp
, &Token
->MnpToken
);
457 if (EFI_ERROR (Status
)) {
458 RemoveEntryList (&Token
->Link
);
459 Token
->CallBack (Token
->Packet
, Status
, 0, Token
->Context
);
461 Ip6FreeLinkTxToken (Token
);
469 // Free the ArpQue only but not the whole neighbor entry.
471 Ip6FreeNeighborEntry (IpSb
, ArpQue
, FALSE
, FALSE
, EFI_SUCCESS
, NULL
, NULL
);
473 if (Sent
&& (ArpQue
->State
== EfiNeighborStale
)) {
474 ArpQue
->State
= EfiNeighborDelay
;
475 ArpQue
->Ticks
= (UINT32
)IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME
);
480 Allocate and initialize an IP6 neighbor cache entry.
482 @param[in] IpSb The pointer to the IP6_SERVICE instance.
483 @param[in] CallBack The callback function to be called when
484 address resolution is finished.
485 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
486 @param[in] LinkAddress Points to the MAC address of the neighbor.
489 @return NULL if failed to allocate memory for the neighbor cache entry.
490 Otherwise, point to the created neighbor cache entry.
494 Ip6CreateNeighborEntry (
495 IN IP6_SERVICE
*IpSb
,
496 IN IP6_ARP_CALLBACK CallBack
,
497 IN EFI_IPv6_ADDRESS
*Ip6Address
,
498 IN EFI_MAC_ADDRESS
*LinkAddress OPTIONAL
501 IP6_NEIGHBOR_ENTRY
*Entry
;
502 IP6_DEFAULT_ROUTER
*DefaultRouter
;
504 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
505 ASSERT (Ip6Address
!= NULL
);
507 Entry
= AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY
));
513 Entry
->IsRouter
= FALSE
;
514 Entry
->ArpFree
= FALSE
;
515 Entry
->Dynamic
= FALSE
;
516 Entry
->State
= EfiNeighborInComplete
;
517 Entry
->Transmit
= IP6_MAX_MULTICAST_SOLICIT
+ 1;
518 Entry
->CallBack
= CallBack
;
519 Entry
->Interface
= NULL
;
521 InitializeListHead (&Entry
->Frames
);
523 IP6_COPY_ADDRESS (&Entry
->Neighbor
, Ip6Address
);
525 if (LinkAddress
!= NULL
) {
526 IP6_COPY_LINK_ADDRESS (&Entry
->LinkAddress
, LinkAddress
);
528 IP6_COPY_LINK_ADDRESS (&Entry
->LinkAddress
, &mZeroMacAddress
);
531 InsertHeadList (&IpSb
->NeighborTable
, &Entry
->Link
);
534 // If corresponding default router entry exists, establish the relationship.
536 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, Ip6Address
);
537 if (DefaultRouter
!= NULL
) {
538 DefaultRouter
->NeighborCache
= Entry
;
545 Search a IP6 neighbor cache entry.
547 @param[in] IpSb The pointer to the IP6_SERVICE instance.
548 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
550 @return NULL if it failed to find the matching neighbor cache entry.
551 Otherwise, point to the found neighbor cache entry.
555 Ip6FindNeighborEntry (
556 IN IP6_SERVICE
*IpSb
,
557 IN EFI_IPv6_ADDRESS
*Ip6Address
562 IP6_NEIGHBOR_ENTRY
*Neighbor
;
564 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
565 ASSERT (Ip6Address
!= NULL
);
567 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->NeighborTable
) {
568 Neighbor
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, Link
);
569 if (EFI_IP6_EQUAL (Ip6Address
, &Neighbor
->Neighbor
)) {
570 RemoveEntryList (Entry
);
571 InsertHeadList (&IpSb
->NeighborTable
, Entry
);
581 Free a IP6 neighbor cache entry and remove all the frames on the address
582 resolution queue that pass the FrameToCancel. That is, either FrameToCancel
583 is NULL, or it returns true for the frame.
585 @param[in] IpSb The pointer to the IP6_SERVICE instance.
586 @param[in] NeighborCache The to be free neighbor cache entry.
587 @param[in] SendIcmpError If TRUE, send out ICMP error.
588 @param[in] FullFree If TRUE, remove the neighbor cache entry.
589 Otherwise remove the pending frames.
590 @param[in] IoStatus The status returned to the cancelled frames'
592 @param[in] FrameToCancel Function to select which frame to cancel.
593 This is an optional parameter that may be NULL.
594 @param[in] Context Opaque parameter to the FrameToCancel.
595 Ignored if FrameToCancel is NULL.
597 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
598 @retval EFI_SUCCESS The operation finished successfully.
602 Ip6FreeNeighborEntry (
603 IN IP6_SERVICE
*IpSb
,
604 IN IP6_NEIGHBOR_ENTRY
*NeighborCache
,
605 IN BOOLEAN SendIcmpError
,
607 IN EFI_STATUS IoStatus
,
608 IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL
,
609 IN VOID
*Context OPTIONAL
612 IP6_LINK_TX_TOKEN
*TxToken
;
615 IP6_DEFAULT_ROUTER
*DefaultRouter
;
618 // If FrameToCancel fails, the token will not be released.
619 // To avoid the memory leak, stop this usage model.
621 if (FullFree
&& (FrameToCancel
!= NULL
)) {
622 return EFI_INVALID_PARAMETER
;
625 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &NeighborCache
->Frames
) {
626 TxToken
= NET_LIST_USER_STRUCT (Entry
, IP6_LINK_TX_TOKEN
, Link
);
628 if (SendIcmpError
&& !IP6_IS_MULTICAST (&TxToken
->Packet
->Ip
.Ip6
->DestinationAddress
)) {
633 &TxToken
->Packet
->Ip
.Ip6
->SourceAddress
,
634 ICMP_V6_DEST_UNREACHABLE
,
635 ICMP_V6_ADDR_UNREACHABLE
,
640 if ((FrameToCancel
== NULL
) || FrameToCancel (TxToken
, Context
)) {
641 RemoveEntryList (Entry
);
642 TxToken
->CallBack (TxToken
->Packet
, IoStatus
, 0, TxToken
->Context
);
643 Ip6FreeLinkTxToken (TxToken
);
647 if (NeighborCache
->ArpFree
&& IsListEmpty (&NeighborCache
->Frames
)) {
648 RemoveEntryList (&NeighborCache
->ArpList
);
649 NeighborCache
->ArpFree
= FALSE
;
653 if (NeighborCache
->IsRouter
) {
654 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &NeighborCache
->Neighbor
);
655 if (DefaultRouter
!= NULL
) {
656 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
660 RemoveEntryList (&NeighborCache
->Link
);
661 FreePool (NeighborCache
);
668 Allocate and initialize an IP6 default router entry.
670 @param[in] IpSb The pointer to the IP6_SERVICE instance.
671 @param[in] Ip6Address The IPv6 address of the default router.
672 @param[in] RouterLifetime The lifetime associated with the default
673 router, in units of seconds.
675 @return NULL if it failed to allocate memory for the default router node.
676 Otherwise, point to the created default router node.
680 Ip6CreateDefaultRouter (
681 IN IP6_SERVICE
*IpSb
,
682 IN EFI_IPv6_ADDRESS
*Ip6Address
,
683 IN UINT16 RouterLifetime
686 IP6_DEFAULT_ROUTER
*Entry
;
687 IP6_ROUTE_ENTRY
*RtEntry
;
689 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
690 ASSERT (Ip6Address
!= NULL
);
692 Entry
= AllocatePool (sizeof (IP6_DEFAULT_ROUTER
));
698 Entry
->Lifetime
= RouterLifetime
;
699 Entry
->NeighborCache
= Ip6FindNeighborEntry (IpSb
, Ip6Address
);
700 IP6_COPY_ADDRESS (&Entry
->Router
, Ip6Address
);
703 // Add a default route into route table with both Destination and PrefixLength set to zero.
705 RtEntry
= Ip6CreateRouteEntry (NULL
, 0, Ip6Address
);
706 if (RtEntry
== NULL
) {
711 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[0], &RtEntry
->Link
);
712 IpSb
->RouteTable
->TotalNum
++;
714 InsertTailList (&IpSb
->DefaultRouterList
, &Entry
->Link
);
720 Destroy an IP6 default router entry.
722 @param[in] IpSb The pointer to the IP6_SERVICE instance.
723 @param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
727 Ip6DestroyDefaultRouter (
728 IN IP6_SERVICE
*IpSb
,
729 IN IP6_DEFAULT_ROUTER
*DefaultRouter
734 RemoveEntryList (&DefaultRouter
->Link
);
737 // Update the Destination Cache - all entries using the time-out router as next-hop
738 // should perform next-hop determination again.
741 Status
= Ip6DelRoute (IpSb
->RouteTable
, NULL
, 0, &DefaultRouter
->Router
);
742 } while (Status
!= EFI_NOT_FOUND
);
744 FreePool (DefaultRouter
);
748 Clean an IP6 default router list.
750 @param[in] IpSb The pointer to the IP6_SERVICE instance.
754 Ip6CleanDefaultRouterList (
758 IP6_DEFAULT_ROUTER
*DefaultRouter
;
760 while (!IsListEmpty (&IpSb
->DefaultRouterList
)) {
761 DefaultRouter
= NET_LIST_HEAD (&IpSb
->DefaultRouterList
, IP6_DEFAULT_ROUTER
, Link
);
762 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
767 Search a default router node from an IP6 default router list.
769 @param[in] IpSb The pointer to the IP6_SERVICE instance.
770 @param[in] Ip6Address The IPv6 address of the to be searched default router node.
772 @return NULL if it failed to find the matching default router node.
773 Otherwise, point to the found default router node.
777 Ip6FindDefaultRouter (
778 IN IP6_SERVICE
*IpSb
,
779 IN EFI_IPv6_ADDRESS
*Ip6Address
783 IP6_DEFAULT_ROUTER
*DefaultRouter
;
785 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
786 ASSERT (Ip6Address
!= NULL
);
788 NET_LIST_FOR_EACH (Entry
, &IpSb
->DefaultRouterList
) {
789 DefaultRouter
= NET_LIST_USER_STRUCT (Entry
, IP6_DEFAULT_ROUTER
, Link
);
790 if (EFI_IP6_EQUAL (Ip6Address
, &DefaultRouter
->Router
)) {
791 return DefaultRouter
;
799 The function to be called after DAD (Duplicate Address Detection) is performed.
801 @param[in] IsDadPassed If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
802 @param[in] IpIf Points to the IP6_INTERFACE.
803 @param[in] DadEntry The DAD entry which already performed DAD.
808 IN BOOLEAN IsDadPassed
,
809 IN IP6_INTERFACE
*IpIf
,
810 IN IP6_DAD_ENTRY
*DadEntry
814 IP6_ADDRESS_INFO
*AddrInfo
;
815 EFI_DHCP6_PROTOCOL
*Dhcp6
;
817 EFI_DHCP6_PACKET_OPTION
*Oro
;
818 EFI_DHCP6_RETRANSMISSION InfoReqReXmit
;
819 EFI_IPv6_ADDRESS AllNodes
;
821 IpSb
= IpIf
->Service
;
822 AddrInfo
= DadEntry
->AddressInfo
;
828 if (NetIp6IsLinkLocalAddr (&AddrInfo
->Address
)) {
829 ASSERT (!IpSb
->LinkLocalOk
);
831 IP6_COPY_ADDRESS (&IpSb
->LinkLocalAddr
, &AddrInfo
->Address
);
832 IpSb
->LinkLocalOk
= TRUE
;
833 IpIf
->Configured
= TRUE
;
836 // Check whether DHCP6 need to be started.
838 Dhcp6
= IpSb
->Ip6ConfigInstance
.Dhcp6
;
840 if (IpSb
->Dhcp6NeedStart
) {
841 Dhcp6
->Start (Dhcp6
);
842 IpSb
->Dhcp6NeedStart
= FALSE
;
845 if (IpSb
->Dhcp6NeedInfoRequest
) {
847 // Set the exta options to send. Here we only want the option request option
850 Oro
= (EFI_DHCP6_PACKET_OPTION
*)OptBuf
;
851 Oro
->OpCode
= HTONS (DHCP6_OPT_ORO
);
852 Oro
->OpLen
= HTONS (2);
853 *((UINT16
*)&Oro
->Data
[0]) = HTONS (DHCP6_OPT_DNS_SERVERS
);
855 InfoReqReXmit
.Irt
= 4;
856 InfoReqReXmit
.Mrc
= 64;
857 InfoReqReXmit
.Mrt
= 60;
858 InfoReqReXmit
.Mrd
= 0;
867 IpSb
->Ip6ConfigInstance
.Dhcp6Event
,
868 Ip6ConfigOnDhcp6Reply
,
869 &IpSb
->Ip6ConfigInstance
874 // Add an on-link prefix for link-local address.
876 Ip6CreatePrefixListEntry (
879 (UINT32
)IP6_INFINIT_LIFETIME
,
880 (UINT32
)IP6_INFINIT_LIFETIME
,
881 IP6_LINK_LOCAL_PREFIX_LENGTH
,
886 // Global scope unicast address.
888 Ip6AddAddr (IpIf
, AddrInfo
);
891 // Add an on-link prefix for this address.
893 Ip6CreatePrefixListEntry (
896 AddrInfo
->ValidLifetime
,
897 AddrInfo
->PreferredLifetime
,
898 AddrInfo
->PrefixLength
,
902 IpIf
->Configured
= TRUE
;
906 // Leave the group we joined before.
908 Ip6LeaveGroup (IpSb
, &DadEntry
->Destination
);
911 if (DadEntry
->Callback
!= NULL
) {
912 DadEntry
->Callback (IsDadPassed
, &AddrInfo
->Address
, DadEntry
->Context
);
915 if (!IsDadPassed
&& NetIp6IsLinkLocalAddr (&AddrInfo
->Address
)) {
917 RemoveEntryList (&DadEntry
->Link
);
920 // Leave link-scope all-nodes multicast address (FF02::1)
922 Ip6SetToAllNodeMulticast (FALSE
, IP6_LINK_LOCAL_SCOPE
, &AllNodes
);
923 Ip6LeaveGroup (IpSb
, &AllNodes
);
925 // Disable IP operation since link-local address is a duplicate address.
927 IpSb
->LinkLocalDadFail
= TRUE
;
928 IpSb
->Mnp
->Configure (IpSb
->Mnp
, NULL
);
929 gBS
->SetTimer (IpSb
->Timer
, TimerCancel
, 0);
930 gBS
->SetTimer (IpSb
->FasterTimer
, TimerCancel
, 0);
934 if (!IsDadPassed
|| NetIp6IsLinkLocalAddr (&AddrInfo
->Address
)) {
936 // Free the AddressInfo we hold if DAD fails or it is a link-local address.
941 RemoveEntryList (&DadEntry
->Link
);
946 Create a DAD (Duplicate Address Detection) entry and queue it to be performed.
948 @param[in] IpIf Points to the IP6_INTERFACE.
949 @param[in] AddressInfo The address information which needs DAD performed.
950 @param[in] Callback The callback routine that will be called after DAD
951 is performed. This is an optional parameter that
953 @param[in] Context The opaque parameter for a DAD callback routine.
954 This is an optional parameter that may be NULL.
956 @retval EFI_SUCCESS The DAD entry was created and queued.
957 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory to complete the
964 IN IP6_INTERFACE
*IpIf
,
965 IN IP6_ADDRESS_INFO
*AddressInfo
,
966 IN IP6_DAD_CALLBACK Callback OPTIONAL
,
967 IN VOID
*Context OPTIONAL
970 IP6_DAD_ENTRY
*Entry
;
971 EFI_IP6_CONFIG_DUP_ADDR_DETECT_TRANSMITS
*DadXmits
;
976 NET_CHECK_SIGNATURE (IpIf
, IP6_INTERFACE_SIGNATURE
);
977 ASSERT (AddressInfo
!= NULL
);
980 // Do nothing if we have already started DAD on the address.
982 if (Ip6FindDADEntry (IpIf
->Service
, &AddressInfo
->Address
, NULL
) != NULL
) {
986 Status
= EFI_SUCCESS
;
987 IpSb
= IpIf
->Service
;
988 DadXmits
= &IpSb
->Ip6ConfigInstance
.DadXmits
;
991 // Allocate the resources and insert info
993 Entry
= AllocatePool (sizeof (IP6_DAD_ENTRY
));
995 return EFI_OUT_OF_RESOURCES
;
999 // Map the incoming unicast address to solicited-node multicast address
1001 Ip6CreateSNMulticastAddr (&AddressInfo
->Address
, &Entry
->Destination
);
1004 // Join in the solicited-node multicast address.
1006 Status
= Ip6JoinGroup (IpSb
, IpIf
, &Entry
->Destination
);
1007 if (EFI_ERROR (Status
)) {
1012 Entry
->Signature
= IP6_DAD_ENTRY_SIGNATURE
;
1013 Entry
->MaxTransmit
= DadXmits
->DupAddrDetectTransmits
;
1014 Entry
->Transmit
= 0;
1016 MaxDelayTick
= IP6_MAX_RTR_SOLICITATION_DELAY
/ IP6_TIMER_INTERVAL_IN_MS
;
1017 Entry
->RetransTick
= (MaxDelayTick
* ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5;
1018 Entry
->AddressInfo
= AddressInfo
;
1019 Entry
->Callback
= Callback
;
1020 Entry
->Context
= Context
;
1021 InsertTailList (&IpIf
->DupAddrDetectList
, &Entry
->Link
);
1023 if (Entry
->MaxTransmit
== 0) {
1025 // DAD is disabled on this interface, immediately mark this DAD successful.
1027 Ip6OnDADFinished (TRUE
, IpIf
, Entry
);
1034 Search IP6_DAD_ENTRY from the Duplicate Address Detection List.
1036 @param[in] IpSb The pointer to the IP6_SERVICE instance.
1037 @param[in] Target The address information which needs DAD performed .
1038 @param[out] Interface If not NULL, output the IP6 interface that configures
1039 the tentative address.
1041 @return NULL if failed to find the matching DAD entry.
1042 Otherwise, point to the found DAD entry.
1047 IN IP6_SERVICE
*IpSb
,
1048 IN EFI_IPv6_ADDRESS
*Target
,
1049 OUT IP6_INTERFACE
**Interface OPTIONAL
1054 IP6_INTERFACE
*IpIf
;
1055 IP6_DAD_ENTRY
*DupAddrDetect
;
1056 IP6_ADDRESS_INFO
*AddrInfo
;
1058 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
1059 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
1061 NET_LIST_FOR_EACH (Entry2
, &IpIf
->DupAddrDetectList
) {
1062 DupAddrDetect
= NET_LIST_USER_STRUCT_S (Entry2
, IP6_DAD_ENTRY
, Link
, IP6_DAD_ENTRY_SIGNATURE
);
1063 AddrInfo
= DupAddrDetect
->AddressInfo
;
1064 if (EFI_IP6_EQUAL (&AddrInfo
->Address
, Target
)) {
1065 if (Interface
!= NULL
) {
1069 return DupAddrDetect
;
1078 Generate router solicit message and send it out to Destination Address or
1079 All Router Link Local scope multicast address.
1081 @param[in] IpSb The IP service to send the packet.
1082 @param[in] Interface If not NULL, points to the IP6 interface to send
1084 @param[in] SourceAddress If not NULL, the source address of the message.
1085 @param[in] DestinationAddress If not NULL, the destination address of the message.
1086 @param[in] SourceLinkAddress If not NULL, the MAC address of the source.
1087 A source link-layer address option will be appended
1090 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1092 @retval EFI_SUCCESS The router solicit message was successfully sent.
1096 Ip6SendRouterSolicit (
1097 IN IP6_SERVICE
*IpSb
,
1098 IN IP6_INTERFACE
*Interface OPTIONAL
,
1099 IN EFI_IPv6_ADDRESS
*SourceAddress OPTIONAL
,
1100 IN EFI_IPv6_ADDRESS
*DestinationAddress OPTIONAL
,
1101 IN EFI_MAC_ADDRESS
*SourceLinkAddress OPTIONAL
1105 EFI_IP6_HEADER Head
;
1106 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
1107 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
1109 IP6_INTERFACE
*IpIf
;
1111 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
1114 if ((IpIf
== NULL
) && (IpSb
->DefaultInterface
!= NULL
)) {
1115 IpIf
= IpSb
->DefaultInterface
;
1119 // Generate the packet to be sent
1122 PayloadLen
= (UINT16
)sizeof (IP6_ICMP_INFORMATION_HEAD
);
1123 if (SourceLinkAddress
!= NULL
) {
1124 PayloadLen
+= sizeof (IP6_ETHER_ADDR_OPTION
);
1127 Packet
= NetbufAlloc (sizeof (EFI_IP6_HEADER
) + (UINT32
)PayloadLen
);
1128 if (Packet
== NULL
) {
1129 return EFI_OUT_OF_RESOURCES
;
1133 // Create the basic IPv6 header.
1135 Head
.FlowLabelL
= 0;
1136 Head
.FlowLabelH
= 0;
1137 Head
.PayloadLength
= HTONS (PayloadLen
);
1138 Head
.NextHeader
= IP6_ICMP
;
1139 Head
.HopLimit
= IP6_HOP_LIMIT
;
1141 if (SourceAddress
!= NULL
) {
1142 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
1144 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
1147 if (DestinationAddress
!= NULL
) {
1148 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
1150 Ip6SetToAllNodeMulticast (TRUE
, IP6_LINK_LOCAL_SCOPE
, &Head
.DestinationAddress
);
1153 NetbufReserve (Packet
, sizeof (EFI_IP6_HEADER
));
1156 // Fill in the ICMP header, and Source link-layer address if contained.
1159 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*)NetbufAllocSpace (Packet
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
1160 ASSERT (IcmpHead
!= NULL
);
1161 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
1162 IcmpHead
->Head
.Type
= ICMP_V6_ROUTER_SOLICIT
;
1163 IcmpHead
->Head
.Code
= 0;
1165 LinkLayerOption
= NULL
;
1166 if (SourceLinkAddress
!= NULL
) {
1167 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*)NetbufAllocSpace (
1169 sizeof (IP6_ETHER_ADDR_OPTION
),
1172 ASSERT (LinkLayerOption
!= NULL
);
1173 LinkLayerOption
->Type
= Ip6OptionEtherSource
;
1174 LinkLayerOption
->Length
= (UINT8
)sizeof (IP6_ETHER_ADDR_OPTION
);
1175 CopyMem (LinkLayerOption
->EtherAddr
, SourceLinkAddress
, 6);
1179 // Transmit the packet
1181 return Ip6Output (IpSb
, IpIf
, NULL
, Packet
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);
1185 Generate a Neighbor Advertisement message and send it out to Destination Address.
1187 @param[in] IpSb The IP service to send the packet.
1188 @param[in] SourceAddress The source address of the message.
1189 @param[in] DestinationAddress The destination address of the message.
1190 @param[in] TargetIp6Address The target address field in the Neighbor Solicitation
1191 message that prompted this advertisement.
1192 @param[in] TargetLinkAddress The MAC address for the target, i.e. the sender
1193 of the advertisement.
1194 @param[in] IsRouter If TRUE, indicates the sender is a router.
1195 @param[in] Override If TRUE, indicates the advertisement should override
1196 an existing cache entry and update the MAC address.
1197 @param[in] Solicited If TRUE, indicates the advertisement was sent
1198 in response to a Neighbor Solicitation from
1199 the Destination address.
1201 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1203 @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
1207 Ip6SendNeighborAdvertise (
1208 IN IP6_SERVICE
*IpSb
,
1209 IN EFI_IPv6_ADDRESS
*SourceAddress
,
1210 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
1211 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
1212 IN EFI_MAC_ADDRESS
*TargetLinkAddress
,
1213 IN BOOLEAN IsRouter
,
1214 IN BOOLEAN Override
,
1215 IN BOOLEAN Solicited
1219 EFI_IP6_HEADER Head
;
1220 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
1221 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
1222 EFI_IPv6_ADDRESS
*Target
;
1225 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
1228 // The Neighbor Advertisement message must include a Target link-layer address option
1229 // when responding to multicast solicitation and should include such option when
1230 // responding to unicast solicitation. It also must include such option as unsolicited
1233 ASSERT (DestinationAddress
!= NULL
&& TargetIp6Address
!= NULL
&& TargetLinkAddress
!= NULL
);
1235 PayloadLen
= (UINT16
)(sizeof (IP6_ICMP_INFORMATION_HEAD
) + sizeof (EFI_IPv6_ADDRESS
) + sizeof (IP6_ETHER_ADDR_OPTION
));
1238 // Generate the packet to be sent
1241 Packet
= NetbufAlloc (sizeof (EFI_IP6_HEADER
) + (UINT32
)PayloadLen
);
1242 if (Packet
== NULL
) {
1243 return EFI_OUT_OF_RESOURCES
;
1247 // Create the basic IPv6 header.
1249 Head
.FlowLabelL
= 0;
1250 Head
.FlowLabelH
= 0;
1251 Head
.PayloadLength
= HTONS (PayloadLen
);
1252 Head
.NextHeader
= IP6_ICMP
;
1253 Head
.HopLimit
= IP6_HOP_LIMIT
;
1255 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
1256 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
1258 NetbufReserve (Packet
, sizeof (EFI_IP6_HEADER
));
1261 // Fill in the ICMP header, Target address, and Target link-layer address.
1262 // Set the Router flag, Solicited flag and Override flag.
1265 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*)NetbufAllocSpace (Packet
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
1266 ASSERT (IcmpHead
!= NULL
);
1267 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
1268 IcmpHead
->Head
.Type
= ICMP_V6_NEIGHBOR_ADVERTISE
;
1269 IcmpHead
->Head
.Code
= 0;
1272 IcmpHead
->Fourth
|= IP6_IS_ROUTER_FLAG
;
1276 IcmpHead
->Fourth
|= IP6_SOLICITED_FLAG
;
1280 IcmpHead
->Fourth
|= IP6_OVERRIDE_FLAG
;
1283 Target
= (EFI_IPv6_ADDRESS
*)NetbufAllocSpace (Packet
, sizeof (EFI_IPv6_ADDRESS
), FALSE
);
1284 ASSERT (Target
!= NULL
);
1285 IP6_COPY_ADDRESS (Target
, TargetIp6Address
);
1287 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*)NetbufAllocSpace (
1289 sizeof (IP6_ETHER_ADDR_OPTION
),
1292 ASSERT (LinkLayerOption
!= NULL
);
1293 LinkLayerOption
->Type
= Ip6OptionEtherTarget
;
1294 LinkLayerOption
->Length
= 1;
1295 CopyMem (LinkLayerOption
->EtherAddr
, TargetLinkAddress
, 6);
1298 // Transmit the packet
1300 return Ip6Output (IpSb
, NULL
, NULL
, Packet
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);
1304 Generate the Neighbor Solicitation message and send it to the Destination Address.
1306 @param[in] IpSb The IP service to send the packet
1307 @param[in] SourceAddress The source address of the message.
1308 @param[in] DestinationAddress The destination address of the message.
1309 @param[in] TargetIp6Address The IP address of the target of the solicitation.
1310 It must not be a multicast address.
1311 @param[in] SourceLinkAddress The MAC address for the sender. If not NULL,
1312 a source link-layer address option will be appended
1315 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1316 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1318 @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
1322 Ip6SendNeighborSolicit (
1323 IN IP6_SERVICE
*IpSb
,
1324 IN EFI_IPv6_ADDRESS
*SourceAddress
,
1325 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
1326 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
1327 IN EFI_MAC_ADDRESS
*SourceLinkAddress OPTIONAL
1331 EFI_IP6_HEADER Head
;
1332 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
1333 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
1334 EFI_IPv6_ADDRESS
*Target
;
1337 IP6_NEIGHBOR_ENTRY
*Neighbor
;
1340 // Check input parameters
1342 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
1343 if ((DestinationAddress
== NULL
) || (TargetIp6Address
== NULL
)) {
1344 return EFI_INVALID_PARAMETER
;
1349 if ((SourceAddress
== NULL
) || ((SourceAddress
!= NULL
) && NetIp6IsUnspecifiedAddr (SourceAddress
))) {
1354 // The Neighbor Solicitation message should include a source link-layer address option
1355 // if the solicitation is not sent by performing DAD - Duplicate Address Detection.
1356 // Otherwise must not include it.
1358 PayloadLen
= (UINT16
)(sizeof (IP6_ICMP_INFORMATION_HEAD
) + sizeof (EFI_IPv6_ADDRESS
));
1361 if (SourceLinkAddress
== NULL
) {
1362 return EFI_INVALID_PARAMETER
;
1365 PayloadLen
= (UINT16
)(PayloadLen
+ sizeof (IP6_ETHER_ADDR_OPTION
));
1369 // Generate the packet to be sent
1372 Packet
= NetbufAlloc (sizeof (EFI_IP6_HEADER
) + (UINT32
)PayloadLen
);
1373 if (Packet
== NULL
) {
1374 return EFI_OUT_OF_RESOURCES
;
1378 // Create the basic IPv6 header
1380 Head
.FlowLabelL
= 0;
1381 Head
.FlowLabelH
= 0;
1382 Head
.PayloadLength
= HTONS (PayloadLen
);
1383 Head
.NextHeader
= IP6_ICMP
;
1384 Head
.HopLimit
= IP6_HOP_LIMIT
;
1386 if (SourceAddress
!= NULL
) {
1387 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
1389 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
1392 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
1394 NetbufReserve (Packet
, sizeof (EFI_IP6_HEADER
));
1397 // Fill in the ICMP header, Target address, and Source link-layer address.
1399 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*)NetbufAllocSpace (Packet
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
1400 ASSERT (IcmpHead
!= NULL
);
1401 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
1402 IcmpHead
->Head
.Type
= ICMP_V6_NEIGHBOR_SOLICIT
;
1403 IcmpHead
->Head
.Code
= 0;
1405 Target
= (EFI_IPv6_ADDRESS
*)NetbufAllocSpace (Packet
, sizeof (EFI_IPv6_ADDRESS
), FALSE
);
1406 ASSERT (Target
!= NULL
);
1407 IP6_COPY_ADDRESS (Target
, TargetIp6Address
);
1409 LinkLayerOption
= NULL
;
1412 // Fill in the source link-layer address option
1414 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*)NetbufAllocSpace (
1416 sizeof (IP6_ETHER_ADDR_OPTION
),
1419 ASSERT (LinkLayerOption
!= NULL
);
1420 LinkLayerOption
->Type
= Ip6OptionEtherSource
;
1421 LinkLayerOption
->Length
= 1;
1422 CopyMem (LinkLayerOption
->EtherAddr
, SourceLinkAddress
, 6);
1426 // Create a Neighbor Cache entry in the INCOMPLETE state when performing
1427 // address resolution.
1429 if (!IsDAD
&& Ip6IsSNMulticastAddr (DestinationAddress
)) {
1430 Neighbor
= Ip6FindNeighborEntry (IpSb
, TargetIp6Address
);
1431 if (Neighbor
== NULL
) {
1432 Neighbor
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, TargetIp6Address
, NULL
);
1433 ASSERT (Neighbor
!= NULL
);
1438 // Transmit the packet
1440 return Ip6Output (IpSb
, IpSb
->DefaultInterface
, NULL
, Packet
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);
1444 Process the Neighbor Solicitation message. The message may be sent for Duplicate
1445 Address Detection or Address Resolution.
1447 @param[in] IpSb The IP service that received the packet.
1448 @param[in] Head The IP head of the message.
1449 @param[in] Packet The content of the message with IP head removed.
1451 @retval EFI_SUCCESS The packet processed successfully.
1452 @retval EFI_INVALID_PARAMETER The packet is invalid.
1453 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1454 @retval Others Failed to process the packet.
1458 Ip6ProcessNeighborSolicit (
1459 IN IP6_SERVICE
*IpSb
,
1460 IN EFI_IP6_HEADER
*Head
,
1464 IP6_ICMP_INFORMATION_HEAD Icmp
;
1465 EFI_IPv6_ADDRESS Target
;
1466 IP6_ETHER_ADDR_OPTION LinkLayerOption
;
1469 BOOLEAN IsMaintained
;
1470 IP6_DAD_ENTRY
*DupAddrDetect
;
1471 IP6_INTERFACE
*IpIf
;
1472 IP6_NEIGHBOR_ENTRY
*Neighbor
;
1474 BOOLEAN UpdateCache
;
1475 EFI_IPv6_ADDRESS Dest
;
1482 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
1483 NetbufCopy (Packet
, sizeof (Icmp
), sizeof (Target
), Target
.Addr
);
1486 // Perform Message Validation:
1487 // The IP Hop Limit field has a value of 255, i.e., the packet
1488 // could not possibly have been forwarded by a router.
1490 // Target Address is not a multicast address.
1492 Status
= EFI_INVALID_PARAMETER
;
1494 if ((Head
->HopLimit
!= IP6_HOP_LIMIT
) || (Icmp
.Head
.Code
!= 0) || !NetIp6IsValidUnicast (&Target
)) {
1499 // ICMP length is 24 or more octets.
1502 if (Head
->PayloadLength
< IP6_ND_LENGTH
) {
1505 OptionLen
= (UINT16
)(Head
->PayloadLength
- IP6_ND_LENGTH
);
1506 if (OptionLen
!= 0) {
1507 Option
= NetbufGetByte (Packet
, IP6_ND_LENGTH
, NULL
);
1508 ASSERT (Option
!= NULL
);
1511 // All included options should have a length that is greater than zero.
1513 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
1519 IsDAD
= NetIp6IsUnspecifiedAddr (&Head
->SourceAddress
);
1520 IsUnicast
= (BOOLEAN
) !Ip6IsSNMulticastAddr (&Head
->DestinationAddress
);
1521 IsMaintained
= Ip6IsOneOfSetAddress (IpSb
, &Target
, &IpIf
, NULL
);
1524 if (OptionLen
>= sizeof (IP6_ETHER_ADDR_OPTION
)) {
1528 sizeof (IP6_ETHER_ADDR_OPTION
),
1529 (UINT8
*)&LinkLayerOption
1532 // The solicitation for neighbor discovery should include a source link-layer
1533 // address option. If the option is not recognized, silently ignore it.
1535 if (LinkLayerOption
.Type
== Ip6OptionEtherSource
) {
1538 // If the IP source address is the unspecified address, the source
1539 // link-layer address option must not be included in the message.
1549 // If the IP source address is the unspecified address, the IP
1550 // destination address is a solicited-node multicast address.
1552 if (IsDAD
&& IsUnicast
) {
1557 // If the target address is tentative, and the source address is a unicast address,
1558 // the solicitation's sender is performing address resolution on the target;
1559 // the solicitation should be silently ignored.
1561 if (!IsDAD
&& !IsMaintained
) {
1566 // If received unicast neighbor solicitation but destination is not this node,
1569 if (IsUnicast
&& !IsMaintained
) {
1574 // In DAD, when target address is a tentative address,
1575 // process the received neighbor solicitation message but not send out response.
1577 if (IsDAD
&& !IsMaintained
) {
1578 DupAddrDetect
= Ip6FindDADEntry (IpSb
, &Target
, &IpIf
);
1579 if (DupAddrDetect
!= NULL
) {
1581 // Check the MAC address of the incoming packet.
1583 if (IpSb
->RecvRequest
.MnpToken
.Packet
.RxData
== NULL
) {
1587 MacAddress
= IpSb
->RecvRequest
.MnpToken
.Packet
.RxData
->SourceAddress
;
1588 if (MacAddress
!= NULL
) {
1591 &IpSb
->SnpMode
.CurrentAddress
,
1592 IpSb
->SnpMode
.HwAddressSize
1596 // The NS is from another node to performing DAD on the same address.
1597 // Fail DAD for the tentative address.
1599 Ip6OnDADFinished (FALSE
, IpIf
, DupAddrDetect
);
1600 Status
= EFI_ICMP_ERROR
;
1603 // The below layer loopback the NS we sent. Record it and wait for more.
1605 DupAddrDetect
->Receive
++;
1606 Status
= EFI_SUCCESS
;
1615 // If the solicitation does not contain a link-layer address, DO NOT create or
1616 // update the neighbor cache entries.
1619 Neighbor
= Ip6FindNeighborEntry (IpSb
, &Head
->SourceAddress
);
1620 UpdateCache
= FALSE
;
1622 if (Neighbor
== NULL
) {
1623 Neighbor
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, &Head
->SourceAddress
, NULL
);
1624 if (Neighbor
== NULL
) {
1625 Status
= EFI_OUT_OF_RESOURCES
;
1631 if (CompareMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6) != 0) {
1637 Neighbor
->State
= EfiNeighborStale
;
1638 Neighbor
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
1639 CopyMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1641 // Send queued packets if exist.
1643 Neighbor
->CallBack ((VOID
*)Neighbor
);
1648 // Sends a Neighbor Advertisement as response.
1649 // Set the Router flag to zero since the node is a host.
1650 // If the source address of the solicitation is unspecified, and target address
1651 // is one of the maintained address, reply a unsolicited multicast advertisement.
1653 if (IsDAD
&& IsMaintained
) {
1655 Ip6SetToAllNodeMulticast (FALSE
, IP6_LINK_LOCAL_SCOPE
, &Dest
);
1658 IP6_COPY_ADDRESS (&Dest
, &Head
->SourceAddress
);
1661 Status
= Ip6SendNeighborAdvertise (
1666 &IpSb
->SnpMode
.CurrentAddress
,
1672 NetbufFree (Packet
);
1677 Process the Neighbor Advertisement message.
1679 @param[in] IpSb The IP service that received the packet.
1680 @param[in] Head The IP head of the message.
1681 @param[in] Packet The content of the message with IP head removed.
1683 @retval EFI_SUCCESS The packet processed successfully.
1684 @retval EFI_INVALID_PARAMETER The packet is invalid.
1685 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1686 @retval Others Failed to process the packet.
1690 Ip6ProcessNeighborAdvertise (
1691 IN IP6_SERVICE
*IpSb
,
1692 IN EFI_IP6_HEADER
*Head
,
1696 IP6_ICMP_INFORMATION_HEAD Icmp
;
1697 EFI_IPv6_ADDRESS Target
;
1698 IP6_ETHER_ADDR_OPTION LinkLayerOption
;
1701 IP6_NEIGHBOR_ENTRY
*Neighbor
;
1702 IP6_DEFAULT_ROUTER
*DefaultRouter
;
1706 IP6_DAD_ENTRY
*DupAddrDetect
;
1707 IP6_INTERFACE
*IpIf
;
1712 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
1713 NetbufCopy (Packet
, sizeof (Icmp
), sizeof (Target
), Target
.Addr
);
1716 // Validate the incoming Neighbor Advertisement
1718 Status
= EFI_INVALID_PARAMETER
;
1720 // The IP Hop Limit field has a value of 255, i.e., the packet
1721 // could not possibly have been forwarded by a router.
1723 // Target Address is not a multicast address.
1725 if ((Head
->HopLimit
!= IP6_HOP_LIMIT
) || (Icmp
.Head
.Code
!= 0) || !NetIp6IsValidUnicast (&Target
)) {
1730 // ICMP length is 24 or more octets.
1734 if (Head
->PayloadLength
< IP6_ND_LENGTH
) {
1737 OptionLen
= (UINT16
)(Head
->PayloadLength
- IP6_ND_LENGTH
);
1738 if (OptionLen
!= 0) {
1739 Option
= NetbufGetByte (Packet
, IP6_ND_LENGTH
, NULL
);
1740 ASSERT (Option
!= NULL
);
1743 // All included options should have a length that is greater than zero.
1745 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
1752 // If the IP destination address is a multicast address, Solicited Flag is ZERO.
1755 if ((Icmp
.Fourth
& IP6_SOLICITED_FLAG
) == IP6_SOLICITED_FLAG
) {
1759 if (IP6_IS_MULTICAST (&Head
->DestinationAddress
) && Solicited
) {
1764 // DAD - Check whether the Target is one of our tentative address.
1766 DupAddrDetect
= Ip6FindDADEntry (IpSb
, &Target
, &IpIf
);
1767 if (DupAddrDetect
!= NULL
) {
1769 // DAD fails, some other node is using this address.
1771 NetbufFree (Packet
);
1772 Ip6OnDADFinished (FALSE
, IpIf
, DupAddrDetect
);
1773 return EFI_ICMP_ERROR
;
1777 // Search the Neighbor Cache for the target's entry. If no entry exists,
1778 // the advertisement should be silently discarded.
1780 Neighbor
= Ip6FindNeighborEntry (IpSb
, &Target
);
1781 if (Neighbor
== NULL
) {
1786 // Get IsRouter Flag and Override Flag
1790 if ((Icmp
.Fourth
& IP6_IS_ROUTER_FLAG
) == IP6_IS_ROUTER_FLAG
) {
1794 if ((Icmp
.Fourth
& IP6_OVERRIDE_FLAG
) == IP6_OVERRIDE_FLAG
) {
1799 // Check whether link layer option is included.
1801 if (OptionLen
>= sizeof (IP6_ETHER_ADDR_OPTION
)) {
1805 sizeof (IP6_ETHER_ADDR_OPTION
),
1806 (UINT8
*)&LinkLayerOption
1809 if (LinkLayerOption
.Type
== Ip6OptionEtherTarget
) {
1816 Compare
= CompareMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1819 if (!Neighbor
->IsRouter
&& IsRouter
) {
1820 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &Target
);
1821 if (DefaultRouter
!= NULL
) {
1822 DefaultRouter
->NeighborCache
= Neighbor
;
1826 if (Neighbor
->State
== EfiNeighborInComplete
) {
1828 // If the target's Neighbor Cache entry is in INCOMPLETE state and no
1829 // Target Link-Layer address option is included while link layer has
1830 // address, the message should be silently discarded.
1837 // Update the Neighbor Cache
1839 CopyMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1841 Neighbor
->State
= EfiNeighborReachable
;
1842 Neighbor
->Ticks
= IP6_GET_TICKS (IpSb
->ReachableTime
);
1844 Neighbor
->State
= EfiNeighborStale
;
1845 Neighbor
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
1847 // Send any packets queued for the neighbor awaiting address resolution.
1849 Neighbor
->CallBack ((VOID
*)Neighbor
);
1852 Neighbor
->IsRouter
= IsRouter
;
1854 if (!Override
&& (Compare
!= 0)) {
1856 // When the Override Flag is clear and supplied link-layer address differs from
1857 // that in the cache, if the state of the entry is not REACHABLE, ignore the
1858 // message. Otherwise set it to STALE but do not update the entry in any
1861 if (Neighbor
->State
== EfiNeighborReachable
) {
1862 Neighbor
->State
= EfiNeighborStale
;
1863 Neighbor
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
1867 CopyMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1871 // Update the entry's state
1874 Neighbor
->State
= EfiNeighborReachable
;
1875 Neighbor
->Ticks
= IP6_GET_TICKS (IpSb
->ReachableTime
);
1878 Neighbor
->State
= EfiNeighborStale
;
1879 Neighbor
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
1884 // When IsRouter is changed from TRUE to FALSE, remove the router from the
1885 // Default Router List and remove the Destination Cache entries for all destinations
1886 // using the neighbor as a router.
1888 if (Neighbor
->IsRouter
&& !IsRouter
) {
1889 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &Target
);
1890 if (DefaultRouter
!= NULL
) {
1891 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
1895 Neighbor
->IsRouter
= IsRouter
;
1899 if (Neighbor
->State
== EfiNeighborReachable
) {
1900 Neighbor
->CallBack ((VOID
*)Neighbor
);
1903 Status
= EFI_SUCCESS
;
1906 NetbufFree (Packet
);
1911 Process the Router Advertisement message according to RFC4861.
1913 @param[in] IpSb The IP service that received the packet.
1914 @param[in] Head The IP head of the message.
1915 @param[in] Packet The content of the message with the IP head removed.
1917 @retval EFI_SUCCESS The packet processed successfully.
1918 @retval EFI_INVALID_PARAMETER The packet is invalid.
1919 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1921 @retval Others Failed to process the packet.
1925 Ip6ProcessRouterAdvertise (
1926 IN IP6_SERVICE
*IpSb
,
1927 IN EFI_IP6_HEADER
*Head
,
1931 IP6_ICMP_INFORMATION_HEAD Icmp
;
1932 UINT32 ReachableTime
;
1933 UINT32 RetransTimer
;
1934 UINT16 RouterLifetime
;
1938 IP6_ETHER_ADDR_OPTION LinkLayerOption
;
1943 IP6_DEFAULT_ROUTER
*DefaultRouter
;
1944 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
1945 EFI_MAC_ADDRESS LinkLayerAddress
;
1946 IP6_MTU_OPTION MTUOption
;
1947 IP6_PREFIX_INFO_OPTION PrefixOption
;
1948 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
1951 EFI_IPv6_ADDRESS StatelessAddress
;
1957 Status
= EFI_INVALID_PARAMETER
;
1959 if (IpSb
->Ip6ConfigInstance
.Policy
!= Ip6ConfigPolicyAutomatic
) {
1961 // Skip the process below as it's not required under the current policy.
1966 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*)&Icmp
);
1969 // Validate the incoming Router Advertisement
1973 // The IP source address must be a link-local address
1975 if (!NetIp6IsLinkLocalAddr (&Head
->SourceAddress
)) {
1980 // The IP Hop Limit field has a value of 255, i.e. the packet
1981 // could not possibly have been forwarded by a router.
1983 // ICMP length (derived from the IP length) is 16 or more octets.
1985 if ((Head
->HopLimit
!= IP6_HOP_LIMIT
) || (Icmp
.Head
.Code
!= 0) ||
1986 (Head
->PayloadLength
< IP6_RA_LENGTH
))
1992 // All included options have a length that is greater than zero.
1994 OptionLen
= (UINT16
)(Head
->PayloadLength
- IP6_RA_LENGTH
);
1995 if (OptionLen
!= 0) {
1996 Option
= NetbufGetByte (Packet
, IP6_RA_LENGTH
, NULL
);
1997 ASSERT (Option
!= NULL
);
1999 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
2005 // Process Fourth field.
2006 // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
2007 // and Router Lifetime (16 bit).
2010 Fourth
= NTOHL (Icmp
.Fourth
);
2011 CopyMem (&RouterLifetime
, &Fourth
, sizeof (UINT16
));
2014 // If the source address already in the default router list, update it.
2015 // Otherwise create a new entry.
2016 // A Lifetime of zero indicates that the router is not a default router.
2018 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &Head
->SourceAddress
);
2019 if (DefaultRouter
== NULL
) {
2020 if (RouterLifetime
!= 0) {
2021 DefaultRouter
= Ip6CreateDefaultRouter (IpSb
, &Head
->SourceAddress
, RouterLifetime
);
2022 if (DefaultRouter
== NULL
) {
2023 Status
= EFI_OUT_OF_RESOURCES
;
2028 if (RouterLifetime
!= 0) {
2029 DefaultRouter
->Lifetime
= RouterLifetime
;
2031 // Check the corresponding neighbor cache entry here.
2033 if (DefaultRouter
->NeighborCache
== NULL
) {
2034 DefaultRouter
->NeighborCache
= Ip6FindNeighborEntry (IpSb
, &Head
->SourceAddress
);
2038 // If the address is in the host's default router list and the router lifetime is zero,
2039 // immediately time-out the entry.
2041 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
2045 CurHopLimit
= *((UINT8
*)&Fourth
+ 3);
2046 if (CurHopLimit
!= 0) {
2047 IpSb
->CurHopLimit
= CurHopLimit
;
2052 if ((*((UINT8
*)&Fourth
+ 2) & IP6_M_ADDR_CONFIG_FLAG
) == IP6_M_ADDR_CONFIG_FLAG
) {
2055 if ((*((UINT8
*)&Fourth
+ 2) & IP6_O_CONFIG_FLAG
) == IP6_O_CONFIG_FLAG
) {
2060 if (Mflag
|| Oflag
) {
2062 // Use Ip6Config to get available addresses or other configuration from DHCP.
2064 Ip6ConfigStartStatefulAutoConfig (&IpSb
->Ip6ConfigInstance
, Oflag
);
2068 // Process Reachable Time and Retrans Timer fields.
2070 NetbufCopy (Packet
, sizeof (Icmp
), sizeof (UINT32
), (UINT8
*)&ReachableTime
);
2071 NetbufCopy (Packet
, sizeof (Icmp
) + sizeof (UINT32
), sizeof (UINT32
), (UINT8
*)&RetransTimer
);
2072 ReachableTime
= NTOHL (ReachableTime
);
2073 RetransTimer
= NTOHL (RetransTimer
);
2075 if ((ReachableTime
!= 0) && (ReachableTime
!= IpSb
->BaseReachableTime
)) {
2077 // If new value is not unspecified and differs from the previous one, record it
2078 // in BaseReachableTime and recompute a ReachableTime.
2080 IpSb
->BaseReachableTime
= ReachableTime
;
2081 Ip6UpdateReachableTime (IpSb
);
2084 if (RetransTimer
!= 0) {
2085 IpSb
->RetransTimer
= RetransTimer
;
2089 // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
2091 NeighborCache
= Ip6FindNeighborEntry (IpSb
, &Head
->SourceAddress
);
2092 if (NeighborCache
!= NULL
) {
2093 NeighborCache
->IsRouter
= TRUE
;
2097 // If an valid router advertisement is received, stops router solicitation.
2099 IpSb
->RouterAdvertiseReceived
= TRUE
;
2102 // The only defined options that may appear are the Source
2103 // Link-Layer Address, Prefix information and MTU options.
2104 // All included options have a length that is greater than zero and
2105 // fit within the input packet.
2108 while (Offset
< (UINT32
)Head
->PayloadLength
) {
2109 NetbufCopy (Packet
, Offset
, sizeof (UINT8
), &Type
);
2111 case Ip6OptionEtherSource
:
2113 // Update the neighbor cache
2115 NetbufCopy (Packet
, Offset
, sizeof (IP6_ETHER_ADDR_OPTION
), (UINT8
*)&LinkLayerOption
);
2118 // Option size validity ensured by Ip6IsNDOptionValid().
2120 ASSERT (LinkLayerOption
.Length
!= 0);
2121 ASSERT (Offset
+ (UINT32
)LinkLayerOption
.Length
* 8 <= (UINT32
)Head
->PayloadLength
);
2123 ZeroMem (&LinkLayerAddress
, sizeof (EFI_MAC_ADDRESS
));
2124 CopyMem (&LinkLayerAddress
, LinkLayerOption
.EtherAddr
, 6);
2126 if (NeighborCache
== NULL
) {
2127 NeighborCache
= Ip6CreateNeighborEntry (
2130 &Head
->SourceAddress
,
2133 if (NeighborCache
== NULL
) {
2134 Status
= EFI_OUT_OF_RESOURCES
;
2138 NeighborCache
->IsRouter
= TRUE
;
2139 NeighborCache
->State
= EfiNeighborStale
;
2140 NeighborCache
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
2142 Result
= CompareMem (&LinkLayerAddress
, &NeighborCache
->LinkAddress
, 6);
2145 // If the link-local address is the same as that already in the cache,
2146 // the cache entry's state remains unchanged. Otherwise update the
2147 // reachability state to STALE.
2149 if ((NeighborCache
->State
== EfiNeighborInComplete
) || (Result
!= 0)) {
2150 CopyMem (&NeighborCache
->LinkAddress
, &LinkLayerAddress
, 6);
2152 NeighborCache
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
2154 if (NeighborCache
->State
== EfiNeighborInComplete
) {
2156 // Send queued packets if exist.
2158 NeighborCache
->State
= EfiNeighborStale
;
2159 NeighborCache
->CallBack ((VOID
*)NeighborCache
);
2161 NeighborCache
->State
= EfiNeighborStale
;
2166 Offset
+= (UINT32
)LinkLayerOption
.Length
* 8;
2168 case Ip6OptionPrefixInfo
:
2169 NetbufCopy (Packet
, Offset
, sizeof (IP6_PREFIX_INFO_OPTION
), (UINT8
*)&PrefixOption
);
2172 // Option size validity ensured by Ip6IsNDOptionValid().
2174 ASSERT (PrefixOption
.Length
== 4);
2175 ASSERT (Offset
+ (UINT32
)PrefixOption
.Length
* 8 <= (UINT32
)Head
->PayloadLength
);
2177 PrefixOption
.ValidLifetime
= NTOHL (PrefixOption
.ValidLifetime
);
2178 PrefixOption
.PreferredLifetime
= NTOHL (PrefixOption
.PreferredLifetime
);
2181 // Get L and A flag, recorded in the lower 2 bits of Reserved1
2184 if ((PrefixOption
.Reserved1
& IP6_ON_LINK_FLAG
) == IP6_ON_LINK_FLAG
) {
2189 if ((PrefixOption
.Reserved1
& IP6_AUTO_CONFIG_FLAG
) == IP6_AUTO_CONFIG_FLAG
) {
2194 // If the prefix is the link-local prefix, silently ignore the prefix option.
2196 if ((PrefixOption
.PrefixLength
== IP6_LINK_LOCAL_PREFIX_LENGTH
) &&
2197 NetIp6IsLinkLocalAddr (&PrefixOption
.Prefix
)
2200 Offset
+= sizeof (IP6_PREFIX_INFO_OPTION
);
2205 // Do following if on-link flag is set according to RFC4861.
2208 PrefixList
= Ip6FindPrefixListEntry (
2211 PrefixOption
.PrefixLength
,
2212 &PrefixOption
.Prefix
2215 // Create a new entry for the prefix, if the ValidLifetime is zero,
2216 // silently ignore the prefix option.
2218 if ((PrefixList
== NULL
) && (PrefixOption
.ValidLifetime
!= 0)) {
2219 PrefixList
= Ip6CreatePrefixListEntry (
2222 PrefixOption
.ValidLifetime
,
2223 PrefixOption
.PreferredLifetime
,
2224 PrefixOption
.PrefixLength
,
2225 &PrefixOption
.Prefix
2227 if (PrefixList
== NULL
) {
2228 Status
= EFI_OUT_OF_RESOURCES
;
2231 } else if (PrefixList
!= NULL
) {
2232 if (PrefixOption
.ValidLifetime
!= 0) {
2233 PrefixList
->ValidLifetime
= PrefixOption
.ValidLifetime
;
2236 // If the prefix exists and incoming ValidLifetime is zero, immediately
2237 // remove the prefix.
2238 Ip6DestroyPrefixListEntry (IpSb
, PrefixList
, OnLink
, TRUE
);
2244 // Do following if Autonomous flag is set according to RFC4862.
2246 if (Autonomous
&& (PrefixOption
.PreferredLifetime
<= PrefixOption
.ValidLifetime
)) {
2247 PrefixList
= Ip6FindPrefixListEntry (
2250 PrefixOption
.PrefixLength
,
2251 &PrefixOption
.Prefix
2254 // Create a new entry for the prefix, and form an address by prefix + interface id
2255 // If the sum of the prefix length and interface identifier length
2256 // does not equal 128 bits, the Prefix Information option MUST be ignored.
2258 if ((PrefixList
== NULL
) &&
2259 (PrefixOption
.ValidLifetime
!= 0) &&
2260 (PrefixOption
.PrefixLength
+ IpSb
->InterfaceIdLen
* 8 == 128)
2264 // Form the address in network order.
2266 CopyMem (&StatelessAddress
, &PrefixOption
.Prefix
, sizeof (UINT64
));
2267 CopyMem (&StatelessAddress
.Addr
[8], IpSb
->InterfaceId
, sizeof (UINT64
));
2270 // If the address is not yet in the assigned address list, adds it into.
2272 if (!Ip6IsOneOfSetAddress (IpSb
, &StatelessAddress
, NULL
, NULL
)) {
2274 // And also not in the DAD process, check its uniqueness firstly.
2276 if (Ip6FindDADEntry (IpSb
, &StatelessAddress
, NULL
) == NULL
) {
2277 Status
= Ip6SetAddress (
2278 IpSb
->DefaultInterface
,
2281 PrefixOption
.PrefixLength
,
2282 PrefixOption
.ValidLifetime
,
2283 PrefixOption
.PreferredLifetime
,
2287 if (EFI_ERROR (Status
)) {
2294 // Adds the prefix option to stateless prefix option list.
2296 PrefixList
= Ip6CreatePrefixListEntry (
2299 PrefixOption
.ValidLifetime
,
2300 PrefixOption
.PreferredLifetime
,
2301 PrefixOption
.PrefixLength
,
2302 &PrefixOption
.Prefix
2304 if (PrefixList
== NULL
) {
2305 Status
= EFI_OUT_OF_RESOURCES
;
2308 } else if (PrefixList
!= NULL
) {
2310 // Reset the preferred lifetime of the address if the advertised prefix exists.
2311 // Perform specific action to valid lifetime together.
2313 PrefixList
->PreferredLifetime
= PrefixOption
.PreferredLifetime
;
2314 if ((PrefixOption
.ValidLifetime
> 7200) ||
2315 (PrefixOption
.ValidLifetime
> PrefixList
->ValidLifetime
))
2318 // If the received Valid Lifetime is greater than 2 hours or
2319 // greater than RemainingLifetime, set the valid lifetime of the
2320 // corresponding address to the advertised Valid Lifetime.
2322 PrefixList
->ValidLifetime
= PrefixOption
.ValidLifetime
;
2323 } else if (PrefixList
->ValidLifetime
<= 7200) {
2325 // If RemainingLifetime is less than or equals to 2 hours, ignore the
2326 // Prefix Information option with regards to the valid lifetime.
2327 // TODO: If this option has been authenticated, set the valid lifetime.
2331 // Otherwise, reset the valid lifetime of the corresponding
2332 // address to 2 hours.
2334 PrefixList
->ValidLifetime
= 7200;
2339 Offset
+= sizeof (IP6_PREFIX_INFO_OPTION
);
2342 NetbufCopy (Packet
, Offset
, sizeof (IP6_MTU_OPTION
), (UINT8
*)&MTUOption
);
2345 // Option size validity ensured by Ip6IsNDOptionValid().
2347 ASSERT (MTUOption
.Length
== 1);
2348 ASSERT (Offset
+ (UINT32
)MTUOption
.Length
* 8 <= (UINT32
)Head
->PayloadLength
);
2351 // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
2352 // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
2353 // in Router Advertisement.
2356 Offset
+= sizeof (IP6_MTU_OPTION
);
2360 // Silently ignore unrecognized options
2362 NetbufCopy (Packet
, Offset
+ sizeof (UINT8
), sizeof (UINT8
), &Length
);
2364 ASSERT (Length
!= 0);
2366 Offset
+= (UINT32
)Length
* 8;
2371 Status
= EFI_SUCCESS
;
2374 NetbufFree (Packet
);
2379 Process the ICMPv6 redirect message. Find the instance, then update
2382 @param[in] IpSb The IP6 service binding instance that received
2384 @param[in] Head The IP head of the received ICMPv6 packet.
2385 @param[in] Packet The content of the ICMPv6 redirect packet with
2386 the IP head removed.
2388 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2389 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
2391 @retval EFI_SUCCESS Successfully updated the route caches.
2395 Ip6ProcessRedirect (
2396 IN IP6_SERVICE
*IpSb
,
2397 IN EFI_IP6_HEADER
*Head
,
2401 IP6_ICMP_INFORMATION_HEAD
*Icmp
;
2402 EFI_IPv6_ADDRESS
*Target
;
2403 EFI_IPv6_ADDRESS
*IcmpDest
;
2406 IP6_ROUTE_ENTRY
*RouteEntry
;
2407 IP6_ROUTE_CACHE_ENTRY
*RouteCache
;
2408 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
2411 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
2412 EFI_MAC_ADDRESS Mac
;
2418 Status
= EFI_INVALID_PARAMETER
;
2420 Icmp
= (IP6_ICMP_INFORMATION_HEAD
*)NetbufGetByte (Packet
, 0, NULL
);
2426 // Validate the incoming Redirect message
2430 // The IP Hop Limit field has a value of 255, i.e. the packet
2431 // could not possibly have been forwarded by a router.
2433 // ICMP length (derived from the IP length) is 40 or more octets.
2435 if ((Head
->HopLimit
!= IP6_HOP_LIMIT
) || (Icmp
->Head
.Code
!= 0) ||
2436 (Head
->PayloadLength
< IP6_REDITECT_LENGTH
))
2442 // The IP source address must be a link-local address
2444 if (!NetIp6IsLinkLocalAddr (&Head
->SourceAddress
)) {
2449 // The dest of this ICMP redirect message is not us.
2451 if (!Ip6IsOneOfSetAddress (IpSb
, &Head
->DestinationAddress
, NULL
, NULL
)) {
2456 // All included options have a length that is greater than zero.
2458 OptionLen
= (UINT16
)(Head
->PayloadLength
- IP6_REDITECT_LENGTH
);
2459 if (OptionLen
!= 0) {
2460 Option
= NetbufGetByte (Packet
, IP6_REDITECT_LENGTH
, NULL
);
2461 ASSERT (Option
!= NULL
);
2463 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
2468 Target
= (EFI_IPv6_ADDRESS
*)(Icmp
+ 1);
2469 IcmpDest
= Target
+ 1;
2472 // The ICMP Destination Address field in the redirect message does not contain
2473 // a multicast address.
2475 if (IP6_IS_MULTICAST (IcmpDest
)) {
2480 // The ICMP Target Address is either a link-local address (when redirected to
2481 // a router) or the same as the ICMP Destination Address (when redirected to
2482 // the on-link destination).
2484 IsRouter
= (BOOLEAN
) !EFI_IP6_EQUAL (Target
, IcmpDest
);
2485 if (!NetIp6IsLinkLocalAddr (Target
) && IsRouter
) {
2490 // Check the options. The only interested option here is the target-link layer
2493 Length
= Packet
->TotalSize
- 40;
2494 Option
= (UINT8
*)(IcmpDest
+ 1);
2495 LinkLayerOption
= NULL
;
2496 while (Length
> 0) {
2498 case Ip6OptionEtherTarget
:
2500 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*)Option
;
2501 OptLen
= LinkLayerOption
->Length
;
2504 // For ethernet, the length must be 1.
2513 OptLen
= *(Option
+ 1);
2516 // A length of 0 is invalid.
2524 Length
-= 8 * OptLen
;
2525 Option
+= 8 * OptLen
;
2533 // The IP source address of the Redirect is the same as the current
2534 // first-hop router for the specified ICMP Destination Address.
2536 RouteCache
= Ip6FindRouteCache (IpSb
->RouteTable
, IcmpDest
, &Head
->DestinationAddress
);
2537 if (RouteCache
!= NULL
) {
2538 if (!EFI_IP6_EQUAL (&RouteCache
->NextHop
, &Head
->SourceAddress
)) {
2540 // The source of this Redirect message must match the NextHop of the
2541 // corresponding route cache entry.
2547 // Update the NextHop.
2549 IP6_COPY_ADDRESS (&RouteCache
->NextHop
, Target
);
2552 RouteEntry
= (IP6_ROUTE_ENTRY
*)RouteCache
->Tag
;
2553 RouteEntry
->Flag
= RouteEntry
->Flag
| IP6_DIRECT_ROUTE
;
2557 // Get the Route Entry.
2559 RouteEntry
= Ip6FindRouteEntry (IpSb
->RouteTable
, IcmpDest
, NULL
);
2560 if (RouteEntry
== NULL
) {
2561 RouteEntry
= Ip6CreateRouteEntry (IcmpDest
, 0, NULL
);
2562 if (RouteEntry
== NULL
) {
2563 Status
= EFI_OUT_OF_RESOURCES
;
2569 RouteEntry
->Flag
= IP6_DIRECT_ROUTE
;
2573 // Create a route cache for this.
2575 RouteCache
= Ip6CreateRouteCacheEntry (
2577 &Head
->DestinationAddress
,
2581 if (RouteCache
== NULL
) {
2582 Status
= EFI_OUT_OF_RESOURCES
;
2587 // Insert the newly created route cache entry.
2589 Index
= IP6_ROUTE_CACHE_HASH (IcmpDest
, &Head
->DestinationAddress
);
2590 InsertHeadList (&IpSb
->RouteTable
->Cache
.CacheBucket
[Index
], &RouteCache
->Link
);
2594 // Try to locate the neighbor cache for the Target.
2596 NeighborCache
= Ip6FindNeighborEntry (IpSb
, Target
);
2598 if (LinkLayerOption
!= NULL
) {
2599 if (NeighborCache
== NULL
) {
2601 // Create a neighbor cache for the Target.
2603 ZeroMem (&Mac
, sizeof (EFI_MAC_ADDRESS
));
2604 CopyMem (&Mac
, LinkLayerOption
->EtherAddr
, 6);
2605 NeighborCache
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, Target
, &Mac
);
2606 if (NeighborCache
== NULL
) {
2608 // Just report a success here. The neighbor cache can be created in
2609 // some other place.
2611 Status
= EFI_SUCCESS
;
2615 NeighborCache
->State
= EfiNeighborStale
;
2616 NeighborCache
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
2618 Result
= CompareMem (LinkLayerOption
->EtherAddr
, &NeighborCache
->LinkAddress
, 6);
2621 // If the link-local address is the same as that already in the cache,
2622 // the cache entry's state remains unchanged. Otherwise update the
2623 // reachability state to STALE.
2625 if ((NeighborCache
->State
== EfiNeighborInComplete
) || (Result
!= 0)) {
2626 CopyMem (&NeighborCache
->LinkAddress
, LinkLayerOption
->EtherAddr
, 6);
2628 NeighborCache
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
2630 if (NeighborCache
->State
== EfiNeighborInComplete
) {
2632 // Send queued packets if exist.
2634 NeighborCache
->State
= EfiNeighborStale
;
2635 NeighborCache
->CallBack ((VOID
*)NeighborCache
);
2637 NeighborCache
->State
= EfiNeighborStale
;
2643 if ((NeighborCache
!= NULL
) && IsRouter
) {
2645 // The Target is a router, set IsRouter to TRUE.
2647 NeighborCache
->IsRouter
= TRUE
;
2650 Status
= EFI_SUCCESS
;
2653 NetbufFree (Packet
);
2658 Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2660 @param[in] IpSb The IP6 service binding instance.
2661 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2662 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2663 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2664 cache. It will be deleted after Timeout. A value of zero means that
2665 the entry is permanent. A non-zero value means that the entry is
2667 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2668 be overridden and updated; if FALSE, and if a
2669 corresponding cache entry already existed, EFI_ACCESS_DENIED
2672 @retval EFI_SUCCESS The neighbor cache entry has been added.
2673 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache
2674 due to insufficient resources.
2675 @retval EFI_NOT_FOUND TargetLinkAddress is NULL.
2676 @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
2677 and that entry is tagged as un-overridden (when DeleteFlag
2683 IN IP6_SERVICE
*IpSb
,
2684 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
2685 IN EFI_MAC_ADDRESS
*TargetLinkAddress OPTIONAL
,
2690 IP6_NEIGHBOR_ENTRY
*Neighbor
;
2692 Neighbor
= Ip6FindNeighborEntry (IpSb
, TargetIp6Address
);
2693 if (Neighbor
!= NULL
) {
2695 return EFI_ACCESS_DENIED
;
2697 if (TargetLinkAddress
!= NULL
) {
2698 IP6_COPY_LINK_ADDRESS (&Neighbor
->LinkAddress
, TargetLinkAddress
);
2702 if (TargetLinkAddress
== NULL
) {
2703 return EFI_NOT_FOUND
;
2706 Neighbor
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, TargetIp6Address
, TargetLinkAddress
);
2707 if (Neighbor
== NULL
) {
2708 return EFI_OUT_OF_RESOURCES
;
2712 Neighbor
->State
= EfiNeighborReachable
;
2715 Neighbor
->Ticks
= IP6_GET_TICKS (Timeout
/ TICKS_PER_MS
);
2716 Neighbor
->Dynamic
= TRUE
;
2718 Neighbor
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
2725 Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2727 @param[in] IpSb The IP6 service binding instance.
2728 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2729 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2730 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2731 cache. It will be deleted after Timeout. A value of zero means that
2732 the entry is permanent. A non-zero value means that the entry is
2734 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2735 be overridden and updated; if FALSE, and if a
2736 corresponding cache entry already existed, EFI_ACCESS_DENIED
2739 @retval EFI_SUCCESS The neighbor cache entry has been updated or deleted.
2740 @retval EFI_NOT_FOUND This entry is not in the neighbor cache.
2745 IN IP6_SERVICE
*IpSb
,
2746 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
2747 IN EFI_MAC_ADDRESS
*TargetLinkAddress OPTIONAL
,
2752 IP6_NEIGHBOR_ENTRY
*Neighbor
;
2754 Neighbor
= Ip6FindNeighborEntry (IpSb
, TargetIp6Address
);
2755 if (Neighbor
== NULL
) {
2756 return EFI_NOT_FOUND
;
2759 RemoveEntryList (&Neighbor
->Link
);
2760 FreePool (Neighbor
);
2766 The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
2767 This time routine handles DAD module and neighbor state transition.
2768 It is also responsible for sending out router solicitations.
2770 @param[in] Event The IP6 service instance's heartbeat timer.
2771 @param[in] Context The IP6 service instance.
2776 Ip6NdFasterTimerTicking (
2784 IP6_INTERFACE
*IpIf
;
2785 IP6_DELAY_JOIN_LIST
*DelayNode
;
2786 EFI_IPv6_ADDRESS Source
;
2787 IP6_DAD_ENTRY
*DupAddrDetect
;
2789 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
2790 EFI_IPv6_ADDRESS Destination
;
2794 IpSb
= (IP6_SERVICE
*)Context
;
2795 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
2797 ZeroMem (&Source
, sizeof (EFI_IPv6_ADDRESS
));
2800 // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
2801 // Solicitation messages, each separated by at least
2802 // RTR_SOLICITATION_INTERVAL (4) seconds.
2804 if ((IpSb
->Ip6ConfigInstance
.Policy
== Ip6ConfigPolicyAutomatic
) &&
2805 !IpSb
->RouterAdvertiseReceived
&&
2806 (IpSb
->SolicitTimer
> 0)
2809 if ((IpSb
->Ticks
== 0) || (--IpSb
->Ticks
== 0)) {
2810 Status
= Ip6SendRouterSolicit (IpSb
, NULL
, NULL
, NULL
, NULL
);
2811 if (!EFI_ERROR (Status
)) {
2812 IpSb
->SolicitTimer
--;
2813 IpSb
->Ticks
= (UINT32
)IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL
);
2818 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
2819 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
2822 // Process the delay list to join the solicited-node multicast address.
2824 NET_LIST_FOR_EACH_SAFE (Entry2
, Next
, &IpIf
->DelayJoinList
) {
2825 DelayNode
= NET_LIST_USER_STRUCT (Entry2
, IP6_DELAY_JOIN_LIST
, Link
);
2826 if ((DelayNode
->DelayTime
== 0) || (--DelayNode
->DelayTime
== 0)) {
2828 // The timer expires, init the duplicate address detection.
2831 DelayNode
->Interface
,
2832 DelayNode
->AddressInfo
,
2833 DelayNode
->DadCallback
,
2838 // Remove the delay node
2840 RemoveEntryList (&DelayNode
->Link
);
2841 FreePool (DelayNode
);
2846 // Process the duplicate address detection list.
2848 NET_LIST_FOR_EACH_SAFE (Entry2
, Next
, &IpIf
->DupAddrDetectList
) {
2849 DupAddrDetect
= NET_LIST_USER_STRUCT (Entry2
, IP6_DAD_ENTRY
, Link
);
2851 if ((DupAddrDetect
->RetransTick
== 0) || (--DupAddrDetect
->RetransTick
== 0)) {
2853 // The timer expires, check the remaining transmit counts.
2855 if (DupAddrDetect
->Transmit
< DupAddrDetect
->MaxTransmit
) {
2857 // Send the Neighbor Solicitation message with
2858 // Source - unspecified address, destination - solicited-node multicast address
2859 // Target - the address to be validated
2861 Status
= Ip6SendNeighborSolicit (
2864 &DupAddrDetect
->Destination
,
2865 &DupAddrDetect
->AddressInfo
->Address
,
2868 if (EFI_ERROR (Status
)) {
2872 DupAddrDetect
->Transmit
++;
2873 DupAddrDetect
->RetransTick
= IP6_GET_TICKS (IpSb
->RetransTimer
);
2876 // All required solicitation has been sent out, and the RetransTime after the last
2877 // Neighbor Solicit is elapsed, finish the DAD process.
2880 if ((DupAddrDetect
->Receive
== 0) ||
2881 (DupAddrDetect
->Transmit
<= DupAddrDetect
->Receive
))
2886 Ip6OnDADFinished (Flag
, IpIf
, DupAddrDetect
);
2893 // Polling the state of Neighbor cache
2895 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->NeighborTable
) {
2896 NeighborCache
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, Link
);
2898 switch (NeighborCache
->State
) {
2899 case EfiNeighborInComplete
:
2900 if (NeighborCache
->Ticks
> 0) {
2901 --NeighborCache
->Ticks
;
2905 // Retransmit Neighbor Solicitation messages approximately every
2906 // RetransTimer milliseconds while awaiting a response.
2908 if (NeighborCache
->Ticks
== 0) {
2909 if (NeighborCache
->Transmit
> 1) {
2911 // Send out multicast neighbor solicitation for address resolution.
2912 // After last neighbor solicitation message has been sent out, wait
2913 // for RetransTimer and then remove entry if no response is received.
2915 Ip6CreateSNMulticastAddr (&NeighborCache
->Neighbor
, &Destination
);
2916 Status
= Ip6SelectSourceAddress (IpSb
, &NeighborCache
->Neighbor
, &Source
);
2917 if (EFI_ERROR (Status
)) {
2921 Status
= Ip6SendNeighborSolicit (
2925 &NeighborCache
->Neighbor
,
2926 &IpSb
->SnpMode
.CurrentAddress
2928 if (EFI_ERROR (Status
)) {
2934 // Update the retransmit times.
2936 if (NeighborCache
->Transmit
> 0) {
2937 --NeighborCache
->Transmit
;
2938 NeighborCache
->Ticks
= IP6_GET_TICKS (IpSb
->RetransTimer
);
2942 if (NeighborCache
->Transmit
== 0) {
2944 // Timeout, send ICMP destination unreachable packet and then remove entry
2946 Status
= Ip6FreeNeighborEntry (
2955 if (EFI_ERROR (Status
)) {
2962 case EfiNeighborReachable
:
2964 // This entry is inserted by EfiIp6Neighbors() as static entry
2965 // and will not timeout.
2967 if (!NeighborCache
->Dynamic
&& (NeighborCache
->Ticks
== IP6_INFINIT_LIFETIME
)) {
2971 if ((NeighborCache
->Ticks
== 0) || (--NeighborCache
->Ticks
== 0)) {
2972 if (NeighborCache
->Dynamic
) {
2974 // This entry is inserted by EfiIp6Neighbors() as dynamic entry
2975 // and will be deleted after timeout.
2977 Status
= Ip6FreeNeighborEntry (
2986 if (EFI_ERROR (Status
)) {
2990 NeighborCache
->State
= EfiNeighborStale
;
2991 NeighborCache
->Ticks
= (UINT32
)IP6_INFINIT_LIFETIME
;
2997 case EfiNeighborDelay
:
2998 if ((NeighborCache
->Ticks
== 0) || (--NeighborCache
->Ticks
== 0)) {
2999 NeighborCache
->State
= EfiNeighborProbe
;
3000 NeighborCache
->Ticks
= IP6_GET_TICKS (IpSb
->RetransTimer
);
3001 NeighborCache
->Transmit
= IP6_MAX_UNICAST_SOLICIT
+ 1;
3003 // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
3005 Status
= Ip6SelectSourceAddress (IpSb
, &NeighborCache
->Neighbor
, &Source
);
3006 if (EFI_ERROR (Status
)) {
3010 Status
= Ip6SendNeighborSolicit (
3013 &NeighborCache
->Neighbor
,
3014 &NeighborCache
->Neighbor
,
3015 &IpSb
->SnpMode
.CurrentAddress
3017 if (EFI_ERROR (Status
)) {
3021 NeighborCache
->Transmit
--;
3026 case EfiNeighborProbe
:
3027 if (NeighborCache
->Ticks
> 0) {
3028 --NeighborCache
->Ticks
;
3032 // Retransmit Neighbor Solicitation messages approximately every
3033 // RetransTimer milliseconds while awaiting a response.
3035 if (NeighborCache
->Ticks
== 0) {
3036 if (NeighborCache
->Transmit
> 1) {
3038 // Send out unicast neighbor solicitation for Neighbor Unreachability
3039 // Detection. After last neighbor solicitation message has been sent out,
3040 // wait for RetransTimer and then remove entry if no response is received.
3042 Status
= Ip6SelectSourceAddress (IpSb
, &NeighborCache
->Neighbor
, &Source
);
3043 if (EFI_ERROR (Status
)) {
3047 Status
= Ip6SendNeighborSolicit (
3050 &NeighborCache
->Neighbor
,
3051 &NeighborCache
->Neighbor
,
3052 &IpSb
->SnpMode
.CurrentAddress
3054 if (EFI_ERROR (Status
)) {
3060 // Update the retransmit times.
3062 if (NeighborCache
->Transmit
> 0) {
3063 --NeighborCache
->Transmit
;
3064 NeighborCache
->Ticks
= IP6_GET_TICKS (IpSb
->RetransTimer
);
3068 if (NeighborCache
->Transmit
== 0) {
3070 // Delete the neighbor entry.
3072 Status
= Ip6FreeNeighborEntry (
3081 if (EFI_ERROR (Status
)) {
3095 The heartbeat timer of ND module in 1 second. This time routine handles following
3096 things: 1) maintain default router list; 2) maintain prefix options;
3097 3) maintain route caches.
3099 @param[in] IpSb The IP6 service binding instance.
3104 IN IP6_SERVICE
*IpSb
3109 IP6_DEFAULT_ROUTER
*DefaultRouter
;
3110 IP6_PREFIX_LIST_ENTRY
*PrefixOption
;
3112 IP6_ROUTE_CACHE_ENTRY
*RouteCache
;
3115 // Decrease the lifetime of default router, if expires remove it from default router list.
3117 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->DefaultRouterList
) {
3118 DefaultRouter
= NET_LIST_USER_STRUCT (Entry
, IP6_DEFAULT_ROUTER
, Link
);
3119 if (DefaultRouter
->Lifetime
!= IP6_INF_ROUTER_LIFETIME
) {
3120 if ((DefaultRouter
->Lifetime
== 0) || (--DefaultRouter
->Lifetime
== 0)) {
3121 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
3127 // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
3129 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->AutonomousPrefix
) {
3130 PrefixOption
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
3131 if (PrefixOption
->ValidLifetime
!= (UINT32
)IP6_INFINIT_LIFETIME
) {
3132 if ((PrefixOption
->ValidLifetime
> 0) && (--PrefixOption
->ValidLifetime
> 0)) {
3133 if ((PrefixOption
->PreferredLifetime
!= (UINT32
)IP6_INFINIT_LIFETIME
) &&
3134 (PrefixOption
->PreferredLifetime
> 0)
3137 --PrefixOption
->PreferredLifetime
;
3140 Ip6DestroyPrefixListEntry (IpSb
, PrefixOption
, FALSE
, TRUE
);
3145 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->OnlinkPrefix
) {
3146 PrefixOption
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
3147 if (PrefixOption
->ValidLifetime
!= (UINT32
)IP6_INFINIT_LIFETIME
) {
3148 if ((PrefixOption
->ValidLifetime
== 0) || (--PrefixOption
->ValidLifetime
== 0)) {
3149 Ip6DestroyPrefixListEntry (IpSb
, PrefixOption
, TRUE
, TRUE
);
3155 // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
3156 // Remove the entries at the tail of the bucket. These entries
3157 // are likely to be used least.
3158 // Reclaim frequency is set to 1 second.
3160 for (Index
= 0; Index
< IP6_ROUTE_CACHE_HASH_SIZE
; Index
++) {
3161 while (IpSb
->RouteTable
->Cache
.CacheNum
[Index
] > IP6_ROUTE_CACHE_MAX
) {
3162 Entry
= NetListRemoveTail (&IpSb
->RouteTable
->Cache
.CacheBucket
[Index
]);
3163 if (Entry
== NULL
) {
3167 RouteCache
= NET_LIST_USER_STRUCT (Entry
, IP6_ROUTE_CACHE_ENTRY
, Link
);
3168 Ip6FreeRouteCacheEntry (RouteCache
);
3169 ASSERT (IpSb
->RouteTable
->Cache
.CacheNum
[Index
] > 0);
3170 IpSb
->RouteTable
->Cache
.CacheNum
[Index
]--;