4 Copyright (c) 2005 - 2009, Intel Corporation.<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include <Protocol/Udp4.h>
18 #include <Library/IpIoLib.h>
19 #include <Library/BaseLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/BaseMemoryLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/MemoryAllocationLib.h>
24 #include <Library/DpcLib.h>
27 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList
= {
32 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData
= {
49 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData
= {
54 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
55 {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
63 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap
[10] = {
64 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_NET
65 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_HOST
66 {TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PROTOCOL
67 {TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PORT
68 {TRUE
, TRUE
}, // ICMP_ERR_MSGSIZE
69 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_SRCFAIL
70 {FALSE
, TRUE
}, // ICMP_ERR_TIMXCEED_INTRANS
71 {FALSE
, TRUE
}, // ICMP_ERR_TIMEXCEED_REASS
72 {FALSE
, FALSE
}, // ICMP_ERR_QUENCH
73 {FALSE
, TRUE
} // ICMP_ERR_PARAMPROB
76 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap
[10] = {
77 {FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_NET
78 {FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_HOST
79 {TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PROTOCOL
80 {TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PORT
81 {TRUE
, TRUE
}, // ICMP6_ERR_PACKAGE_TOOBIG
82 {FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
83 {FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_REASS
84 {FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_HEADER
85 {FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_NEXHEADER
86 {FALSE
, TRUE
} // ICMP6_ERR_PARAMPROB_IPV6OPTION
91 Notify function for IP transmit token.
93 @param[in] Context The context passed in by the event notifier.
98 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 (
119 This function create an IP child ,open the IP protocol, and return the opened
120 IP protocol as Interface.
122 @param[in] ControllerHandle The controller handle.
123 @param[in] ImageHandle The image handle.
124 @param[in] ChildHandle Pointer to the buffer to save the IP child handle.
125 @param[in] IpVersion The version of the IP protocol to use, either
127 @param[out] Interface Pointer used to get the IP protocol interface.
129 @retval EFI_SUCCESS The IP child is created and the IP protocol
130 interface is retrieved.
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 (
198 This function close the previously openned IP protocol and destroy the IP child.
200 @param[in] ControllerHandle The controller handle.
201 @param[in] ImageHandle The image handle.
202 @param[in] ChildHandle The child handle of the IP child.
203 @param[in] IpVersion The version of the IP protocol to use, either
206 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child
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 openned IP protocol.
244 // Destroy the IP child.
246 Status
= NetLibDestroyServiceChild (
257 This function handles ICMPv4 packets. It is the worker function of
260 @param[in] IpIo Pointer to the IP_IO instance.
261 @param[in, out] Pkt Pointer to the ICMPv4 packet.
262 @param[in] Session Pointer to the net session of this ICMPv4 packet.
264 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.
265 @retval EFI_ABORTED This type of ICMPv4 packet is not supported.
272 IN EFI_NET_SESSION_DATA
*Session
275 IP4_ICMP_ERROR_HEAD
*IcmpHdr
;
276 EFI_IP4_HEADER
*IpHdr
;
283 ASSERT (IpIo
->IpVersion
== IP_VERSION_4
);
285 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP4_ICMP_ERROR_HEAD
);
286 IpHdr
= (EFI_IP4_HEADER
*) (&IcmpHdr
->IpHead
);
289 // Check the ICMP packet length.
291 if (Pkt
->TotalSize
< ICMP_ERRLEN (IpHdr
)) {
296 Type
= IcmpHdr
->Head
.Type
;
297 Code
= IcmpHdr
->Head
.Code
;
300 // Analyze the ICMP Error in this ICMP pkt
303 case ICMP_TYPE_UNREACH
:
305 case ICMP_CODE_UNREACH_NET
:
306 case ICMP_CODE_UNREACH_HOST
:
307 case ICMP_CODE_UNREACH_PROTOCOL
:
308 case ICMP_CODE_UNREACH_PORT
:
309 case ICMP_CODE_UNREACH_SRCFAIL
:
310 IcmpErr
= (UINT8
) (ICMP_ERR_UNREACH_NET
+ Code
);
314 case ICMP_CODE_UNREACH_NEEDFRAG
:
315 IcmpErr
= ICMP_ERR_MSGSIZE
;
319 case ICMP_CODE_UNREACH_NET_UNKNOWN
:
320 case ICMP_CODE_UNREACH_NET_PROHIB
:
321 case ICMP_CODE_UNREACH_TOSNET
:
322 IcmpErr
= ICMP_ERR_UNREACH_NET
;
326 case ICMP_CODE_UNREACH_HOST_UNKNOWN
:
327 case ICMP_CODE_UNREACH_ISOLATED
:
328 case ICMP_CODE_UNREACH_HOST_PROHIB
:
329 case ICMP_CODE_UNREACH_TOSHOST
:
330 IcmpErr
= ICMP_ERR_UNREACH_HOST
;
340 case ICMP_TYPE_TIMXCEED
:
345 IcmpErr
= (UINT8
) (Code
+ ICMP_ERR_TIMXCEED_INTRANS
);
349 case ICMP_TYPE_PARAMPROB
:
354 IcmpErr
= ICMP_ERR_PARAMPROB
;
358 case ICMP_TYPE_SOURCEQUENCH
:
363 IcmpErr
= ICMP_ERR_QUENCH
;
372 // Notify user the ICMP pkt only containing payload except
373 // IP and ICMP header
375 PayLoadHdr
= (UINT8
*) ((UINT8
*) IpHdr
+ EFI_IP4_HEADER_LEN (IpHdr
));
376 TrimBytes
= (UINT32
) (PayLoadHdr
- (UINT8
*) IcmpHdr
);
378 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
380 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
386 This function handles ICMPv6 packets. It is the worker function of
389 @param[in] IpIo Pointer to the IP_IO instance.
390 @param[in, out] Pkt Pointer to the ICMPv6 packet.
391 @param[in] Session Pointer to the net session of this ICMPv6 packet.
393 @retval EFI_SUCCESS The ICMPv6 packet is handled successfully.
394 @retval EFI_ABORTED This type of ICMPv6 packet is not supported.
401 IN EFI_NET_SESSION_DATA
*Session
404 IP6_ICMP_ERROR_HEAD
*IcmpHdr
;
405 EFI_IP6_HEADER
*IpHdr
;
414 ASSERT (IpIo
->IpVersion
== IP_VERSION_6
);
417 // Check the ICMPv6 packet length.
419 if (Pkt
->TotalSize
< sizeof (IP6_ICMP_ERROR_HEAD
)) {
424 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP6_ICMP_ERROR_HEAD
);
425 Type
= IcmpHdr
->Head
.Type
;
426 Code
= IcmpHdr
->Head
.Code
;
429 // Analyze the ICMPv6 Error in this ICMPv6 packet
432 case ICMP_V6_DEST_UNREACHABLE
:
434 case ICMP_V6_NO_ROUTE_TO_DEST
:
435 case ICMP_V6_BEYOND_SCOPE
:
436 case ICMP_V6_ROUTE_REJECTED
:
437 IcmpErr
= ICMP6_ERR_UNREACH_NET
;
441 case ICMP_V6_COMM_PROHIBITED
:
442 case ICMP_V6_ADDR_UNREACHABLE
:
443 case ICMP_V6_SOURCE_ADDR_FAILED
:
444 IcmpErr
= ICMP6_ERR_UNREACH_HOST
;
448 case ICMP_V6_PORT_UNREACHABLE
:
449 IcmpErr
= ICMP6_ERR_UNREACH_PORT
;
459 case ICMP_V6_PACKET_TOO_BIG
:
464 IcmpErr
= ICMP6_ERR_PACKAGE_TOOBIG
;
468 case ICMP_V6_TIME_EXCEEDED
:
473 IcmpErr
= (UINT8
) (ICMP6_ERR_TIMXCEED_HOPLIMIT
+ Code
);
477 case ICMP_V6_PARAMETER_PROBLEM
:
482 IcmpErr
= (UINT8
) (ICMP6_ERR_PARAMPROB_HEADER
+ Code
);
492 // Notify user the ICMPv6 packet only containing payload except
493 // IPv6 basic header, extension header and ICMP header
496 IpHdr
= (EFI_IP6_HEADER
*) (&IcmpHdr
->IpHead
);
497 NextHeader
= IpHdr
->NextHeader
;
498 PayLoadHdr
= (UINT8
*) ((UINT8
*) IcmpHdr
+ sizeof (IP6_ICMP_ERROR_HEAD
));
502 switch (NextHeader
) {
503 case EFI_IP_PROTO_UDP
:
504 case EFI_IP_PROTO_TCP
:
505 case EFI_IP_PROTO_ICMP
:
506 case IP6_NO_NEXT_HEADER
:
512 case IP6_DESTINATION
:
514 // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
515 // the first 8 octets.
517 NextHeader
= *(PayLoadHdr
);
518 PayLoadHdr
= (UINT8
*) (PayLoadHdr
+ (*(PayLoadHdr
+ 1) + 1) * 8);
524 // The Fragment Header Length is 8 octets.
526 NextHeader
= *(PayLoadHdr
);
527 PayLoadHdr
= (UINT8
*) (PayLoadHdr
+ 8);
537 TrimBytes
= (UINT32
) (PayLoadHdr
- (UINT8
*) IcmpHdr
);
539 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
541 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
547 This function handles ICMP packets.
549 @param[in] IpIo Pointer to the IP_IO instance.
550 @param[in, out] Pkt Pointer to the ICMP packet.
551 @param[in] Session Pointer to the net session of this ICMP packet.
553 @retval EFI_SUCCESS The ICMP packet is handled successfully.
554 @retval EFI_ABORTED This type of ICMP packet is not supported.
555 @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
562 IN EFI_NET_SESSION_DATA
*Session
566 if (IpIo
->IpVersion
== IP_VERSION_4
) {
568 return IpIoIcmpv4Handler (IpIo
, Pkt
, Session
);
570 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
572 return IpIoIcmpv6Handler (IpIo
, Pkt
, Session
);
576 return EFI_UNSUPPORTED
;
582 Free function for receive token of IP_IO. It is used to
583 signal the recycle event to notify IP to recycle the
586 @param[in] Event The event to be signaled.
594 gBS
->SignalEvent ((EFI_EVENT
) Event
);
599 Create a send entry to wrap a packet before sending
602 @param[in, out] IpIo Pointer to the IP_IO instance.
603 @param[in, out] Pkt Pointer to the packet.
604 @param[in] Sender Pointer to the IP sender.
605 @param[in] Context Pointer to the context.
606 @param[in] NotifyData Pointer to the notify data.
607 @param[in] Dest Pointer to the destination IP address.
608 @param[in] Override Pointer to the overriden IP_IO data.
610 @return Pointer to the data structure created to wrap the packet. If NULL,
611 @return resource limit occurred.
619 IN VOID
*Context OPTIONAL
,
620 IN VOID
*NotifyData OPTIONAL
,
621 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
622 IN IP_IO_OVERRIDE
*Override
625 IP_IO_SEND_ENTRY
*SndEntry
;
628 NET_FRAGMENT
*ExtFragment
;
629 UINT32 FragmentCount
;
630 IP_IO_OVERRIDE
*OverrideData
;
631 IP_IO_IP_TX_DATA
*TxData
;
632 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
633 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
635 if ((IpIo
->IpVersion
!= IP_VERSION_4
) && (IpIo
->IpVersion
!= IP_VERSION_6
)) {
644 // Allocate resource for SndEntry
646 SndEntry
= AllocatePool (sizeof (IP_IO_SEND_ENTRY
));
647 if (NULL
== SndEntry
) {
651 Status
= gBS
->CreateEvent (
658 if (EFI_ERROR (Status
)) {
662 FragmentCount
= Pkt
->BlockOpNum
;
665 // Allocate resource for TxData
667 TxData
= (IP_IO_IP_TX_DATA
*) AllocatePool (
668 sizeof (IP_IO_IP_TX_DATA
) + sizeof (NET_FRAGMENT
) * (FragmentCount
- 1)
671 if (NULL
== TxData
) {
676 // Build a fragment table to contain the fragments in the packet.
678 if (IpIo
->IpVersion
== IP_VERSION_4
) {
679 ExtFragment
= (NET_FRAGMENT
*) TxData
->Ip4TxData
.FragmentTable
;
681 ExtFragment
= (NET_FRAGMENT
*) TxData
->Ip6TxData
.FragmentTable
;
684 NetbufBuildExt (Pkt
, ExtFragment
, &FragmentCount
);
688 // Allocate resource for OverrideData if needed
690 if (NULL
!= Override
) {
692 OverrideData
= AllocateCopyPool (sizeof (IP_IO_OVERRIDE
), Override
);
693 if (NULL
== OverrideData
) {
699 // Set other fields of TxData except the fragment table
701 if (IpIo
->IpVersion
== IP_VERSION_4
) {
703 Ip4TxData
= &TxData
->Ip4TxData
;
705 CopyMem (&Ip4TxData
->DestinationAddress
, Dest
, sizeof (EFI_IPv4_ADDRESS
));
707 Ip4TxData
->OverrideData
= &OverrideData
->Ip4OverrideData
;
708 Ip4TxData
->OptionsLength
= 0;
709 Ip4TxData
->OptionsBuffer
= NULL
;
710 Ip4TxData
->TotalDataLength
= Pkt
->TotalSize
;
711 Ip4TxData
->FragmentCount
= FragmentCount
;
714 // Set the fields of SndToken
716 SndEntry
->SndToken
.Ip4Token
.Event
= Event
;
717 SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
= Ip4TxData
;
720 Ip6TxData
= &TxData
->Ip6TxData
;
723 CopyMem (&Ip6TxData
->DestinationAddress
, Dest
, sizeof (EFI_IPv6_ADDRESS
));
725 ZeroMem (&Ip6TxData
->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
));
728 Ip6TxData
->OverrideData
= &OverrideData
->Ip6OverrideData
;
729 Ip6TxData
->DataLength
= Pkt
->TotalSize
;
730 Ip6TxData
->FragmentCount
= FragmentCount
;
731 Ip6TxData
->ExtHdrsLength
= 0;
732 Ip6TxData
->ExtHdrs
= NULL
;
735 // Set the fields of SndToken
737 SndEntry
->SndToken
.Ip6Token
.Event
= Event
;
738 SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
= Ip6TxData
;
742 // Set the fields of SndEntry
744 SndEntry
->IpIo
= IpIo
;
745 SndEntry
->Ip
= Sender
;
746 SndEntry
->Context
= Context
;
747 SndEntry
->NotifyData
= NotifyData
;
752 InsertTailList (&IpIo
->PendingSndList
, &SndEntry
->Entry
);
758 if (OverrideData
!= NULL
) {
759 FreePool (OverrideData
);
762 if (TxData
!= NULL
) {
766 if (SndEntry
!= NULL
) {
771 gBS
->CloseEvent (Event
);
779 Destroy the SndEntry.
781 This function pairs with IpIoCreateSndEntry().
783 @param[in] SndEntry Pointer to the send entry to be destroyed.
787 IpIoDestroySndEntry (
788 IN IP_IO_SEND_ENTRY
*SndEntry
792 IP_IO_IP_TX_DATA
*TxData
;
793 IP_IO_OVERRIDE
*Override
;
795 if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_4
) {
796 Event
= SndEntry
->SndToken
.Ip4Token
.Event
;
797 TxData
= (IP_IO_IP_TX_DATA
*) SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
;
798 Override
= (IP_IO_OVERRIDE
*) TxData
->Ip4TxData
.OverrideData
;
799 } else if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_6
) {
800 Event
= SndEntry
->SndToken
.Ip6Token
.Event
;
801 TxData
= (IP_IO_IP_TX_DATA
*) SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
;
802 Override
= (IP_IO_OVERRIDE
*) TxData
->Ip6TxData
.OverrideData
;
807 gBS
->CloseEvent (Event
);
811 if (NULL
!= Override
) {
815 NetbufFree (SndEntry
->Pkt
);
817 RemoveEntryList (&SndEntry
->Entry
);
824 Notify function for IP transmit token.
826 @param[in] Context The context passed in by the event notifier.
831 IpIoTransmitHandlerDpc (
836 IP_IO_SEND_ENTRY
*SndEntry
;
839 SndEntry
= (IP_IO_SEND_ENTRY
*) Context
;
841 IpIo
= SndEntry
->IpIo
;
843 if (IpIo
->IpVersion
== IP_VERSION_4
) {
844 Status
= SndEntry
->SndToken
.Ip4Token
.Status
;
845 } else if (IpIo
->IpVersion
== IP_VERSION_6
){
846 Status
= SndEntry
->SndToken
.Ip6Token
.Status
;
851 if ((IpIo
->PktSentNotify
!= NULL
) && (SndEntry
->NotifyData
!= NULL
)) {
852 IpIo
->PktSentNotify (
860 IpIoDestroySndEntry (SndEntry
);
865 Notify function for IP transmit token.
867 @param[in] Event The event signaled.
868 @param[in] Context The context passed in by the event notifier.
873 IpIoTransmitHandler (
879 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
881 QueueDpc (TPL_CALLBACK
, IpIoTransmitHandlerDpc
, Context
);
886 The dummy handler for the dummy IP receive token.
888 @param[in] Context The context passed in by the event notifier.
893 IpIoDummyHandlerDpc (
897 IP_IO_IP_INFO
*IpInfo
;
899 EFI_EVENT RecycleEvent
;
901 IpInfo
= (IP_IO_IP_INFO
*) Context
;
903 if ((IpInfo
->IpVersion
!= IP_VERSION_4
) && (IpInfo
->IpVersion
!= IP_VERSION_6
)) {
909 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
910 Status
= IpInfo
->DummyRcvToken
.Ip4Token
.Status
;
912 if (IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
!= NULL
) {
913 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
->RecycleSignal
;
916 Status
= IpInfo
->DummyRcvToken
.Ip6Token
.Status
;
918 if (IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
!= NULL
) {
919 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
->RecycleSignal
;
925 if (EFI_ABORTED
== Status
) {
927 // The reception is actively aborted by the consumer, directly return.
930 } else if (EFI_SUCCESS
== Status
) {
932 // Recycle the RxData.
934 ASSERT (RecycleEvent
!= NULL
);
936 gBS
->SignalEvent (RecycleEvent
);
940 // Continue the receive.
942 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
943 ((EFI_IP4_PROTOCOL
*) (IpInfo
->Ip
))->Receive (
944 (EFI_IP4_PROTOCOL
*) (IpInfo
->Ip
),
945 &IpInfo
->DummyRcvToken
.Ip4Token
948 ((EFI_IP6_PROTOCOL
*) (IpInfo
->Ip
))->Receive (
949 (EFI_IP6_PROTOCOL
*) (IpInfo
->Ip
),
950 &IpInfo
->DummyRcvToken
.Ip6Token
957 This function add IpIoDummyHandlerDpc to the end of the DPC queue.
959 @param[in] Event The event signaled.
960 @param[in] Context The context passed in by the event notifier.
971 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
973 QueueDpc (TPL_CALLBACK
, IpIoDummyHandlerDpc
, Context
);
978 Notify function for the IP receive token, used to process
979 the received IP packets.
981 @param[in] Context The context passed in by the event notifier.
986 IpIoListenHandlerDpc (
992 IP_IO_IP_RX_DATA
*RxData
;
994 EFI_NET_SESSION_DATA Session
;
997 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
)) || (NULL
== RxData
)) {
1019 // @bug Only process the normal packets and the icmp error packets, if RxData is NULL
1020 // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
1021 // @bug this should be a bug of the low layer (IP).
1026 if (NULL
== IpIo
->PktRcvdNotify
) {
1030 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1031 if ((EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
) != 0) &&
1032 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), 0)) {
1034 // The source address is not zero and it's not a unicast IP address, discard it.
1040 // Create a netbuffer representing IPv4 packet
1042 Pkt
= NetbufFromExt (
1043 (NET_FRAGMENT
*) RxData
->Ip4RxData
.FragmentTable
,
1044 RxData
->Ip4RxData
.FragmentCount
,
1048 RxData
->Ip4RxData
.RecycleSignal
1055 // Create a net session
1057 Session
.Source
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
);
1058 Session
.Dest
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->DestinationAddress
);
1059 Session
.IpHdr
.Ip4Hdr
= RxData
->Ip4RxData
.Header
;
1060 Session
.IpHdrLen
= RxData
->Ip4RxData
.HeaderLength
;
1061 Session
.IpVersion
= IP_VERSION_4
;
1064 if (!NetIp6IsValidUnicast(&RxData
->Ip6RxData
.Header
->SourceAddress
)) {
1069 // Create a netbuffer representing IPv6 packet
1071 Pkt
= NetbufFromExt (
1072 (NET_FRAGMENT
*) RxData
->Ip6RxData
.FragmentTable
,
1073 RxData
->Ip6RxData
.FragmentCount
,
1077 RxData
->Ip6RxData
.RecycleSignal
1084 // Create a net session
1088 &RxData
->Ip6RxData
.Header
->SourceAddress
,
1089 sizeof(EFI_IPv6_ADDRESS
)
1093 &RxData
->Ip6RxData
.Header
->DestinationAddress
,
1094 sizeof(EFI_IPv6_ADDRESS
)
1096 Session
.IpHdr
.Ip6Hdr
= RxData
->Ip6RxData
.Header
;
1097 Session
.IpHdrLen
= RxData
->Ip6RxData
.HeaderLength
;
1098 Session
.IpVersion
= IP_VERSION_6
;
1101 if (EFI_SUCCESS
== Status
) {
1103 IpIo
->PktRcvdNotify (EFI_SUCCESS
, 0, &Session
, Pkt
, IpIo
->RcvdContext
);
1106 // Status is EFI_ICMP_ERROR
1108 Status
= IpIoIcmpHandler (IpIo
, Pkt
, &Session
);
1109 if (EFI_ERROR (Status
)) {
1118 if (IpIo
->IpVersion
== IP_VERSION_4
){
1119 gBS
->SignalEvent (RxData
->Ip4RxData
.RecycleSignal
);
1121 gBS
->SignalEvent (RxData
->Ip6RxData
.RecycleSignal
);
1126 if (IpIo
->IpVersion
== IP_VERSION_4
){
1127 ((EFI_IP4_PROTOCOL
*) Ip
)->Receive (Ip
, &(IpIo
->RcvToken
.Ip4Token
));
1129 ((EFI_IP6_PROTOCOL
*) Ip
)->Receive (Ip
, &(IpIo
->RcvToken
.Ip6Token
));
1134 This function add IpIoListenHandlerDpc to the end of the DPC queue.
1136 @param[in] Event The event signaled.
1137 @param[in] Context The context passed in by the event notifier.
1148 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1150 QueueDpc (TPL_CALLBACK
, IpIoListenHandlerDpc
, Context
);
1155 Create a new IP_IO instance.
1157 This function uses IP4/IP6 service binding protocol in Controller to create
1158 an IP4/IP6 child (aka IP4/IP6 instance).
1160 @param[in] Image The image handle of the driver or application that
1162 @param[in] Controller The controller handle that has IP4 or IP6 service
1163 binding protocol installed.
1164 @param[in] IpVersion The version of the IP protocol to use, either
1167 @return Pointer to a newly created IP_IO instance, or NULL if failed.
1173 IN EFI_HANDLE Image
,
1174 IN EFI_HANDLE Controller
,
1182 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1184 IpIo
= AllocateZeroPool (sizeof (IP_IO
));
1189 InitializeListHead (&(IpIo
->PendingSndList
));
1190 InitializeListHead (&(IpIo
->IpList
));
1191 IpIo
->Controller
= Controller
;
1192 IpIo
->Image
= Image
;
1193 IpIo
->IpVersion
= IpVersion
;
1196 Status
= gBS
->CreateEvent (
1203 if (EFI_ERROR (Status
)) {
1207 if (IpVersion
== IP_VERSION_4
) {
1208 IpIo
->RcvToken
.Ip4Token
.Event
= Event
;
1210 IpIo
->RcvToken
.Ip6Token
.Event
= Event
;
1214 // Create an IP child and open IP protocol
1216 Status
= IpIoCreateIpChildOpenProtocol (
1221 (VOID
**)&(IpIo
->Ip
)
1223 if (EFI_ERROR (Status
)) {
1231 if (Event
!= NULL
) {
1232 gBS
->CloseEvent (Event
);
1235 gBS
->FreePool (IpIo
);
1242 Open an IP_IO instance for use.
1244 This function is called after IpIoCreate(). It is used for configuring the IP
1245 instance and register the callbacks and their context data for sending and
1246 receiving IP packets.
1248 @param[in, out] IpIo Pointer to an IP_IO instance that needs
1250 @param[in] OpenData The configuration data and callbacks for
1253 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
1255 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
1257 @retval Others Error condition occurred.
1264 IN IP_IO_OPEN_DATA
*OpenData
1271 if (IpIo
->IsConfigured
) {
1272 return EFI_ACCESS_DENIED
;
1275 IpVersion
= IpIo
->IpVersion
;
1277 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1284 if (IpVersion
== IP_VERSION_4
){
1285 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Configure (
1286 (EFI_IP4_PROTOCOL
*) Ip
,
1287 &OpenData
->IpConfigData
.Ip4CfgData
1291 Status
= ((EFI_IP6_PROTOCOL
*) Ip
)->Configure (
1292 (EFI_IP6_PROTOCOL
*) Ip
,
1293 &OpenData
->IpConfigData
.Ip6CfgData
1297 if (EFI_ERROR (Status
)) {
1302 // @bug To delete the default route entry in this Ip, if it is:
1303 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1306 if (IpVersion
== IP_VERSION_4
){
1307 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Routes (
1308 (EFI_IP4_PROTOCOL
*) Ip
,
1315 if (EFI_ERROR (Status
) && (EFI_NOT_FOUND
!= Status
)) {
1320 IpIo
->PktRcvdNotify
= OpenData
->PktRcvdNotify
;
1321 IpIo
->PktSentNotify
= OpenData
->PktSentNotify
;
1323 IpIo
->RcvdContext
= OpenData
->RcvdContext
;
1324 IpIo
->SndContext
= OpenData
->SndContext
;
1326 if (IpVersion
== IP_VERSION_4
){
1327 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip4CfgData
.DefaultProtocol
;
1330 // start to listen incoming packet
1332 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Receive (
1333 (EFI_IP4_PROTOCOL
*) Ip
,
1334 &(IpIo
->RcvToken
.Ip4Token
)
1336 if (EFI_ERROR (Status
)) {
1337 ((EFI_IP4_PROTOCOL
*) Ip
)->Configure ((EFI_IP4_PROTOCOL
*) Ip
, NULL
);
1343 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip6CfgData
.DefaultProtocol
;
1344 Status
= ((EFI_IP6_PROTOCOL
*) Ip
)->Receive (
1345 (EFI_IP6_PROTOCOL
*) Ip
,
1346 &(IpIo
->RcvToken
.Ip6Token
)
1348 if (EFI_ERROR (Status
)) {
1349 ((EFI_IP6_PROTOCOL
*) Ip
)->Configure ((EFI_IP6_PROTOCOL
*) Ip
, NULL
);
1354 IpIo
->IsConfigured
= TRUE
;
1355 InsertTailList (&mActiveIpIoList
, &IpIo
->Entry
);
1364 Stop an IP_IO instance.
1366 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1367 the pending send/receive tokens will be canceled.
1369 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1371 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1372 @retval Others Error condition occurred.
1383 IP_IO_IP_INFO
*IpInfo
;
1386 if (!IpIo
->IsConfigured
) {
1390 IpVersion
= IpIo
->IpVersion
;
1392 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1395 // Remove the IpIo from the active IpIo list.
1397 RemoveEntryList (&IpIo
->Entry
);
1402 // Configure NULL Ip
1404 if (IpVersion
== IP_VERSION_4
) {
1405 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Configure ((EFI_IP4_PROTOCOL
*) Ip
, NULL
);
1407 Status
= ((EFI_IP6_PROTOCOL
*) Ip
)->Configure ((EFI_IP6_PROTOCOL
*) Ip
, NULL
);
1409 if (EFI_ERROR (Status
)) {
1413 IpIo
->IsConfigured
= FALSE
;
1416 // Detroy the Ip List used by IpIo
1419 while (!IsListEmpty (&(IpIo
->IpList
))) {
1420 IpInfo
= NET_LIST_HEAD (&(IpIo
->IpList
), IP_IO_IP_INFO
, Entry
);
1422 IpIoRemoveIp (IpIo
, IpInfo
);
1426 // All pending send tokens should be flushed by reseting the IP instances.
1428 ASSERT (IsListEmpty (&IpIo
->PendingSndList
));
1431 // Close the receive event.
1433 if (IpVersion
== IP_VERSION_4
){
1434 gBS
->CloseEvent (IpIo
->RcvToken
.Ip4Token
.Event
);
1436 gBS
->CloseEvent (IpIo
->RcvToken
.Ip6Token
.Event
);
1444 Destroy an IP_IO instance.
1446 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1447 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1449 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1452 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1453 @retval Others Error condition occurred.
1468 // Close the IP protocol and destroy the child.
1470 IpIoCloseProtocolDestroyIpChild (
1477 gBS
->FreePool (IpIo
);
1484 Send out an IP packet.
1486 This function is called after IpIoOpen(). The data to be sent are wrapped in
1487 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1488 overriden by Sender. Other sending configs, like source address and gateway
1489 address etc., are specified in OverrideData.
1491 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1493 @param[in, out] Pkt Pointer to the IP packet to be sent.
1494 @param[in] Sender The IP protocol instance used for sending.
1495 @param[in] Context Optional context data.
1496 @param[in] NotifyData Optional notify data.
1497 @param[in] Dest The destination IP address to send this packet to.
1498 @param[in] OverrideData The data to override some configuration of the IP
1499 instance used for sending.
1501 @retval EFI_SUCCESS The operation is completed successfully.
1502 @retval EFI_NOT_STARTED The IpIo is not configured.
1503 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1510 IN OUT NET_BUF
*Pkt
,
1511 IN IP_IO_IP_INFO
*Sender OPTIONAL
,
1512 IN VOID
*Context OPTIONAL
,
1513 IN VOID
*NotifyData OPTIONAL
,
1514 IN EFI_IP_ADDRESS
*Dest
,
1515 IN IP_IO_OVERRIDE
*OverrideData OPTIONAL
1520 IP_IO_SEND_ENTRY
*SndEntry
;
1522 ASSERT ((IpIo
->IpVersion
!= IP_VERSION_4
) || (Dest
!= NULL
));
1524 if (!IpIo
->IsConfigured
) {
1525 return EFI_NOT_STARTED
;
1528 Ip
= (NULL
== Sender
) ? IpIo
->Ip
: Sender
->Ip
;
1531 // create a new SndEntry
1533 SndEntry
= IpIoCreateSndEntry (IpIo
, Pkt
, Ip
, Context
, NotifyData
, Dest
, OverrideData
);
1534 if (NULL
== SndEntry
) {
1535 return EFI_OUT_OF_RESOURCES
;
1541 if (IpIo
->IpVersion
== IP_VERSION_4
){
1542 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Transmit (
1543 (EFI_IP4_PROTOCOL
*) Ip
,
1544 &SndEntry
->SndToken
.Ip4Token
1547 Status
= ((EFI_IP6_PROTOCOL
*) Ip
)->Transmit (
1548 (EFI_IP6_PROTOCOL
*) Ip
,
1549 &SndEntry
->SndToken
.Ip6Token
1553 if (EFI_ERROR (Status
)) {
1554 IpIoDestroySndEntry (SndEntry
);
1562 Cancel the IP transmit token which wraps this Packet.
1564 @param[in] IpIo Pointer to the IP_IO instance.
1565 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1576 IP_IO_SEND_ENTRY
*SndEntry
;
1579 ASSERT ((IpIo
!= NULL
) && (Packet
!= NULL
));
1581 NET_LIST_FOR_EACH (Node
, &IpIo
->PendingSndList
) {
1583 SndEntry
= NET_LIST_USER_STRUCT (Node
, IP_IO_SEND_ENTRY
, Entry
);
1585 if (SndEntry
->Pkt
== Packet
) {
1589 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1590 ((EFI_IP4_PROTOCOL
*) Ip
)->Cancel (
1591 (EFI_IP4_PROTOCOL
*) Ip
,
1592 &SndEntry
->SndToken
.Ip4Token
1595 ((EFI_IP6_PROTOCOL
*) Ip
)->Cancel (
1596 (EFI_IP6_PROTOCOL
*) Ip
,
1597 &SndEntry
->SndToken
.Ip6Token
1609 Add a new IP instance for sending data.
1611 The function is used to add the IP_IO to the IP_IO sending list. The caller
1612 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1615 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1616 instance for sending purpose.
1618 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1628 IP_IO_IP_INFO
*IpInfo
;
1631 ASSERT (IpIo
!= NULL
);
1633 IpInfo
= AllocatePool (sizeof (IP_IO_IP_INFO
));
1634 if (IpInfo
== NULL
) {
1639 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1642 InitializeListHead (&IpInfo
->Entry
);
1643 IpInfo
->ChildHandle
= NULL
;
1644 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1645 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1648 IpInfo
->IpVersion
= IpIo
->IpVersion
;
1651 // Create the IP instance and open the IP protocol.
1653 Status
= IpIoCreateIpChildOpenProtocol (
1656 &IpInfo
->ChildHandle
,
1658 (VOID
**) &IpInfo
->Ip
1660 if (EFI_ERROR (Status
)) {
1665 // Create the event for the DummyRcvToken.
1667 Status
= gBS
->CreateEvent (
1674 if (EFI_ERROR (Status
)) {
1675 goto ReleaseIpChild
;
1678 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1679 IpInfo
->DummyRcvToken
.Ip4Token
.Event
= Event
;
1681 IpInfo
->DummyRcvToken
.Ip6Token
.Event
= Event
;
1685 // Link this IpInfo into the IpIo.
1687 InsertTailList (&IpIo
->IpList
, &IpInfo
->Entry
);
1693 IpIoCloseProtocolDestroyIpChild (
1696 IpInfo
->ChildHandle
,
1702 gBS
->FreePool (IpInfo
);
1709 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1712 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1713 @param[in, out] IpConfigData The IP configure data used to configure the IP
1714 instance, if NULL the IP instance is reset. If
1715 UseDefaultAddress is set to TRUE, and the configure
1716 operation succeeds, the default address information
1717 is written back in this IpConfigData.
1719 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1720 or no need to reconfigure it.
1721 @retval Others Configuration fails.
1727 IN OUT IP_IO_IP_INFO
*IpInfo
,
1728 IN OUT VOID
*IpConfigData OPTIONAL
1734 EFI_IP4_MODE_DATA Ip4ModeData
;
1735 EFI_IP6_MODE_DATA Ip6ModeData
;
1737 ASSERT (IpInfo
!= NULL
);
1739 if (IpInfo
->RefCnt
> 1) {
1741 // This IP instance is shared, don't reconfigure it until it has only one
1742 // consumer. Currently, only the tcp children cloned from their passive parent
1743 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1744 // let the last consumer clean the IP instance.
1749 IpVersion
= IpInfo
->IpVersion
;
1750 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1754 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1755 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Configure ((EFI_IP4_PROTOCOL
*) Ip
, IpConfigData
);
1757 Status
= ((EFI_IP6_PROTOCOL
*) Ip
)->Configure ((EFI_IP6_PROTOCOL
*) Ip
, IpConfigData
);
1760 if (EFI_ERROR (Status
)) {
1764 if (IpConfigData
!= NULL
) {
1765 if (IpInfo
->IpVersion
== IP_VERSION_4
){
1767 if (((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->UseDefaultAddress
) {
1768 ((EFI_IP4_PROTOCOL
*) Ip
)->GetModeData (
1769 (EFI_IP4_PROTOCOL
*) Ip
,
1775 ((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
= Ip4ModeData
.ConfigData
.StationAddress
;
1776 ((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
= Ip4ModeData
.ConfigData
.SubnetMask
;
1781 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1785 &IpInfo
->PreMask
.SubnetMask
,
1786 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
,
1790 Status
= ((EFI_IP4_PROTOCOL
*) Ip
)->Receive (
1791 (EFI_IP4_PROTOCOL
*) Ip
,
1792 &IpInfo
->DummyRcvToken
.Ip4Token
1794 if (EFI_ERROR (Status
)) {
1795 ((EFI_IP4_PROTOCOL
*)Ip
)->Configure (Ip
, NULL
);
1799 ((EFI_IP6_PROTOCOL
*) Ip
)->GetModeData (
1800 (EFI_IP6_PROTOCOL
*) Ip
,
1806 if (Ip6ModeData
.IsConfigured
) {
1808 &((EFI_IP6_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1809 &Ip6ModeData
.ConfigData
.StationAddress
,
1810 sizeof (EFI_IPv6_ADDRESS
)
1813 if (Ip6ModeData
.AddressList
!= NULL
) {
1814 FreePool (Ip6ModeData
.AddressList
);
1817 if (Ip6ModeData
.GroupTable
!= NULL
) {
1818 FreePool (Ip6ModeData
.GroupTable
);
1821 if (Ip6ModeData
.RouteTable
!= NULL
) {
1822 FreePool (Ip6ModeData
.RouteTable
);
1825 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1826 FreePool (Ip6ModeData
.NeighborCache
);
1829 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1830 FreePool (Ip6ModeData
.PrefixTable
);
1833 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1834 FreePool (Ip6ModeData
.IcmpTypeList
);
1838 Status
= EFI_NO_MAPPING
;
1844 &Ip6ModeData
.ConfigData
.StationAddress
,
1845 sizeof (EFI_IPv6_ADDRESS
)
1848 Status
= ((EFI_IP6_PROTOCOL
*) Ip
)->Receive (
1849 (EFI_IP6_PROTOCOL
*) Ip
,
1850 &IpInfo
->DummyRcvToken
.Ip6Token
1852 if (EFI_ERROR (Status
)) {
1853 ((EFI_IP6_PROTOCOL
*) Ip
)->Configure ((EFI_IP6_PROTOCOL
*) Ip
, NULL
);
1858 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1860 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1861 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1871 Destroy an IP instance maintained in IpIo->IpList for
1874 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1875 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1876 will be dstroyed if the RefCnt is zero.
1878 @param[in] IpIo Pointer to the IP_IO instance.
1879 @param[in] IpInfo Pointer to the IpInfo to be removed.
1886 IN IP_IO_IP_INFO
*IpInfo
1892 ASSERT (IpInfo
->RefCnt
> 0);
1894 NET_PUT_REF (IpInfo
);
1896 if (IpInfo
->RefCnt
> 0) {
1901 IpVersion
= IpIo
->IpVersion
;
1903 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1905 RemoveEntryList (&IpInfo
->Entry
);
1907 if (IpVersion
== IP_VERSION_4
){
1908 ((EFI_IP4_PROTOCOL
*) (IpInfo
->Ip
))->Configure (
1909 (EFI_IP4_PROTOCOL
*) (IpInfo
->Ip
),
1912 IpIoCloseProtocolDestroyIpChild (
1915 IpInfo
->ChildHandle
,
1919 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip4Token
.Event
);
1923 ((EFI_IP6_PROTOCOL
*) (IpInfo
->Ip
))->Configure (
1924 (EFI_IP6_PROTOCOL
*) (IpInfo
->Ip
),
1928 IpIoCloseProtocolDestroyIpChild (
1931 IpInfo
->ChildHandle
,
1935 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip6Token
.Event
);
1943 Find the first IP protocol maintained in IpIo whose local
1944 address is the same as Src.
1946 This function is called when the caller needs the IpIo to send data to the
1947 specified Src. The IpIo was added previously by IpIoAddIp().
1949 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
1950 @param[in] IpVersion The version of the IP protocol to use, either
1952 @param[in] Src The local IP address.
1954 @return Pointer to the IP protocol can be used for sending purpose and its local
1955 address is the same with Src.
1961 IN OUT IP_IO
**IpIo
,
1963 IN EFI_IP_ADDRESS
*Src
1966 LIST_ENTRY
*IpIoEntry
;
1968 LIST_ENTRY
*IpInfoEntry
;
1969 IP_IO_IP_INFO
*IpInfo
;
1971 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1973 NET_LIST_FOR_EACH (IpIoEntry
, &mActiveIpIoList
) {
1974 IpIoPtr
= NET_LIST_USER_STRUCT (IpIoEntry
, IP_IO
, Entry
);
1976 if (((*IpIo
!= NULL
) && (*IpIo
!= IpIoPtr
)) || (IpIoPtr
->IpVersion
!= IpVersion
)) {
1980 NET_LIST_FOR_EACH (IpInfoEntry
, &IpIoPtr
->IpList
) {
1981 IpInfo
= NET_LIST_USER_STRUCT (IpInfoEntry
, IP_IO_IP_INFO
, Entry
);
1982 if (IpInfo
->IpVersion
== IP_VERSION_4
){
1984 if (EFI_IP4_EQUAL (&IpInfo
->Addr
.v4
, &Src
->v4
)) {
1991 if (EFI_IP6_EQUAL (&IpInfo
->Addr
.v6
, &Src
->v6
)) {
2008 Get the ICMP error map information.
2010 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2011 are not NULL, this routine will fill them.
2013 @param[in] IcmpError IcmpError Type.
2014 @param[in] IpVersion The version of the IP protocol to use,
2015 either IPv4 or IPv6.
2017 @param[out] IsHard Whether it is a hard error.
2018 @param[out] Notify Whether it need to notify SockError.
2020 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2025 IpIoGetIcmpErrStatus (
2028 OUT BOOLEAN
*IsHard OPTIONAL
,
2029 OUT BOOLEAN
*Notify OPTIONAL
2032 if (IpVersion
== IP_VERSION_4
) {
2033 ASSERT (IcmpError
<= ICMP_ERR_PARAMPROB
);
2035 if (IsHard
!= NULL
) {
2036 *IsHard
= mIcmpErrMap
[IcmpError
].IsHard
;
2039 if (Notify
!= NULL
) {
2040 *Notify
= mIcmpErrMap
[IcmpError
].Notify
;
2043 switch (IcmpError
) {
2044 case ICMP_ERR_UNREACH_NET
:
2045 return EFI_NETWORK_UNREACHABLE
;
2047 case ICMP_ERR_TIMXCEED_INTRANS
:
2048 case ICMP_ERR_TIMXCEED_REASS
:
2049 case ICMP_ERR_UNREACH_HOST
:
2050 return EFI_HOST_UNREACHABLE
;
2052 case ICMP_ERR_UNREACH_PROTOCOL
:
2053 return EFI_PROTOCOL_UNREACHABLE
;
2055 case ICMP_ERR_UNREACH_PORT
:
2056 return EFI_PORT_UNREACHABLE
;
2058 case ICMP_ERR_MSGSIZE
:
2059 case ICMP_ERR_UNREACH_SRCFAIL
:
2060 case ICMP_ERR_QUENCH
:
2061 case ICMP_ERR_PARAMPROB
:
2062 return EFI_ICMP_ERROR
;
2066 return EFI_UNSUPPORTED
;
2069 } else if (IpVersion
== IP_VERSION_6
) {
2071 ASSERT (IcmpError
<= ICMP6_ERR_PARAMPROB_IPV6OPTION
);
2073 if (IsHard
!= NULL
) {
2074 *IsHard
= mIcmp6ErrMap
[IcmpError
].IsHard
;
2077 if (Notify
!= NULL
) {
2078 *Notify
= mIcmp6ErrMap
[IcmpError
].Notify
;
2081 switch (IcmpError
) {
2082 case ICMP6_ERR_UNREACH_NET
:
2083 return EFI_NETWORK_UNREACHABLE
;
2085 case ICMP6_ERR_UNREACH_HOST
:
2086 case ICMP6_ERR_TIMXCEED_HOPLIMIT
:
2087 case ICMP6_ERR_TIMXCEED_REASS
:
2088 return EFI_HOST_UNREACHABLE
;
2090 case ICMP6_ERR_UNREACH_PROTOCOL
:
2091 return EFI_PROTOCOL_UNREACHABLE
;
2093 case ICMP6_ERR_UNREACH_PORT
:
2094 return EFI_PORT_UNREACHABLE
;
2096 case ICMP6_ERR_PACKAGE_TOOBIG
:
2097 case ICMP6_ERR_PARAMPROB_HEADER
:
2098 case ICMP6_ERR_PARAMPROB_NEXHEADER
:
2099 case ICMP6_ERR_PARAMPROB_IPV6OPTION
:
2100 return EFI_ICMP_ERROR
;
2104 return EFI_UNSUPPORTED
;
2109 // Should never be here
2112 return EFI_UNSUPPORTED
;
2118 Refresh the remote peer's Neighbor Cache entries.
2120 This function is called when the caller needs the IpIo to refresh the existing
2121 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2122 node has recently received a confirmation that packets sent recently to the
2123 neighbor were received by its IP layer.
2125 @param[in] IpIo Pointer to an IP_IO instance
2126 @param[in] Neighbor The IP address of the neighbor
2127 @param[in] Timeout Time in 100-ns units that this entry will
2128 remain in the neighbor cache. A value of
2129 zero means that the entry is permanent.
2130 A value of non-zero means that the entry is
2131 dynamic and will be deleted after Timeout.
2133 @retval EFI_SUCCESS The operation is completed successfully.
2134 @retval EFI_NOT_STARTED The IpIo is not configured.
2135 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2136 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2138 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2142 IpIoRefreshNeighbor (
2144 IN EFI_IP_ADDRESS
*Neighbor
,
2148 EFI_IP6_PROTOCOL
*Ip
;
2150 if (!IpIo
->IsConfigured
|| IpIo
->IpVersion
!= IP_VERSION_6
) {
2151 return EFI_NOT_STARTED
;
2154 Ip
= (EFI_IP6_PROTOCOL
*) (IpIo
->Ip
);
2156 return Ip
->Neighbors (Ip
, FALSE
, &Neighbor
->v6
, NULL
, Timeout
, TRUE
);