2 Implement IP6 pseudo interface.
4 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
13 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
15 @param[in] Event The transmit token's event.
16 @param[in] Context The Context which is pointed to the token.
27 Fileter function to cancel all the frame related to an IP instance.
29 @param[in] Frame The transmit request to test whether to cancel.
30 @param[in] Context The context which is the Ip instance that issued
33 @retval TRUE The frame belongs to this instance and is to be
35 @retval FALSE The frame doesn't belong to this instance.
39 Ip6CancelInstanceFrame (
40 IN IP6_LINK_TX_TOKEN
*Frame
,
44 if (Frame
->IpInstance
== (IP6_PROTOCOL
*)Context
) {
52 Set the interface's address. This will trigger the DAD process for the
53 address to set. To set an already set address, the lifetimes wil be
54 updated to the new value passed in.
56 @param[in] Interface The interface to set the address.
57 @param[in] Ip6Addr The interface's to be assigned IPv6 address.
58 @param[in] IsAnycast If TRUE, the unicast IPv6 address is anycast.
59 Otherwise, it is not anycast.
60 @param[in] PrefixLength The prefix length of the Ip6Addr.
61 @param[in] ValidLifetime The valid lifetime for this address.
62 @param[in] PreferredLifetime The preferred lifetime for this address.
63 @param[in] DadCallback The caller's callback to trigger when DAD finishes.
64 This is an optional parameter that may be NULL.
65 @param[in] Context The context that will be passed to DadCallback.
66 This is an optional parameter that may be NULL.
68 @retval EFI_SUCCESS The interface is scheduled to be configured with
69 the specified address.
70 @retval EFI_OUT_OF_RESOURCES Failed to set the interface's address due to
76 IN IP6_INTERFACE
*Interface
,
77 IN EFI_IPv6_ADDRESS
*Ip6Addr
,
79 IN UINT8 PrefixLength
,
80 IN UINT32 ValidLifetime
,
81 IN UINT32 PreferredLifetime
,
82 IN IP6_DAD_CALLBACK DadCallback OPTIONAL
,
83 IN VOID
*Context OPTIONAL
87 IP6_ADDRESS_INFO
*AddressInfo
;
89 IP6_PREFIX_LIST_ENTRY
*PrefixEntry
;
91 IP6_DELAY_JOIN_LIST
*DelayNode
;
93 NET_CHECK_SIGNATURE (Interface
, IP6_INTERFACE_SIGNATURE
);
95 IpSb
= Interface
->Service
;
97 if (Ip6IsOneOfSetAddress (IpSb
, Ip6Addr
, NULL
, &AddressInfo
)) {
98 ASSERT (AddressInfo
!= NULL
);
100 // Update the lifetime.
102 AddressInfo
->ValidLifetime
= ValidLifetime
;
103 AddressInfo
->PreferredLifetime
= PreferredLifetime
;
105 if (DadCallback
!= NULL
) {
106 DadCallback (TRUE
, Ip6Addr
, Context
);
112 AddressInfo
= (IP6_ADDRESS_INFO
*)AllocatePool (sizeof (IP6_ADDRESS_INFO
));
113 if (AddressInfo
== NULL
) {
114 return EFI_OUT_OF_RESOURCES
;
117 AddressInfo
->Signature
= IP6_ADDR_INFO_SIGNATURE
;
118 IP6_COPY_ADDRESS (&AddressInfo
->Address
, Ip6Addr
);
119 AddressInfo
->IsAnycast
= IsAnycast
;
120 AddressInfo
->PrefixLength
= PrefixLength
;
121 AddressInfo
->ValidLifetime
= ValidLifetime
;
122 AddressInfo
->PreferredLifetime
= PreferredLifetime
;
124 if (AddressInfo
->PrefixLength
== 0) {
126 // Find an appropriate prefix from on-link prefixes and update the prefixlength.
127 // Longest prefix match is used here.
129 NET_LIST_FOR_EACH (Entry
, &IpSb
->OnlinkPrefix
) {
130 PrefixEntry
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
132 if (NetIp6IsNetEqual (&PrefixEntry
->Prefix
, &AddressInfo
->Address
, PrefixEntry
->PrefixLength
)) {
133 AddressInfo
->PrefixLength
= PrefixEntry
->PrefixLength
;
139 if (AddressInfo
->PrefixLength
== 0) {
141 // If the prefix length is still zero, try the autonomous prefixes.
142 // Longest prefix match is used here.
144 NET_LIST_FOR_EACH (Entry
, &IpSb
->AutonomousPrefix
) {
145 PrefixEntry
= NET_LIST_USER_STRUCT (Entry
, IP6_PREFIX_LIST_ENTRY
, Link
);
147 if (NetIp6IsNetEqual (&PrefixEntry
->Prefix
, &AddressInfo
->Address
, PrefixEntry
->PrefixLength
)) {
148 AddressInfo
->PrefixLength
= PrefixEntry
->PrefixLength
;
154 if (AddressInfo
->PrefixLength
== 0) {
156 // BUGBUG: Stil fail, use 64 as the default prefix length.
158 AddressInfo
->PrefixLength
= IP6_LINK_LOCAL_PREFIX_LENGTH
;
162 // Node should delay joining the solicited-node multicast address by a random delay
163 // between 0 and MAX_RTR_SOLICITATION_DELAY (1 second).
164 // Thus queue the address to be processed in Duplicate Address Detection module
165 // after the delay time (in milliseconds).
167 Delay
= (UINT64
)NET_RANDOM (NetRandomInitSeed ());
168 Delay
= MultU64x32 (Delay
, IP6_ONE_SECOND_IN_MS
);
169 Delay
= RShiftU64 (Delay
, 32);
171 DelayNode
= (IP6_DELAY_JOIN_LIST
*)AllocatePool (sizeof (IP6_DELAY_JOIN_LIST
));
172 if (DelayNode
== NULL
) {
173 FreePool (AddressInfo
);
174 return EFI_OUT_OF_RESOURCES
;
177 DelayNode
->DelayTime
= (UINT32
)(DivU64x32 (Delay
, IP6_TIMER_INTERVAL_IN_MS
));
178 DelayNode
->Interface
= Interface
;
179 DelayNode
->AddressInfo
= AddressInfo
;
180 DelayNode
->DadCallback
= DadCallback
;
181 DelayNode
->Context
= Context
;
183 InsertTailList (&Interface
->DelayJoinList
, &DelayNode
->Link
);
188 Create an IP6_INTERFACE.
190 @param[in] IpSb The IP6 service binding instance.
191 @param[in] LinkLocal If TRUE, the instance is created for link-local address.
192 Otherwise, it is not for a link-local address.
194 @return Point to the created IP6_INTERFACE, otherwise NULL.
199 IN IP6_SERVICE
*IpSb
,
204 IP6_INTERFACE
*Interface
;
205 EFI_IPv6_ADDRESS
*Ip6Addr
;
207 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
209 Interface
= AllocatePool (sizeof (IP6_INTERFACE
));
210 if (Interface
== NULL
) {
214 Interface
->Signature
= IP6_INTERFACE_SIGNATURE
;
215 Interface
->RefCnt
= 1;
217 InitializeListHead (&Interface
->AddressList
);
218 Interface
->AddressCount
= 0;
219 Interface
->Configured
= FALSE
;
221 Interface
->Service
= IpSb
;
222 Interface
->Controller
= IpSb
->Controller
;
223 Interface
->Image
= IpSb
->Image
;
225 InitializeListHead (&Interface
->ArpQues
);
226 InitializeListHead (&Interface
->SentFrames
);
228 Interface
->DupAddrDetect
= IpSb
->Ip6ConfigInstance
.DadXmits
.DupAddrDetectTransmits
;
229 InitializeListHead (&Interface
->DupAddrDetectList
);
231 InitializeListHead (&Interface
->DelayJoinList
);
233 InitializeListHead (&Interface
->IpInstances
);
234 Interface
->PromiscRecv
= FALSE
;
241 // Get the link local addr
243 Ip6Addr
= Ip6CreateLinkLocalAddr (IpSb
);
244 if (Ip6Addr
== NULL
) {
249 // Perform DAD - Duplicate Address Detection.
251 Status
= Ip6SetAddress (
255 IP6_LINK_LOCAL_PREFIX_LENGTH
,
256 (UINT32
)IP6_INFINIT_LIFETIME
,
257 (UINT32
)IP6_INFINIT_LIFETIME
,
264 if (EFI_ERROR (Status
)) {
272 FreePool (Interface
);
277 Free the interface used by IpInstance. All the IP instance with
278 the same Ip/prefix pair share the same interface. It is reference
279 counted. All the frames that haven't been sent will be cancelled.
280 Because the IpInstance is optional, the caller must remove
281 IpInstance from the interface's instance list.
283 @param[in] Interface The interface used by the IpInstance.
284 @param[in] IpInstance The IP instance that free the interface. NULL if
285 the IP driver is releasing the default interface.
290 IN IP6_INTERFACE
*Interface
,
291 IN IP6_PROTOCOL
*IpInstance OPTIONAL
294 IP6_DAD_ENTRY
*Duplicate
;
295 IP6_DELAY_JOIN_LIST
*Delay
;
297 NET_CHECK_SIGNATURE (Interface
, IP6_INTERFACE_SIGNATURE
);
298 ASSERT (Interface
->RefCnt
> 0);
301 // Remove all the pending transmit token related to this IP instance.
303 Ip6CancelFrames (Interface
, EFI_ABORTED
, Ip6CancelInstanceFrame
, IpInstance
);
305 if (--Interface
->RefCnt
> 0) {
310 // Destroy the interface if this is the last IP instance.
311 // Remove all the system transmitted packets
312 // from this interface, cancel the receive request if exists.
314 Ip6CancelFrames (Interface
, EFI_ABORTED
, Ip6CancelInstanceFrame
, NULL
);
316 ASSERT (IsListEmpty (&Interface
->IpInstances
));
317 ASSERT (IsListEmpty (&Interface
->ArpQues
));
318 ASSERT (IsListEmpty (&Interface
->SentFrames
));
320 while (!IsListEmpty (&Interface
->DupAddrDetectList
)) {
321 Duplicate
= NET_LIST_HEAD (&Interface
->DupAddrDetectList
, IP6_DAD_ENTRY
, Link
);
322 NetListRemoveHead (&Interface
->DupAddrDetectList
);
323 FreePool (Duplicate
);
326 while (!IsListEmpty (&Interface
->DelayJoinList
)) {
327 Delay
= NET_LIST_HEAD (&Interface
->DelayJoinList
, IP6_DELAY_JOIN_LIST
, Link
);
328 NetListRemoveHead (&Interface
->DelayJoinList
);
332 Ip6RemoveAddr (Interface
->Service
, &Interface
->AddressList
, &Interface
->AddressCount
, NULL
, 0);
334 RemoveEntryList (&Interface
->Link
);
335 FreePool (Interface
);
339 Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN.
341 @param[in] Interface The interface to send out from.
342 @param[in] IpInstance The IpInstance that transmit the packet. NULL if
343 the packet is sent by the IP6 driver itself.
344 @param[in] Packet The packet to transmit
345 @param[in] CallBack Call back function to execute if transmission
347 @param[in] Context Opaque parameter to the callback.
349 @return The wrapped token if succeed or NULL.
353 Ip6CreateLinkTxToken (
354 IN IP6_INTERFACE
*Interface
,
355 IN IP6_PROTOCOL
*IpInstance OPTIONAL
,
357 IN IP6_FRAME_CALLBACK CallBack
,
361 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*MnpToken
;
362 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*MnpTxData
;
363 IP6_LINK_TX_TOKEN
*Token
;
367 Token
= AllocatePool (sizeof (IP6_LINK_TX_TOKEN
) + (Packet
->BlockOpNum
- 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA
));
373 Token
->Signature
= IP6_LINK_TX_SIGNATURE
;
374 InitializeListHead (&Token
->Link
);
376 Token
->IpInstance
= IpInstance
;
377 Token
->CallBack
= CallBack
;
378 Token
->Packet
= Packet
;
379 Token
->Context
= Context
;
380 ZeroMem (&Token
->DstMac
, sizeof (EFI_MAC_ADDRESS
));
381 IP6_COPY_LINK_ADDRESS (&Token
->SrcMac
, &Interface
->Service
->SnpMode
.CurrentAddress
);
383 MnpToken
= &(Token
->MnpToken
);
384 MnpToken
->Status
= EFI_NOT_READY
;
386 Status
= gBS
->CreateEvent (
394 if (EFI_ERROR (Status
)) {
399 MnpTxData
= &Token
->MnpTxData
;
400 MnpToken
->Packet
.TxData
= MnpTxData
;
402 MnpTxData
->DestinationAddress
= &Token
->DstMac
;
403 MnpTxData
->SourceAddress
= &Token
->SrcMac
;
404 MnpTxData
->ProtocolType
= IP6_ETHER_PROTO
;
405 MnpTxData
->DataLength
= Packet
->TotalSize
;
406 MnpTxData
->HeaderLength
= 0;
408 Count
= Packet
->BlockOpNum
;
410 NetbufBuildExt (Packet
, (NET_FRAGMENT
*)MnpTxData
->FragmentTable
, &Count
);
411 MnpTxData
->FragmentCount
= (UINT16
)Count
;
417 Free the link layer transmit token. It will close the event,
418 then free the memory used.
420 @param[in] Token Token to free.
425 IN IP6_LINK_TX_TOKEN
*Token
428 NET_CHECK_SIGNATURE (Token
, IP6_LINK_TX_SIGNATURE
);
430 gBS
->CloseEvent (Token
->MnpToken
.Event
);
435 Callback function when the received packet is freed.
436 Check Ip6OnFrameReceived for information.
438 @param[in] Context Points to EFI_MANAGED_NETWORK_RECEIVE_DATA.
447 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
449 RxData
= (EFI_MANAGED_NETWORK_RECEIVE_DATA
*)Context
;
451 gBS
->SignalEvent (RxData
->RecycleEvent
);
455 Received a frame from MNP. Wrap it in net buffer then deliver
456 it to IP's input function. The ownship of the packet also
457 is transferred to IP. When Ip is finished with this packet, it
458 will call NetbufFree to release the packet, NetbufFree will
459 again call the Ip6RecycleFrame to signal MNP's event and free
462 @param[in] Context Context for the callback.
467 Ip6OnFrameReceivedDpc (
471 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*MnpToken
;
472 EFI_MANAGED_NETWORK_RECEIVE_DATA
*MnpRxData
;
473 IP6_LINK_RX_TOKEN
*Token
;
474 NET_FRAGMENT Netfrag
;
479 Token
= (IP6_LINK_RX_TOKEN
*)Context
;
480 NET_CHECK_SIGNATURE (Token
, IP6_LINK_RX_SIGNATURE
);
483 // First clear the interface's receive request in case the
484 // caller wants to call Ip6ReceiveFrame in the callback.
486 IpSb
= (IP6_SERVICE
*)Token
->Context
;
487 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
489 MnpToken
= &Token
->MnpToken
;
490 MnpRxData
= MnpToken
->Packet
.RxData
;
492 if (EFI_ERROR (MnpToken
->Status
) || (MnpRxData
== NULL
)) {
493 Token
->CallBack (NULL
, MnpToken
->Status
, 0, Token
->Context
);
498 // Wrap the frame in a net buffer then deliver it to IP input.
499 // IP will reassemble the packet, and deliver it to upper layer
501 Netfrag
.Len
= MnpRxData
->DataLength
;
502 Netfrag
.Bulk
= MnpRxData
->PacketData
;
504 Packet
= NetbufFromExt (&Netfrag
, 1, IP6_MAX_HEADLEN
, 0, Ip6RecycleFrame
, Token
->MnpToken
.Packet
.RxData
);
506 if (Packet
== NULL
) {
507 gBS
->SignalEvent (MnpRxData
->RecycleEvent
);
509 Token
->CallBack (NULL
, EFI_OUT_OF_RESOURCES
, 0, Token
->Context
);
514 Flag
= (MnpRxData
->BroadcastFlag
? IP6_LINK_BROADCAST
: 0);
515 Flag
|= (MnpRxData
->MulticastFlag
? IP6_LINK_MULTICAST
: 0);
516 Flag
|= (MnpRxData
->PromiscuousFlag
? IP6_LINK_PROMISC
: 0);
518 Token
->CallBack (Packet
, EFI_SUCCESS
, Flag
, Token
->Context
);
522 Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
524 @param Event The receive event delivered to MNP for receive.
525 @param Context Context for the callback.
536 // Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK
538 QueueDpc (TPL_CALLBACK
, Ip6OnFrameReceivedDpc
, Context
);
542 Request to receive the packet from the interface.
544 @param[in] CallBack Function to call when receive finished.
545 @param[in] IpSb Points to IP6 service binding instance.
547 @retval EFI_ALREADY_STARTED There is already a pending receive request.
548 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive.
549 @retval EFI_SUCCESS The receive request has been started.
554 IN IP6_FRAME_CALLBACK CallBack
,
559 IP6_LINK_RX_TOKEN
*Token
;
561 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
563 Token
= &IpSb
->RecvRequest
;
564 Token
->CallBack
= CallBack
;
565 Token
->Context
= (VOID
*)IpSb
;
567 Status
= IpSb
->Mnp
->Receive (IpSb
->Mnp
, &Token
->MnpToken
);
568 if (EFI_ERROR (Status
)) {
576 Callback function when frame transmission is finished. It will
577 call the frame owner's callback function to tell it the result.
579 @param[in] Context Context which points to the token.
588 IP6_LINK_TX_TOKEN
*Token
;
590 Token
= (IP6_LINK_TX_TOKEN
*)Context
;
591 NET_CHECK_SIGNATURE (Token
, IP6_LINK_TX_SIGNATURE
);
593 RemoveEntryList (&Token
->Link
);
597 Token
->MnpToken
.Status
,
602 Ip6FreeLinkTxToken (Token
);
606 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
608 @param[in] Event The transmit token's event.
609 @param[in] Context Context which points to the token.
620 // Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK
622 QueueDpc (TPL_CALLBACK
, Ip6OnFrameSentDpc
, Context
);
626 Send a frame from the interface. If the next hop is a multicast address,
627 it is transmitted immediately. If the next hop is a unicast,
628 and the NextHop's MAC is not known, it will perform address resolution.
629 If an error occurred, the CallBack won't be called. So, the caller
630 must test the return value, and take action when there is an error.
632 @param[in] Interface The interface to send the frame from
633 @param[in] IpInstance The IP child that request the transmission.
634 NULL if it is the IP6 driver itself.
635 @param[in] Packet The packet to transmit.
636 @param[in] NextHop The immediate destination to transmit the packet to.
637 @param[in] CallBack Function to call back when transmit finished.
638 @param[in] Context Opaque parameter to the callback.
640 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame.
641 @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop.
642 @retval EFI_SUCCESS The packet successfully transmitted.
647 IN IP6_INTERFACE
*Interface
,
648 IN IP6_PROTOCOL
*IpInstance OPTIONAL
,
650 IN EFI_IPv6_ADDRESS
*NextHop
,
651 IN IP6_FRAME_CALLBACK CallBack
,
656 IP6_LINK_TX_TOKEN
*Token
;
658 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
660 IP6_NEIGHBOR_ENTRY
*ArpQue
;
662 IpSb
= Interface
->Service
;
663 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
666 // Only when link local address is performing DAD, the interface could be used in unconfigured.
668 if (IpSb
->LinkLocalOk
) {
669 ASSERT (Interface
->Configured
);
672 Token
= Ip6CreateLinkTxToken (Interface
, IpInstance
, Packet
, CallBack
, Context
);
675 return EFI_OUT_OF_RESOURCES
;
678 if (IP6_IS_MULTICAST (NextHop
)) {
679 Status
= Ip6GetMulticastMac (IpSb
->Mnp
, NextHop
, &Token
->DstMac
);
680 if (EFI_ERROR (Status
)) {
688 // If send to itself, directly send out
690 if (EFI_IP6_EQUAL (&Packet
->Ip
.Ip6
->DestinationAddress
, &Packet
->Ip
.Ip6
->SourceAddress
)) {
691 IP6_COPY_LINK_ADDRESS (&Token
->DstMac
, &IpSb
->SnpMode
.CurrentAddress
);
696 // If unicast, check the neighbor state.
699 NeighborCache
= Ip6FindNeighborEntry (IpSb
, NextHop
);
700 ASSERT (NeighborCache
!= NULL
);
702 if (NeighborCache
->Interface
== NULL
) {
703 NeighborCache
->Interface
= Interface
;
706 switch (NeighborCache
->State
) {
707 case EfiNeighborStale
:
708 NeighborCache
->State
= EfiNeighborDelay
;
709 NeighborCache
->Ticks
= (UINT32
)IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME
);
713 case EfiNeighborReachable
:
714 case EfiNeighborDelay
:
715 case EfiNeighborProbe
:
716 IP6_COPY_LINK_ADDRESS (&Token
->DstMac
, &NeighborCache
->LinkAddress
);
725 // Have to do asynchronous ARP resolution. First check whether there is
726 // already a pending request.
728 NET_LIST_FOR_EACH (Entry
, &Interface
->ArpQues
) {
729 ArpQue
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, ArpList
);
730 if (ArpQue
== NeighborCache
) {
731 InsertTailList (&NeighborCache
->Frames
, &Token
->Link
);
732 NeighborCache
->ArpFree
= TRUE
;
738 // First frame requires ARP.
740 InsertTailList (&NeighborCache
->Frames
, &Token
->Link
);
741 InsertTailList (&Interface
->ArpQues
, &NeighborCache
->ArpList
);
743 NeighborCache
->ArpFree
= TRUE
;
749 // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
750 // Remove it if the returned status is not EFI_SUCCESS.
752 InsertTailList (&Interface
->SentFrames
, &Token
->Link
);
753 Status
= IpSb
->Mnp
->Transmit (IpSb
->Mnp
, &Token
->MnpToken
);
754 if (EFI_ERROR (Status
)) {
755 RemoveEntryList (&Token
->Link
);
762 Ip6FreeLinkTxToken (Token
);
767 The heartbeat timer of IP6 service instance. It times out
768 all of its IP6 children's received-but-not-delivered and
769 transmitted-but-not-recycle packets.
771 @param[in] Event The IP6 service instance's heartbeat timer.
772 @param[in] Context The IP6 service instance.
784 IpSb
= (IP6_SERVICE
*)Context
;
785 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
787 Ip6PacketTimerTicking (IpSb
);
788 Ip6NdTimerTicking (IpSb
);
789 Ip6MldTimerTicking (IpSb
);