4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
11 #include <Protocol/Udp4.h>
13 #include <Library/IpIoLib.h>
14 #include <Library/BaseLib.h>
15 #include <Library/DebugLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/UefiBootServicesTableLib.h>
18 #include <Library/MemoryAllocationLib.h>
19 #include <Library/DpcLib.h>
21 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList
= {
26 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData
= {
47 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData
= {
53 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
56 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
65 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap
[10] = {
66 { FALSE
, TRUE
}, // ICMP_ERR_UNREACH_NET
67 { FALSE
, TRUE
}, // ICMP_ERR_UNREACH_HOST
68 { TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PROTOCOL
69 { TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PORT
70 { TRUE
, TRUE
}, // ICMP_ERR_MSGSIZE
71 { FALSE
, TRUE
}, // ICMP_ERR_UNREACH_SRCFAIL
72 { FALSE
, TRUE
}, // ICMP_ERR_TIMXCEED_INTRANS
73 { FALSE
, TRUE
}, // ICMP_ERR_TIMEXCEED_REASS
74 { FALSE
, FALSE
}, // ICMP_ERR_QUENCH
75 { FALSE
, TRUE
} // ICMP_ERR_PARAMPROB
78 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap
[10] = {
79 { FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_NET
80 { FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_HOST
81 { TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PROTOCOL
82 { TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PORT
83 { TRUE
, TRUE
}, // ICMP6_ERR_PACKAGE_TOOBIG
84 { FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
85 { FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_REASS
86 { FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_HEADER
87 { FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_NEXHEADER
88 { FALSE
, TRUE
} // ICMP6_ERR_PARAMPROB_IPV6OPTION
92 Notify function for IP transmit token.
94 @param[in] Context The context passed in by the event notifier.
99 IpIoTransmitHandlerDpc (
104 Notify function for IP transmit token.
106 @param[in] Event The event signaled.
107 @param[in] Context The context passed in by the event notifier.
112 IpIoTransmitHandler (
118 This function create an IP child ,open the IP protocol, and return the opened
119 IP protocol as Interface.
121 @param[in] ControllerHandle The controller handle.
122 @param[in] ImageHandle The image handle.
123 @param[in] ChildHandle Pointer to the buffer to save the IP child handle.
124 @param[in] IpVersion The version of the IP protocol to use, either
126 @param[out] Interface Pointer used to get the IP protocol interface.
128 @retval EFI_SUCCESS The IP child is created and the IP protocol
129 interface is retrieved.
130 @retval EFI_UNSUPPORTED Unsupported IpVersion.
131 @retval Others The required operation failed.
135 IpIoCreateIpChildOpenProtocol (
136 IN EFI_HANDLE ControllerHandle
,
137 IN EFI_HANDLE ImageHandle
,
138 IN EFI_HANDLE
*ChildHandle
,
144 EFI_GUID
*ServiceBindingGuid
;
145 EFI_GUID
*IpProtocolGuid
;
147 if (IpVersion
== IP_VERSION_4
) {
148 ServiceBindingGuid
= &gEfiIp4ServiceBindingProtocolGuid
;
149 IpProtocolGuid
= &gEfiIp4ProtocolGuid
;
150 } else if (IpVersion
== IP_VERSION_6
) {
151 ServiceBindingGuid
= &gEfiIp6ServiceBindingProtocolGuid
;
152 IpProtocolGuid
= &gEfiIp6ProtocolGuid
;
154 return EFI_UNSUPPORTED
;
158 // Create an IP child.
160 Status
= NetLibCreateServiceChild (
166 if (EFI_ERROR (Status
)) {
171 // Open the IP protocol installed on the *ChildHandle.
173 Status
= gBS
->OpenProtocol (
179 EFI_OPEN_PROTOCOL_BY_DRIVER
181 if (EFI_ERROR (Status
)) {
183 // On failure, destroy the IP child.
185 NetLibDestroyServiceChild (
197 This function close the previously opened IP protocol and destroy the IP child.
199 @param[in] ControllerHandle The controller handle.
200 @param[in] ImageHandle The image handle.
201 @param[in] ChildHandle The child handle of the IP child.
202 @param[in] IpVersion The version of the IP protocol to use, either
205 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child
207 @retval EFI_UNSUPPORTED Unsupported IpVersion.
208 @retval Others The required operation failed.
212 IpIoCloseProtocolDestroyIpChild (
213 IN EFI_HANDLE ControllerHandle
,
214 IN EFI_HANDLE ImageHandle
,
215 IN EFI_HANDLE ChildHandle
,
220 EFI_GUID
*ServiceBindingGuid
;
221 EFI_GUID
*IpProtocolGuid
;
223 if (IpVersion
== IP_VERSION_4
) {
224 ServiceBindingGuid
= &gEfiIp4ServiceBindingProtocolGuid
;
225 IpProtocolGuid
= &gEfiIp4ProtocolGuid
;
226 } else if (IpVersion
== IP_VERSION_6
) {
227 ServiceBindingGuid
= &gEfiIp6ServiceBindingProtocolGuid
;
228 IpProtocolGuid
= &gEfiIp6ProtocolGuid
;
230 return EFI_UNSUPPORTED
;
234 // Close the previously opened IP protocol.
236 Status
= gBS
->CloseProtocol (
242 if (EFI_ERROR (Status
)) {
247 // Destroy the IP child.
249 return NetLibDestroyServiceChild (
258 This function handles ICMPv4 packets. It is the worker function of
261 @param[in] IpIo Pointer to the IP_IO instance.
262 @param[in, out] Pkt Pointer to the ICMPv4 packet.
263 @param[in] Session Pointer to the net session of this ICMPv4 packet.
265 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.
266 @retval EFI_ABORTED This type of ICMPv4 packet is not supported.
273 IN EFI_NET_SESSION_DATA
*Session
276 IP4_ICMP_ERROR_HEAD
*IcmpHdr
;
277 EFI_IP4_HEADER
*IpHdr
;
284 ASSERT (IpIo
!= NULL
);
285 ASSERT (Pkt
!= NULL
);
286 ASSERT (Session
!= NULL
);
287 ASSERT (IpIo
->IpVersion
== IP_VERSION_4
);
290 // Check the ICMP packet length.
292 if (Pkt
->TotalSize
< sizeof (IP4_ICMP_ERROR_HEAD
)) {
296 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP4_ICMP_ERROR_HEAD
);
297 IpHdr
= (EFI_IP4_HEADER
*)(&IcmpHdr
->IpHead
);
299 if (Pkt
->TotalSize
< ICMP_ERRLEN (IpHdr
)) {
303 Type
= IcmpHdr
->Head
.Type
;
304 Code
= IcmpHdr
->Head
.Code
;
307 // Analyze the ICMP Error in this ICMP pkt
310 case ICMP_TYPE_UNREACH
:
312 case ICMP_CODE_UNREACH_NET
:
313 case ICMP_CODE_UNREACH_HOST
:
314 case ICMP_CODE_UNREACH_PROTOCOL
:
315 case ICMP_CODE_UNREACH_PORT
:
316 case ICMP_CODE_UNREACH_SRCFAIL
:
317 IcmpErr
= (UINT8
)(ICMP_ERR_UNREACH_NET
+ Code
);
321 case ICMP_CODE_UNREACH_NEEDFRAG
:
322 IcmpErr
= ICMP_ERR_MSGSIZE
;
326 case ICMP_CODE_UNREACH_NET_UNKNOWN
:
327 case ICMP_CODE_UNREACH_NET_PROHIB
:
328 case ICMP_CODE_UNREACH_TOSNET
:
329 IcmpErr
= ICMP_ERR_UNREACH_NET
;
333 case ICMP_CODE_UNREACH_HOST_UNKNOWN
:
334 case ICMP_CODE_UNREACH_ISOLATED
:
335 case ICMP_CODE_UNREACH_HOST_PROHIB
:
336 case ICMP_CODE_UNREACH_TOSHOST
:
337 IcmpErr
= ICMP_ERR_UNREACH_HOST
;
347 case ICMP_TYPE_TIMXCEED
:
352 IcmpErr
= (UINT8
)(Code
+ ICMP_ERR_TIMXCEED_INTRANS
);
356 case ICMP_TYPE_PARAMPROB
:
361 IcmpErr
= ICMP_ERR_PARAMPROB
;
365 case ICMP_TYPE_SOURCEQUENCH
:
370 IcmpErr
= ICMP_ERR_QUENCH
;
379 // Notify user the ICMP pkt only containing payload except
380 // IP and ICMP header
382 PayLoadHdr
= (UINT8
*)((UINT8
*)IpHdr
+ EFI_IP4_HEADER_LEN (IpHdr
));
383 TrimBytes
= (UINT32
)(PayLoadHdr
- (UINT8
*)IcmpHdr
);
385 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
388 // If the input packet has invalid format, and TrimBytes is larger than
389 // the packet size, the NetbufTrim might trim the packet to zero.
391 if (Pkt
->TotalSize
!= 0) {
392 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
399 This function handles ICMPv6 packets. It is the worker function of
402 @param[in] IpIo Pointer to the IP_IO instance.
403 @param[in, out] Pkt Pointer to the ICMPv6 packet.
404 @param[in] Session Pointer to the net session of this ICMPv6 packet.
406 @retval EFI_SUCCESS The ICMPv6 packet is handled successfully.
407 @retval EFI_ABORTED This type of ICMPv6 packet is not supported.
414 IN EFI_NET_SESSION_DATA
*Session
417 IP6_ICMP_ERROR_HEAD
*IcmpHdr
;
418 EFI_IP6_HEADER
*IpHdr
;
427 ASSERT (IpIo
!= NULL
);
428 ASSERT (Pkt
!= NULL
);
429 ASSERT (Session
!= NULL
);
430 ASSERT (IpIo
->IpVersion
== IP_VERSION_6
);
433 // Check the ICMPv6 packet length.
435 if (Pkt
->TotalSize
< sizeof (IP6_ICMP_ERROR_HEAD
)) {
439 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP6_ICMP_ERROR_HEAD
);
440 Type
= IcmpHdr
->Head
.Type
;
441 Code
= IcmpHdr
->Head
.Code
;
444 // Analyze the ICMPv6 Error in this ICMPv6 packet
447 case ICMP_V6_DEST_UNREACHABLE
:
449 case ICMP_V6_NO_ROUTE_TO_DEST
:
450 case ICMP_V6_BEYOND_SCOPE
:
451 case ICMP_V6_ROUTE_REJECTED
:
452 IcmpErr
= ICMP6_ERR_UNREACH_NET
;
456 case ICMP_V6_COMM_PROHIBITED
:
457 case ICMP_V6_ADDR_UNREACHABLE
:
458 case ICMP_V6_SOURCE_ADDR_FAILED
:
459 IcmpErr
= ICMP6_ERR_UNREACH_HOST
;
463 case ICMP_V6_PORT_UNREACHABLE
:
464 IcmpErr
= ICMP6_ERR_UNREACH_PORT
;
474 case ICMP_V6_PACKET_TOO_BIG
:
479 IcmpErr
= ICMP6_ERR_PACKAGE_TOOBIG
;
483 case ICMP_V6_TIME_EXCEEDED
:
488 IcmpErr
= (UINT8
)(ICMP6_ERR_TIMXCEED_HOPLIMIT
+ Code
);
492 case ICMP_V6_PARAMETER_PROBLEM
:
497 IcmpErr
= (UINT8
)(ICMP6_ERR_PARAMPROB_HEADER
+ Code
);
507 // Notify user the ICMPv6 packet only containing payload except
508 // IPv6 basic header, extension header and ICMP header
511 IpHdr
= (EFI_IP6_HEADER
*)(&IcmpHdr
->IpHead
);
512 NextHeader
= IpHdr
->NextHeader
;
513 PayLoadHdr
= (UINT8
*)((UINT8
*)IcmpHdr
+ sizeof (IP6_ICMP_ERROR_HEAD
));
517 switch (NextHeader
) {
518 case EFI_IP_PROTO_UDP
:
519 case EFI_IP_PROTO_TCP
:
520 case EFI_IP_PROTO_ICMP
:
521 case IP6_NO_NEXT_HEADER
:
527 case IP6_DESTINATION
:
529 // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
530 // the first 8 octets.
532 NextHeader
= *(PayLoadHdr
);
533 PayLoadHdr
= (UINT8
*)(PayLoadHdr
+ (*(PayLoadHdr
+ 1) + 1) * 8);
539 // The Fragment Header Length is 8 octets.
541 NextHeader
= *(PayLoadHdr
);
542 PayLoadHdr
= (UINT8
*)(PayLoadHdr
+ 8);
552 TrimBytes
= (UINT32
)(PayLoadHdr
- (UINT8
*)IcmpHdr
);
554 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
557 // If the input packet has invalid format, and TrimBytes is larger than
558 // the packet size, the NetbufTrim might trim the packet to zero.
560 if (Pkt
->TotalSize
!= 0) {
561 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
568 This function handles ICMP packets.
570 @param[in] IpIo Pointer to the IP_IO instance.
571 @param[in, out] Pkt Pointer to the ICMP packet.
572 @param[in] Session Pointer to the net session of this ICMP packet.
574 @retval EFI_SUCCESS The ICMP packet is handled successfully.
575 @retval EFI_ABORTED This type of ICMP packet is not supported.
576 @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
583 IN EFI_NET_SESSION_DATA
*Session
586 if (IpIo
->IpVersion
== IP_VERSION_4
) {
587 return IpIoIcmpv4Handler (IpIo
, Pkt
, Session
);
588 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
589 return IpIoIcmpv6Handler (IpIo
, Pkt
, Session
);
591 return EFI_UNSUPPORTED
;
596 Free function for receive token of IP_IO. It is used to
597 signal the recycle event to notify IP to recycle the
600 @param[in] Event The event to be signaled.
609 gBS
->SignalEvent ((EFI_EVENT
)Event
);
613 Create a send entry to wrap a packet before sending
616 @param[in, out] IpIo Pointer to the IP_IO instance.
617 @param[in, out] Pkt Pointer to the packet.
618 @param[in] Sender Pointer to the IP sender.
619 @param[in] Context Pointer to the context.
620 @param[in] NotifyData Pointer to the notify data.
621 @param[in] Dest Pointer to the destination IP address.
622 @param[in] Override Pointer to the overridden IP_IO data.
624 @return Pointer to the data structure created to wrap the packet. If any error occurs,
632 IN IP_IO_IP_PROTOCOL Sender
,
633 IN VOID
*Context OPTIONAL
,
634 IN VOID
*NotifyData OPTIONAL
,
635 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
636 IN IP_IO_OVERRIDE
*Override
639 IP_IO_SEND_ENTRY
*SndEntry
;
642 NET_FRAGMENT
*ExtFragment
;
643 UINT32 FragmentCount
;
644 IP_IO_OVERRIDE
*OverrideData
;
645 IP_IO_IP_TX_DATA
*TxData
;
646 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
647 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
649 if ((IpIo
->IpVersion
!= IP_VERSION_4
) && (IpIo
->IpVersion
!= IP_VERSION_6
)) {
658 // Allocate resource for SndEntry
660 SndEntry
= AllocatePool (sizeof (IP_IO_SEND_ENTRY
));
661 if (NULL
== SndEntry
) {
665 Status
= gBS
->CreateEvent (
672 if (EFI_ERROR (Status
)) {
676 FragmentCount
= Pkt
->BlockOpNum
;
679 // Allocate resource for TxData
681 TxData
= (IP_IO_IP_TX_DATA
*)AllocatePool (
682 sizeof (IP_IO_IP_TX_DATA
) + sizeof (NET_FRAGMENT
) * (FragmentCount
- 1)
685 if (NULL
== TxData
) {
690 // Build a fragment table to contain the fragments in the packet.
692 if (IpIo
->IpVersion
== IP_VERSION_4
) {
693 ExtFragment
= (NET_FRAGMENT
*)TxData
->Ip4TxData
.FragmentTable
;
695 ExtFragment
= (NET_FRAGMENT
*)TxData
->Ip6TxData
.FragmentTable
;
698 NetbufBuildExt (Pkt
, ExtFragment
, &FragmentCount
);
701 // Allocate resource for OverrideData if needed
703 if (NULL
!= Override
) {
704 OverrideData
= AllocateCopyPool (sizeof (IP_IO_OVERRIDE
), Override
);
705 if (NULL
== OverrideData
) {
711 // Set other fields of TxData except the fragment table
713 if (IpIo
->IpVersion
== IP_VERSION_4
) {
714 Ip4TxData
= &TxData
->Ip4TxData
;
716 IP4_COPY_ADDRESS (&Ip4TxData
->DestinationAddress
, Dest
);
718 Ip4TxData
->OverrideData
= &OverrideData
->Ip4OverrideData
;
719 Ip4TxData
->OptionsLength
= 0;
720 Ip4TxData
->OptionsBuffer
= NULL
;
721 Ip4TxData
->TotalDataLength
= Pkt
->TotalSize
;
722 Ip4TxData
->FragmentCount
= FragmentCount
;
725 // Set the fields of SndToken
727 SndEntry
->SndToken
.Ip4Token
.Event
= Event
;
728 SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
= Ip4TxData
;
730 Ip6TxData
= &TxData
->Ip6TxData
;
733 CopyMem (&Ip6TxData
->DestinationAddress
, Dest
, sizeof (EFI_IPv6_ADDRESS
));
735 ZeroMem (&Ip6TxData
->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
));
738 Ip6TxData
->OverrideData
= &OverrideData
->Ip6OverrideData
;
739 Ip6TxData
->DataLength
= Pkt
->TotalSize
;
740 Ip6TxData
->FragmentCount
= FragmentCount
;
741 Ip6TxData
->ExtHdrsLength
= 0;
742 Ip6TxData
->ExtHdrs
= NULL
;
745 // Set the fields of SndToken
747 SndEntry
->SndToken
.Ip6Token
.Event
= Event
;
748 SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
= Ip6TxData
;
752 // Set the fields of SndEntry
754 SndEntry
->IpIo
= IpIo
;
755 SndEntry
->Ip
= Sender
;
756 SndEntry
->Context
= Context
;
757 SndEntry
->NotifyData
= NotifyData
;
762 InsertTailList (&IpIo
->PendingSndList
, &SndEntry
->Entry
);
768 if (OverrideData
!= NULL
) {
769 FreePool (OverrideData
);
772 if (TxData
!= NULL
) {
776 if (SndEntry
!= NULL
) {
781 gBS
->CloseEvent (Event
);
788 Destroy the SndEntry.
790 This function pairs with IpIoCreateSndEntry().
792 @param[in] SndEntry Pointer to the send entry to be destroyed.
796 IpIoDestroySndEntry (
797 IN IP_IO_SEND_ENTRY
*SndEntry
801 IP_IO_IP_TX_DATA
*TxData
;
802 IP_IO_OVERRIDE
*Override
;
804 if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_4
) {
805 Event
= SndEntry
->SndToken
.Ip4Token
.Event
;
806 TxData
= (IP_IO_IP_TX_DATA
*)SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
;
807 Override
= (IP_IO_OVERRIDE
*)TxData
->Ip4TxData
.OverrideData
;
808 } else if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_6
) {
809 Event
= SndEntry
->SndToken
.Ip6Token
.Event
;
810 TxData
= (IP_IO_IP_TX_DATA
*)SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
;
811 Override
= (IP_IO_OVERRIDE
*)TxData
->Ip6TxData
.OverrideData
;
816 gBS
->CloseEvent (Event
);
820 if (NULL
!= Override
) {
824 NetbufFree (SndEntry
->Pkt
);
826 RemoveEntryList (&SndEntry
->Entry
);
832 Notify function for IP transmit token.
834 @param[in] Context The context passed in by the event notifier.
839 IpIoTransmitHandlerDpc (
844 IP_IO_SEND_ENTRY
*SndEntry
;
847 SndEntry
= (IP_IO_SEND_ENTRY
*)Context
;
849 IpIo
= SndEntry
->IpIo
;
851 if (IpIo
->IpVersion
== IP_VERSION_4
) {
852 Status
= SndEntry
->SndToken
.Ip4Token
.Status
;
853 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
854 Status
= SndEntry
->SndToken
.Ip6Token
.Status
;
859 if ((IpIo
->PktSentNotify
!= NULL
) && (SndEntry
->NotifyData
!= NULL
)) {
860 IpIo
->PktSentNotify (
868 IpIoDestroySndEntry (SndEntry
);
872 Notify function for IP transmit token.
874 @param[in] Event The event signaled.
875 @param[in] Context The context passed in by the event notifier.
880 IpIoTransmitHandler (
886 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
888 QueueDpc (TPL_CALLBACK
, IpIoTransmitHandlerDpc
, Context
);
892 The dummy handler for the dummy IP receive token.
894 @param[in] Context The context passed in by the event notifier.
899 IpIoDummyHandlerDpc (
903 IP_IO_IP_INFO
*IpInfo
;
905 EFI_EVENT RecycleEvent
;
907 IpInfo
= (IP_IO_IP_INFO
*)Context
;
909 if ((IpInfo
->IpVersion
!= IP_VERSION_4
) && (IpInfo
->IpVersion
!= IP_VERSION_6
)) {
915 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
916 Status
= IpInfo
->DummyRcvToken
.Ip4Token
.Status
;
918 if (IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
!= NULL
) {
919 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
->RecycleSignal
;
922 Status
= IpInfo
->DummyRcvToken
.Ip6Token
.Status
;
924 if (IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
!= NULL
) {
925 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
->RecycleSignal
;
929 if (EFI_ABORTED
== Status
) {
931 // The reception is actively aborted by the consumer, directly return.
934 } else if (EFI_SUCCESS
== Status
) {
936 // Recycle the RxData.
938 ASSERT (RecycleEvent
!= NULL
);
940 gBS
->SignalEvent (RecycleEvent
);
944 // Continue the receive.
946 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
947 IpInfo
->Ip
.Ip4
->Receive (
949 &IpInfo
->DummyRcvToken
.Ip4Token
952 IpInfo
->Ip
.Ip6
->Receive (
954 &IpInfo
->DummyRcvToken
.Ip6Token
960 This function add IpIoDummyHandlerDpc to the end of the DPC queue.
962 @param[in] Event The event signaled.
963 @param[in] Context The context passed in by the event notifier.
974 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
976 QueueDpc (TPL_CALLBACK
, IpIoDummyHandlerDpc
, Context
);
980 Notify function for the IP receive token, used to process
981 the received IP packets.
983 @param[in] Context The context passed in by the event notifier.
988 IpIoListenHandlerDpc (
994 IP_IO_IP_RX_DATA
*RxData
;
995 EFI_NET_SESSION_DATA Session
;
998 IpIo
= (IP_IO
*)Context
;
1000 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1001 Status
= IpIo
->RcvToken
.Ip4Token
.Status
;
1002 RxData
= (IP_IO_IP_RX_DATA
*)IpIo
->RcvToken
.Ip4Token
.Packet
.RxData
;
1003 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
1004 Status
= IpIo
->RcvToken
.Ip6Token
.Status
;
1005 RxData
= (IP_IO_IP_RX_DATA
*)IpIo
->RcvToken
.Ip6Token
.Packet
.RxData
;
1010 if (EFI_ABORTED
== Status
) {
1012 // The reception is actively aborted by the consumer, directly return.
1017 if ((EFI_SUCCESS
!= Status
) && (EFI_ICMP_ERROR
!= Status
)) {
1019 // Only process the normal packets and the icmp error packets.
1021 if (RxData
!= NULL
) {
1029 // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).
1031 ASSERT (RxData
!= NULL
);
1032 if (RxData
== NULL
) {
1036 if (NULL
== IpIo
->PktRcvdNotify
) {
1040 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1041 ASSERT (RxData
->Ip4RxData
.Header
!= NULL
);
1042 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
))) {
1044 // The source address is a broadcast address, discard it.
1049 if ((EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
) != 0) &&
1050 (IpIo
->SubnetMask
!= 0) &&
1051 IP4_NET_EQUAL (IpIo
->StationIp
, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*)RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
) &&
1052 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*)RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
))
1055 // The source address doesn't match StationIp and it's not a unicast IP address, discard it.
1060 if (RxData
->Ip4RxData
.DataLength
== 0) {
1062 // Discard zero length data payload packet.
1068 // The fragment should always be valid for non-zero length packet.
1070 ASSERT (RxData
->Ip4RxData
.FragmentCount
!= 0);
1073 // Create a netbuffer representing IPv4 packet
1075 Pkt
= NetbufFromExt (
1076 (NET_FRAGMENT
*)RxData
->Ip4RxData
.FragmentTable
,
1077 RxData
->Ip4RxData
.FragmentCount
,
1081 RxData
->Ip4RxData
.RecycleSignal
1088 // Create a net session
1090 Session
.Source
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
);
1091 Session
.Dest
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->DestinationAddress
);
1092 Session
.IpHdr
.Ip4Hdr
= RxData
->Ip4RxData
.Header
;
1093 Session
.IpHdrLen
= RxData
->Ip4RxData
.HeaderLength
;
1094 Session
.IpVersion
= IP_VERSION_4
;
1096 ASSERT (RxData
->Ip6RxData
.Header
!= NULL
);
1097 if (!NetIp6IsValidUnicast (&RxData
->Ip6RxData
.Header
->SourceAddress
)) {
1101 if (RxData
->Ip6RxData
.DataLength
== 0) {
1103 // Discard zero length data payload packet.
1109 // The fragment should always be valid for non-zero length packet.
1111 ASSERT (RxData
->Ip6RxData
.FragmentCount
!= 0);
1114 // Create a netbuffer representing IPv6 packet
1116 Pkt
= NetbufFromExt (
1117 (NET_FRAGMENT
*)RxData
->Ip6RxData
.FragmentTable
,
1118 RxData
->Ip6RxData
.FragmentCount
,
1122 RxData
->Ip6RxData
.RecycleSignal
1129 // Create a net session
1133 &RxData
->Ip6RxData
.Header
->SourceAddress
,
1134 sizeof (EFI_IPv6_ADDRESS
)
1138 &RxData
->Ip6RxData
.Header
->DestinationAddress
,
1139 sizeof (EFI_IPv6_ADDRESS
)
1141 Session
.IpHdr
.Ip6Hdr
= RxData
->Ip6RxData
.Header
;
1142 Session
.IpHdrLen
= RxData
->Ip6RxData
.HeaderLength
;
1143 Session
.IpVersion
= IP_VERSION_6
;
1146 if (EFI_SUCCESS
== Status
) {
1147 IpIo
->PktRcvdNotify (EFI_SUCCESS
, 0, &Session
, Pkt
, IpIo
->RcvdContext
);
1150 // Status is EFI_ICMP_ERROR
1152 Status
= IpIoIcmpHandler (IpIo
, Pkt
, &Session
);
1153 if (EFI_ERROR (Status
)) {
1162 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1163 gBS
->SignalEvent (RxData
->Ip4RxData
.RecycleSignal
);
1165 gBS
->SignalEvent (RxData
->Ip6RxData
.RecycleSignal
);
1170 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1171 IpIo
->Ip
.Ip4
->Receive (IpIo
->Ip
.Ip4
, &(IpIo
->RcvToken
.Ip4Token
));
1173 IpIo
->Ip
.Ip6
->Receive (IpIo
->Ip
.Ip6
, &(IpIo
->RcvToken
.Ip6Token
));
1178 This function add IpIoListenHandlerDpc to the end of the DPC queue.
1180 @param[in] Event The event signaled.
1181 @param[in] Context The context passed in by the event notifier.
1192 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1194 QueueDpc (TPL_CALLBACK
, IpIoListenHandlerDpc
, Context
);
1198 Create a new IP_IO instance.
1200 If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1202 This function uses IP4/IP6 service binding protocol in Controller to create
1203 an IP4/IP6 child (aka IP4/IP6 instance).
1205 @param[in] Image The image handle of the driver or application that
1207 @param[in] Controller The controller handle that has IP4 or IP6 service
1208 binding protocol installed.
1209 @param[in] IpVersion The version of the IP protocol to use, either
1212 @return Pointer to a newly created IP_IO instance, or NULL if failed.
1218 IN EFI_HANDLE Image
,
1219 IN EFI_HANDLE Controller
,
1227 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1229 IpIo
= AllocateZeroPool (sizeof (IP_IO
));
1234 InitializeListHead (&(IpIo
->PendingSndList
));
1235 InitializeListHead (&(IpIo
->IpList
));
1236 IpIo
->Controller
= Controller
;
1237 IpIo
->Image
= Image
;
1238 IpIo
->IpVersion
= IpVersion
;
1241 Status
= gBS
->CreateEvent (
1248 if (EFI_ERROR (Status
)) {
1252 if (IpVersion
== IP_VERSION_4
) {
1253 IpIo
->RcvToken
.Ip4Token
.Event
= Event
;
1255 IpIo
->RcvToken
.Ip6Token
.Event
= Event
;
1259 // Create an IP child and open IP protocol
1261 Status
= IpIoCreateIpChildOpenProtocol (
1266 (VOID
**)&(IpIo
->Ip
)
1268 if (EFI_ERROR (Status
)) {
1276 if (Event
!= NULL
) {
1277 gBS
->CloseEvent (Event
);
1280 gBS
->FreePool (IpIo
);
1286 Open an IP_IO instance for use.
1288 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1290 This function is called after IpIoCreate(). It is used for configuring the IP
1291 instance and register the callbacks and their context data for sending and
1292 receiving IP packets.
1294 @param[in, out] IpIo Pointer to an IP_IO instance that needs
1296 @param[in] OpenData The configuration data and callbacks for
1299 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
1301 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
1303 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported.
1304 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1305 @retval Others Error condition occurred.
1312 IN IP_IO_OPEN_DATA
*OpenData
1318 if ((IpIo
== NULL
) || (OpenData
== NULL
)) {
1319 return EFI_INVALID_PARAMETER
;
1322 if (IpIo
->IsConfigured
) {
1323 return EFI_ACCESS_DENIED
;
1326 IpVersion
= IpIo
->IpVersion
;
1328 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1333 if (IpVersion
== IP_VERSION_4
) {
1335 // RawData mode is no supported.
1337 ASSERT (!OpenData
->IpConfigData
.Ip4CfgData
.RawData
);
1338 if (OpenData
->IpConfigData
.Ip4CfgData
.RawData
) {
1339 return EFI_UNSUPPORTED
;
1342 if (!OpenData
->IpConfigData
.Ip4CfgData
.UseDefaultAddress
) {
1343 IpIo
->StationIp
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.StationAddress
);
1344 IpIo
->SubnetMask
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.SubnetMask
);
1347 Status
= IpIo
->Ip
.Ip4
->Configure (
1349 &OpenData
->IpConfigData
.Ip4CfgData
1352 Status
= IpIo
->Ip
.Ip6
->Configure (
1354 &OpenData
->IpConfigData
.Ip6CfgData
1358 if (EFI_ERROR (Status
)) {
1363 // @bug To delete the default route entry in this Ip, if it is:
1364 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1367 if (IpVersion
== IP_VERSION_4
) {
1368 Status
= IpIo
->Ip
.Ip4
->Routes (
1376 if (EFI_ERROR (Status
) && (EFI_NOT_FOUND
!= Status
)) {
1381 IpIo
->PktRcvdNotify
= OpenData
->PktRcvdNotify
;
1382 IpIo
->PktSentNotify
= OpenData
->PktSentNotify
;
1384 IpIo
->RcvdContext
= OpenData
->RcvdContext
;
1385 IpIo
->SndContext
= OpenData
->SndContext
;
1387 if (IpVersion
== IP_VERSION_4
) {
1388 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip4CfgData
.DefaultProtocol
;
1391 // start to listen incoming packet
1393 Status
= IpIo
->Ip
.Ip4
->Receive (
1395 &(IpIo
->RcvToken
.Ip4Token
)
1397 if (EFI_ERROR (Status
)) {
1398 IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1402 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip6CfgData
.DefaultProtocol
;
1403 Status
= IpIo
->Ip
.Ip6
->Receive (
1405 &(IpIo
->RcvToken
.Ip6Token
)
1407 if (EFI_ERROR (Status
)) {
1408 IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1413 IpIo
->IsConfigured
= TRUE
;
1414 InsertTailList (&mActiveIpIoList
, &IpIo
->Entry
);
1420 Stop an IP_IO instance.
1422 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1424 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1425 the pending send/receive tokens will be canceled.
1427 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1429 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1430 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1431 @retval Others Error condition occurred.
1441 IP_IO_IP_INFO
*IpInfo
;
1445 return EFI_INVALID_PARAMETER
;
1448 if (!IpIo
->IsConfigured
) {
1452 IpVersion
= IpIo
->IpVersion
;
1454 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1457 // Remove the IpIo from the active IpIo list.
1459 RemoveEntryList (&IpIo
->Entry
);
1462 // Configure NULL Ip
1464 if (IpVersion
== IP_VERSION_4
) {
1465 Status
= IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1467 Status
= IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1470 if (EFI_ERROR (Status
)) {
1474 IpIo
->IsConfigured
= FALSE
;
1477 // Destroy the Ip List used by IpIo
1480 while (!IsListEmpty (&(IpIo
->IpList
))) {
1481 IpInfo
= NET_LIST_HEAD (&(IpIo
->IpList
), IP_IO_IP_INFO
, Entry
);
1483 IpIoRemoveIp (IpIo
, IpInfo
);
1487 // All pending send tokens should be flushed by resetting the IP instances.
1489 ASSERT (IsListEmpty (&IpIo
->PendingSndList
));
1492 // Close the receive event.
1494 if (IpVersion
== IP_VERSION_4
) {
1495 gBS
->CloseEvent (IpIo
->RcvToken
.Ip4Token
.Event
);
1497 gBS
->CloseEvent (IpIo
->RcvToken
.Ip6Token
.Event
);
1504 Destroy an IP_IO instance.
1506 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1507 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1509 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1512 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1513 @retval Others Error condition occurred.
1527 Status
= IpIoStop (IpIo
);
1528 if (EFI_ERROR (Status
)) {
1533 // Close the IP protocol and destroy the child.
1535 Status
= IpIoCloseProtocolDestroyIpChild (
1541 if (EFI_ERROR (Status
)) {
1545 gBS
->FreePool (IpIo
);
1551 Send out an IP packet.
1553 This function is called after IpIoOpen(). The data to be sent is wrapped in
1554 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1555 overridden by Sender. Other sending configs, like source address and gateway
1556 address etc., are specified in OverrideData.
1558 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1560 @param[in, out] Pkt Pointer to the IP packet to be sent.
1561 @param[in] Sender The IP protocol instance used for sending.
1562 @param[in] Context Optional context data.
1563 @param[in] NotifyData Optional notify data.
1564 @param[in] Dest The destination IP address to send this packet to.
1565 This parameter is optional when using IPv6.
1566 @param[in] OverrideData The data to override some configuration of the IP
1567 instance used for sending.
1569 @retval EFI_SUCCESS The operation is completed successfully.
1570 @retval EFI_INVALID_PARAMETER The input parameter is not correct.
1571 @retval EFI_NOT_STARTED The IpIo is not configured.
1572 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1573 @retval Others Error condition occurred.
1580 IN OUT NET_BUF
*Pkt
,
1581 IN IP_IO_IP_INFO
*Sender OPTIONAL
,
1582 IN VOID
*Context OPTIONAL
,
1583 IN VOID
*NotifyData OPTIONAL
,
1584 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
1585 IN IP_IO_OVERRIDE
*OverrideData OPTIONAL
1589 IP_IO_IP_PROTOCOL Ip
;
1590 IP_IO_SEND_ENTRY
*SndEntry
;
1592 if ((IpIo
== NULL
) || (Pkt
== NULL
)) {
1593 return EFI_INVALID_PARAMETER
;
1596 if ((IpIo
->IpVersion
== IP_VERSION_4
) && (Dest
== NULL
)) {
1597 return EFI_INVALID_PARAMETER
;
1600 if (!IpIo
->IsConfigured
) {
1601 return EFI_NOT_STARTED
;
1604 Ip
= (NULL
== Sender
) ? IpIo
->Ip
: Sender
->Ip
;
1607 // create a new SndEntry
1609 SndEntry
= IpIoCreateSndEntry (IpIo
, Pkt
, Ip
, Context
, NotifyData
, Dest
, OverrideData
);
1610 if (NULL
== SndEntry
) {
1611 return EFI_OUT_OF_RESOURCES
;
1617 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1618 Status
= Ip
.Ip4
->Transmit (
1620 &SndEntry
->SndToken
.Ip4Token
1623 Status
= Ip
.Ip6
->Transmit (
1625 &SndEntry
->SndToken
.Ip6Token
1629 if (EFI_ERROR (Status
)) {
1630 IpIoDestroySndEntry (SndEntry
);
1637 Cancel the IP transmit token which wraps this Packet.
1639 If IpIo is NULL, then ASSERT().
1640 If Packet is NULL, then ASSERT().
1642 @param[in] IpIo Pointer to the IP_IO instance.
1643 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1654 IP_IO_SEND_ENTRY
*SndEntry
;
1655 IP_IO_IP_PROTOCOL Ip
;
1657 ASSERT ((IpIo
!= NULL
) && (Packet
!= NULL
));
1659 NET_LIST_FOR_EACH (Node
, &IpIo
->PendingSndList
) {
1660 SndEntry
= NET_LIST_USER_STRUCT (Node
, IP_IO_SEND_ENTRY
, Entry
);
1662 if (SndEntry
->Pkt
== Packet
) {
1665 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1668 &SndEntry
->SndToken
.Ip4Token
1673 &SndEntry
->SndToken
.Ip6Token
1683 Add a new IP instance for sending data.
1685 If IpIo is NULL, then ASSERT().
1686 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1688 The function is used to add the IP_IO to the IP_IO sending list. The caller
1689 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1692 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1693 instance for sending purpose.
1695 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1705 IP_IO_IP_INFO
*IpInfo
;
1708 ASSERT (IpIo
!= NULL
);
1709 ASSERT ((IpIo
->IpVersion
== IP_VERSION_4
) || (IpIo
->IpVersion
== IP_VERSION_6
));
1711 IpInfo
= AllocatePool (sizeof (IP_IO_IP_INFO
));
1712 if (IpInfo
== NULL
) {
1717 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1720 InitializeListHead (&IpInfo
->Entry
);
1721 IpInfo
->ChildHandle
= NULL
;
1722 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1723 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1726 IpInfo
->IpVersion
= IpIo
->IpVersion
;
1729 // Create the IP instance and open the IP protocol.
1731 Status
= IpIoCreateIpChildOpenProtocol (
1734 &IpInfo
->ChildHandle
,
1736 (VOID
**)&IpInfo
->Ip
1738 if (EFI_ERROR (Status
)) {
1743 // Create the event for the DummyRcvToken.
1745 Status
= gBS
->CreateEvent (
1752 if (EFI_ERROR (Status
)) {
1753 goto ReleaseIpChild
;
1756 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1757 IpInfo
->DummyRcvToken
.Ip4Token
.Event
= Event
;
1759 IpInfo
->DummyRcvToken
.Ip6Token
.Event
= Event
;
1763 // Link this IpInfo into the IpIo.
1765 InsertTailList (&IpIo
->IpList
, &IpInfo
->Entry
);
1771 IpIoCloseProtocolDestroyIpChild (
1774 IpInfo
->ChildHandle
,
1780 gBS
->FreePool (IpInfo
);
1786 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1789 If IpInfo is NULL, then ASSERT().
1790 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1792 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1793 @param[in, out] IpConfigData The IP configure data used to configure the IP
1794 instance, if NULL the IP instance is reset. If
1795 UseDefaultAddress is set to TRUE, and the configure
1796 operation succeeds, the default address information
1797 is written back in this IpConfigData.
1799 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1800 or no need to reconfigure it.
1801 @retval Others Configuration fails.
1807 IN OUT IP_IO_IP_INFO
*IpInfo
,
1808 IN OUT VOID
*IpConfigData OPTIONAL
1812 IP_IO_IP_PROTOCOL Ip
;
1814 EFI_IP4_MODE_DATA Ip4ModeData
;
1815 EFI_IP6_MODE_DATA Ip6ModeData
;
1817 ASSERT (IpInfo
!= NULL
);
1819 if (IpInfo
->RefCnt
> 1) {
1821 // This IP instance is shared, don't reconfigure it until it has only one
1822 // consumer. Currently, only the tcp children cloned from their passive parent
1823 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1824 // let the last consumer clean the IP instance.
1829 IpVersion
= IpInfo
->IpVersion
;
1830 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1834 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1835 Status
= Ip
.Ip4
->Configure (Ip
.Ip4
, IpConfigData
);
1837 Status
= Ip
.Ip6
->Configure (Ip
.Ip6
, IpConfigData
);
1840 if (EFI_ERROR (Status
)) {
1844 if (IpConfigData
!= NULL
) {
1845 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1846 if (((EFI_IP4_CONFIG_DATA
*)IpConfigData
)->UseDefaultAddress
) {
1847 Status
= Ip
.Ip4
->GetModeData (
1853 if (EFI_ERROR (Status
)) {
1854 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1858 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*)IpConfigData
)->StationAddress
, &Ip4ModeData
.ConfigData
.StationAddress
);
1859 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*)IpConfigData
)->SubnetMask
, &Ip4ModeData
.ConfigData
.SubnetMask
);
1864 &((EFI_IP4_CONFIG_DATA
*)IpConfigData
)->StationAddress
,
1868 &IpInfo
->PreMask
.SubnetMask
,
1869 &((EFI_IP4_CONFIG_DATA
*)IpConfigData
)->SubnetMask
,
1873 Status
= Ip
.Ip4
->Receive (
1875 &IpInfo
->DummyRcvToken
.Ip4Token
1877 if (EFI_ERROR (Status
)) {
1878 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1881 Status
= Ip
.Ip6
->GetModeData (
1887 if (EFI_ERROR (Status
)) {
1888 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1892 if (Ip6ModeData
.IsConfigured
) {
1894 &((EFI_IP6_CONFIG_DATA
*)IpConfigData
)->StationAddress
,
1895 &Ip6ModeData
.ConfigData
.StationAddress
,
1896 sizeof (EFI_IPv6_ADDRESS
)
1899 if (Ip6ModeData
.AddressList
!= NULL
) {
1900 FreePool (Ip6ModeData
.AddressList
);
1903 if (Ip6ModeData
.GroupTable
!= NULL
) {
1904 FreePool (Ip6ModeData
.GroupTable
);
1907 if (Ip6ModeData
.RouteTable
!= NULL
) {
1908 FreePool (Ip6ModeData
.RouteTable
);
1911 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1912 FreePool (Ip6ModeData
.NeighborCache
);
1915 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1916 FreePool (Ip6ModeData
.PrefixTable
);
1919 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1920 FreePool (Ip6ModeData
.IcmpTypeList
);
1923 Status
= EFI_NO_MAPPING
;
1929 &Ip6ModeData
.ConfigData
.StationAddress
,
1930 sizeof (EFI_IPv6_ADDRESS
)
1933 Status
= Ip
.Ip6
->Receive (
1935 &IpInfo
->DummyRcvToken
.Ip6Token
1937 if (EFI_ERROR (Status
)) {
1938 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1943 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1945 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1946 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1953 Destroy an IP instance maintained in IpIo->IpList for
1956 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1958 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1959 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1960 will be destroyed if the RefCnt is zero.
1962 @param[in] IpIo Pointer to the IP_IO instance.
1963 @param[in] IpInfo Pointer to the IpInfo to be removed.
1970 IN IP_IO_IP_INFO
*IpInfo
1975 if ((IpIo
== NULL
) || (IpInfo
== NULL
)) {
1979 ASSERT (IpInfo
->RefCnt
> 0);
1981 NET_PUT_REF (IpInfo
);
1983 if (IpInfo
->RefCnt
> 0) {
1987 IpVersion
= IpIo
->IpVersion
;
1989 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1991 RemoveEntryList (&IpInfo
->Entry
);
1993 if (IpVersion
== IP_VERSION_4
) {
1994 IpInfo
->Ip
.Ip4
->Configure (
1998 IpIoCloseProtocolDestroyIpChild (
2001 IpInfo
->ChildHandle
,
2005 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip4Token
.Event
);
2007 IpInfo
->Ip
.Ip6
->Configure (
2012 IpIoCloseProtocolDestroyIpChild (
2015 IpInfo
->ChildHandle
,
2019 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip6Token
.Event
);
2026 Find the first IP protocol maintained in IpIo whose local
2027 address is the same as Src.
2029 This function is called when the caller needs the IpIo to send data to the
2030 specified Src. The IpIo was added previously by IpIoAddIp().
2032 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
2033 @param[in] IpVersion The version of the IP protocol to use, either
2035 @param[in] Src The local IP address.
2037 @return Pointer to the IP protocol can be used for sending purpose and its local
2038 address is the same with Src. NULL if failed.
2044 IN OUT IP_IO
**IpIo
,
2046 IN EFI_IP_ADDRESS
*Src
2049 LIST_ENTRY
*IpIoEntry
;
2051 LIST_ENTRY
*IpInfoEntry
;
2052 IP_IO_IP_INFO
*IpInfo
;
2054 if ((IpIo
== NULL
) || (Src
== NULL
)) {
2058 if ((IpVersion
!= IP_VERSION_4
) && (IpVersion
!= IP_VERSION_6
)) {
2062 NET_LIST_FOR_EACH (IpIoEntry
, &mActiveIpIoList
) {
2063 IpIoPtr
= NET_LIST_USER_STRUCT (IpIoEntry
, IP_IO
, Entry
);
2065 if (((*IpIo
!= NULL
) && (*IpIo
!= IpIoPtr
)) || (IpIoPtr
->IpVersion
!= IpVersion
)) {
2069 NET_LIST_FOR_EACH (IpInfoEntry
, &IpIoPtr
->IpList
) {
2070 IpInfo
= NET_LIST_USER_STRUCT (IpInfoEntry
, IP_IO_IP_INFO
, Entry
);
2071 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
2072 if (EFI_IP4_EQUAL (&IpInfo
->Addr
.v4
, &Src
->v4
)) {
2077 if (EFI_IP6_EQUAL (&IpInfo
->Addr
.v6
, &Src
->v6
)) {
2092 Get the ICMP error map information.
2094 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2095 are not NULL, this routine will fill them.
2097 @param[in] IcmpError IcmpError Type.
2098 @param[in] IpVersion The version of the IP protocol to use,
2099 either IPv4 or IPv6.
2100 @param[out] IsHard If TRUE, indicates that it is a hard error.
2101 @param[out] Notify If TRUE, SockError needs to be notified.
2103 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code.
2104 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2109 IpIoGetIcmpErrStatus (
2112 OUT BOOLEAN
*IsHard OPTIONAL
,
2113 OUT BOOLEAN
*Notify OPTIONAL
2116 if (IpVersion
== IP_VERSION_4
) {
2117 ASSERT (IcmpError
<= ICMP_ERR_PARAMPROB
);
2119 if (IsHard
!= NULL
) {
2120 *IsHard
= mIcmpErrMap
[IcmpError
].IsHard
;
2123 if (Notify
!= NULL
) {
2124 *Notify
= mIcmpErrMap
[IcmpError
].Notify
;
2127 switch (IcmpError
) {
2128 case ICMP_ERR_UNREACH_NET
:
2129 return EFI_NETWORK_UNREACHABLE
;
2131 case ICMP_ERR_TIMXCEED_INTRANS
:
2132 case ICMP_ERR_TIMXCEED_REASS
:
2133 case ICMP_ERR_UNREACH_HOST
:
2134 return EFI_HOST_UNREACHABLE
;
2136 case ICMP_ERR_UNREACH_PROTOCOL
:
2137 return EFI_PROTOCOL_UNREACHABLE
;
2139 case ICMP_ERR_UNREACH_PORT
:
2140 return EFI_PORT_UNREACHABLE
;
2142 case ICMP_ERR_MSGSIZE
:
2143 case ICMP_ERR_UNREACH_SRCFAIL
:
2144 case ICMP_ERR_QUENCH
:
2145 case ICMP_ERR_PARAMPROB
:
2146 return EFI_ICMP_ERROR
;
2150 return EFI_UNSUPPORTED
;
2152 } else if (IpVersion
== IP_VERSION_6
) {
2153 ASSERT (IcmpError
<= ICMP6_ERR_PARAMPROB_IPV6OPTION
);
2155 if (IsHard
!= NULL
) {
2156 *IsHard
= mIcmp6ErrMap
[IcmpError
].IsHard
;
2159 if (Notify
!= NULL
) {
2160 *Notify
= mIcmp6ErrMap
[IcmpError
].Notify
;
2163 switch (IcmpError
) {
2164 case ICMP6_ERR_UNREACH_NET
:
2165 return EFI_NETWORK_UNREACHABLE
;
2167 case ICMP6_ERR_UNREACH_HOST
:
2168 case ICMP6_ERR_TIMXCEED_HOPLIMIT
:
2169 case ICMP6_ERR_TIMXCEED_REASS
:
2170 return EFI_HOST_UNREACHABLE
;
2172 case ICMP6_ERR_UNREACH_PROTOCOL
:
2173 return EFI_PROTOCOL_UNREACHABLE
;
2175 case ICMP6_ERR_UNREACH_PORT
:
2176 return EFI_PORT_UNREACHABLE
;
2178 case ICMP6_ERR_PACKAGE_TOOBIG
:
2179 case ICMP6_ERR_PARAMPROB_HEADER
:
2180 case ICMP6_ERR_PARAMPROB_NEXHEADER
:
2181 case ICMP6_ERR_PARAMPROB_IPV6OPTION
:
2182 return EFI_ICMP_ERROR
;
2186 return EFI_UNSUPPORTED
;
2190 // Should never be here
2193 return EFI_UNSUPPORTED
;
2198 Refresh the remote peer's Neighbor Cache entries.
2200 This function is called when the caller needs the IpIo to refresh the existing
2201 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2202 node has recently received a confirmation that packets sent recently to the
2203 neighbor were received by its IP layer.
2205 @param[in] IpIo Pointer to an IP_IO instance
2206 @param[in] Neighbor The IP address of the neighbor
2207 @param[in] Timeout Time in 100-ns units that this entry will
2208 remain in the neighbor cache. A value of
2209 zero means that the entry is permanent.
2210 A value of non-zero means that the entry is
2211 dynamic and will be deleted after Timeout.
2213 @retval EFI_SUCCESS The operation is completed successfully.
2214 @retval EFI_NOT_STARTED The IpIo is not configured.
2215 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2216 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2218 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh.
2219 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2224 IpIoRefreshNeighbor (
2226 IN EFI_IP_ADDRESS
*Neighbor
,
2230 EFI_IP6_PROTOCOL
*Ip
;
2232 if (!IpIo
->IsConfigured
) {
2233 return EFI_NOT_STARTED
;
2236 if (IpIo
->IpVersion
!= IP_VERSION_6
) {
2237 return EFI_UNSUPPORTED
;
2242 return Ip
->Neighbors (Ip
, FALSE
, &Neighbor
->v6
, NULL
, Timeout
, TRUE
);