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>
22 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList
= {
27 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData
= {
44 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData
= {
49 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
50 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
58 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap
[10] = {
59 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_NET
60 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_HOST
61 {TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PROTOCOL
62 {TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PORT
63 {TRUE
, TRUE
}, // ICMP_ERR_MSGSIZE
64 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_SRCFAIL
65 {FALSE
, TRUE
}, // ICMP_ERR_TIMXCEED_INTRANS
66 {FALSE
, TRUE
}, // ICMP_ERR_TIMEXCEED_REASS
67 {FALSE
, FALSE
}, // ICMP_ERR_QUENCH
68 {FALSE
, TRUE
} // ICMP_ERR_PARAMPROB
71 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap
[10] = {
72 {FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_NET
73 {FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_HOST
74 {TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PROTOCOL
75 {TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PORT
76 {TRUE
, TRUE
}, // ICMP6_ERR_PACKAGE_TOOBIG
77 {FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
78 {FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_REASS
79 {FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_HEADER
80 {FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_NEXHEADER
81 {FALSE
, TRUE
} // ICMP6_ERR_PARAMPROB_IPV6OPTION
86 Notify function for IP transmit token.
88 @param[in] Context The context passed in by the event notifier.
93 IpIoTransmitHandlerDpc (
99 Notify function for IP transmit token.
101 @param[in] Event The event signaled.
102 @param[in] Context The context passed in by the event notifier.
107 IpIoTransmitHandler (
114 This function create an IP child ,open the IP protocol, and return the opened
115 IP protocol as Interface.
117 @param[in] ControllerHandle The controller handle.
118 @param[in] ImageHandle The image handle.
119 @param[in] ChildHandle Pointer to the buffer to save the IP child handle.
120 @param[in] IpVersion The version of the IP protocol to use, either
122 @param[out] Interface Pointer used to get the IP protocol interface.
124 @retval EFI_SUCCESS The IP child is created and the IP protocol
125 interface is retrieved.
126 @retval EFI_UNSUPPORTED Upsupported IpVersion.
127 @retval Others The required operation failed.
131 IpIoCreateIpChildOpenProtocol (
132 IN EFI_HANDLE ControllerHandle
,
133 IN EFI_HANDLE ImageHandle
,
134 IN EFI_HANDLE
*ChildHandle
,
140 EFI_GUID
*ServiceBindingGuid
;
141 EFI_GUID
*IpProtocolGuid
;
143 if (IpVersion
== IP_VERSION_4
) {
144 ServiceBindingGuid
= &gEfiIp4ServiceBindingProtocolGuid
;
145 IpProtocolGuid
= &gEfiIp4ProtocolGuid
;
146 } else if (IpVersion
== IP_VERSION_6
){
147 ServiceBindingGuid
= &gEfiIp6ServiceBindingProtocolGuid
;
148 IpProtocolGuid
= &gEfiIp6ProtocolGuid
;
150 return EFI_UNSUPPORTED
;
154 // Create an IP child.
156 Status
= NetLibCreateServiceChild (
162 if (EFI_ERROR (Status
)) {
167 // Open the IP protocol installed on the *ChildHandle.
169 Status
= gBS
->OpenProtocol (
175 EFI_OPEN_PROTOCOL_BY_DRIVER
177 if (EFI_ERROR (Status
)) {
179 // On failure, destroy the IP child.
181 NetLibDestroyServiceChild (
194 This function close the previously openned IP protocol and destroy the IP child.
196 @param[in] ControllerHandle The controller handle.
197 @param[in] ImageHandle The image handle.
198 @param[in] ChildHandle The child handle of the IP child.
199 @param[in] IpVersion The version of the IP protocol to use, either
202 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child
204 @retval EFI_UNSUPPORTED Upsupported IpVersion.
205 @retval Others The required operation failed.
209 IpIoCloseProtocolDestroyIpChild (
210 IN EFI_HANDLE ControllerHandle
,
211 IN EFI_HANDLE ImageHandle
,
212 IN EFI_HANDLE ChildHandle
,
217 EFI_GUID
*ServiceBindingGuid
;
218 EFI_GUID
*IpProtocolGuid
;
220 if (IpVersion
== IP_VERSION_4
) {
221 ServiceBindingGuid
= &gEfiIp4ServiceBindingProtocolGuid
;
222 IpProtocolGuid
= &gEfiIp4ProtocolGuid
;
223 } else if (IpVersion
== IP_VERSION_6
) {
224 ServiceBindingGuid
= &gEfiIp6ServiceBindingProtocolGuid
;
225 IpProtocolGuid
= &gEfiIp6ProtocolGuid
;
227 return EFI_UNSUPPORTED
;
231 // Close the previously openned IP protocol.
233 Status
= gBS
->CloseProtocol (
239 if (EFI_ERROR (Status
)) {
244 // Destroy the IP child.
246 return NetLibDestroyServiceChild (
255 This function handles ICMPv4 packets. It is the worker function of
258 @param[in] IpIo Pointer to the IP_IO instance.
259 @param[in, out] Pkt Pointer to the ICMPv4 packet.
260 @param[in] Session Pointer to the net session of this ICMPv4 packet.
262 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.
263 @retval EFI_ABORTED This type of ICMPv4 packet is not supported.
270 IN EFI_NET_SESSION_DATA
*Session
273 IP4_ICMP_ERROR_HEAD
*IcmpHdr
;
274 EFI_IP4_HEADER
*IpHdr
;
281 ASSERT (IpIo
!= NULL
);
282 ASSERT (Pkt
!= NULL
);
283 ASSERT (Session
!= NULL
);
284 ASSERT (IpIo
->IpVersion
== IP_VERSION_4
);
287 // Check the ICMP packet length.
289 if (Pkt
->TotalSize
< sizeof (IP4_ICMP_ERROR_HEAD
)) {
293 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP4_ICMP_ERROR_HEAD
);
294 IpHdr
= (EFI_IP4_HEADER
*) (&IcmpHdr
->IpHead
);
296 if (Pkt
->TotalSize
< ICMP_ERRLEN (IpHdr
)) {
301 Type
= IcmpHdr
->Head
.Type
;
302 Code
= IcmpHdr
->Head
.Code
;
305 // Analyze the ICMP Error in this ICMP pkt
308 case ICMP_TYPE_UNREACH
:
310 case ICMP_CODE_UNREACH_NET
:
311 case ICMP_CODE_UNREACH_HOST
:
312 case ICMP_CODE_UNREACH_PROTOCOL
:
313 case ICMP_CODE_UNREACH_PORT
:
314 case ICMP_CODE_UNREACH_SRCFAIL
:
315 IcmpErr
= (UINT8
) (ICMP_ERR_UNREACH_NET
+ Code
);
319 case ICMP_CODE_UNREACH_NEEDFRAG
:
320 IcmpErr
= ICMP_ERR_MSGSIZE
;
324 case ICMP_CODE_UNREACH_NET_UNKNOWN
:
325 case ICMP_CODE_UNREACH_NET_PROHIB
:
326 case ICMP_CODE_UNREACH_TOSNET
:
327 IcmpErr
= ICMP_ERR_UNREACH_NET
;
331 case ICMP_CODE_UNREACH_HOST_UNKNOWN
:
332 case ICMP_CODE_UNREACH_ISOLATED
:
333 case ICMP_CODE_UNREACH_HOST_PROHIB
:
334 case ICMP_CODE_UNREACH_TOSHOST
:
335 IcmpErr
= ICMP_ERR_UNREACH_HOST
;
345 case ICMP_TYPE_TIMXCEED
:
350 IcmpErr
= (UINT8
) (Code
+ ICMP_ERR_TIMXCEED_INTRANS
);
354 case ICMP_TYPE_PARAMPROB
:
359 IcmpErr
= ICMP_ERR_PARAMPROB
;
363 case ICMP_TYPE_SOURCEQUENCH
:
368 IcmpErr
= ICMP_ERR_QUENCH
;
377 // Notify user the ICMP pkt only containing payload except
378 // IP and ICMP header
380 PayLoadHdr
= (UINT8
*) ((UINT8
*) IpHdr
+ EFI_IP4_HEADER_LEN (IpHdr
));
381 TrimBytes
= (UINT32
) (PayLoadHdr
- (UINT8
*) IcmpHdr
);
383 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
386 // If the input packet has invalid format, and TrimBytes is larger than
387 // the packet size, the NetbufTrim might trim the packet to zero.
389 if (Pkt
->TotalSize
!= 0) {
390 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
397 This function handles ICMPv6 packets. It is the worker function of
400 @param[in] IpIo Pointer to the IP_IO instance.
401 @param[in, out] Pkt Pointer to the ICMPv6 packet.
402 @param[in] Session Pointer to the net session of this ICMPv6 packet.
404 @retval EFI_SUCCESS The ICMPv6 packet is handled successfully.
405 @retval EFI_ABORTED This type of ICMPv6 packet is not supported.
412 IN EFI_NET_SESSION_DATA
*Session
415 IP6_ICMP_ERROR_HEAD
*IcmpHdr
;
416 EFI_IP6_HEADER
*IpHdr
;
425 ASSERT (IpIo
!= NULL
);
426 ASSERT (Pkt
!= NULL
);
427 ASSERT (Session
!= NULL
);
428 ASSERT (IpIo
->IpVersion
== IP_VERSION_6
);
431 // Check the ICMPv6 packet length.
433 if (Pkt
->TotalSize
< sizeof (IP6_ICMP_ERROR_HEAD
)) {
438 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP6_ICMP_ERROR_HEAD
);
439 Type
= IcmpHdr
->Head
.Type
;
440 Code
= IcmpHdr
->Head
.Code
;
443 // Analyze the ICMPv6 Error in this ICMPv6 packet
446 case ICMP_V6_DEST_UNREACHABLE
:
448 case ICMP_V6_NO_ROUTE_TO_DEST
:
449 case ICMP_V6_BEYOND_SCOPE
:
450 case ICMP_V6_ROUTE_REJECTED
:
451 IcmpErr
= ICMP6_ERR_UNREACH_NET
;
455 case ICMP_V6_COMM_PROHIBITED
:
456 case ICMP_V6_ADDR_UNREACHABLE
:
457 case ICMP_V6_SOURCE_ADDR_FAILED
:
458 IcmpErr
= ICMP6_ERR_UNREACH_HOST
;
462 case ICMP_V6_PORT_UNREACHABLE
:
463 IcmpErr
= ICMP6_ERR_UNREACH_PORT
;
473 case ICMP_V6_PACKET_TOO_BIG
:
478 IcmpErr
= ICMP6_ERR_PACKAGE_TOOBIG
;
482 case ICMP_V6_TIME_EXCEEDED
:
487 IcmpErr
= (UINT8
) (ICMP6_ERR_TIMXCEED_HOPLIMIT
+ Code
);
491 case ICMP_V6_PARAMETER_PROBLEM
:
496 IcmpErr
= (UINT8
) (ICMP6_ERR_PARAMPROB_HEADER
+ Code
);
506 // Notify user the ICMPv6 packet only containing payload except
507 // IPv6 basic header, extension header and ICMP header
510 IpHdr
= (EFI_IP6_HEADER
*) (&IcmpHdr
->IpHead
);
511 NextHeader
= IpHdr
->NextHeader
;
512 PayLoadHdr
= (UINT8
*) ((UINT8
*) IcmpHdr
+ sizeof (IP6_ICMP_ERROR_HEAD
));
516 switch (NextHeader
) {
517 case EFI_IP_PROTO_UDP
:
518 case EFI_IP_PROTO_TCP
:
519 case EFI_IP_PROTO_ICMP
:
520 case IP6_NO_NEXT_HEADER
:
526 case IP6_DESTINATION
:
528 // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
529 // the first 8 octets.
531 NextHeader
= *(PayLoadHdr
);
532 PayLoadHdr
= (UINT8
*) (PayLoadHdr
+ (*(PayLoadHdr
+ 1) + 1) * 8);
538 // The Fragment Header Length is 8 octets.
540 NextHeader
= *(PayLoadHdr
);
541 PayLoadHdr
= (UINT8
*) (PayLoadHdr
+ 8);
551 TrimBytes
= (UINT32
) (PayLoadHdr
- (UINT8
*) IcmpHdr
);
553 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
556 // If the input packet has invalid format, and TrimBytes is larger than
557 // the packet size, the NetbufTrim might trim the packet to zero.
559 if (Pkt
->TotalSize
!= 0) {
560 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
567 This function handles ICMP packets.
569 @param[in] IpIo Pointer to the IP_IO instance.
570 @param[in, out] Pkt Pointer to the ICMP packet.
571 @param[in] Session Pointer to the net session of this ICMP packet.
573 @retval EFI_SUCCESS The ICMP packet is handled successfully.
574 @retval EFI_ABORTED This type of ICMP packet is not supported.
575 @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
582 IN EFI_NET_SESSION_DATA
*Session
586 if (IpIo
->IpVersion
== IP_VERSION_4
) {
588 return IpIoIcmpv4Handler (IpIo
, Pkt
, Session
);
590 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
592 return IpIoIcmpv6Handler (IpIo
, Pkt
, Session
);
596 return EFI_UNSUPPORTED
;
602 Free function for receive token of IP_IO. It is used to
603 signal the recycle event to notify IP to recycle the
606 @param[in] Event The event to be signaled.
615 gBS
->SignalEvent ((EFI_EVENT
) Event
);
620 Create a send entry to wrap a packet before sending
623 @param[in, out] IpIo Pointer to the IP_IO instance.
624 @param[in, out] Pkt Pointer to the packet.
625 @param[in] Sender Pointer to the IP sender.
626 @param[in] Context Pointer to the context.
627 @param[in] NotifyData Pointer to the notify data.
628 @param[in] Dest Pointer to the destination IP address.
629 @param[in] Override Pointer to the overriden IP_IO data.
631 @return Pointer to the data structure created to wrap the packet. If any error occurs,
639 IN IP_IO_IP_PROTOCOL Sender
,
640 IN VOID
*Context OPTIONAL
,
641 IN VOID
*NotifyData OPTIONAL
,
642 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
643 IN IP_IO_OVERRIDE
*Override
646 IP_IO_SEND_ENTRY
*SndEntry
;
649 NET_FRAGMENT
*ExtFragment
;
650 UINT32 FragmentCount
;
651 IP_IO_OVERRIDE
*OverrideData
;
652 IP_IO_IP_TX_DATA
*TxData
;
653 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
654 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
656 if ((IpIo
->IpVersion
!= IP_VERSION_4
) && (IpIo
->IpVersion
!= IP_VERSION_6
)) {
665 // Allocate resource for SndEntry
667 SndEntry
= AllocatePool (sizeof (IP_IO_SEND_ENTRY
));
668 if (NULL
== SndEntry
) {
672 Status
= gBS
->CreateEvent (
679 if (EFI_ERROR (Status
)) {
683 FragmentCount
= Pkt
->BlockOpNum
;
686 // Allocate resource for TxData
688 TxData
= (IP_IO_IP_TX_DATA
*) AllocatePool (
689 sizeof (IP_IO_IP_TX_DATA
) + sizeof (NET_FRAGMENT
) * (FragmentCount
- 1)
692 if (NULL
== TxData
) {
697 // Build a fragment table to contain the fragments in the packet.
699 if (IpIo
->IpVersion
== IP_VERSION_4
) {
700 ExtFragment
= (NET_FRAGMENT
*) TxData
->Ip4TxData
.FragmentTable
;
702 ExtFragment
= (NET_FRAGMENT
*) TxData
->Ip6TxData
.FragmentTable
;
705 NetbufBuildExt (Pkt
, ExtFragment
, &FragmentCount
);
709 // Allocate resource for OverrideData if needed
711 if (NULL
!= Override
) {
713 OverrideData
= AllocateCopyPool (sizeof (IP_IO_OVERRIDE
), Override
);
714 if (NULL
== OverrideData
) {
720 // Set other fields of TxData except the fragment table
722 if (IpIo
->IpVersion
== IP_VERSION_4
) {
724 Ip4TxData
= &TxData
->Ip4TxData
;
726 IP4_COPY_ADDRESS (&Ip4TxData
->DestinationAddress
, Dest
);
728 Ip4TxData
->OverrideData
= &OverrideData
->Ip4OverrideData
;
729 Ip4TxData
->OptionsLength
= 0;
730 Ip4TxData
->OptionsBuffer
= NULL
;
731 Ip4TxData
->TotalDataLength
= Pkt
->TotalSize
;
732 Ip4TxData
->FragmentCount
= FragmentCount
;
735 // Set the fields of SndToken
737 SndEntry
->SndToken
.Ip4Token
.Event
= Event
;
738 SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
= Ip4TxData
;
741 Ip6TxData
= &TxData
->Ip6TxData
;
744 CopyMem (&Ip6TxData
->DestinationAddress
, Dest
, sizeof (EFI_IPv6_ADDRESS
));
746 ZeroMem (&Ip6TxData
->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
));
749 Ip6TxData
->OverrideData
= &OverrideData
->Ip6OverrideData
;
750 Ip6TxData
->DataLength
= Pkt
->TotalSize
;
751 Ip6TxData
->FragmentCount
= FragmentCount
;
752 Ip6TxData
->ExtHdrsLength
= 0;
753 Ip6TxData
->ExtHdrs
= NULL
;
756 // Set the fields of SndToken
758 SndEntry
->SndToken
.Ip6Token
.Event
= Event
;
759 SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
= Ip6TxData
;
763 // Set the fields of SndEntry
765 SndEntry
->IpIo
= IpIo
;
766 SndEntry
->Ip
= Sender
;
767 SndEntry
->Context
= Context
;
768 SndEntry
->NotifyData
= NotifyData
;
773 InsertTailList (&IpIo
->PendingSndList
, &SndEntry
->Entry
);
779 if (OverrideData
!= NULL
) {
780 FreePool (OverrideData
);
783 if (TxData
!= NULL
) {
787 if (SndEntry
!= NULL
) {
792 gBS
->CloseEvent (Event
);
800 Destroy the SndEntry.
802 This function pairs with IpIoCreateSndEntry().
804 @param[in] SndEntry Pointer to the send entry to be destroyed.
808 IpIoDestroySndEntry (
809 IN IP_IO_SEND_ENTRY
*SndEntry
813 IP_IO_IP_TX_DATA
*TxData
;
814 IP_IO_OVERRIDE
*Override
;
816 if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_4
) {
817 Event
= SndEntry
->SndToken
.Ip4Token
.Event
;
818 TxData
= (IP_IO_IP_TX_DATA
*) SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
;
819 Override
= (IP_IO_OVERRIDE
*) TxData
->Ip4TxData
.OverrideData
;
820 } else if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_6
) {
821 Event
= SndEntry
->SndToken
.Ip6Token
.Event
;
822 TxData
= (IP_IO_IP_TX_DATA
*) SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
;
823 Override
= (IP_IO_OVERRIDE
*) TxData
->Ip6TxData
.OverrideData
;
828 gBS
->CloseEvent (Event
);
832 if (NULL
!= Override
) {
836 NetbufFree (SndEntry
->Pkt
);
838 RemoveEntryList (&SndEntry
->Entry
);
845 Notify function for IP transmit token.
847 @param[in] Context The context passed in by the event notifier.
852 IpIoTransmitHandlerDpc (
857 IP_IO_SEND_ENTRY
*SndEntry
;
860 SndEntry
= (IP_IO_SEND_ENTRY
*) Context
;
862 IpIo
= SndEntry
->IpIo
;
864 if (IpIo
->IpVersion
== IP_VERSION_4
) {
865 Status
= SndEntry
->SndToken
.Ip4Token
.Status
;
866 } else if (IpIo
->IpVersion
== IP_VERSION_6
){
867 Status
= SndEntry
->SndToken
.Ip6Token
.Status
;
872 if ((IpIo
->PktSentNotify
!= NULL
) && (SndEntry
->NotifyData
!= NULL
)) {
873 IpIo
->PktSentNotify (
881 IpIoDestroySndEntry (SndEntry
);
886 Notify function for IP transmit token.
888 @param[in] Event The event signaled.
889 @param[in] Context The context passed in by the event notifier.
894 IpIoTransmitHandler (
900 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
902 QueueDpc (TPL_CALLBACK
, IpIoTransmitHandlerDpc
, Context
);
907 The dummy handler for the dummy IP receive token.
909 @param[in] Context The context passed in by the event notifier.
914 IpIoDummyHandlerDpc (
918 IP_IO_IP_INFO
*IpInfo
;
920 EFI_EVENT RecycleEvent
;
922 IpInfo
= (IP_IO_IP_INFO
*) Context
;
924 if ((IpInfo
->IpVersion
!= IP_VERSION_4
) && (IpInfo
->IpVersion
!= IP_VERSION_6
)) {
930 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
931 Status
= IpInfo
->DummyRcvToken
.Ip4Token
.Status
;
933 if (IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
!= NULL
) {
934 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
->RecycleSignal
;
937 Status
= IpInfo
->DummyRcvToken
.Ip6Token
.Status
;
939 if (IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
!= NULL
) {
940 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
->RecycleSignal
;
946 if (EFI_ABORTED
== Status
) {
948 // The reception is actively aborted by the consumer, directly return.
951 } else if (EFI_SUCCESS
== Status
) {
953 // Recycle the RxData.
955 ASSERT (RecycleEvent
!= NULL
);
957 gBS
->SignalEvent (RecycleEvent
);
961 // Continue the receive.
963 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
964 IpInfo
->Ip
.Ip4
->Receive (
966 &IpInfo
->DummyRcvToken
.Ip4Token
969 IpInfo
->Ip
.Ip6
->Receive (
971 &IpInfo
->DummyRcvToken
.Ip6Token
978 This function add IpIoDummyHandlerDpc to the end of the DPC queue.
980 @param[in] Event The event signaled.
981 @param[in] Context The context passed in by the event notifier.
992 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
994 QueueDpc (TPL_CALLBACK
, IpIoDummyHandlerDpc
, Context
);
999 Notify function for the IP receive token, used to process
1000 the received IP packets.
1002 @param[in] Context The context passed in by the event notifier.
1007 IpIoListenHandlerDpc (
1013 IP_IO_IP_RX_DATA
*RxData
;
1014 EFI_NET_SESSION_DATA Session
;
1017 IpIo
= (IP_IO
*) Context
;
1019 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1020 Status
= IpIo
->RcvToken
.Ip4Token
.Status
;
1021 RxData
= (IP_IO_IP_RX_DATA
*) IpIo
->RcvToken
.Ip4Token
.Packet
.RxData
;
1022 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
1023 Status
= IpIo
->RcvToken
.Ip6Token
.Status
;
1024 RxData
= (IP_IO_IP_RX_DATA
*) IpIo
->RcvToken
.Ip6Token
.Packet
.RxData
;
1029 if (EFI_ABORTED
== Status
) {
1031 // The reception is actively aborted by the consumer, directly return.
1036 if ((EFI_SUCCESS
!= Status
) && (EFI_ICMP_ERROR
!= Status
)) {
1038 // Only process the normal packets and the icmp error packets.
1040 if (RxData
!= NULL
) {
1048 // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).
1050 ASSERT (RxData
!= NULL
);
1051 if (RxData
== NULL
) {
1055 if (NULL
== IpIo
->PktRcvdNotify
) {
1059 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1060 ASSERT (RxData
->Ip4RxData
.Header
!= NULL
);
1061 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
))) {
1063 // The source address is a broadcast address, discard it.
1067 if ((EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
) != 0) &&
1068 (IpIo
->SubnetMask
!= 0) &&
1069 IP4_NET_EQUAL (IpIo
->StationIp
, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
) &&
1070 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
)) {
1072 // The source address doesn't match StationIp and it's not a unicast IP address, discard it.
1077 if (RxData
->Ip4RxData
.DataLength
== 0) {
1079 // Discard zero length data payload packet.
1085 // The fragment should always be valid for non-zero length packet.
1087 ASSERT (RxData
->Ip4RxData
.FragmentCount
!= 0);
1090 // Create a netbuffer representing IPv4 packet
1092 Pkt
= NetbufFromExt (
1093 (NET_FRAGMENT
*) RxData
->Ip4RxData
.FragmentTable
,
1094 RxData
->Ip4RxData
.FragmentCount
,
1098 RxData
->Ip4RxData
.RecycleSignal
1105 // Create a net session
1107 Session
.Source
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
);
1108 Session
.Dest
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->DestinationAddress
);
1109 Session
.IpHdr
.Ip4Hdr
= RxData
->Ip4RxData
.Header
;
1110 Session
.IpHdrLen
= RxData
->Ip4RxData
.HeaderLength
;
1111 Session
.IpVersion
= IP_VERSION_4
;
1113 ASSERT (RxData
->Ip6RxData
.Header
!= NULL
);
1114 if (!NetIp6IsValidUnicast(&RxData
->Ip6RxData
.Header
->SourceAddress
)) {
1118 if (RxData
->Ip6RxData
.DataLength
== 0) {
1120 // Discard zero length data payload packet.
1126 // The fragment should always be valid for non-zero length packet.
1128 ASSERT (RxData
->Ip6RxData
.FragmentCount
!= 0);
1131 // Create a netbuffer representing IPv6 packet
1133 Pkt
= NetbufFromExt (
1134 (NET_FRAGMENT
*) RxData
->Ip6RxData
.FragmentTable
,
1135 RxData
->Ip6RxData
.FragmentCount
,
1139 RxData
->Ip6RxData
.RecycleSignal
1146 // Create a net session
1150 &RxData
->Ip6RxData
.Header
->SourceAddress
,
1151 sizeof(EFI_IPv6_ADDRESS
)
1155 &RxData
->Ip6RxData
.Header
->DestinationAddress
,
1156 sizeof(EFI_IPv6_ADDRESS
)
1158 Session
.IpHdr
.Ip6Hdr
= RxData
->Ip6RxData
.Header
;
1159 Session
.IpHdrLen
= RxData
->Ip6RxData
.HeaderLength
;
1160 Session
.IpVersion
= IP_VERSION_6
;
1163 if (EFI_SUCCESS
== Status
) {
1165 IpIo
->PktRcvdNotify (EFI_SUCCESS
, 0, &Session
, Pkt
, IpIo
->RcvdContext
);
1168 // Status is EFI_ICMP_ERROR
1170 Status
= IpIoIcmpHandler (IpIo
, Pkt
, &Session
);
1171 if (EFI_ERROR (Status
)) {
1180 if (IpIo
->IpVersion
== IP_VERSION_4
){
1181 gBS
->SignalEvent (RxData
->Ip4RxData
.RecycleSignal
);
1183 gBS
->SignalEvent (RxData
->Ip6RxData
.RecycleSignal
);
1188 if (IpIo
->IpVersion
== IP_VERSION_4
){
1189 IpIo
->Ip
.Ip4
->Receive (IpIo
->Ip
.Ip4
, &(IpIo
->RcvToken
.Ip4Token
));
1191 IpIo
->Ip
.Ip6
->Receive (IpIo
->Ip
.Ip6
, &(IpIo
->RcvToken
.Ip6Token
));
1196 This function add IpIoListenHandlerDpc to the end of the DPC queue.
1198 @param[in] Event The event signaled.
1199 @param[in] Context The context passed in by the event notifier.
1210 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1212 QueueDpc (TPL_CALLBACK
, IpIoListenHandlerDpc
, Context
);
1217 Create a new IP_IO instance.
1219 If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1221 This function uses IP4/IP6 service binding protocol in Controller to create
1222 an IP4/IP6 child (aka IP4/IP6 instance).
1224 @param[in] Image The image handle of the driver or application that
1226 @param[in] Controller The controller handle that has IP4 or IP6 service
1227 binding protocol installed.
1228 @param[in] IpVersion The version of the IP protocol to use, either
1231 @return Pointer to a newly created IP_IO instance, or NULL if failed.
1237 IN EFI_HANDLE Image
,
1238 IN EFI_HANDLE Controller
,
1246 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1248 IpIo
= AllocateZeroPool (sizeof (IP_IO
));
1253 InitializeListHead (&(IpIo
->PendingSndList
));
1254 InitializeListHead (&(IpIo
->IpList
));
1255 IpIo
->Controller
= Controller
;
1256 IpIo
->Image
= Image
;
1257 IpIo
->IpVersion
= IpVersion
;
1260 Status
= gBS
->CreateEvent (
1267 if (EFI_ERROR (Status
)) {
1271 if (IpVersion
== IP_VERSION_4
) {
1272 IpIo
->RcvToken
.Ip4Token
.Event
= Event
;
1274 IpIo
->RcvToken
.Ip6Token
.Event
= Event
;
1278 // Create an IP child and open IP protocol
1280 Status
= IpIoCreateIpChildOpenProtocol (
1285 (VOID
**) & (IpIo
->Ip
)
1287 if (EFI_ERROR (Status
)) {
1295 if (Event
!= NULL
) {
1296 gBS
->CloseEvent (Event
);
1299 gBS
->FreePool (IpIo
);
1306 Open an IP_IO instance for use.
1308 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1310 This function is called after IpIoCreate(). It is used for configuring the IP
1311 instance and register the callbacks and their context data for sending and
1312 receiving IP packets.
1314 @param[in, out] IpIo Pointer to an IP_IO instance that needs
1316 @param[in] OpenData The configuration data and callbacks for
1319 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
1321 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
1323 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported.
1324 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1325 @retval Others Error condition occurred.
1332 IN IP_IO_OPEN_DATA
*OpenData
1338 if (IpIo
== NULL
|| OpenData
== NULL
) {
1339 return EFI_INVALID_PARAMETER
;
1342 if (IpIo
->IsConfigured
) {
1343 return EFI_ACCESS_DENIED
;
1346 IpVersion
= IpIo
->IpVersion
;
1348 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1353 if (IpVersion
== IP_VERSION_4
){
1355 // RawData mode is no supported.
1357 ASSERT (!OpenData
->IpConfigData
.Ip4CfgData
.RawData
);
1358 if (OpenData
->IpConfigData
.Ip4CfgData
.RawData
) {
1359 return EFI_UNSUPPORTED
;
1362 if (!OpenData
->IpConfigData
.Ip4CfgData
.UseDefaultAddress
) {
1363 IpIo
->StationIp
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.StationAddress
);
1364 IpIo
->SubnetMask
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.SubnetMask
);
1367 Status
= IpIo
->Ip
.Ip4
->Configure (
1369 &OpenData
->IpConfigData
.Ip4CfgData
1373 Status
= IpIo
->Ip
.Ip6
->Configure (
1375 &OpenData
->IpConfigData
.Ip6CfgData
1379 if (EFI_ERROR (Status
)) {
1384 // @bug To delete the default route entry in this Ip, if it is:
1385 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1388 if (IpVersion
== IP_VERSION_4
){
1389 Status
= IpIo
->Ip
.Ip4
->Routes (
1397 if (EFI_ERROR (Status
) && (EFI_NOT_FOUND
!= Status
)) {
1402 IpIo
->PktRcvdNotify
= OpenData
->PktRcvdNotify
;
1403 IpIo
->PktSentNotify
= OpenData
->PktSentNotify
;
1405 IpIo
->RcvdContext
= OpenData
->RcvdContext
;
1406 IpIo
->SndContext
= OpenData
->SndContext
;
1408 if (IpVersion
== IP_VERSION_4
){
1409 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip4CfgData
.DefaultProtocol
;
1412 // start to listen incoming packet
1414 Status
= IpIo
->Ip
.Ip4
->Receive (
1416 &(IpIo
->RcvToken
.Ip4Token
)
1418 if (EFI_ERROR (Status
)) {
1419 IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1425 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip6CfgData
.DefaultProtocol
;
1426 Status
= IpIo
->Ip
.Ip6
->Receive (
1428 &(IpIo
->RcvToken
.Ip6Token
)
1430 if (EFI_ERROR (Status
)) {
1431 IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1436 IpIo
->IsConfigured
= TRUE
;
1437 InsertTailList (&mActiveIpIoList
, &IpIo
->Entry
);
1444 Stop an IP_IO instance.
1446 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1448 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1449 the pending send/receive tokens will be canceled.
1451 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1453 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1454 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1455 @retval Others Error condition occurred.
1465 IP_IO_IP_INFO
*IpInfo
;
1469 return EFI_INVALID_PARAMETER
;
1472 if (!IpIo
->IsConfigured
) {
1476 IpVersion
= IpIo
->IpVersion
;
1478 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1481 // Remove the IpIo from the active IpIo list.
1483 RemoveEntryList (&IpIo
->Entry
);
1486 // Configure NULL Ip
1488 if (IpVersion
== IP_VERSION_4
) {
1489 Status
= IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1491 Status
= IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1493 if (EFI_ERROR (Status
)) {
1497 IpIo
->IsConfigured
= FALSE
;
1500 // Detroy the Ip List used by IpIo
1503 while (!IsListEmpty (&(IpIo
->IpList
))) {
1504 IpInfo
= NET_LIST_HEAD (&(IpIo
->IpList
), IP_IO_IP_INFO
, Entry
);
1506 IpIoRemoveIp (IpIo
, IpInfo
);
1510 // All pending send tokens should be flushed by resetting the IP instances.
1512 ASSERT (IsListEmpty (&IpIo
->PendingSndList
));
1515 // Close the receive event.
1517 if (IpVersion
== IP_VERSION_4
){
1518 gBS
->CloseEvent (IpIo
->RcvToken
.Ip4Token
.Event
);
1520 gBS
->CloseEvent (IpIo
->RcvToken
.Ip6Token
.Event
);
1528 Destroy an IP_IO instance.
1530 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1531 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1533 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1536 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1537 @retval Others Error condition occurred.
1551 Status
= IpIoStop (IpIo
);
1552 if (EFI_ERROR (Status
)) {
1557 // Close the IP protocol and destroy the child.
1559 Status
= IpIoCloseProtocolDestroyIpChild (
1565 if (EFI_ERROR (Status
)) {
1569 gBS
->FreePool (IpIo
);
1576 Send out an IP packet.
1578 This function is called after IpIoOpen(). The data to be sent is wrapped in
1579 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1580 overriden by Sender. Other sending configs, like source address and gateway
1581 address etc., are specified in OverrideData.
1583 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1585 @param[in, out] Pkt Pointer to the IP packet to be sent.
1586 @param[in] Sender The IP protocol instance used for sending.
1587 @param[in] Context Optional context data.
1588 @param[in] NotifyData Optional notify data.
1589 @param[in] Dest The destination IP address to send this packet to.
1590 This parameter is optional when using IPv6.
1591 @param[in] OverrideData The data to override some configuration of the IP
1592 instance used for sending.
1594 @retval EFI_SUCCESS The operation is completed successfully.
1595 @retval EFI_INVALID_PARAMETER The input parameter is not correct.
1596 @retval EFI_NOT_STARTED The IpIo is not configured.
1597 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1598 @retval Others Error condition occurred.
1605 IN OUT NET_BUF
*Pkt
,
1606 IN IP_IO_IP_INFO
*Sender OPTIONAL
,
1607 IN VOID
*Context OPTIONAL
,
1608 IN VOID
*NotifyData OPTIONAL
,
1609 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
1610 IN IP_IO_OVERRIDE
*OverrideData OPTIONAL
1614 IP_IO_IP_PROTOCOL Ip
;
1615 IP_IO_SEND_ENTRY
*SndEntry
;
1617 if ((IpIo
== NULL
) || (Pkt
== NULL
)) {
1618 return EFI_INVALID_PARAMETER
;
1621 if ((IpIo
->IpVersion
== IP_VERSION_4
) && (Dest
== NULL
)) {
1622 return EFI_INVALID_PARAMETER
;
1625 if (!IpIo
->IsConfigured
) {
1626 return EFI_NOT_STARTED
;
1629 Ip
= (NULL
== Sender
) ? IpIo
->Ip
: Sender
->Ip
;
1632 // create a new SndEntry
1634 SndEntry
= IpIoCreateSndEntry (IpIo
, Pkt
, Ip
, Context
, NotifyData
, Dest
, OverrideData
);
1635 if (NULL
== SndEntry
) {
1636 return EFI_OUT_OF_RESOURCES
;
1642 if (IpIo
->IpVersion
== IP_VERSION_4
){
1643 Status
= Ip
.Ip4
->Transmit (
1645 &SndEntry
->SndToken
.Ip4Token
1648 Status
= Ip
.Ip6
->Transmit (
1650 &SndEntry
->SndToken
.Ip6Token
1654 if (EFI_ERROR (Status
)) {
1655 IpIoDestroySndEntry (SndEntry
);
1663 Cancel the IP transmit token which wraps this Packet.
1665 If IpIo is NULL, then ASSERT().
1666 If Packet is NULL, then ASSERT().
1668 @param[in] IpIo Pointer to the IP_IO instance.
1669 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1680 IP_IO_SEND_ENTRY
*SndEntry
;
1681 IP_IO_IP_PROTOCOL Ip
;
1683 ASSERT ((IpIo
!= NULL
) && (Packet
!= NULL
));
1685 NET_LIST_FOR_EACH (Node
, &IpIo
->PendingSndList
) {
1687 SndEntry
= NET_LIST_USER_STRUCT (Node
, IP_IO_SEND_ENTRY
, Entry
);
1689 if (SndEntry
->Pkt
== Packet
) {
1693 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1696 &SndEntry
->SndToken
.Ip4Token
1701 &SndEntry
->SndToken
.Ip6Token
1713 Add a new IP instance for sending data.
1715 If IpIo is NULL, then ASSERT().
1716 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1718 The function is used to add the IP_IO to the IP_IO sending list. The caller
1719 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1722 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1723 instance for sending purpose.
1725 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1735 IP_IO_IP_INFO
*IpInfo
;
1738 ASSERT (IpIo
!= NULL
);
1739 ASSERT ((IpIo
->IpVersion
== IP_VERSION_4
) || (IpIo
->IpVersion
== IP_VERSION_6
));
1741 IpInfo
= AllocatePool (sizeof (IP_IO_IP_INFO
));
1742 if (IpInfo
== NULL
) {
1747 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1750 InitializeListHead (&IpInfo
->Entry
);
1751 IpInfo
->ChildHandle
= NULL
;
1752 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1753 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1756 IpInfo
->IpVersion
= IpIo
->IpVersion
;
1759 // Create the IP instance and open the IP protocol.
1761 Status
= IpIoCreateIpChildOpenProtocol (
1764 &IpInfo
->ChildHandle
,
1766 (VOID
**) &IpInfo
->Ip
1768 if (EFI_ERROR (Status
)) {
1773 // Create the event for the DummyRcvToken.
1775 Status
= gBS
->CreateEvent (
1782 if (EFI_ERROR (Status
)) {
1783 goto ReleaseIpChild
;
1786 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1787 IpInfo
->DummyRcvToken
.Ip4Token
.Event
= Event
;
1789 IpInfo
->DummyRcvToken
.Ip6Token
.Event
= Event
;
1793 // Link this IpInfo into the IpIo.
1795 InsertTailList (&IpIo
->IpList
, &IpInfo
->Entry
);
1801 IpIoCloseProtocolDestroyIpChild (
1804 IpInfo
->ChildHandle
,
1810 gBS
->FreePool (IpInfo
);
1817 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1820 If IpInfo is NULL, then ASSERT().
1821 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1823 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1824 @param[in, out] IpConfigData The IP configure data used to configure the IP
1825 instance, if NULL the IP instance is reset. If
1826 UseDefaultAddress is set to TRUE, and the configure
1827 operation succeeds, the default address information
1828 is written back in this IpConfigData.
1830 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1831 or no need to reconfigure it.
1832 @retval Others Configuration fails.
1838 IN OUT IP_IO_IP_INFO
*IpInfo
,
1839 IN OUT VOID
*IpConfigData OPTIONAL
1843 IP_IO_IP_PROTOCOL Ip
;
1845 EFI_IP4_MODE_DATA Ip4ModeData
;
1846 EFI_IP6_MODE_DATA Ip6ModeData
;
1848 ASSERT (IpInfo
!= NULL
);
1850 if (IpInfo
->RefCnt
> 1) {
1852 // This IP instance is shared, don't reconfigure it until it has only one
1853 // consumer. Currently, only the tcp children cloned from their passive parent
1854 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1855 // let the last consumer clean the IP instance.
1860 IpVersion
= IpInfo
->IpVersion
;
1861 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1865 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1866 Status
= Ip
.Ip4
->Configure (Ip
.Ip4
, IpConfigData
);
1868 Status
= Ip
.Ip6
->Configure (Ip
.Ip6
, IpConfigData
);
1871 if (EFI_ERROR (Status
)) {
1875 if (IpConfigData
!= NULL
) {
1876 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1878 if (((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->UseDefaultAddress
) {
1879 Status
= Ip
.Ip4
->GetModeData (
1885 if (EFI_ERROR (Status
)) {
1886 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1890 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
, &Ip4ModeData
.ConfigData
.StationAddress
);
1891 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
, &Ip4ModeData
.ConfigData
.SubnetMask
);
1896 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1900 &IpInfo
->PreMask
.SubnetMask
,
1901 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
,
1905 Status
= Ip
.Ip4
->Receive (
1907 &IpInfo
->DummyRcvToken
.Ip4Token
1909 if (EFI_ERROR (Status
)) {
1910 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1913 Status
= Ip
.Ip6
->GetModeData (
1919 if (EFI_ERROR (Status
)) {
1920 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1924 if (Ip6ModeData
.IsConfigured
) {
1926 &((EFI_IP6_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1927 &Ip6ModeData
.ConfigData
.StationAddress
,
1928 sizeof (EFI_IPv6_ADDRESS
)
1931 if (Ip6ModeData
.AddressList
!= NULL
) {
1932 FreePool (Ip6ModeData
.AddressList
);
1935 if (Ip6ModeData
.GroupTable
!= NULL
) {
1936 FreePool (Ip6ModeData
.GroupTable
);
1939 if (Ip6ModeData
.RouteTable
!= NULL
) {
1940 FreePool (Ip6ModeData
.RouteTable
);
1943 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1944 FreePool (Ip6ModeData
.NeighborCache
);
1947 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1948 FreePool (Ip6ModeData
.PrefixTable
);
1951 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1952 FreePool (Ip6ModeData
.IcmpTypeList
);
1956 Status
= EFI_NO_MAPPING
;
1962 &Ip6ModeData
.ConfigData
.StationAddress
,
1963 sizeof (EFI_IPv6_ADDRESS
)
1966 Status
= Ip
.Ip6
->Receive (
1968 &IpInfo
->DummyRcvToken
.Ip6Token
1970 if (EFI_ERROR (Status
)) {
1971 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1976 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1978 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1979 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1987 Destroy an IP instance maintained in IpIo->IpList for
1990 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1992 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1993 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1994 will be dstroyed if the RefCnt is zero.
1996 @param[in] IpIo Pointer to the IP_IO instance.
1997 @param[in] IpInfo Pointer to the IpInfo to be removed.
2004 IN IP_IO_IP_INFO
*IpInfo
2010 if (IpIo
== NULL
|| IpInfo
== NULL
) {
2014 ASSERT (IpInfo
->RefCnt
> 0);
2016 NET_PUT_REF (IpInfo
);
2018 if (IpInfo
->RefCnt
> 0) {
2023 IpVersion
= IpIo
->IpVersion
;
2025 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
2027 RemoveEntryList (&IpInfo
->Entry
);
2029 if (IpVersion
== IP_VERSION_4
){
2030 IpInfo
->Ip
.Ip4
->Configure (
2034 IpIoCloseProtocolDestroyIpChild (
2037 IpInfo
->ChildHandle
,
2041 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip4Token
.Event
);
2045 IpInfo
->Ip
.Ip6
->Configure (
2050 IpIoCloseProtocolDestroyIpChild (
2053 IpInfo
->ChildHandle
,
2057 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip6Token
.Event
);
2065 Find the first IP protocol maintained in IpIo whose local
2066 address is the same as Src.
2068 This function is called when the caller needs the IpIo to send data to the
2069 specified Src. The IpIo was added previously by IpIoAddIp().
2071 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
2072 @param[in] IpVersion The version of the IP protocol to use, either
2074 @param[in] Src The local IP address.
2076 @return Pointer to the IP protocol can be used for sending purpose and its local
2077 address is the same with Src. NULL if failed.
2083 IN OUT IP_IO
**IpIo
,
2085 IN EFI_IP_ADDRESS
*Src
2088 LIST_ENTRY
*IpIoEntry
;
2090 LIST_ENTRY
*IpInfoEntry
;
2091 IP_IO_IP_INFO
*IpInfo
;
2093 if (IpIo
== NULL
|| Src
== NULL
) {
2097 if ((IpVersion
!= IP_VERSION_4
) && (IpVersion
!= IP_VERSION_6
)) {
2101 NET_LIST_FOR_EACH (IpIoEntry
, &mActiveIpIoList
) {
2102 IpIoPtr
= NET_LIST_USER_STRUCT (IpIoEntry
, IP_IO
, Entry
);
2104 if (((*IpIo
!= NULL
) && (*IpIo
!= IpIoPtr
)) || (IpIoPtr
->IpVersion
!= IpVersion
)) {
2108 NET_LIST_FOR_EACH (IpInfoEntry
, &IpIoPtr
->IpList
) {
2109 IpInfo
= NET_LIST_USER_STRUCT (IpInfoEntry
, IP_IO_IP_INFO
, Entry
);
2110 if (IpInfo
->IpVersion
== IP_VERSION_4
){
2112 if (EFI_IP4_EQUAL (&IpInfo
->Addr
.v4
, &Src
->v4
)) {
2119 if (EFI_IP6_EQUAL (&IpInfo
->Addr
.v6
, &Src
->v6
)) {
2135 Get the ICMP error map information.
2137 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2138 are not NULL, this routine will fill them.
2140 @param[in] IcmpError IcmpError Type.
2141 @param[in] IpVersion The version of the IP protocol to use,
2142 either IPv4 or IPv6.
2143 @param[out] IsHard If TRUE, indicates that it is a hard error.
2144 @param[out] Notify If TRUE, SockError needs to be notified.
2146 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code.
2147 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2152 IpIoGetIcmpErrStatus (
2155 OUT BOOLEAN
*IsHard OPTIONAL
,
2156 OUT BOOLEAN
*Notify OPTIONAL
2159 if (IpVersion
== IP_VERSION_4
) {
2160 ASSERT (IcmpError
<= ICMP_ERR_PARAMPROB
);
2162 if (IsHard
!= NULL
) {
2163 *IsHard
= mIcmpErrMap
[IcmpError
].IsHard
;
2166 if (Notify
!= NULL
) {
2167 *Notify
= mIcmpErrMap
[IcmpError
].Notify
;
2170 switch (IcmpError
) {
2171 case ICMP_ERR_UNREACH_NET
:
2172 return EFI_NETWORK_UNREACHABLE
;
2174 case ICMP_ERR_TIMXCEED_INTRANS
:
2175 case ICMP_ERR_TIMXCEED_REASS
:
2176 case ICMP_ERR_UNREACH_HOST
:
2177 return EFI_HOST_UNREACHABLE
;
2179 case ICMP_ERR_UNREACH_PROTOCOL
:
2180 return EFI_PROTOCOL_UNREACHABLE
;
2182 case ICMP_ERR_UNREACH_PORT
:
2183 return EFI_PORT_UNREACHABLE
;
2185 case ICMP_ERR_MSGSIZE
:
2186 case ICMP_ERR_UNREACH_SRCFAIL
:
2187 case ICMP_ERR_QUENCH
:
2188 case ICMP_ERR_PARAMPROB
:
2189 return EFI_ICMP_ERROR
;
2193 return EFI_UNSUPPORTED
;
2196 } else if (IpVersion
== IP_VERSION_6
) {
2198 ASSERT (IcmpError
<= ICMP6_ERR_PARAMPROB_IPV6OPTION
);
2200 if (IsHard
!= NULL
) {
2201 *IsHard
= mIcmp6ErrMap
[IcmpError
].IsHard
;
2204 if (Notify
!= NULL
) {
2205 *Notify
= mIcmp6ErrMap
[IcmpError
].Notify
;
2208 switch (IcmpError
) {
2209 case ICMP6_ERR_UNREACH_NET
:
2210 return EFI_NETWORK_UNREACHABLE
;
2212 case ICMP6_ERR_UNREACH_HOST
:
2213 case ICMP6_ERR_TIMXCEED_HOPLIMIT
:
2214 case ICMP6_ERR_TIMXCEED_REASS
:
2215 return EFI_HOST_UNREACHABLE
;
2217 case ICMP6_ERR_UNREACH_PROTOCOL
:
2218 return EFI_PROTOCOL_UNREACHABLE
;
2220 case ICMP6_ERR_UNREACH_PORT
:
2221 return EFI_PORT_UNREACHABLE
;
2223 case ICMP6_ERR_PACKAGE_TOOBIG
:
2224 case ICMP6_ERR_PARAMPROB_HEADER
:
2225 case ICMP6_ERR_PARAMPROB_NEXHEADER
:
2226 case ICMP6_ERR_PARAMPROB_IPV6OPTION
:
2227 return EFI_ICMP_ERROR
;
2231 return EFI_UNSUPPORTED
;
2236 // Should never be here
2239 return EFI_UNSUPPORTED
;
2245 Refresh the remote peer's Neighbor Cache entries.
2247 This function is called when the caller needs the IpIo to refresh the existing
2248 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2249 node has recently received a confirmation that packets sent recently to the
2250 neighbor were received by its IP layer.
2252 @param[in] IpIo Pointer to an IP_IO instance
2253 @param[in] Neighbor The IP address of the neighbor
2254 @param[in] Timeout Time in 100-ns units that this entry will
2255 remain in the neighbor cache. A value of
2256 zero means that the entry is permanent.
2257 A value of non-zero means that the entry is
2258 dynamic and will be deleted after Timeout.
2260 @retval EFI_SUCCESS The operation is completed successfully.
2261 @retval EFI_NOT_STARTED The IpIo is not configured.
2262 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2263 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2265 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh.
2266 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2271 IpIoRefreshNeighbor (
2273 IN EFI_IP_ADDRESS
*Neighbor
,
2277 EFI_IP6_PROTOCOL
*Ip
;
2279 if (!IpIo
->IsConfigured
) {
2280 return EFI_NOT_STARTED
;
2283 if (IpIo
->IpVersion
!= IP_VERSION_6
) {
2284 return EFI_UNSUPPORTED
;
2289 return Ip
->Neighbors (Ip
, FALSE
, &Neighbor
->v6
, NULL
, Timeout
, TRUE
);