2 Implement IP6 pesudo 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
;
163 // Node should delay joining the solicited-node mulitcast address by a random delay
164 // between 0 and MAX_RTR_SOLICITATION_DELAY (1 second).
165 // Thus queue the address to be processed in Duplicate Address Detection module
166 // after the delay time (in milliseconds).
168 Delay
= (UINT64
) NET_RANDOM (NetRandomInitSeed ());
169 Delay
= MultU64x32 (Delay
, IP6_ONE_SECOND_IN_MS
);
170 Delay
= RShiftU64 (Delay
, 32);
172 DelayNode
= (IP6_DELAY_JOIN_LIST
*) AllocatePool (sizeof (IP6_DELAY_JOIN_LIST
));
173 if (DelayNode
== NULL
) {
174 FreePool (AddressInfo
);
175 return EFI_OUT_OF_RESOURCES
;
178 DelayNode
->DelayTime
= (UINT32
) (DivU64x32 (Delay
, IP6_TIMER_INTERVAL_IN_MS
));
179 DelayNode
->Interface
= Interface
;
180 DelayNode
->AddressInfo
= AddressInfo
;
181 DelayNode
->DadCallback
= DadCallback
;
182 DelayNode
->Context
= Context
;
184 InsertTailList (&Interface
->DelayJoinList
, &DelayNode
->Link
);
189 Create an IP6_INTERFACE.
191 @param[in] IpSb The IP6 service binding instance.
192 @param[in] LinkLocal If TRUE, the instance is created for link-local address.
193 Otherwise, it is not for a link-local address.
195 @return Point to the created IP6_INTERFACE, otherwise NULL.
200 IN IP6_SERVICE
*IpSb
,
205 IP6_INTERFACE
*Interface
;
206 EFI_IPv6_ADDRESS
*Ip6Addr
;
208 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
210 Interface
= AllocatePool (sizeof (IP6_INTERFACE
));
211 if (Interface
== NULL
) {
215 Interface
->Signature
= IP6_INTERFACE_SIGNATURE
;
216 Interface
->RefCnt
= 1;
218 InitializeListHead (&Interface
->AddressList
);
219 Interface
->AddressCount
= 0;
220 Interface
->Configured
= FALSE
;
222 Interface
->Service
= IpSb
;
223 Interface
->Controller
= IpSb
->Controller
;
224 Interface
->Image
= IpSb
->Image
;
226 InitializeListHead (&Interface
->ArpQues
);
227 InitializeListHead (&Interface
->SentFrames
);
229 Interface
->DupAddrDetect
= IpSb
->Ip6ConfigInstance
.DadXmits
.DupAddrDetectTransmits
;
230 InitializeListHead (&Interface
->DupAddrDetectList
);
232 InitializeListHead (&Interface
->DelayJoinList
);
234 InitializeListHead (&Interface
->IpInstances
);
235 Interface
->PromiscRecv
= FALSE
;
242 // Get the link local addr
244 Ip6Addr
= Ip6CreateLinkLocalAddr (IpSb
);
245 if (Ip6Addr
== NULL
) {
250 // Perform DAD - Duplicate Address Detection.
252 Status
= Ip6SetAddress (
256 IP6_LINK_LOCAL_PREFIX_LENGTH
,
257 (UINT32
) IP6_INFINIT_LIFETIME
,
258 (UINT32
) IP6_INFINIT_LIFETIME
,
265 if (EFI_ERROR (Status
)) {
273 FreePool (Interface
);
278 Free the interface used by IpInstance. All the IP instance with
279 the same Ip/prefix pair share the same interface. It is reference
280 counted. All the frames that haven't been sent will be cancelled.
281 Because the IpInstance is optional, the caller must remove
282 IpInstance from the interface's instance list.
284 @param[in] Interface The interface used by the IpInstance.
285 @param[in] IpInstance The IP instance that free the interface. NULL if
286 the IP driver is releasing the default interface.
291 IN IP6_INTERFACE
*Interface
,
292 IN IP6_PROTOCOL
*IpInstance OPTIONAL
295 IP6_DAD_ENTRY
*Duplicate
;
296 IP6_DELAY_JOIN_LIST
*Delay
;
298 NET_CHECK_SIGNATURE (Interface
, IP6_INTERFACE_SIGNATURE
);
299 ASSERT (Interface
->RefCnt
> 0);
302 // Remove all the pending transmit token related to this IP instance.
304 Ip6CancelFrames (Interface
, EFI_ABORTED
, Ip6CancelInstanceFrame
, IpInstance
);
306 if (--Interface
->RefCnt
> 0) {
311 // Destroy the interface if this is the last IP instance.
312 // Remove all the system transmitted packets
313 // from this interface, cancel the receive request if exists.
315 Ip6CancelFrames (Interface
, EFI_ABORTED
, Ip6CancelInstanceFrame
, NULL
);
317 ASSERT (IsListEmpty (&Interface
->IpInstances
));
318 ASSERT (IsListEmpty (&Interface
->ArpQues
));
319 ASSERT (IsListEmpty (&Interface
->SentFrames
));
321 while (!IsListEmpty (&Interface
->DupAddrDetectList
)) {
322 Duplicate
= NET_LIST_HEAD (&Interface
->DupAddrDetectList
, IP6_DAD_ENTRY
, Link
);
323 NetListRemoveHead (&Interface
->DupAddrDetectList
);
324 FreePool (Duplicate
);
327 while (!IsListEmpty (&Interface
->DelayJoinList
)) {
328 Delay
= NET_LIST_HEAD (&Interface
->DelayJoinList
, IP6_DELAY_JOIN_LIST
, Link
);
329 NetListRemoveHead (&Interface
->DelayJoinList
);
333 Ip6RemoveAddr (Interface
->Service
, &Interface
->AddressList
, &Interface
->AddressCount
, NULL
, 0);
335 RemoveEntryList (&Interface
->Link
);
336 FreePool (Interface
);
340 Create and wrap a transmit request into a newly allocated IP6_LINK_TX_TOKEN.
342 @param[in] Interface The interface to send out from.
343 @param[in] IpInstance The IpInstance that transmit the packet. NULL if
344 the packet is sent by the IP6 driver itself.
345 @param[in] Packet The packet to transmit
346 @param[in] CallBack Call back function to execute if transmission
348 @param[in] Context Opaque parameter to the callback.
350 @return The wrapped token if succeed or NULL.
354 Ip6CreateLinkTxToken (
355 IN IP6_INTERFACE
*Interface
,
356 IN IP6_PROTOCOL
*IpInstance OPTIONAL
,
358 IN IP6_FRAME_CALLBACK CallBack
,
362 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*MnpToken
;
363 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*MnpTxData
;
364 IP6_LINK_TX_TOKEN
*Token
;
368 Token
= AllocatePool (sizeof (IP6_LINK_TX_TOKEN
) + (Packet
->BlockOpNum
- 1) * sizeof (EFI_MANAGED_NETWORK_FRAGMENT_DATA
));
374 Token
->Signature
= IP6_LINK_TX_SIGNATURE
;
375 InitializeListHead (&Token
->Link
);
377 Token
->IpInstance
= IpInstance
;
378 Token
->CallBack
= CallBack
;
379 Token
->Packet
= Packet
;
380 Token
->Context
= Context
;
381 ZeroMem (&Token
->DstMac
, sizeof (EFI_MAC_ADDRESS
));
382 IP6_COPY_LINK_ADDRESS (&Token
->SrcMac
, &Interface
->Service
->SnpMode
.CurrentAddress
);
384 MnpToken
= &(Token
->MnpToken
);
385 MnpToken
->Status
= EFI_NOT_READY
;
387 Status
= gBS
->CreateEvent (
395 if (EFI_ERROR (Status
)) {
400 MnpTxData
= &Token
->MnpTxData
;
401 MnpToken
->Packet
.TxData
= MnpTxData
;
403 MnpTxData
->DestinationAddress
= &Token
->DstMac
;
404 MnpTxData
->SourceAddress
= &Token
->SrcMac
;
405 MnpTxData
->ProtocolType
= IP6_ETHER_PROTO
;
406 MnpTxData
->DataLength
= Packet
->TotalSize
;
407 MnpTxData
->HeaderLength
= 0;
409 Count
= Packet
->BlockOpNum
;
411 NetbufBuildExt (Packet
, (NET_FRAGMENT
*) MnpTxData
->FragmentTable
, &Count
);
412 MnpTxData
->FragmentCount
= (UINT16
)Count
;
418 Free the link layer transmit token. It will close the event,
419 then free the memory used.
421 @param[in] Token Token to free.
426 IN IP6_LINK_TX_TOKEN
*Token
429 NET_CHECK_SIGNATURE (Token
, IP6_LINK_TX_SIGNATURE
);
431 gBS
->CloseEvent (Token
->MnpToken
.Event
);
436 Callback function when the received packet is freed.
437 Check Ip6OnFrameReceived for information.
439 @param[in] Context Points to EFI_MANAGED_NETWORK_RECEIVE_DATA.
448 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
450 RxData
= (EFI_MANAGED_NETWORK_RECEIVE_DATA
*) Context
;
452 gBS
->SignalEvent (RxData
->RecycleEvent
);
456 Received a frame from MNP. Wrap it in net buffer then deliver
457 it to IP's input function. The ownship of the packet also
458 is transferred to IP. When Ip is finished with this packet, it
459 will call NetbufFree to release the packet, NetbufFree will
460 again call the Ip6RecycleFrame to signal MNP's event and free
463 @param[in] Context Context for the callback.
468 Ip6OnFrameReceivedDpc (
472 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*MnpToken
;
473 EFI_MANAGED_NETWORK_RECEIVE_DATA
*MnpRxData
;
474 IP6_LINK_RX_TOKEN
*Token
;
475 NET_FRAGMENT Netfrag
;
480 Token
= (IP6_LINK_RX_TOKEN
*) Context
;
481 NET_CHECK_SIGNATURE (Token
, IP6_LINK_RX_SIGNATURE
);
484 // First clear the interface's receive request in case the
485 // caller wants to call Ip6ReceiveFrame in the callback.
487 IpSb
= (IP6_SERVICE
*) Token
->Context
;
488 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
491 MnpToken
= &Token
->MnpToken
;
492 MnpRxData
= MnpToken
->Packet
.RxData
;
494 if (EFI_ERROR (MnpToken
->Status
) || (MnpRxData
== NULL
)) {
495 Token
->CallBack (NULL
, MnpToken
->Status
, 0, Token
->Context
);
500 // Wrap the frame in a net buffer then deliever it to IP input.
501 // IP will reassemble the packet, and deliver it to upper layer
503 Netfrag
.Len
= MnpRxData
->DataLength
;
504 Netfrag
.Bulk
= MnpRxData
->PacketData
;
506 Packet
= NetbufFromExt (&Netfrag
, 1, IP6_MAX_HEADLEN
, 0, Ip6RecycleFrame
, Token
->MnpToken
.Packet
.RxData
);
508 if (Packet
== NULL
) {
509 gBS
->SignalEvent (MnpRxData
->RecycleEvent
);
511 Token
->CallBack (NULL
, EFI_OUT_OF_RESOURCES
, 0, Token
->Context
);
516 Flag
= (MnpRxData
->BroadcastFlag
? IP6_LINK_BROADCAST
: 0);
517 Flag
|= (MnpRxData
->MulticastFlag
? IP6_LINK_MULTICAST
: 0);
518 Flag
|= (MnpRxData
->PromiscuousFlag
? IP6_LINK_PROMISC
: 0);
520 Token
->CallBack (Packet
, EFI_SUCCESS
, Flag
, Token
->Context
);
524 Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK.
526 @param Event The receive event delivered to MNP for receive.
527 @param Context Context for the callback.
538 // Request Ip6OnFrameReceivedDpc as a DPC at TPL_CALLBACK
540 QueueDpc (TPL_CALLBACK
, Ip6OnFrameReceivedDpc
, Context
);
544 Request to receive the packet from the interface.
546 @param[in] CallBack Function to call when receive finished.
547 @param[in] IpSb Points to IP6 service binding instance.
549 @retval EFI_ALREADY_STARTED There is already a pending receive request.
550 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to receive.
551 @retval EFI_SUCCESS The recieve request has been started.
556 IN IP6_FRAME_CALLBACK CallBack
,
561 IP6_LINK_RX_TOKEN
*Token
;
563 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
565 Token
= &IpSb
->RecvRequest
;
566 Token
->CallBack
= CallBack
;
567 Token
->Context
= (VOID
*) IpSb
;
569 Status
= IpSb
->Mnp
->Receive (IpSb
->Mnp
, &Token
->MnpToken
);
570 if (EFI_ERROR (Status
)) {
578 Callback funtion when frame transmission is finished. It will
579 call the frame owner's callback function to tell it the result.
581 @param[in] Context Context which points to the token.
590 IP6_LINK_TX_TOKEN
*Token
;
592 Token
= (IP6_LINK_TX_TOKEN
*) Context
;
593 NET_CHECK_SIGNATURE (Token
, IP6_LINK_TX_SIGNATURE
);
595 RemoveEntryList (&Token
->Link
);
599 Token
->MnpToken
.Status
,
604 Ip6FreeLinkTxToken (Token
);
608 Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK.
610 @param[in] Event The transmit token's event.
611 @param[in] Context Context which points to the token.
622 // Request Ip6OnFrameSentDpc as a DPC at TPL_CALLBACK
624 QueueDpc (TPL_CALLBACK
, Ip6OnFrameSentDpc
, Context
);
628 Send a frame from the interface. If the next hop is a multicast address,
629 it is transmitted immediately. If the next hop is a unicast,
630 and the NextHop's MAC is not known, it will perform address resolution.
631 If an error occurred, the CallBack won't be called. So, the caller
632 must test the return value, and take action when there is an error.
634 @param[in] Interface The interface to send the frame from
635 @param[in] IpInstance The IP child that request the transmission.
636 NULL if it is the IP6 driver itself.
637 @param[in] Packet The packet to transmit.
638 @param[in] NextHop The immediate destination to transmit the packet to.
639 @param[in] CallBack Function to call back when transmit finished.
640 @param[in] Context Opaque parameter to the callback.
642 @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to send the frame.
643 @retval EFI_NO_MAPPING Can't resolve the MAC for the nexthop.
644 @retval EFI_SUCCESS The packet successfully transmitted.
649 IN IP6_INTERFACE
*Interface
,
650 IN IP6_PROTOCOL
*IpInstance OPTIONAL
,
652 IN EFI_IPv6_ADDRESS
*NextHop
,
653 IN IP6_FRAME_CALLBACK CallBack
,
658 IP6_LINK_TX_TOKEN
*Token
;
660 IP6_NEIGHBOR_ENTRY
*NeighborCache
;
662 IP6_NEIGHBOR_ENTRY
*ArpQue
;
664 IpSb
= Interface
->Service
;
665 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
668 // Only when link local address is performing DAD, the interface could be used in unconfigured.
670 if (IpSb
->LinkLocalOk
) {
671 ASSERT (Interface
->Configured
);
674 Token
= Ip6CreateLinkTxToken (Interface
, IpInstance
, Packet
, CallBack
, Context
);
677 return EFI_OUT_OF_RESOURCES
;
680 if (IP6_IS_MULTICAST (NextHop
)) {
681 Status
= Ip6GetMulticastMac (IpSb
->Mnp
, NextHop
, &Token
->DstMac
);
682 if (EFI_ERROR (Status
)) {
690 // If send to itself, directly send out
692 if (EFI_IP6_EQUAL (&Packet
->Ip
.Ip6
->DestinationAddress
, &Packet
->Ip
.Ip6
->SourceAddress
)) {
693 IP6_COPY_LINK_ADDRESS (&Token
->DstMac
, &IpSb
->SnpMode
.CurrentAddress
);
698 // If unicast, check the neighbor state.
701 NeighborCache
= Ip6FindNeighborEntry (IpSb
, NextHop
);
702 ASSERT (NeighborCache
!= NULL
);
704 if (NeighborCache
->Interface
== NULL
) {
705 NeighborCache
->Interface
= Interface
;
708 switch (NeighborCache
->State
) {
709 case EfiNeighborStale
:
710 NeighborCache
->State
= EfiNeighborDelay
;
711 NeighborCache
->Ticks
= (UINT32
) IP6_GET_TICKS (IP6_DELAY_FIRST_PROBE_TIME
);
715 case EfiNeighborReachable
:
716 case EfiNeighborDelay
:
717 case EfiNeighborProbe
:
718 IP6_COPY_LINK_ADDRESS (&Token
->DstMac
, &NeighborCache
->LinkAddress
);
727 // Have to do asynchronous ARP resolution. First check whether there is
728 // already a pending request.
730 NET_LIST_FOR_EACH (Entry
, &Interface
->ArpQues
) {
731 ArpQue
= NET_LIST_USER_STRUCT (Entry
, IP6_NEIGHBOR_ENTRY
, ArpList
);
732 if (ArpQue
== NeighborCache
) {
733 InsertTailList (&NeighborCache
->Frames
, &Token
->Link
);
734 NeighborCache
->ArpFree
= TRUE
;
740 // First frame requires ARP.
742 InsertTailList (&NeighborCache
->Frames
, &Token
->Link
);
743 InsertTailList (&Interface
->ArpQues
, &NeighborCache
->ArpList
);
745 NeighborCache
->ArpFree
= TRUE
;
751 // Insert the tx token into the SentFrames list before calling Mnp->Transmit.
752 // Remove it if the returned status is not EFI_SUCCESS.
754 InsertTailList (&Interface
->SentFrames
, &Token
->Link
);
755 Status
= IpSb
->Mnp
->Transmit (IpSb
->Mnp
, &Token
->MnpToken
);
756 if (EFI_ERROR (Status
)) {
757 RemoveEntryList (&Token
->Link
);
764 Ip6FreeLinkTxToken (Token
);
769 The heartbeat timer of IP6 service instance. It times out
770 all of its IP6 children's received-but-not-delivered and
771 transmitted-but-not-recycle packets.
773 @param[in] Event The IP6 service instance's heartbeat timer.
774 @param[in] Context The IP6 service instance.
786 IpSb
= (IP6_SERVICE
*) Context
;
787 NET_CHECK_SIGNATURE (IpSb
, IP6_SERVICE_SIGNATURE
);
789 Ip6PacketTimerTicking (IpSb
);
790 Ip6NdTimerTicking (IpSb
);
791 Ip6MldTimerTicking (IpSb
);