2 Implementation of Neighbor Discovery support routines.
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php.
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 EFI_MAC_ADDRESS mZeroMacAddress
;
21 Update the ReachableTime in IP6 service binding instance data, in milliseconds.
23 @param[in, out] IpSb Points to the IP6_SERVICE.
27 Ip6UpdateReachableTime (
28 IN OUT IP6_SERVICE
*IpSb
33 Random
= (NetRandomInitSeed () / 4294967295UL) * IP6_RANDOM_FACTOR_SCALE
;
34 Random
= Random
+ IP6_MIN_RANDOM_FACTOR_SCALED
;
35 IpSb
->ReachableTime
= (IpSb
->BaseReachableTime
* Random
) / IP6_RANDOM_FACTOR_SCALE
;
39 Build a array of EFI_IP6_NEIGHBOR_CACHE to be returned to the caller. The number
40 of EFI_IP6_NEIGHBOR_CACHE is also returned.
42 @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
43 @param[out] NeighborCount The number of returned neighbor cache entries.
44 @param[out] NeighborCache The pointer to the array of EFI_IP6_NEIGHBOR_CACHE.
46 @retval EFI_SUCCESS The EFI_IP6_NEIGHBOR_CACHE successfully built.
47 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the route table.
51 Ip6BuildEfiNeighborCache (
52 IN IP6_PROTOCOL
*IpInstance
,
53 OUT UINT32
*NeighborCount
,
54 OUT EFI_IP6_NEIGHBOR_CACHE
**NeighborCache
57 IP6_NEIGHBOR_ENTRY
*Neighbor
;
61 EFI_IP6_NEIGHBOR_CACHE
*EfiNeighborCache
;
62 EFI_IP6_NEIGHBOR_CACHE
*NeighborCacheTmp
;
64 NET_CHECK_SIGNATURE (IpInstance
, IP6_PROTOCOL_SIGNATURE
);
65 ASSERT (NeighborCount
!= NULL
&& NeighborCache
!= NULL
);
67 IpSb
= IpInstance
->Service
;
70 NET_LIST_FOR_EACH (Entry
, &IpSb
->NeighborTable
) {
78 NeighborCacheTmp
= AllocatePool (Count
* sizeof (EFI_IP6_NEIGHBOR_CACHE
));
79 if (NeighborCacheTmp
== NULL
) {
80 return EFI_OUT_OF_RESOURCES
;
83 *NeighborCount
= Count
;
86 NET_LIST_FOR_EACH (Entry
, &IpSb
->NeighborTable
) {
87 Neighbor
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, Link
);
89 EfiNeighborCache
= NeighborCacheTmp
+ Count
;
91 EfiNeighborCache
->State
= Neighbor
->State
;
92 IP6_COPY_ADDRESS (&EfiNeighborCache
->Neighbor
, &Neighbor
->Neighbor
);
93 IP6_COPY_LINK_ADDRESS (&EfiNeighborCache
->LinkAddress
, &Neighbor
->LinkAddress
);
98 ASSERT (*NeighborCount
== Count
);
99 *NeighborCache
= NeighborCacheTmp
;
105 Build a array of EFI_IP6_ADDRESS_INFO to be returned to the caller. The number
106 of prefix entries is also returned.
108 @param[in] IpInstance The pointer to IP6_PROTOCOL instance.
109 @param[out] PrefixCount The number of returned prefix entries.
110 @param[out] PrefixTable The pointer to the array of PrefixTable.
112 @retval EFI_SUCCESS The prefix table successfully built.
113 @retval EFI_OUT_OF_RESOURCES Failed to allocate the memory for the prefix table.
117 Ip6BuildPrefixTable (
118 IN IP6_PROTOCOL
*IpInstance
,
119 OUT UINT32
*PrefixCount
,
120 OUT EFI_IP6_ADDRESS_INFO
**PrefixTable
126 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
127 EFI_IP6_ADDRESS_INFO
*EfiPrefix
;
128 EFI_IP6_ADDRESS_INFO
*PrefixTableTmp
;
130 NET_CHECK_SIGNATURE (IpInstance
, IP6_PROTOCOL_SIGNATURE
);
131 ASSERT (PrefixCount
!= NULL
&& PrefixTable
!= NULL
);
133 IpSb
= IpInstance
->Service
;
136 NET_LIST_FOR_EACH (Entry
, &IpSb
->OnlinkPrefix
) {
144 PrefixTableTmp
= AllocatePool (Count
* sizeof (EFI_IP6_ADDRESS_INFO
));
145 if (PrefixTableTmp
== NULL
) {
146 return EFI_OUT_OF_RESOURCES
;
149 *PrefixCount
= Count
;
152 NET_LIST_FOR_EACH (Entry
, &IpSb
->OnlinkPrefix
) {
153 PrefixList
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
154 EfiPrefix
= PrefixTableTmp
+ Count
;
155 IP6_COPY_ADDRESS (&EfiPrefix
->Address
, &PrefixList
->Prefix
);
156 EfiPrefix
->PrefixLength
= PrefixList
->PrefixLength
;
161 ASSERT (*PrefixCount
== Count
);
162 *PrefixTable
= PrefixTableTmp
;
168 Allocate and initialize a IP6 prefix list entry.
170 @param[in] IpSb The pointer to IP6_SERVICE instance.
171 @param[in] OnLinkOrAuto If TRUE, the entry is created for the on link prefix list.
172 Otherwise, it is created for the autoconfiguration prefix list.
173 @param[in] ValidLifetime The length of time in seconds that the prefix
174 is valid for the purpose of on-link determination.
175 @param[in] PreferredLifetime The length of time in seconds that addresses
176 generated from the prefix via stateless address
177 autoconfiguration remain preferred.
178 @param[in] PrefixLength The prefix length of the Prefix.
179 @param[in] Prefix The prefix address.
181 @return NULL if it failed to allocate memory for the prefix node. Otherwise, point
182 to the created or existing prefix list entry.
185 IP6_PREFIX_LIST_ENTRY
*
186 Ip6CreatePrefixListEntry (
187 IN IP6_SERVICE
*IpSb
,
188 IN BOOLEAN OnLinkOrAuto
,
189 IN UINT32 ValidLifetime
,
190 IN UINT32 PreferredLifetime
,
191 IN UINT8 PrefixLength
,
192 IN EFI_IPv6_ADDRESS
*Prefix
195 IP6_PREFIX_LIST_ENTRY
*PrefixEntry
;
196 IP6_ROUTE_ENTRY
*RtEntry
;
197 LIST_ENTRY
*ListHead
;
199 IP6_PREFIX_LIST_ENTRY
*TmpPrefixEntry
;
201 if (Prefix
== NULL
|| PreferredLifetime
> ValidLifetime
|| PrefixLength
>= IP6_PREFIX_NUM
) {
205 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
207 PrefixEntry
= Ip6FindPrefixListEntry (
213 if (PrefixEntry
!= NULL
) {
214 PrefixEntry
->RefCnt
++;
218 PrefixEntry
= AllocatePool (sizeof (IP6_PREFIX_LIST_ENTRY
));
219 if (PrefixEntry
== NULL
) {
223 PrefixEntry
->RefCnt
= 1;
224 PrefixEntry
->ValidLifetime
= ValidLifetime
;
225 PrefixEntry
->PreferredLifetime
= PreferredLifetime
;
226 PrefixEntry
->PrefixLength
= PrefixLength
;
227 IP6_COPY_ADDRESS (&PrefixEntry
->Prefix
, Prefix
);
229 ListHead
= OnLinkOrAuto
? &IpSb
->OnlinkPrefix
: &IpSb
->AutonomousPrefix
;
232 // Create a direct route entry for on-link prefix and insert to route area.
235 RtEntry
= Ip6CreateRouteEntry (Prefix
, PrefixLength
, NULL
);
236 if (RtEntry
== NULL
) {
237 FreePool (PrefixEntry
);
241 RtEntry
->Flag
= IP6_DIRECT_ROUTE
;
242 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[PrefixLength
], &RtEntry
->Link
);
243 IpSb
->RouteTable
->TotalNum
++;
247 // Insert the prefix entry in the order that a prefix with longer prefix length
248 // is put ahead in the list.
250 NET_LIST_FOR_EACH (Entry
, ListHead
) {
251 TmpPrefixEntry
= NET_LIST_USER_STRUCT(Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
253 if (TmpPrefixEntry
->PrefixLength
< PrefixEntry
->PrefixLength
) {
258 NetListInsertBefore (Entry
, &PrefixEntry
->Link
);
264 Destory a IP6 prefix list entry.
266 @param[in] IpSb The pointer to IP6_SERVICE instance.
267 @param[in] PrefixEntry The to be destroyed prefix list entry.
268 @param[in] OnLinkOrAuto If TRUE, the entry is removed from on link prefix list.
269 Otherwise remove from autoconfiguration prefix list.
270 @param[in] ImmediateDelete If TRUE, remove the entry directly.
271 Otherwise, check the reference count to see whether
272 it should be removed.
276 Ip6DestroyPrefixListEntry (
277 IN IP6_SERVICE
*IpSb
,
278 IN IP6_PREFIX_LIST_ENTRY
*PrefixEntry
,
279 IN BOOLEAN OnLinkOrAuto
,
280 IN BOOLEAN ImmediateDelete
287 if ((!ImmediateDelete
) && (PrefixEntry
->RefCnt
> 0) && ((--PrefixEntry
->RefCnt
) > 0)) {
293 // Remove the direct route for onlink prefix from route table.
296 Status
= Ip6DelRoute (
298 &PrefixEntry
->Prefix
,
299 PrefixEntry
->PrefixLength
,
302 } while (Status
!= EFI_NOT_FOUND
);
305 // Remove the corresponding addresses generated from this autonomous prefix.
307 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
308 IpIf
= NET_LIST_USER_STRUCT_S (Entry
, IP6_INTERFACE
, Link
, IP6_INTERFACE_SIGNATURE
);
310 Ip6RemoveAddr (IpSb
, &IpIf
->AddressList
, &IpIf
->AddressCount
, &PrefixEntry
->Prefix
, PrefixEntry
->PrefixLength
);
314 RemoveEntryList (&PrefixEntry
->Link
);
315 FreePool (PrefixEntry
);
319 Search the list array to find an IP6 prefix list entry.
321 @param[in] IpSb The pointer to IP6_SERVICE instance.
322 @param[in] OnLinkOrAuto If TRUE, the search the link prefix list,
323 Otherwise search the autoconfiguration prefix list.
324 @param[in] PrefixLength The prefix length of the Prefix
325 @param[in] Prefix The prefix address.
327 @return NULL if cannot find the IP6 prefix list entry. Otherwise, return the
328 pointer to the IP6 prefix list entry.
331 IP6_PREFIX_LIST_ENTRY
*
332 Ip6FindPrefixListEntry (
333 IN IP6_SERVICE
*IpSb
,
334 IN BOOLEAN OnLinkOrAuto
,
335 IN UINT8 PrefixLength
,
336 IN EFI_IPv6_ADDRESS
*Prefix
339 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
341 LIST_ENTRY
*ListHead
;
343 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
344 ASSERT (Prefix
!= NULL
);
347 ListHead
= &IpSb
->OnlinkPrefix
;
349 ListHead
= &IpSb
->AutonomousPrefix
;
352 NET_LIST_FOR_EACH (Entry
, ListHead
) {
353 PrefixList
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
354 if (PrefixLength
!= 255) {
356 // Perform exactly prefix match.
358 if (PrefixList
->PrefixLength
== PrefixLength
&&
359 NetIp6IsNetEqual (&PrefixList
->Prefix
, Prefix
, PrefixLength
)) {
364 // Perform the longest prefix match. The list is already sorted with
365 // the longest length prefix put at the head of the list.
367 if (NetIp6IsNetEqual (&PrefixList
->Prefix
, Prefix
, PrefixList
->PrefixLength
)) {
377 Release the resource in the prefix list table, and destroy the list entry and
378 corresponding addresses or route entries.
380 @param[in] IpSb The pointer to the IP6_SERVICE instance.
381 @param[in] ListHead The list entry head of the prefix list table.
385 Ip6CleanPrefixListTable (
386 IN IP6_SERVICE
*IpSb
,
387 IN LIST_ENTRY
*ListHead
390 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
393 OnLink
= (BOOLEAN
) (ListHead
== &IpSb
->OnlinkPrefix
);
395 while (!IsListEmpty (ListHead
)) {
396 PrefixList
= NET_LIST_HEAD (ListHead
, IP6_PREFIX_LIST_ENTRY
, Link
);
397 Ip6DestroyPrefixListEntry (IpSb
, PrefixList
, OnLink
, TRUE
);
402 Callback function when address resolution is finished. It will cancel
403 all the queued frames if the address resolution failed, or transmit them
404 if the request succeeded.
406 @param[in] Context The context of the callback, a pointer to IP6_NEIGHBOR_ENTRY.
416 IP6_NEIGHBOR_ENTRY
*ArpQue
;
418 IP6_LINK_TX_TOKEN
*Token
;
422 ArpQue
= (IP6_NEIGHBOR_ENTRY
*) Context
;
423 if ((ArpQue
== NULL
) || (ArpQue
->Interface
== NULL
)) {
427 IpSb
= ArpQue
->Interface
->Service
;
428 if ((IpSb
== NULL
) || (IpSb
->Signature
!= IP6_SERVICE_SIGNATURE
)) {
433 // ARP resolve failed for some reason. Release all the frame
434 // and ARP queue itself. Ip6FreeArpQue will call the frame's
437 if (NET_MAC_EQUAL (&ArpQue
->LinkAddress
, &mZeroMacAddress
, IpSb
->SnpMode
.HwAddressSize
)) {
438 Ip6FreeNeighborEntry (IpSb
, ArpQue
, FALSE
, TRUE
, EFI_NO_MAPPING
, NULL
, NULL
);
443 // ARP resolve succeeded, Transmit all the frame.
446 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &ArpQue
->Frames
) {
447 RemoveEntryList (Entry
);
449 Token
= NET_LIST_USER_STRUCT (Entry
, IP6_LINK_TX_TOKEN
, Link
);
450 IP6_COPY_LINK_ADDRESS (&Token
->DstMac
, &ArpQue
->LinkAddress
);
453 // Insert the tx token before transmitting it via MNP as the FrameSentDpc
454 // may be called before Mnp->Transmit returns which will remove this tx
455 // token from the SentFrames list. Remove it from the list if the returned
456 // Status of Mnp->Transmit is not EFI_SUCCESS as in this case the
457 // FrameSentDpc won't be queued.
459 InsertTailList (&ArpQue
->Interface
->SentFrames
, &Token
->Link
);
461 Status
= IpSb
->Mnp
->Transmit (IpSb
->Mnp
, &Token
->MnpToken
);
462 if (EFI_ERROR (Status
)) {
463 RemoveEntryList (&Token
->Link
);
464 Token
->CallBack (Token
->Packet
, Status
, 0, Token
->Context
);
466 Ip6FreeLinkTxToken (Token
);
474 // Free the ArpQue only but not the whole neighbor entry.
476 Ip6FreeNeighborEntry (IpSb
, ArpQue
, FALSE
, FALSE
, EFI_SUCCESS
, NULL
, NULL
);
478 if (Sent
&& (ArpQue
->State
== EfiNeighborStale
)) {
479 ArpQue
->State
= EfiNeighborDelay
;
480 ArpQue
->Ticks
= (UINT32
) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME
);
485 Allocate and initialize an IP6 neighbor cache entry.
487 @param[in] IpSb The pointer to the IP6_SERVICE instance.
488 @param[in] CallBack The callback function to be called when
489 address resolution is finished.
490 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
491 @param[in] LinkAddress Points to the MAC address of the neighbor.
494 @return NULL if failed to allocate memory for the neighbor cache entry.
495 Otherwise, point to the created neighbor cache entry.
499 Ip6CreateNeighborEntry (
500 IN IP6_SERVICE
*IpSb
,
501 IN IP6_ARP_CALLBACK CallBack
,
502 IN EFI_IPv6_ADDRESS
*Ip6Address
,
503 IN EFI_MAC_ADDRESS
*LinkAddress OPTIONAL
506 IP6_NEIGHBOR_ENTRY
*Entry
;
507 IP6_DEFAULT_ROUTER
*DefaultRouter
;
509 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
510 ASSERT (Ip6Address
!= NULL
);
512 Entry
= AllocateZeroPool (sizeof (IP6_NEIGHBOR_ENTRY
));
518 Entry
->IsRouter
= FALSE
;
519 Entry
->ArpFree
= FALSE
;
520 Entry
->Dynamic
= FALSE
;
521 Entry
->State
= EfiNeighborInComplete
;
522 Entry
->Transmit
= IP6_MAX_MULTICAST_SOLICIT
+ 1;
523 Entry
->CallBack
= CallBack
;
524 Entry
->Interface
= NULL
;
526 InitializeListHead (&Entry
->Frames
);
528 IP6_COPY_ADDRESS (&Entry
->Neighbor
, Ip6Address
);
530 if (LinkAddress
!= NULL
) {
531 IP6_COPY_LINK_ADDRESS (&Entry
->LinkAddress
, LinkAddress
);
533 IP6_COPY_LINK_ADDRESS (&Entry
->LinkAddress
, &mZeroMacAddress
);
536 InsertHeadList (&IpSb
->NeighborTable
, &Entry
->Link
);
539 // If corresponding default router entry exists, establish the relationship.
541 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, Ip6Address
);
542 if (DefaultRouter
!= NULL
) {
543 DefaultRouter
->NeighborCache
= Entry
;
550 Search a IP6 neighbor cache entry.
552 @param[in] IpSb The pointer to the IP6_SERVICE instance.
553 @param[in] Ip6Address Points to the IPv6 address of the neighbor.
555 @return NULL if it failed to find the matching neighbor cache entry.
556 Otherwise, point to the found neighbor cache entry.
560 Ip6FindNeighborEntry (
561 IN IP6_SERVICE
*IpSb
,
562 IN EFI_IPv6_ADDRESS
*Ip6Address
567 IP6_NEIGHBOR_ENTRY
*Neighbor
;
569 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
570 ASSERT (Ip6Address
!= NULL
);
572 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->NeighborTable
) {
573 Neighbor
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, Link
);
574 if (EFI_IP6_EQUAL (Ip6Address
, &Neighbor
->Neighbor
)) {
575 RemoveEntryList (Entry
);
576 InsertHeadList (&IpSb
->NeighborTable
, Entry
);
586 Free a IP6 neighbor cache entry and remove all the frames on the address
587 resolution queue that pass the FrameToCancel. That is, either FrameToCancel
588 is NULL, or it returns true for the frame.
590 @param[in] IpSb The pointer to the IP6_SERVICE instance.
591 @param[in] NeighborCache The to be free neighbor cache entry.
592 @param[in] SendIcmpError If TRUE, send out ICMP error.
593 @param[in] FullFree If TRUE, remove the neighbor cache entry.
594 Otherwise remove the pending frames.
595 @param[in] IoStatus The status returned to the cancelled frames'
597 @param[in] FrameToCancel Function to select which frame to cancel.
598 This is an optional parameter that may be NULL.
599 @param[in] Context Opaque parameter to the FrameToCancel.
600 Ignored if FrameToCancel is NULL.
602 @retval EFI_INVALID_PARAMETER The input parameter is invalid.
603 @retval EFI_SUCCESS The operation finished successfully.
607 Ip6FreeNeighborEntry (
608 IN IP6_SERVICE
*IpSb
,
609 IN IP6_NEIGHBOR_ENTRY
*NeighborCache
,
610 IN BOOLEAN SendIcmpError
,
612 IN EFI_STATUS IoStatus
,
613 IN IP6_FRAME_TO_CANCEL FrameToCancel OPTIONAL
,
614 IN VOID
*Context OPTIONAL
617 IP6_LINK_TX_TOKEN
*TxToken
;
620 IP6_DEFAULT_ROUTER
*DefaultRouter
;
623 // If FrameToCancel fails, the token will not be released.
624 // To avoid the memory leak, stop this usage model.
626 if (FullFree
&& FrameToCancel
!= NULL
) {
627 return EFI_INVALID_PARAMETER
;
630 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &NeighborCache
->Frames
) {
631 TxToken
= NET_LIST_USER_STRUCT (Entry
, IP6_LINK_TX_TOKEN
, Link
);
633 if (SendIcmpError
&& !IP6_IS_MULTICAST (&TxToken
->Packet
->Ip
.Ip6
->DestinationAddress
)) {
638 &TxToken
->Packet
->Ip
.Ip6
->SourceAddress
,
639 ICMP_V6_DEST_UNREACHABLE
,
640 ICMP_V6_ADDR_UNREACHABLE
,
645 if ((FrameToCancel
== NULL
) || FrameToCancel (TxToken
, Context
)) {
646 RemoveEntryList (Entry
);
647 TxToken
->CallBack (TxToken
->Packet
, IoStatus
, 0, TxToken
->Context
);
648 Ip6FreeLinkTxToken (TxToken
);
652 if (NeighborCache
->ArpFree
&& IsListEmpty (&NeighborCache
->Frames
)) {
653 RemoveEntryList (&NeighborCache
->ArpList
);
654 NeighborCache
->ArpFree
= FALSE
;
658 if (NeighborCache
->IsRouter
) {
659 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &NeighborCache
->Neighbor
);
660 if (DefaultRouter
!= NULL
) {
661 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
665 RemoveEntryList (&NeighborCache
->Link
);
666 FreePool (NeighborCache
);
673 Allocate and initialize an IP6 default router entry.
675 @param[in] IpSb The pointer to the IP6_SERVICE instance.
676 @param[in] Ip6Address The IPv6 address of the default router.
677 @param[in] RouterLifetime The lifetime associated with the default
678 router, in units of seconds.
680 @return NULL if it failed to allocate memory for the default router node.
681 Otherwise, point to the created default router node.
685 Ip6CreateDefaultRouter (
686 IN IP6_SERVICE
*IpSb
,
687 IN EFI_IPv6_ADDRESS
*Ip6Address
,
688 IN UINT16 RouterLifetime
691 IP6_DEFAULT_ROUTER
*Entry
;
692 IP6_ROUTE_ENTRY
*RtEntry
;
694 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
695 ASSERT (Ip6Address
!= NULL
);
697 Entry
= AllocatePool (sizeof (IP6_DEFAULT_ROUTER
));
703 Entry
->Lifetime
= RouterLifetime
;
704 Entry
->NeighborCache
= Ip6FindNeighborEntry (IpSb
, Ip6Address
);
705 IP6_COPY_ADDRESS (&Entry
->Router
, Ip6Address
);
708 // Add a default route into route table with both Destination and PrefixLength set to zero.
710 RtEntry
= Ip6CreateRouteEntry (NULL
, 0, Ip6Address
);
711 if (RtEntry
== NULL
) {
716 InsertHeadList (&IpSb
->RouteTable
->RouteArea
[0], &RtEntry
->Link
);
717 IpSb
->RouteTable
->TotalNum
++;
719 InsertTailList (&IpSb
->DefaultRouterList
, &Entry
->Link
);
725 Destroy an IP6 default router entry.
727 @param[in] IpSb The pointer to the IP6_SERVICE instance.
728 @param[in] DefaultRouter The to be destroyed IP6_DEFAULT_ROUTER.
732 Ip6DestroyDefaultRouter (
733 IN IP6_SERVICE
*IpSb
,
734 IN IP6_DEFAULT_ROUTER
*DefaultRouter
739 RemoveEntryList (&DefaultRouter
->Link
);
742 // Update the Destination Cache - all entries using the time-out router as next-hop
743 // should perform next-hop determination again.
746 Status
= Ip6DelRoute (IpSb
->RouteTable
, NULL
, 0, &DefaultRouter
->Router
);
747 } while (Status
!= EFI_NOT_FOUND
);
749 FreePool (DefaultRouter
);
753 Clean an IP6 default router list.
755 @param[in] IpSb The pointer to the IP6_SERVICE instance.
759 Ip6CleanDefaultRouterList (
763 IP6_DEFAULT_ROUTER
*DefaultRouter
;
765 while (!IsListEmpty (&IpSb
->DefaultRouterList
)) {
766 DefaultRouter
= NET_LIST_HEAD (&IpSb
->DefaultRouterList
, IP6_DEFAULT_ROUTER
, Link
);
767 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
772 Search a default router node from an IP6 default router list.
774 @param[in] IpSb The pointer to the IP6_SERVICE instance.
775 @param[in] Ip6Address The IPv6 address of the to be searched default router node.
777 @return NULL if it failed to find the matching default router node.
778 Otherwise, point to the found default router node.
782 Ip6FindDefaultRouter (
783 IN IP6_SERVICE
*IpSb
,
784 IN EFI_IPv6_ADDRESS
*Ip6Address
788 IP6_DEFAULT_ROUTER
*DefaultRouter
;
790 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
791 ASSERT (Ip6Address
!= NULL
);
793 NET_LIST_FOR_EACH (Entry
, &IpSb
->DefaultRouterList
) {
794 DefaultRouter
= NET_LIST_USER_STRUCT (Entry
, IP6_DEFAULT_ROUTER
, Link
);
795 if (EFI_IP6_EQUAL (Ip6Address
, &DefaultRouter
->Router
)) {
796 return DefaultRouter
;
804 The function to be called after DAD (Duplicate Address Detection) is performed.
806 @param[in] IsDadPassed If TRUE, the DAD operation succeed. Otherwise, the DAD operation failed.
807 @param[in] IpIf Points to the IP6_INTERFACE.
808 @param[in] DadEntry The DAD entry which already performed DAD.
813 IN BOOLEAN IsDadPassed
,
814 IN IP6_INTERFACE
*IpIf
,
815 IN IP6_DAD_ENTRY
*DadEntry
819 IP6_ADDRESS_INFO
*AddrInfo
;
820 EFI_DHCP6_PROTOCOL
*Dhcp6
;
822 EFI_DHCP6_PACKET_OPTION
*Oro
;
823 EFI_DHCP6_RETRANSMISSION InfoReqReXmit
;
825 IpSb
= IpIf
->Service
;
826 AddrInfo
= DadEntry
->AddressInfo
;
832 if (NetIp6IsLinkLocalAddr (&AddrInfo
->Address
)) {
833 ASSERT (!IpSb
->LinkLocalOk
);
835 IP6_COPY_ADDRESS (&IpSb
->LinkLocalAddr
, &AddrInfo
->Address
);
836 IpSb
->LinkLocalOk
= TRUE
;
837 IpIf
->Configured
= TRUE
;
840 // Check whether DHCP6 need to be started.
842 Dhcp6
= IpSb
->Ip6ConfigInstance
.Dhcp6
;
844 if (IpSb
->Dhcp6NeedStart
) {
845 Dhcp6
->Start (Dhcp6
);
846 IpSb
->Dhcp6NeedStart
= FALSE
;
849 if (IpSb
->Dhcp6NeedInfoRequest
) {
851 // Set the exta options to send. Here we only want the option request option
854 Oro
= (EFI_DHCP6_PACKET_OPTION
*) OptBuf
;
855 Oro
->OpCode
= HTONS (IP6_CONFIG_DHCP6_OPTION_ORO
);
856 Oro
->OpLen
= HTONS (2);
857 *((UINT16
*) &Oro
->Data
[0]) = HTONS (IP6_CONFIG_DHCP6_OPTION_DNS_SERVERS
);
859 InfoReqReXmit
.Irt
= 4;
860 InfoReqReXmit
.Mrc
= 64;
861 InfoReqReXmit
.Mrt
= 60;
862 InfoReqReXmit
.Mrd
= 0;
871 IpSb
->Ip6ConfigInstance
.Dhcp6Event
,
872 Ip6ConfigOnDhcp6Reply
,
873 &IpSb
->Ip6ConfigInstance
878 // Add an on-link prefix for link-local address.
880 Ip6CreatePrefixListEntry (
883 (UINT32
) IP6_INFINIT_LIFETIME
,
884 (UINT32
) IP6_INFINIT_LIFETIME
,
885 IP6_LINK_LOCAL_PREFIX_LENGTH
,
891 // Global scope unicast address.
893 Ip6AddAddr (IpIf
, AddrInfo
);
896 // Add an on-link prefix for this address.
898 Ip6CreatePrefixListEntry (
901 AddrInfo
->ValidLifetime
,
902 AddrInfo
->PreferredLifetime
,
903 AddrInfo
->PrefixLength
,
907 IpIf
->Configured
= TRUE
;
911 // Leave the group we joined before.
913 Ip6LeaveGroup (IpSb
, &DadEntry
->Destination
);
916 if (DadEntry
->Callback
!= NULL
) {
917 DadEntry
->Callback (IsDadPassed
, &AddrInfo
->Address
, DadEntry
->Context
);
920 if (!IsDadPassed
&& NetIp6IsLinkLocalAddr (&AddrInfo
->Address
)) {
922 RemoveEntryList (&DadEntry
->Link
);
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
);
979 Status
= EFI_SUCCESS
;
980 IpSb
= IpIf
->Service
;
981 DadXmits
= &IpSb
->Ip6ConfigInstance
.DadXmits
;
984 // Allocate the resources and insert info
986 Entry
= AllocatePool (sizeof (IP6_DAD_ENTRY
));
988 return EFI_OUT_OF_RESOURCES
;
992 // Map the incoming unicast address to solicited-node multicast address
994 Ip6CreateSNMulticastAddr (&AddressInfo
->Address
, &Entry
->Destination
);
997 // Join in the solicited-node multicast address.
999 Status
= Ip6JoinGroup (IpSb
, IpIf
, &Entry
->Destination
);
1000 if (EFI_ERROR (Status
)) {
1005 Entry
->Signature
= IP6_DAD_ENTRY_SIGNATURE
;
1006 Entry
->MaxTransmit
= DadXmits
->DupAddrDetectTransmits
;
1007 Entry
->Transmit
= 0;
1009 MaxDelayTick
= IP6_MAX_RTR_SOLICITATION_DELAY
/ IP6_TIMER_INTERVAL_IN_MS
;
1010 Entry
->RetransTick
= (MaxDelayTick
* ((NET_RANDOM (NetRandomInitSeed ()) % 5) + 1)) / 5;
1011 Entry
->AddressInfo
= AddressInfo
;
1012 Entry
->Callback
= Callback
;
1013 Entry
->Context
= Context
;
1014 InsertTailList (&IpIf
->DupAddrDetectList
, &Entry
->Link
);
1016 if (Entry
->MaxTransmit
== 0) {
1018 // DAD is disabled on this interface, immediately mark this DAD successful.
1020 Ip6OnDADFinished (TRUE
, IpIf
, Entry
);
1027 Search IP6_DAD_ENTRY from the Duplicate Address Detection List.
1029 @param[in] IpSb The pointer to the IP6_SERVICE instance.
1030 @param[in] Target The address information which needs DAD performed .
1031 @param[out] Interface If not NULL, output the IP6 interface that configures
1032 the tentative address.
1034 @return NULL if failed to find the matching DAD entry.
1035 Otherwise, point to the found DAD entry.
1040 IN IP6_SERVICE
*IpSb
,
1041 IN EFI_IPv6_ADDRESS
*Target
,
1042 OUT IP6_INTERFACE
**Interface OPTIONAL
1047 IP6_INTERFACE
*IpIf
;
1048 IP6_DAD_ENTRY
*DupAddrDetect
;
1049 IP6_ADDRESS_INFO
*AddrInfo
;
1051 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
1052 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
1054 NET_LIST_FOR_EACH (Entry2
, &IpIf
->DupAddrDetectList
) {
1055 DupAddrDetect
= NET_LIST_USER_STRUCT_S (Entry2
, IP6_DAD_ENTRY
, Link
, IP6_DAD_ENTRY_SIGNATURE
);
1056 AddrInfo
= DupAddrDetect
->AddressInfo
;
1057 if (EFI_IP6_EQUAL (&AddrInfo
->Address
, Target
)) {
1058 if (Interface
!= NULL
) {
1061 return DupAddrDetect
;
1070 Generate router solicit message and send it out to Destination Address or
1071 All Router Link Local scope multicast address.
1073 @param[in] IpSb The IP service to send the packet.
1074 @param[in] Interface If not NULL, points to the IP6 interface to send
1076 @param[in] SourceAddress If not NULL, the source address of the message.
1077 @param[in] DestinationAddress If not NULL, the destination address of the message.
1078 @param[in] SourceLinkAddress If not NULL, the MAC address of the source.
1079 A source link-layer address option will be appended
1082 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1084 @retval EFI_SUCCESS The router solicit message was successfully sent.
1088 Ip6SendRouterSolicit (
1089 IN IP6_SERVICE
*IpSb
,
1090 IN IP6_INTERFACE
*Interface OPTIONAL
,
1091 IN EFI_IPv6_ADDRESS
*SourceAddress OPTIONAL
,
1092 IN EFI_IPv6_ADDRESS
*DestinationAddress OPTIONAL
,
1093 IN EFI_MAC_ADDRESS
*SourceLinkAddress OPTIONAL
1097 EFI_IP6_HEADER Head
;
1098 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
1099 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
1101 IP6_INTERFACE
*IpIf
;
1103 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
1106 if (IpIf
== NULL
&& IpSb
->DefaultInterface
!= NULL
) {
1107 IpIf
= IpSb
->DefaultInterface
;
1111 // Generate the packet to be sent
1114 PayloadLen
= (UINT16
) sizeof (IP6_ICMP_INFORMATION_HEAD
);
1115 if (SourceLinkAddress
!= NULL
) {
1116 PayloadLen
+= sizeof (IP6_ETHER_ADDR_OPTION
);
1119 Packet
= NetbufAlloc (sizeof (EFI_IP6_HEADER
) + (UINT32
) PayloadLen
);
1120 if (Packet
== NULL
) {
1121 return EFI_OUT_OF_RESOURCES
;
1125 // Create the basic IPv6 header.
1127 Head
.FlowLabelL
= 0;
1128 Head
.FlowLabelH
= 0;
1129 Head
.PayloadLength
= HTONS (PayloadLen
);
1130 Head
.NextHeader
= IP6_ICMP
;
1131 Head
.HopLimit
= IP6_HOP_LIMIT
;
1133 if (SourceAddress
!= NULL
) {
1134 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
1136 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
1140 if (DestinationAddress
!= NULL
) {
1141 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
1143 Ip6SetToAllNodeMulticast (TRUE
, IP6_LINK_LOCAL_SCOPE
, &Head
.DestinationAddress
);
1146 NetbufReserve (Packet
, sizeof (EFI_IP6_HEADER
));
1149 // Fill in the ICMP header, and Source link-layer address if contained.
1152 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufAllocSpace (Packet
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
1153 ASSERT (IcmpHead
!= NULL
);
1154 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
1155 IcmpHead
->Head
.Type
= ICMP_V6_ROUTER_SOLICIT
;
1156 IcmpHead
->Head
.Code
= 0;
1158 LinkLayerOption
= NULL
;
1159 if (SourceLinkAddress
!= NULL
) {
1160 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*) NetbufAllocSpace (
1162 sizeof (IP6_ETHER_ADDR_OPTION
),
1165 ASSERT (LinkLayerOption
!= NULL
);
1166 LinkLayerOption
->Type
= Ip6OptionEtherSource
;
1167 LinkLayerOption
->Length
= (UINT8
) sizeof (IP6_ETHER_ADDR_OPTION
);
1168 CopyMem (LinkLayerOption
->EtherAddr
, SourceLinkAddress
, 6);
1172 // Transmit the packet
1174 return Ip6Output (IpSb
, IpIf
, NULL
, Packet
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);
1178 Generate a Neighbor Advertisement message and send it out to Destination Address.
1180 @param[in] IpSb The IP service to send the packet.
1181 @param[in] SourceAddress The source address of the message.
1182 @param[in] DestinationAddress The destination address of the message.
1183 @param[in] TargetIp6Address The target address field in the Neighbor Solicitation
1184 message that prompted this advertisement.
1185 @param[in] TargetLinkAddress The MAC address for the target, i.e. the sender
1186 of the advertisement.
1187 @param[in] IsRouter If TRUE, indicates the sender is a router.
1188 @param[in] Override If TRUE, indicates the advertisement should override
1189 an existing cache entry and update the MAC address.
1190 @param[in] Solicited If TRUE, indicates the advertisement was sent
1191 in response to a Neighbor Solicitation from
1192 the Destination address.
1194 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1196 @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
1200 Ip6SendNeighborAdvertise (
1201 IN IP6_SERVICE
*IpSb
,
1202 IN EFI_IPv6_ADDRESS
*SourceAddress
,
1203 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
1204 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
1205 IN EFI_MAC_ADDRESS
*TargetLinkAddress
,
1206 IN BOOLEAN IsRouter
,
1207 IN BOOLEAN Override
,
1208 IN BOOLEAN Solicited
1212 EFI_IP6_HEADER Head
;
1213 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
1214 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
1215 EFI_IPv6_ADDRESS
*Target
;
1218 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
1221 // The Neighbor Advertisement message must include a Target link-layer address option
1222 // when responding to multicast solicitation and should include such option when
1223 // responding to unicast solicitation. It also must include such option as unsolicited
1226 ASSERT (DestinationAddress
!= NULL
&& TargetIp6Address
!= NULL
&& TargetLinkAddress
!= NULL
);
1228 PayloadLen
= (UINT16
) (sizeof (IP6_ICMP_INFORMATION_HEAD
) + sizeof (EFI_IPv6_ADDRESS
) + sizeof (IP6_ETHER_ADDR_OPTION
));
1231 // Generate the packet to be sent
1234 Packet
= NetbufAlloc (sizeof (EFI_IP6_HEADER
) + (UINT32
) PayloadLen
);
1235 if (Packet
== NULL
) {
1236 return EFI_OUT_OF_RESOURCES
;
1240 // Create the basic IPv6 header.
1242 Head
.FlowLabelL
= 0;
1243 Head
.FlowLabelH
= 0;
1244 Head
.PayloadLength
= HTONS (PayloadLen
);
1245 Head
.NextHeader
= IP6_ICMP
;
1246 Head
.HopLimit
= IP6_HOP_LIMIT
;
1248 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
1249 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
1251 NetbufReserve (Packet
, sizeof (EFI_IP6_HEADER
));
1254 // Fill in the ICMP header, Target address, and Target link-layer address.
1255 // Set the Router flag, Solicited flag and Override flag.
1258 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufAllocSpace (Packet
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
1259 ASSERT (IcmpHead
!= NULL
);
1260 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
1261 IcmpHead
->Head
.Type
= ICMP_V6_NEIGHBOR_ADVERTISE
;
1262 IcmpHead
->Head
.Code
= 0;
1265 IcmpHead
->Fourth
|= IP6_IS_ROUTER_FLAG
;
1269 IcmpHead
->Fourth
|= IP6_SOLICITED_FLAG
;
1273 IcmpHead
->Fourth
|= IP6_OVERRIDE_FLAG
;
1276 Target
= (EFI_IPv6_ADDRESS
*) NetbufAllocSpace (Packet
, sizeof (EFI_IPv6_ADDRESS
), FALSE
);
1277 ASSERT (Target
!= NULL
);
1278 IP6_COPY_ADDRESS (Target
, TargetIp6Address
);
1280 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*) NetbufAllocSpace (
1282 sizeof (IP6_ETHER_ADDR_OPTION
),
1285 ASSERT (LinkLayerOption
!= NULL
);
1286 LinkLayerOption
->Type
= Ip6OptionEtherTarget
;
1287 LinkLayerOption
->Length
= 1;
1288 CopyMem (LinkLayerOption
->EtherAddr
, TargetLinkAddress
, 6);
1291 // Transmit the packet
1293 return Ip6Output (IpSb
, NULL
, NULL
, Packet
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);
1297 Generate the Neighbor Solicitation message and send it to the Destination Address.
1299 @param[in] IpSb The IP service to send the packet
1300 @param[in] SourceAddress The source address of the message.
1301 @param[in] DestinationAddress The destination address of the message.
1302 @param[in] TargetIp6Address The IP address of the target of the solicitation.
1303 It must not be a multicast address.
1304 @param[in] SourceLinkAddress The MAC address for the sender. If not NULL,
1305 a source link-layer address option will be appended
1308 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
1309 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1311 @retval EFI_SUCCESS The Neighbor Advertise message was successfully sent.
1315 Ip6SendNeighborSolicit (
1316 IN IP6_SERVICE
*IpSb
,
1317 IN EFI_IPv6_ADDRESS
*SourceAddress
,
1318 IN EFI_IPv6_ADDRESS
*DestinationAddress
,
1319 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
1320 IN EFI_MAC_ADDRESS
*SourceLinkAddress OPTIONAL
1324 EFI_IP6_HEADER Head
;
1325 IP6_ICMP_INFORMATION_HEAD
*IcmpHead
;
1326 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
1327 EFI_IPv6_ADDRESS
*Target
;
1330 IP6_NEIGHBOR_ENTRY
*Neighbor
;
1333 // Check input parameters
1335 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
1336 if (DestinationAddress
== NULL
|| TargetIp6Address
== NULL
) {
1337 return EFI_INVALID_PARAMETER
;
1342 if (SourceAddress
== NULL
|| (SourceAddress
!= NULL
&& NetIp6IsUnspecifiedAddr (SourceAddress
))) {
1347 // The Neighbor Solicitation message should include a source link-layer address option
1348 // if the solicitation is not sent by performing DAD - Duplicate Address Detection.
1349 // Otherwise must not include it.
1351 PayloadLen
= (UINT16
) (sizeof (IP6_ICMP_INFORMATION_HEAD
) + sizeof (EFI_IPv6_ADDRESS
));
1354 if (SourceLinkAddress
== NULL
) {
1355 return EFI_INVALID_PARAMETER
;
1358 PayloadLen
= (UINT16
) (PayloadLen
+ sizeof (IP6_ETHER_ADDR_OPTION
));
1362 // Generate the packet to be sent
1365 Packet
= NetbufAlloc (sizeof (EFI_IP6_HEADER
) + (UINT32
) PayloadLen
);
1366 if (Packet
== NULL
) {
1367 return EFI_OUT_OF_RESOURCES
;
1371 // Create the basic IPv6 header
1373 Head
.FlowLabelL
= 0;
1374 Head
.FlowLabelH
= 0;
1375 Head
.PayloadLength
= HTONS (PayloadLen
);
1376 Head
.NextHeader
= IP6_ICMP
;
1377 Head
.HopLimit
= IP6_HOP_LIMIT
;
1379 if (SourceAddress
!= NULL
) {
1380 IP6_COPY_ADDRESS (&Head
.SourceAddress
, SourceAddress
);
1382 ZeroMem (&Head
.SourceAddress
, sizeof (EFI_IPv6_ADDRESS
));
1385 IP6_COPY_ADDRESS (&Head
.DestinationAddress
, DestinationAddress
);
1387 NetbufReserve (Packet
, sizeof (EFI_IP6_HEADER
));
1390 // Fill in the ICMP header, Target address, and Source link-layer address.
1392 IcmpHead
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufAllocSpace (Packet
, sizeof (IP6_ICMP_INFORMATION_HEAD
), FALSE
);
1393 ASSERT (IcmpHead
!= NULL
);
1394 ZeroMem (IcmpHead
, sizeof (IP6_ICMP_INFORMATION_HEAD
));
1395 IcmpHead
->Head
.Type
= ICMP_V6_NEIGHBOR_SOLICIT
;
1396 IcmpHead
->Head
.Code
= 0;
1398 Target
= (EFI_IPv6_ADDRESS
*) NetbufAllocSpace (Packet
, sizeof (EFI_IPv6_ADDRESS
), FALSE
);
1399 ASSERT (Target
!= NULL
);
1400 IP6_COPY_ADDRESS (Target
, TargetIp6Address
);
1402 LinkLayerOption
= NULL
;
1406 // Fill in the source link-layer address option
1408 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*) NetbufAllocSpace (
1410 sizeof (IP6_ETHER_ADDR_OPTION
),
1413 ASSERT (LinkLayerOption
!= NULL
);
1414 LinkLayerOption
->Type
= Ip6OptionEtherSource
;
1415 LinkLayerOption
->Length
= 1;
1416 CopyMem (LinkLayerOption
->EtherAddr
, SourceLinkAddress
, 6);
1420 // Create a Neighbor Cache entry in the INCOMPLETE state when performing
1421 // address resolution.
1423 if (!IsDAD
&& Ip6IsSNMulticastAddr (DestinationAddress
)) {
1424 Neighbor
= Ip6FindNeighborEntry (IpSb
, TargetIp6Address
);
1425 if (Neighbor
== NULL
) {
1426 Neighbor
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, TargetIp6Address
, NULL
);
1427 ASSERT (Neighbor
!= NULL
);
1432 // Transmit the packet
1434 return Ip6Output (IpSb
, IpSb
->DefaultInterface
, NULL
, Packet
, &Head
, NULL
, 0, Ip6SysPacketSent
, NULL
);
1438 Process the Neighbor Solicitation message. The message may be sent for Duplicate
1439 Address Detection or Address Resolution.
1441 @param[in] IpSb The IP service that received the packet.
1442 @param[in] Head The IP head of the message.
1443 @param[in] Packet The content of the message with IP head removed.
1445 @retval EFI_SUCCESS The packet processed successfully.
1446 @retval EFI_INVALID_PARAMETER The packet is invalid.
1447 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1448 @retval Others Failed to process the packet.
1452 Ip6ProcessNeighborSolicit (
1453 IN IP6_SERVICE
*IpSb
,
1454 IN EFI_IP6_HEADER
*Head
,
1458 IP6_ICMP_INFORMATION_HEAD Icmp
;
1459 EFI_IPv6_ADDRESS Target
;
1460 IP6_ETHER_ADDR_OPTION LinkLayerOption
;
1463 BOOLEAN IsMaintained
;
1464 IP6_DAD_ENTRY
*DupAddrDetect
;
1465 IP6_INTERFACE
*IpIf
;
1466 IP6_NEIGHBOR_ENTRY
*Neighbor
;
1468 BOOLEAN UpdateCache
;
1469 EFI_IPv6_ADDRESS Dest
;
1476 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
1477 NetbufCopy (Packet
, sizeof (Icmp
), sizeof (Target
), Target
.Addr
);
1480 // Perform Message Validation:
1481 // The IP Hop Limit field has a value of 255, i.e., the packet
1482 // could not possibly have been forwarded by a router.
1484 // Target Address is not a multicast address.
1486 Status
= EFI_INVALID_PARAMETER
;
1488 if (Head
->HopLimit
!= IP6_HOP_LIMIT
|| Icmp
.Head
.Code
!= 0 || !NetIp6IsValidUnicast (&Target
)) {
1493 // ICMP length is 24 or more octets.
1496 if (Head
->PayloadLength
< IP6_ND_LENGTH
) {
1499 OptionLen
= (UINT16
) (Head
->PayloadLength
- IP6_ND_LENGTH
);
1500 Option
= NetbufGetByte (Packet
, IP6_ND_LENGTH
, NULL
);
1503 // All included options should have a length that is greater than zero.
1505 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
1510 IsDAD
= NetIp6IsUnspecifiedAddr (&Head
->SourceAddress
);
1511 IsUnicast
= (BOOLEAN
) !Ip6IsSNMulticastAddr (&Head
->DestinationAddress
);
1512 IsMaintained
= Ip6IsOneOfSetAddress (IpSb
, &Target
, &IpIf
, NULL
);
1515 if (OptionLen
>= sizeof (IP6_ETHER_ADDR_OPTION
)) {
1519 sizeof (IP6_ETHER_ADDR_OPTION
),
1520 (UINT8
*) &LinkLayerOption
1523 // The solicitation for neighbor discovery should include a source link-layer
1524 // address option. If the option is not recognized, silently ignore it.
1526 if (LinkLayerOption
.Type
== Ip6OptionEtherSource
) {
1529 // If the IP source address is the unspecified address, the source
1530 // link-layer address option must not be included in the message.
1540 // If the IP source address is the unspecified address, the IP
1541 // destination address is a solicited-node multicast address.
1543 if (IsDAD
&& IsUnicast
) {
1548 // If the target address is tentative, and the source address is a unicast address,
1549 // the solicitation's sender is performing address resolution on the target;
1550 // the solicitation should be silently ignored.
1552 if (!IsDAD
&& !IsMaintained
) {
1557 // If received unicast neighbor solicitation but destination is not this node,
1560 if (IsUnicast
&& !IsMaintained
) {
1565 // In DAD, when target address is a tentative address,
1566 // process the received neighbor solicitation message but not send out response.
1568 if (IsDAD
&& !IsMaintained
) {
1569 DupAddrDetect
= Ip6FindDADEntry (IpSb
, &Target
, &IpIf
);
1570 if (DupAddrDetect
!= NULL
) {
1571 if (DupAddrDetect
->Transmit
== 0) {
1573 // The NS is from another node to performing DAD on the same address since
1574 // we haven't send out any NS yet. Fail DAD for the tentative address.
1576 Ip6OnDADFinished (FALSE
, IpIf
, DupAddrDetect
);
1577 Status
= EFI_ICMP_ERROR
;
1582 // Check the MAC address of the incoming packet.
1584 if (IpSb
->RecvRequest
.MnpToken
.Packet
.RxData
== NULL
) {
1588 MacAddress
= IpSb
->RecvRequest
.MnpToken
.Packet
.RxData
->SourceAddress
;
1589 if (MacAddress
!= NULL
) {
1592 &IpSb
->SnpMode
.CurrentAddress
,
1593 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
;
1614 // If the solicitation does not contain a link-layer address, DO NOT create or
1615 // update the neighbor cache entries.
1618 Neighbor
= Ip6FindNeighborEntry (IpSb
, &Head
->SourceAddress
);
1619 UpdateCache
= FALSE
;
1621 if (Neighbor
== NULL
) {
1622 Neighbor
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, &Head
->SourceAddress
, NULL
);
1623 if (Neighbor
== NULL
) {
1624 Status
= EFI_OUT_OF_RESOURCES
;
1629 if (CompareMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6) != 0) {
1635 Neighbor
->State
= EfiNeighborStale
;
1636 Neighbor
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
1637 CopyMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1639 // Send queued packets if exist.
1641 Neighbor
->CallBack ((VOID
*) Neighbor
);
1646 // Sends a Neighbor Advertisement as response.
1647 // Set the Router flag to zero since the node is a host.
1648 // If the source address of the solicitation is unspeicifed, and target address
1649 // is one of the maintained address, reply a unsolicited multicast advertisement.
1651 if (IsDAD
&& IsMaintained
) {
1653 Ip6SetToAllNodeMulticast (FALSE
, IP6_LINK_LOCAL_SCOPE
, &Dest
);
1656 IP6_COPY_ADDRESS (&Dest
, &Head
->SourceAddress
);
1659 Status
= Ip6SendNeighborAdvertise (
1664 &IpSb
->SnpMode
.CurrentAddress
,
1670 NetbufFree (Packet
);
1675 Process the Neighbor Advertisement message.
1677 @param[in] IpSb The IP service that received the packet.
1678 @param[in] Head The IP head of the message.
1679 @param[in] Packet The content of the message with IP head removed.
1681 @retval EFI_SUCCESS The packet processed successfully.
1682 @retval EFI_INVALID_PARAMETER The packet is invalid.
1683 @retval EFI_ICMP_ERROR The packet indicates that DAD is failed.
1684 @retval Others Failed to process the packet.
1688 Ip6ProcessNeighborAdvertise (
1689 IN IP6_SERVICE
*IpSb
,
1690 IN EFI_IP6_HEADER
*Head
,
1694 IP6_ICMP_INFORMATION_HEAD Icmp
;
1695 EFI_IPv6_ADDRESS Target
;
1696 IP6_ETHER_ADDR_OPTION LinkLayerOption
;
1699 IP6_NEIGHBOR_ENTRY
*Neighbor
;
1700 IP6_DEFAULT_ROUTER
*DefaultRouter
;
1704 IP6_DAD_ENTRY
*DupAddrDetect
;
1705 IP6_INTERFACE
*IpIf
;
1710 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
1711 NetbufCopy (Packet
, sizeof (Icmp
), sizeof (Target
), Target
.Addr
);
1714 // Validate the incoming Neighbor Advertisement
1716 Status
= EFI_INVALID_PARAMETER
;
1718 // The IP Hop Limit field has a value of 255, i.e., the packet
1719 // could not possibly have been forwarded by a router.
1721 // Target Address is not a multicast address.
1723 if (Head
->HopLimit
!= IP6_HOP_LIMIT
|| Icmp
.Head
.Code
!= 0 || !NetIp6IsValidUnicast (&Target
)) {
1728 // ICMP length is 24 or more octets.
1732 if (Head
->PayloadLength
< IP6_ND_LENGTH
) {
1735 OptionLen
= (UINT16
) (Head
->PayloadLength
- IP6_ND_LENGTH
);
1736 Option
= NetbufGetByte (Packet
, IP6_ND_LENGTH
, NULL
);
1739 // All included options should have a length that is greater than zero.
1741 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
1747 // If the IP destination address is a multicast address, Solicited Flag is ZERO.
1750 if ((Icmp
.Fourth
& IP6_SOLICITED_FLAG
) == IP6_SOLICITED_FLAG
) {
1753 if (IP6_IS_MULTICAST (&Head
->DestinationAddress
) && Solicited
) {
1758 // DAD - Check whether the Target is one of our tentative address.
1760 DupAddrDetect
= Ip6FindDADEntry (IpSb
, &Target
, &IpIf
);
1761 if (DupAddrDetect
!= NULL
) {
1763 // DAD fails, some other node is using this address.
1765 NetbufFree (Packet
);
1766 Ip6OnDADFinished (FALSE
, IpIf
, DupAddrDetect
);
1767 return EFI_ICMP_ERROR
;
1771 // Search the Neighbor Cache for the target's entry. If no entry exists,
1772 // the advertisement should be silently discarded.
1774 Neighbor
= Ip6FindNeighborEntry (IpSb
, &Target
);
1775 if (Neighbor
== NULL
) {
1780 // Get IsRouter Flag and Override Flag
1784 if ((Icmp
.Fourth
& IP6_IS_ROUTER_FLAG
) == IP6_IS_ROUTER_FLAG
) {
1787 if ((Icmp
.Fourth
& IP6_OVERRIDE_FLAG
) == IP6_OVERRIDE_FLAG
) {
1792 // Check whether link layer option is included.
1794 if (OptionLen
>= sizeof (IP6_ETHER_ADDR_OPTION
)) {
1798 sizeof (IP6_ETHER_ADDR_OPTION
),
1799 (UINT8
*) &LinkLayerOption
1802 if (LinkLayerOption
.Type
== Ip6OptionEtherTarget
) {
1809 Compare
= CompareMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1812 if (!Neighbor
->IsRouter
&& IsRouter
) {
1813 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &Target
);
1814 if (DefaultRouter
!= NULL
) {
1815 DefaultRouter
->NeighborCache
= Neighbor
;
1819 if (Neighbor
->State
== EfiNeighborInComplete
) {
1821 // If the target's Neighbor Cache entry is in INCOMPLETE state and no
1822 // Target Link-Layer address option is included while link layer has
1823 // address, the message should be silently discarded.
1829 // Update the Neighbor Cache
1831 CopyMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1833 Neighbor
->State
= EfiNeighborReachable
;
1834 Neighbor
->Ticks
= IP6_GET_TICKS (IpSb
->ReachableTime
);
1836 Neighbor
->State
= EfiNeighborStale
;
1837 Neighbor
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
1839 // Send any packets queued for the neighbor awaiting address resolution.
1841 Neighbor
->CallBack ((VOID
*) Neighbor
);
1844 Neighbor
->IsRouter
= IsRouter
;
1847 if (!Override
&& Compare
!= 0) {
1849 // When the Override Flag is clear and supplied link-layer address differs from
1850 // that in the cache, if the state of the entry is not REACHABLE, ignore the
1851 // message. Otherwise set it to STALE but do not update the entry in any
1854 if (Neighbor
->State
== EfiNeighborReachable
) {
1855 Neighbor
->State
= EfiNeighborStale
;
1856 Neighbor
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
1860 CopyMem (Neighbor
->LinkAddress
.Addr
, LinkLayerOption
.EtherAddr
, 6);
1863 // Update the entry's state
1866 Neighbor
->State
= EfiNeighborReachable
;
1867 Neighbor
->Ticks
= IP6_GET_TICKS (IpSb
->ReachableTime
);
1870 Neighbor
->State
= EfiNeighborStale
;
1871 Neighbor
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
1876 // When IsRouter is changed from TRUE to FALSE, remove the router from the
1877 // Default Router List and remove the Destination Cache entries for all destinations
1878 // using the neighbor as a router.
1880 if (Neighbor
->IsRouter
&& !IsRouter
) {
1881 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &Target
);
1882 if (DefaultRouter
!= NULL
) {
1883 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
1887 Neighbor
->IsRouter
= IsRouter
;
1891 if (Neighbor
->State
== EfiNeighborReachable
) {
1892 Neighbor
->CallBack ((VOID
*) Neighbor
);
1895 Status
= EFI_SUCCESS
;
1898 NetbufFree (Packet
);
1903 Process the Router Advertisement message according to RFC4861.
1905 @param[in] IpSb The IP service that received the packet.
1906 @param[in] Head The IP head of the message.
1907 @param[in] Packet The content of the message with the IP head removed.
1909 @retval EFI_SUCCESS The packet processed successfully.
1910 @retval EFI_INVALID_PARAMETER The packet is invalid.
1911 @retval EFI_OUT_OF_RESOURCES Insufficient resources to complete the
1913 @retval Others Failed to process the packet.
1917 Ip6ProcessRouterAdvertise (
1918 IN IP6_SERVICE
*IpSb
,
1919 IN EFI_IP6_HEADER
*Head
,
1923 IP6_ICMP_INFORMATION_HEAD Icmp
;
1924 UINT32 ReachableTime
;
1925 UINT32 RetransTimer
;
1926 UINT16 RouterLifetime
;
1930 IP6_ETHER_ADDR_OPTION LinkLayerOption
;
1935 IP6_DEFAULT_ROUTER
*DefaultRouter
;
1936 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
1937 EFI_MAC_ADDRESS LinkLayerAddress
;
1938 IP6_MTU_OPTION MTUOption
;
1939 IP6_PREFIX_INFO_OPTION PrefixOption
;
1940 IP6_PREFIX_LIST_ENTRY
*PrefixList
;
1943 EFI_IPv6_ADDRESS StatelessAddress
;
1949 Status
= EFI_INVALID_PARAMETER
;
1951 if (IpSb
->Ip6ConfigInstance
.Policy
!= Ip6ConfigPolicyAutomatic
) {
1953 // Skip the process below as it's not required under the current policy.
1958 NetbufCopy (Packet
, 0, sizeof (Icmp
), (UINT8
*) &Icmp
);
1961 // Validate the incoming Router Advertisement
1965 // The IP source address must be a link-local address
1967 if (!NetIp6IsLinkLocalAddr (&Head
->SourceAddress
)) {
1971 // The IP Hop Limit field has a value of 255, i.e. the packet
1972 // could not possibly have been forwarded by a router.
1974 // ICMP length (derived from the IP length) is 16 or more octets.
1976 if (Head
->HopLimit
!= IP6_HOP_LIMIT
|| Icmp
.Head
.Code
!= 0 ||
1977 Head
->PayloadLength
< IP6_RA_LENGTH
) {
1982 // All included options have a length that is greater than zero.
1984 OptionLen
= (UINT16
) (Head
->PayloadLength
- IP6_RA_LENGTH
);
1985 Option
= NetbufGetByte (Packet
, IP6_RA_LENGTH
, NULL
);
1987 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
1992 // Process Fourth field.
1993 // In Router Advertisement, Fourth is composed of CurHopLimit (8bit), M flag, O flag,
1994 // and Router Lifetime (16 bit).
1997 Fourth
= NTOHL (Icmp
.Fourth
);
1998 CopyMem (&RouterLifetime
, &Fourth
, sizeof (UINT16
));
2001 // If the source address already in the default router list, update it.
2002 // Otherwise create a new entry.
2003 // A Lifetime of zero indicates that the router is not a default router.
2005 DefaultRouter
= Ip6FindDefaultRouter (IpSb
, &Head
->SourceAddress
);
2006 if (DefaultRouter
== NULL
) {
2007 if (RouterLifetime
!= 0) {
2008 DefaultRouter
= Ip6CreateDefaultRouter (IpSb
, &Head
->SourceAddress
, RouterLifetime
);
2009 if (DefaultRouter
== NULL
) {
2010 Status
= EFI_OUT_OF_RESOURCES
;
2015 if (RouterLifetime
!= 0) {
2016 DefaultRouter
->Lifetime
= RouterLifetime
;
2018 // Check the corresponding neighbor cache entry here.
2020 if (DefaultRouter
->NeighborCache
== NULL
) {
2021 DefaultRouter
->NeighborCache
= Ip6FindNeighborEntry (IpSb
, &Head
->SourceAddress
);
2025 // If the address is in the host's default router list and the router lifetime is zero,
2026 // immediately time-out the entry.
2028 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
2032 CurHopLimit
= *((UINT8
*) &Fourth
+ 3);
2033 if (CurHopLimit
!= 0) {
2034 IpSb
->CurHopLimit
= CurHopLimit
;
2039 if ((*((UINT8
*) &Fourth
+ 2) & IP6_M_ADDR_CONFIG_FLAG
) == IP6_M_ADDR_CONFIG_FLAG
) {
2042 if ((*((UINT8
*) &Fourth
+ 2) & IP6_O_CONFIG_FLAG
) == IP6_O_CONFIG_FLAG
) {
2047 if (Mflag
|| Oflag
) {
2049 // Use Ip6Config to get available addresses or other configuration from DHCP.
2051 Ip6ConfigStartStatefulAutoConfig (&IpSb
->Ip6ConfigInstance
, Oflag
);
2055 // Process Reachable Time and Retrans Timer fields.
2057 NetbufCopy (Packet
, sizeof (Icmp
), sizeof (UINT32
), (UINT8
*) &ReachableTime
);
2058 NetbufCopy (Packet
, sizeof (Icmp
) + sizeof (UINT32
), sizeof (UINT32
), (UINT8
*) &RetransTimer
);
2059 ReachableTime
= NTOHL (ReachableTime
);
2060 RetransTimer
= NTOHL (RetransTimer
);
2062 if (ReachableTime
!= 0 && ReachableTime
!= IpSb
->BaseReachableTime
) {
2064 // If new value is not unspecified and differs from the previous one, record it
2065 // in BaseReachableTime and recompute a ReachableTime.
2067 IpSb
->BaseReachableTime
= ReachableTime
;
2068 Ip6UpdateReachableTime (IpSb
);
2071 if (RetransTimer
!= 0) {
2072 IpSb
->RetransTimer
= RetransTimer
;
2076 // IsRouter flag must be set to TRUE if corresponding neighbor cache entry exists.
2078 NeighborCache
= Ip6FindNeighborEntry (IpSb
, &Head
->SourceAddress
);
2079 if (NeighborCache
!= NULL
) {
2080 NeighborCache
->IsRouter
= TRUE
;
2084 // If an valid router advertisment is received, stops router solicitation.
2086 IpSb
->RouterAdvertiseReceived
= TRUE
;
2089 // The only defined options that may appear are the Source
2090 // Link-Layer Address, Prefix information and MTU options.
2091 // All included options have a length that is greater than zero.
2094 while (Offset
< Head
->PayloadLength
) {
2095 NetbufCopy (Packet
, Offset
, sizeof (UINT8
), &Type
);
2097 case Ip6OptionEtherSource
:
2099 // Update the neighbor cache
2101 NetbufCopy (Packet
, Offset
, sizeof (IP6_ETHER_ADDR_OPTION
), (UINT8
*) &LinkLayerOption
);
2102 if (LinkLayerOption
.Length
<= 0) {
2106 ZeroMem (&LinkLayerAddress
, sizeof (EFI_MAC_ADDRESS
));
2107 CopyMem (&LinkLayerAddress
, LinkLayerOption
.EtherAddr
, 6);
2109 if (NeighborCache
== NULL
) {
2110 NeighborCache
= Ip6CreateNeighborEntry (
2113 &Head
->SourceAddress
,
2116 if (NeighborCache
== NULL
) {
2117 Status
= EFI_OUT_OF_RESOURCES
;
2120 NeighborCache
->IsRouter
= TRUE
;
2121 NeighborCache
->State
= EfiNeighborStale
;
2122 NeighborCache
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
2124 Result
= CompareMem (&LinkLayerAddress
, &NeighborCache
->LinkAddress
, 6);
2127 // If the link-local address is the same as that already in the cache,
2128 // the cache entry's state remains unchanged. Otherwise update the
2129 // reachability state to STALE.
2131 if ((NeighborCache
->State
== EfiNeighborInComplete
) || (Result
!= 0)) {
2132 CopyMem (&NeighborCache
->LinkAddress
, &LinkLayerAddress
, 6);
2134 NeighborCache
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
2136 if (NeighborCache
->State
== EfiNeighborInComplete
) {
2138 // Send queued packets if exist.
2140 NeighborCache
->State
= EfiNeighborStale
;
2141 NeighborCache
->CallBack ((VOID
*) NeighborCache
);
2143 NeighborCache
->State
= EfiNeighborStale
;
2148 Offset
= (UINT16
) (Offset
+ (UINT16
) LinkLayerOption
.Length
* 8);
2150 case Ip6OptionPrefixInfo
:
2151 NetbufCopy (Packet
, Offset
, sizeof (IP6_PREFIX_INFO_OPTION
), (UINT8
*) &PrefixOption
);
2152 if (PrefixOption
.Length
!= 4) {
2155 PrefixOption
.ValidLifetime
= NTOHL (PrefixOption
.ValidLifetime
);
2156 PrefixOption
.PreferredLifetime
= NTOHL (PrefixOption
.PreferredLifetime
);
2159 // Get L and A flag, recorded in the lower 2 bits of Reserved1
2162 if ((PrefixOption
.Reserved1
& IP6_ON_LINK_FLAG
) == IP6_ON_LINK_FLAG
) {
2166 if ((PrefixOption
.Reserved1
& IP6_AUTO_CONFIG_FLAG
) == IP6_AUTO_CONFIG_FLAG
) {
2171 // If the prefix is the link-local prefix, silently ignore the prefix option.
2173 if (PrefixOption
.PrefixLength
== IP6_LINK_LOCAL_PREFIX_LENGTH
&&
2174 NetIp6IsLinkLocalAddr (&PrefixOption
.Prefix
)
2176 Offset
+= sizeof (IP6_PREFIX_INFO_OPTION
);
2180 // Do following if on-link flag is set according to RFC4861.
2183 PrefixList
= Ip6FindPrefixListEntry (
2186 PrefixOption
.PrefixLength
,
2187 &PrefixOption
.Prefix
2190 // Create a new entry for the prefix, if the ValidLifetime is zero,
2191 // silently ignore the prefix option.
2193 if (PrefixList
== NULL
&& PrefixOption
.ValidLifetime
!= 0) {
2194 PrefixList
= Ip6CreatePrefixListEntry (
2197 PrefixOption
.ValidLifetime
,
2198 PrefixOption
.PreferredLifetime
,
2199 PrefixOption
.PrefixLength
,
2200 &PrefixOption
.Prefix
2202 if (PrefixList
== NULL
) {
2203 Status
= EFI_OUT_OF_RESOURCES
;
2206 } else if (PrefixList
!= NULL
) {
2207 if (PrefixOption
.ValidLifetime
!= 0) {
2208 PrefixList
->ValidLifetime
= PrefixOption
.ValidLifetime
;
2211 // If the prefix exists and incoming ValidLifetime is zero, immediately
2212 // remove the prefix.
2213 Ip6DestroyPrefixListEntry (IpSb
, PrefixList
, OnLink
, TRUE
);
2219 // Do following if Autonomous flag is set according to RFC4862.
2221 if (Autonomous
&& PrefixOption
.PreferredLifetime
<= PrefixOption
.ValidLifetime
) {
2222 PrefixList
= Ip6FindPrefixListEntry (
2225 PrefixOption
.PrefixLength
,
2226 &PrefixOption
.Prefix
2229 // Create a new entry for the prefix, and form an address by prefix + interface id
2230 // If the sum of the prefix length and interface identifier length
2231 // does not equal 128 bits, the Prefix Information option MUST be ignored.
2233 if (PrefixList
== NULL
&&
2234 PrefixOption
.ValidLifetime
!= 0 &&
2235 PrefixOption
.PrefixLength
+ IpSb
->InterfaceIdLen
* 8 == 128
2238 // Form the address in network order.
2240 CopyMem (&StatelessAddress
, &PrefixOption
.Prefix
, sizeof (UINT64
));
2241 CopyMem (&StatelessAddress
.Addr
[8], IpSb
->InterfaceId
, sizeof (UINT64
));
2244 // If the address is not yet in the assigned address list, adds it into.
2246 if (!Ip6IsOneOfSetAddress (IpSb
, &StatelessAddress
, NULL
, NULL
)) {
2248 // And also not in the DAD process, check its uniqeness firstly.
2250 if (Ip6FindDADEntry (IpSb
, &StatelessAddress
, NULL
) == NULL
) {
2251 Status
= Ip6SetAddress (
2252 IpSb
->DefaultInterface
,
2255 PrefixOption
.PrefixLength
,
2256 PrefixOption
.ValidLifetime
,
2257 PrefixOption
.PreferredLifetime
,
2261 if (EFI_ERROR (Status
)) {
2268 // Adds the prefix option to stateless prefix option list.
2270 PrefixList
= Ip6CreatePrefixListEntry (
2273 PrefixOption
.ValidLifetime
,
2274 PrefixOption
.PreferredLifetime
,
2275 PrefixOption
.PrefixLength
,
2276 &PrefixOption
.Prefix
2278 if (PrefixList
== NULL
) {
2279 Status
= EFI_OUT_OF_RESOURCES
;
2282 } else if (PrefixList
!= NULL
) {
2285 // Reset the preferred lifetime of the address if the advertised prefix exists.
2286 // Perform specific action to valid lifetime together.
2288 PrefixList
->PreferredLifetime
= PrefixOption
.PreferredLifetime
;
2289 if ((PrefixOption
.ValidLifetime
> 7200) ||
2290 (PrefixOption
.ValidLifetime
> PrefixList
->ValidLifetime
)) {
2292 // If the received Valid Lifetime is greater than 2 hours or
2293 // greater than RemainingLifetime, set the valid lifetime of the
2294 // corresponding address to the advertised Valid Lifetime.
2296 PrefixList
->ValidLifetime
= PrefixOption
.ValidLifetime
;
2298 } else if (PrefixList
->ValidLifetime
<= 7200) {
2300 // If RemainingLifetime is less than or equls to 2 hours, ignore the
2301 // Prefix Information option with regards to the valid lifetime.
2302 // TODO: If this option has been authenticated, set the valid lifetime.
2306 // Otherwise, reset the valid lifetime of the corresponding
2307 // address to 2 hours.
2309 PrefixList
->ValidLifetime
= 7200;
2314 Offset
+= sizeof (IP6_PREFIX_INFO_OPTION
);
2317 NetbufCopy (Packet
, Offset
, sizeof (IP6_MTU_OPTION
), (UINT8
*) &MTUOption
);
2318 if (MTUOption
.Length
!= 1) {
2323 // Use IPv6 minimum link MTU 1280 bytes as the maximum packet size in order
2324 // to omit implementation of Path MTU Discovery. Thus ignore the MTU option
2325 // in Router Advertisement.
2328 Offset
+= sizeof (IP6_MTU_OPTION
);
2332 // Silently ignore unrecognized options
2334 NetbufCopy (Packet
, Offset
+ sizeof (UINT8
), sizeof (UINT8
), &Length
);
2339 Offset
= (UINT16
) (Offset
+ (UINT16
) Length
* 8);
2344 Status
= EFI_SUCCESS
;
2347 NetbufFree (Packet
);
2352 Process the ICMPv6 redirect message. Find the instance, then update
2355 @param[in] IpSb The IP6 service binding instance that received
2357 @param[in] Head The IP head of the received ICMPv6 packet.
2358 @param[in] Packet The content of the ICMPv6 redirect packet with
2359 the IP head removed.
2361 @retval EFI_INVALID_PARAMETER The parameter is invalid.
2362 @retval EFI_OUT_OF_RESOURCES Insuffcient resources to complete the
2364 @retval EFI_SUCCESS Successfully updated the route caches.
2368 Ip6ProcessRedirect (
2369 IN IP6_SERVICE
*IpSb
,
2370 IN EFI_IP6_HEADER
*Head
,
2374 IP6_ICMP_INFORMATION_HEAD
*Icmp
;
2375 EFI_IPv6_ADDRESS
*Target
;
2376 EFI_IPv6_ADDRESS
*IcmpDest
;
2379 IP6_ROUTE_ENTRY
*RouteEntry
;
2380 IP6_ROUTE_CACHE_ENTRY
*RouteCache
;
2381 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
2384 IP6_ETHER_ADDR_OPTION
*LinkLayerOption
;
2385 EFI_MAC_ADDRESS Mac
;
2391 Status
= EFI_INVALID_PARAMETER
;
2393 Icmp
= (IP6_ICMP_INFORMATION_HEAD
*) NetbufGetByte (Packet
, 0, NULL
);
2399 // Validate the incoming Redirect message
2403 // The IP Hop Limit field has a value of 255, i.e. the packet
2404 // could not possibly have been forwarded by a router.
2406 // ICMP length (derived from the IP length) is 40 or more octets.
2408 if (Head
->HopLimit
!= IP6_HOP_LIMIT
|| Icmp
->Head
.Code
!= 0 ||
2409 Head
->PayloadLength
< IP6_REDITECT_LENGTH
) {
2414 // The IP source address must be a link-local address
2416 if (!NetIp6IsLinkLocalAddr (&Head
->SourceAddress
)) {
2421 // The dest of this ICMP redirect message is not us.
2423 if (!Ip6IsOneOfSetAddress (IpSb
, &Head
->DestinationAddress
, NULL
, NULL
)) {
2428 // All included options have a length that is greater than zero.
2430 OptionLen
= (UINT16
) (Head
->PayloadLength
- IP6_REDITECT_LENGTH
);
2431 Option
= NetbufGetByte (Packet
, IP6_REDITECT_LENGTH
, NULL
);
2433 if (!Ip6IsNDOptionValid (Option
, OptionLen
)) {
2437 Target
= (EFI_IPv6_ADDRESS
*) (Icmp
+ 1);
2438 IcmpDest
= Target
+ 1;
2441 // The ICMP Destination Address field in the redirect message does not contain
2442 // a multicast address.
2444 if (IP6_IS_MULTICAST (IcmpDest
)) {
2449 // The ICMP Target Address is either a link-local address (when redirected to
2450 // a router) or the same as the ICMP Destination Address (when redirected to
2451 // the on-link destination).
2453 IsRouter
= (BOOLEAN
) !EFI_IP6_EQUAL (Target
, IcmpDest
);
2454 if (!NetIp6IsLinkLocalAddr (Target
) && IsRouter
) {
2459 // Check the options. The only interested option here is the target-link layer
2462 Length
= Packet
->TotalSize
- 40;
2463 Option
= (UINT8
*) (IcmpDest
+ 1);
2464 LinkLayerOption
= NULL
;
2465 while (Length
> 0) {
2467 case Ip6OptionEtherTarget
:
2469 LinkLayerOption
= (IP6_ETHER_ADDR_OPTION
*) Option
;
2470 OptLen
= LinkLayerOption
->Length
;
2473 // For ethernet, the length must be 1.
2481 OptLen
= *(Option
+ 1);
2484 // A length of 0 is invalid.
2491 Length
-= 8 * OptLen
;
2492 Option
+= 8 * OptLen
;
2500 // The IP source address of the Redirect is the same as the current
2501 // first-hop router for the specified ICMP Destination Address.
2503 RouteCache
= Ip6FindRouteCache (IpSb
->RouteTable
, IcmpDest
, &Head
->DestinationAddress
);
2504 if (RouteCache
!= NULL
) {
2505 if (!EFI_IP6_EQUAL (&RouteCache
->NextHop
, &Head
->SourceAddress
)) {
2507 // The source of this Redirect message must match the NextHop of the
2508 // corresponding route cache entry.
2514 // Update the NextHop.
2516 IP6_COPY_ADDRESS (&RouteCache
->NextHop
, Target
);
2519 RouteEntry
= (IP6_ROUTE_ENTRY
*) RouteCache
->Tag
;
2520 RouteEntry
->Flag
= RouteEntry
->Flag
| IP6_DIRECT_ROUTE
;
2525 // Get the Route Entry.
2527 RouteEntry
= Ip6FindRouteEntry (IpSb
->RouteTable
, IcmpDest
, NULL
);
2528 if (RouteEntry
== NULL
) {
2529 RouteEntry
= Ip6CreateRouteEntry (IcmpDest
, 0, NULL
);
2530 if (RouteEntry
== NULL
) {
2531 Status
= EFI_OUT_OF_RESOURCES
;
2537 RouteEntry
->Flag
= IP6_DIRECT_ROUTE
;
2541 // Create a route cache for this.
2543 RouteCache
= Ip6CreateRouteCacheEntry (
2545 &Head
->DestinationAddress
,
2549 if (RouteCache
== NULL
) {
2550 Status
= EFI_OUT_OF_RESOURCES
;
2555 // Insert the newly created route cache entry.
2557 Index
= IP6_ROUTE_CACHE_HASH (IcmpDest
, &Head
->DestinationAddress
);
2558 InsertHeadList (&IpSb
->RouteTable
->Cache
.CacheBucket
[Index
], &RouteCache
->Link
);
2562 // Try to locate the neighbor cache for the Target.
2564 NeighborCache
= Ip6FindNeighborEntry (IpSb
, Target
);
2566 if (LinkLayerOption
!= NULL
) {
2567 if (NeighborCache
== NULL
) {
2569 // Create a neighbor cache for the Target.
2571 ZeroMem (&Mac
, sizeof (EFI_MAC_ADDRESS
));
2572 CopyMem (&Mac
, LinkLayerOption
->EtherAddr
, 6);
2573 NeighborCache
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, Target
, &Mac
);
2574 if (NeighborCache
== NULL
) {
2576 // Just report a success here. The neighbor cache can be created in
2577 // some other place.
2579 Status
= EFI_SUCCESS
;
2583 NeighborCache
->State
= EfiNeighborStale
;
2584 NeighborCache
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
2586 Result
= CompareMem (LinkLayerOption
->EtherAddr
, &NeighborCache
->LinkAddress
, 6);
2589 // If the link-local address is the same as that already in the cache,
2590 // the cache entry's state remains unchanged. Otherwise update the
2591 // reachability state to STALE.
2593 if ((NeighborCache
->State
== EfiNeighborInComplete
) || (Result
!= 0)) {
2594 CopyMem (&NeighborCache
->LinkAddress
, LinkLayerOption
->EtherAddr
, 6);
2596 NeighborCache
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
2598 if (NeighborCache
->State
== EfiNeighborInComplete
) {
2600 // Send queued packets if exist.
2602 NeighborCache
->State
= EfiNeighborStale
;
2603 NeighborCache
->CallBack ((VOID
*) NeighborCache
);
2605 NeighborCache
->State
= EfiNeighborStale
;
2611 if (NeighborCache
!= NULL
&& IsRouter
) {
2613 // The Target is a router, set IsRouter to TRUE.
2615 NeighborCache
->IsRouter
= TRUE
;
2618 Status
= EFI_SUCCESS
;
2621 NetbufFree (Packet
);
2626 Add Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2628 @param[in] IpSb The IP6 service binding instance.
2629 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2630 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2631 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2632 cache. It will be deleted after Timeout. A value of zero means that
2633 the entry is permanent. A non-zero value means that the entry is
2635 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2636 be overridden and updated; if FALSE, and if a
2637 corresponding cache entry already existed, EFI_ACCESS_DENIED
2640 @retval EFI_SUCCESS The neighbor cache entry has been added.
2641 @retval EFI_OUT_OF_RESOURCES Could not add the entry to the neighbor cache
2642 due to insufficient resources.
2643 @retval EFI_NOT_FOUND TargetLinkAddress is NULL.
2644 @retval EFI_ACCESS_DENIED The to-be-added entry is already defined in the neighbor cache,
2645 and that entry is tagged as un-overridden (when DeleteFlag
2651 IN IP6_SERVICE
*IpSb
,
2652 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
2653 IN EFI_MAC_ADDRESS
*TargetLinkAddress OPTIONAL
,
2658 IP6_NEIGHBOR_ENTRY
*Neighbor
;
2660 Neighbor
= Ip6FindNeighborEntry (IpSb
, TargetIp6Address
);
2661 if (Neighbor
!= NULL
) {
2663 return EFI_ACCESS_DENIED
;
2665 if (TargetLinkAddress
!= NULL
) {
2666 IP6_COPY_LINK_ADDRESS (&Neighbor
->LinkAddress
, TargetLinkAddress
);
2670 if (TargetLinkAddress
== NULL
) {
2671 return EFI_NOT_FOUND
;
2674 Neighbor
= Ip6CreateNeighborEntry (IpSb
, Ip6OnArpResolved
, TargetIp6Address
, TargetLinkAddress
);
2675 if (Neighbor
== NULL
) {
2676 return EFI_OUT_OF_RESOURCES
;
2680 Neighbor
->State
= EfiNeighborReachable
;
2683 Neighbor
->Ticks
= IP6_GET_TICKS (Timeout
/ TICKS_PER_MS
);
2684 Neighbor
->Dynamic
= TRUE
;
2686 Neighbor
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
2693 Delete or update Neighbor cache entries. It is a work function for EfiIp6Neighbors().
2695 @param[in] IpSb The IP6 service binding instance.
2696 @param[in] TargetIp6Address Pointer to Target IPv6 address.
2697 @param[in] TargetLinkAddress Pointer to link-layer address of the target. Ignored if NULL.
2698 @param[in] Timeout Time in 100-ns units that this entry will remain in the neighbor
2699 cache. It will be deleted after Timeout. A value of zero means that
2700 the entry is permanent. A non-zero value means that the entry is
2702 @param[in] Override If TRUE, the cached link-layer address of the matching entry will
2703 be overridden and updated; if FALSE, and if a
2704 corresponding cache entry already existed, EFI_ACCESS_DENIED
2707 @retval EFI_SUCCESS The neighbor cache entry has been updated or deleted.
2708 @retval EFI_NOT_FOUND This entry is not in the neighbor cache.
2713 IN IP6_SERVICE
*IpSb
,
2714 IN EFI_IPv6_ADDRESS
*TargetIp6Address
,
2715 IN EFI_MAC_ADDRESS
*TargetLinkAddress OPTIONAL
,
2720 IP6_NEIGHBOR_ENTRY
*Neighbor
;
2722 Neighbor
= Ip6FindNeighborEntry (IpSb
, TargetIp6Address
);
2723 if (Neighbor
== NULL
) {
2724 return EFI_NOT_FOUND
;
2727 RemoveEntryList (&Neighbor
->Link
);
2728 FreePool (Neighbor
);
2734 The heartbeat timer of ND module in IP6_TIMER_INTERVAL_IN_MS milliseconds.
2735 This time routine handles DAD module and neighbor state transition.
2736 It is also responsible for sending out router solicitations.
2738 @param[in] Event The IP6 service instance's heartbeat timer.
2739 @param[in] Context The IP6 service instance.
2744 Ip6NdFasterTimerTicking (
2752 IP6_INTERFACE
*IpIf
;
2753 IP6_DELAY_JOIN_LIST
*DelayNode
;
2754 EFI_IPv6_ADDRESS Source
;
2755 IP6_DAD_ENTRY
*DupAddrDetect
;
2757 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
2758 EFI_IPv6_ADDRESS Destination
;
2762 IpSb
= (IP6_SERVICE
*) Context
;
2763 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
2765 ZeroMem (&Source
, sizeof (EFI_IPv6_ADDRESS
));
2768 // A host SHOULD transmit up to MAX_RTR_SOLICITATIONS (3) Router
2769 // Solicitation messages, each separated by at least
2770 // RTR_SOLICITATION_INTERVAL (4) seconds.
2772 if ((IpSb
->Ip6ConfigInstance
.Policy
== Ip6ConfigPolicyAutomatic
) &&
2773 !IpSb
->RouterAdvertiseReceived
&&
2774 IpSb
->SolicitTimer
> 0
2776 if ((IpSb
->Ticks
== 0) || (--IpSb
->Ticks
== 0)) {
2777 Status
= Ip6SendRouterSolicit (IpSb
, NULL
, NULL
, NULL
, NULL
);
2778 if (!EFI_ERROR (Status
)) {
2779 IpSb
->SolicitTimer
--;
2780 IpSb
->Ticks
= (UINT32
) IP6_GET_TICKS (IP6_RTR_SOLICITATION_INTERVAL
);
2785 NET_LIST_FOR_EACH (Entry
, &IpSb
->Interfaces
) {
2786 IpIf
= NET_LIST_USER_STRUCT (Entry
, IP6_INTERFACE
, Link
);
2789 // Process the delay list to join the solicited-node multicast address.
2791 NET_LIST_FOR_EACH_SAFE (Entry2
, Next
, &IpIf
->DelayJoinList
) {
2792 DelayNode
= NET_LIST_USER_STRUCT (Entry2
, IP6_DELAY_JOIN_LIST
, Link
);
2793 if ((DelayNode
->DelayTime
== 0) || (--DelayNode
->DelayTime
== 0)) {
2795 // The timer expires, init the duplicate address detection.
2798 DelayNode
->Interface
,
2799 DelayNode
->AddressInfo
,
2800 DelayNode
->DadCallback
,
2805 // Remove the delay node
2807 RemoveEntryList (&DelayNode
->Link
);
2808 FreePool (DelayNode
);
2813 // Process the duplicate address detection list.
2815 NET_LIST_FOR_EACH_SAFE (Entry2
, Next
, &IpIf
->DupAddrDetectList
) {
2816 DupAddrDetect
= NET_LIST_USER_STRUCT (Entry2
, IP6_DAD_ENTRY
, Link
);
2818 if ((DupAddrDetect
->RetransTick
== 0) || (--DupAddrDetect
->RetransTick
== 0)) {
2820 // The timer expires, check the remaining transmit counts.
2822 if (DupAddrDetect
->Transmit
< DupAddrDetect
->MaxTransmit
) {
2824 // Send the Neighbor Solicitation message with
2825 // Source - unspecified address, destination - solicited-node multicast address
2826 // Target - the address to be validated
2828 Status
= Ip6SendNeighborSolicit (
2831 &DupAddrDetect
->Destination
,
2832 &DupAddrDetect
->AddressInfo
->Address
,
2835 if (EFI_ERROR (Status
)) {
2839 DupAddrDetect
->Transmit
++;
2840 DupAddrDetect
->RetransTick
= IP6_GET_TICKS (IpSb
->RetransTimer
);
2843 // All required solicitation has been sent out, and the RetransTime after the last
2844 // Neighbor Solicit is elapsed, finish the DAD process.
2847 if ((DupAddrDetect
->Receive
== 0) ||
2848 (DupAddrDetect
->Transmit
== DupAddrDetect
->Receive
)) {
2852 Ip6OnDADFinished (Flag
, IpIf
, DupAddrDetect
);
2859 // Polling the state of Neighbor cache
2861 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->NeighborTable
) {
2862 NeighborCache
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, Link
);
2864 switch (NeighborCache
->State
) {
2865 case EfiNeighborInComplete
:
2866 if (NeighborCache
->Ticks
> 0) {
2867 --NeighborCache
->Ticks
;
2871 // Retransmit Neighbor Solicitation messages approximately every
2872 // RetransTimer milliseconds while awaiting a response.
2874 if (NeighborCache
->Ticks
== 0) {
2875 if (NeighborCache
->Transmit
> 1) {
2877 // Send out multicast neighbor solicitation for address resolution.
2878 // After last neighbor solicitation message has been sent out, wait
2879 // for RetransTimer and then remove entry if no response is received.
2881 Ip6CreateSNMulticastAddr (&NeighborCache
->Neighbor
, &Destination
);
2882 Status
= Ip6SelectSourceAddress (IpSb
, &NeighborCache
->Neighbor
, &Source
);
2883 if (EFI_ERROR (Status
)) {
2887 Status
= Ip6SendNeighborSolicit (
2891 &NeighborCache
->Neighbor
,
2892 &IpSb
->SnpMode
.CurrentAddress
2894 if (EFI_ERROR (Status
)) {
2900 // Update the retransmit times.
2902 if (NeighborCache
->Transmit
> 0) {
2903 --NeighborCache
->Transmit
;
2904 NeighborCache
->Ticks
= IP6_GET_TICKS (IpSb
->RetransTimer
);
2908 if (NeighborCache
->Transmit
== 0) {
2910 // Timeout, send ICMP destination unreachable packet and then remove entry
2912 Status
= Ip6FreeNeighborEntry (
2921 if (EFI_ERROR (Status
)) {
2928 case EfiNeighborReachable
:
2930 // This entry is inserted by EfiIp6Neighbors() as static entry
2931 // and will not timeout.
2933 if (!NeighborCache
->Dynamic
&& (NeighborCache
->Ticks
== IP6_INFINIT_LIFETIME
)) {
2937 if ((NeighborCache
->Ticks
== 0) || (--NeighborCache
->Ticks
== 0)) {
2938 if (NeighborCache
->Dynamic
) {
2940 // This entry is inserted by EfiIp6Neighbors() as dynamic entry
2941 // and will be deleted after timeout.
2943 Status
= Ip6FreeNeighborEntry (
2952 if (EFI_ERROR (Status
)) {
2956 NeighborCache
->State
= EfiNeighborStale
;
2957 NeighborCache
->Ticks
= (UINT32
) IP6_INFINIT_LIFETIME
;
2963 case EfiNeighborDelay
:
2964 if ((NeighborCache
->Ticks
== 0) || (--NeighborCache
->Ticks
== 0)) {
2966 NeighborCache
->State
= EfiNeighborProbe
;
2967 NeighborCache
->Ticks
= IP6_GET_TICKS (IpSb
->RetransTimer
);
2968 NeighborCache
->Transmit
= IP6_MAX_UNICAST_SOLICIT
+ 1;
2970 // Send out unicast neighbor solicitation for Neighbor Unreachability Detection
2972 Status
= Ip6SelectSourceAddress (IpSb
, &NeighborCache
->Neighbor
, &Source
);
2973 if (EFI_ERROR (Status
)) {
2977 Status
= Ip6SendNeighborSolicit (
2980 &NeighborCache
->Neighbor
,
2981 &NeighborCache
->Neighbor
,
2982 &IpSb
->SnpMode
.CurrentAddress
2984 if (EFI_ERROR (Status
)) {
2988 NeighborCache
->Transmit
--;
2993 case EfiNeighborProbe
:
2994 if (NeighborCache
->Ticks
> 0) {
2995 --NeighborCache
->Ticks
;
2999 // Retransmit Neighbor Solicitation messages approximately every
3000 // RetransTimer milliseconds while awaiting a response.
3002 if (NeighborCache
->Ticks
== 0) {
3003 if (NeighborCache
->Transmit
> 1) {
3005 // Send out unicast neighbor solicitation for Neighbor Unreachability
3006 // Detection. After last neighbor solicitation message has been sent out,
3007 // wait for RetransTimer and then remove entry if no response is received.
3009 Status
= Ip6SelectSourceAddress (IpSb
, &NeighborCache
->Neighbor
, &Source
);
3010 if (EFI_ERROR (Status
)) {
3014 Status
= Ip6SendNeighborSolicit (
3017 &NeighborCache
->Neighbor
,
3018 &NeighborCache
->Neighbor
,
3019 &IpSb
->SnpMode
.CurrentAddress
3021 if (EFI_ERROR (Status
)) {
3027 // Update the retransmit times.
3029 if (NeighborCache
->Transmit
> 0) {
3030 --NeighborCache
->Transmit
;
3031 NeighborCache
->Ticks
= IP6_GET_TICKS (IpSb
->RetransTimer
);
3035 if (NeighborCache
->Transmit
== 0) {
3037 // Delete the neighbor entry.
3039 Status
= Ip6FreeNeighborEntry (
3048 if (EFI_ERROR (Status
)) {
3062 The heartbeat timer of ND module in 1 second. This time routine handles following
3063 things: 1) maitain default router list; 2) maintain prefix options;
3064 3) maintain route caches.
3066 @param[in] IpSb The IP6 service binding instance.
3071 IN IP6_SERVICE
*IpSb
3076 IP6_DEFAULT_ROUTER
*DefaultRouter
;
3077 IP6_PREFIX_LIST_ENTRY
*PrefixOption
;
3079 IP6_ROUTE_CACHE_ENTRY
*RouteCache
;
3082 // Decrease the lifetime of default router, if expires remove it from default router list.
3084 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->DefaultRouterList
) {
3085 DefaultRouter
= NET_LIST_USER_STRUCT (Entry
, IP6_DEFAULT_ROUTER
, Link
);
3086 if (DefaultRouter
->Lifetime
!= IP6_INF_ROUTER_LIFETIME
) {
3087 if ((DefaultRouter
->Lifetime
== 0) || (--DefaultRouter
->Lifetime
== 0)) {
3088 Ip6DestroyDefaultRouter (IpSb
, DefaultRouter
);
3094 // Decrease Valid lifetime and Preferred lifetime of Prefix options and corresponding addresses.
3096 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->AutonomousPrefix
) {
3097 PrefixOption
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
3098 if (PrefixOption
->ValidLifetime
!= (UINT32
) IP6_INFINIT_LIFETIME
) {
3099 if ((PrefixOption
->ValidLifetime
> 0) && (--PrefixOption
->ValidLifetime
> 0)) {
3100 if ((PrefixOption
->PreferredLifetime
!= (UINT32
) IP6_INFINIT_LIFETIME
) &&
3101 (PrefixOption
->PreferredLifetime
> 0)
3103 --PrefixOption
->PreferredLifetime
;
3106 Ip6DestroyPrefixListEntry (IpSb
, PrefixOption
, FALSE
, TRUE
);
3111 NET_LIST_FOR_EACH_SAFE (Entry
, Next
, &IpSb
->OnlinkPrefix
) {
3112 PrefixOption
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
3113 if (PrefixOption
->ValidLifetime
!= (UINT32
) IP6_INFINIT_LIFETIME
) {
3114 if ((PrefixOption
->ValidLifetime
== 0) || (--PrefixOption
->ValidLifetime
== 0)) {
3115 Ip6DestroyPrefixListEntry (IpSb
, PrefixOption
, TRUE
, TRUE
);
3121 // Each bucket of route cache can contain at most IP6_ROUTE_CACHE_MAX entries.
3122 // Remove the entries at the tail of the bucket. These entries
3123 // are likely to be used least.
3124 // Reclaim frequency is set to 1 second.
3126 for (Index
= 0; Index
< IP6_ROUTE_CACHE_HASH_SIZE
; Index
++) {
3127 while (IpSb
->RouteTable
->Cache
.CacheNum
[Index
] > IP6_ROUTE_CACHE_MAX
) {
3128 Entry
= NetListRemoveTail (&IpSb
->RouteTable
->Cache
.CacheBucket
[Index
]);
3129 if (Entry
== NULL
) {
3133 RouteCache
= NET_LIST_USER_STRUCT (Entry
, IP6_ROUTE_CACHE_ENTRY
, Link
);
3134 Ip6FreeRouteCacheEntry (RouteCache
);
3135 ASSERT (IpSb
->RouteTable
->Cache
.CacheNum
[Index
] > 0);
3136 IpSb
->RouteTable
->Cache
.CacheNum
[Index
]--;