4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Protocol/Udp4.h>
19 #include <Library/IpIoLib.h>
20 #include <Library/BaseLib.h>
21 #include <Library/DebugLib.h>
22 #include <Library/BaseMemoryLib.h>
23 #include <Library/UefiBootServicesTableLib.h>
24 #include <Library/MemoryAllocationLib.h>
25 #include <Library/DpcLib.h>
28 GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY mActiveIpIoList
= {
33 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA mIp4IoDefaultIpConfigData
= {
50 GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA mIp6IoDefaultIpConfigData
= {
55 {{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}},
64 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmpErrMap
[10] = {
65 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_NET
66 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_HOST
67 {TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PROTOCOL
68 {TRUE
, TRUE
}, // ICMP_ERR_UNREACH_PORT
69 {TRUE
, TRUE
}, // ICMP_ERR_MSGSIZE
70 {FALSE
, TRUE
}, // ICMP_ERR_UNREACH_SRCFAIL
71 {FALSE
, TRUE
}, // ICMP_ERR_TIMXCEED_INTRANS
72 {FALSE
, TRUE
}, // ICMP_ERR_TIMEXCEED_REASS
73 {FALSE
, FALSE
}, // ICMP_ERR_QUENCH
74 {FALSE
, TRUE
} // ICMP_ERR_PARAMPROB
77 GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO mIcmp6ErrMap
[10] = {
78 {FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_NET
79 {FALSE
, TRUE
}, // ICMP6_ERR_UNREACH_HOST
80 {TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PROTOCOL
81 {TRUE
, TRUE
}, // ICMP6_ERR_UNREACH_PORT
82 {TRUE
, TRUE
}, // ICMP6_ERR_PACKAGE_TOOBIG
83 {FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
84 {FALSE
, TRUE
}, // ICMP6_ERR_TIMXCEED_REASS
85 {FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_HEADER
86 {FALSE
, TRUE
}, // ICMP6_ERR_PARAMPROB_NEXHEADER
87 {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 (
105 Notify function for IP transmit token.
107 @param[in] Event The event signaled.
108 @param[in] Context The context passed in by the event notifier.
113 IpIoTransmitHandler (
120 This function create an IP child ,open the IP protocol, and return the opened
121 IP protocol as Interface.
123 @param[in] ControllerHandle The controller handle.
124 @param[in] ImageHandle The image handle.
125 @param[in] ChildHandle Pointer to the buffer to save the IP child handle.
126 @param[in] IpVersion The version of the IP protocol to use, either
128 @param[out] Interface Pointer used to get the IP protocol interface.
130 @retval EFI_SUCCESS The IP child is created and the IP protocol
131 interface is retrieved.
132 @retval EFI_UNSUPPORTED Upsupported IpVersion.
133 @retval Others The required operation failed.
137 IpIoCreateIpChildOpenProtocol (
138 IN EFI_HANDLE ControllerHandle
,
139 IN EFI_HANDLE ImageHandle
,
140 IN EFI_HANDLE
*ChildHandle
,
146 EFI_GUID
*ServiceBindingGuid
;
147 EFI_GUID
*IpProtocolGuid
;
149 if (IpVersion
== IP_VERSION_4
) {
150 ServiceBindingGuid
= &gEfiIp4ServiceBindingProtocolGuid
;
151 IpProtocolGuid
= &gEfiIp4ProtocolGuid
;
152 } else if (IpVersion
== IP_VERSION_6
){
153 ServiceBindingGuid
= &gEfiIp6ServiceBindingProtocolGuid
;
154 IpProtocolGuid
= &gEfiIp6ProtocolGuid
;
156 return EFI_UNSUPPORTED
;
160 // Create an IP child.
162 Status
= NetLibCreateServiceChild (
168 if (EFI_ERROR (Status
)) {
173 // Open the IP protocol installed on the *ChildHandle.
175 Status
= gBS
->OpenProtocol (
181 EFI_OPEN_PROTOCOL_BY_DRIVER
183 if (EFI_ERROR (Status
)) {
185 // On failure, destroy the IP child.
187 NetLibDestroyServiceChild (
200 This function close the previously openned IP protocol and destroy the IP child.
202 @param[in] ControllerHandle The controller handle.
203 @param[in] ImageHandle The image handle.
204 @param[in] ChildHandle The child handle of the IP child.
205 @param[in] IpVersion The version of the IP protocol to use, either
208 @retval EFI_SUCCESS The IP protocol is closed and the relevant IP child
210 @retval EFI_UNSUPPORTED Upsupported IpVersion.
211 @retval Others The required operation failed.
215 IpIoCloseProtocolDestroyIpChild (
216 IN EFI_HANDLE ControllerHandle
,
217 IN EFI_HANDLE ImageHandle
,
218 IN EFI_HANDLE ChildHandle
,
223 EFI_GUID
*ServiceBindingGuid
;
224 EFI_GUID
*IpProtocolGuid
;
226 if (IpVersion
== IP_VERSION_4
) {
227 ServiceBindingGuid
= &gEfiIp4ServiceBindingProtocolGuid
;
228 IpProtocolGuid
= &gEfiIp4ProtocolGuid
;
229 } else if (IpVersion
== IP_VERSION_6
) {
230 ServiceBindingGuid
= &gEfiIp6ServiceBindingProtocolGuid
;
231 IpProtocolGuid
= &gEfiIp6ProtocolGuid
;
233 return EFI_UNSUPPORTED
;
237 // Close the previously openned IP protocol.
239 Status
= gBS
->CloseProtocol (
245 if (EFI_ERROR (Status
)) {
250 // Destroy the IP child.
252 return NetLibDestroyServiceChild (
261 This function handles ICMPv4 packets. It is the worker function of
264 @param[in] IpIo Pointer to the IP_IO instance.
265 @param[in, out] Pkt Pointer to the ICMPv4 packet.
266 @param[in] Session Pointer to the net session of this ICMPv4 packet.
268 @retval EFI_SUCCESS The ICMPv4 packet is handled successfully.
269 @retval EFI_ABORTED This type of ICMPv4 packet is not supported.
276 IN EFI_NET_SESSION_DATA
*Session
279 IP4_ICMP_ERROR_HEAD
*IcmpHdr
;
280 EFI_IP4_HEADER
*IpHdr
;
287 ASSERT (IpIo
!= NULL
);
288 ASSERT (Pkt
!= NULL
);
289 ASSERT (Session
!= NULL
);
290 ASSERT (IpIo
->IpVersion
== IP_VERSION_4
);
293 // Check the ICMP packet length.
295 if (Pkt
->TotalSize
< sizeof (IP4_ICMP_ERROR_HEAD
)) {
299 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP4_ICMP_ERROR_HEAD
);
300 IpHdr
= (EFI_IP4_HEADER
*) (&IcmpHdr
->IpHead
);
302 if (Pkt
->TotalSize
< ICMP_ERRLEN (IpHdr
)) {
307 Type
= IcmpHdr
->Head
.Type
;
308 Code
= IcmpHdr
->Head
.Code
;
311 // Analyze the ICMP Error in this ICMP pkt
314 case ICMP_TYPE_UNREACH
:
316 case ICMP_CODE_UNREACH_NET
:
317 case ICMP_CODE_UNREACH_HOST
:
318 case ICMP_CODE_UNREACH_PROTOCOL
:
319 case ICMP_CODE_UNREACH_PORT
:
320 case ICMP_CODE_UNREACH_SRCFAIL
:
321 IcmpErr
= (UINT8
) (ICMP_ERR_UNREACH_NET
+ Code
);
325 case ICMP_CODE_UNREACH_NEEDFRAG
:
326 IcmpErr
= ICMP_ERR_MSGSIZE
;
330 case ICMP_CODE_UNREACH_NET_UNKNOWN
:
331 case ICMP_CODE_UNREACH_NET_PROHIB
:
332 case ICMP_CODE_UNREACH_TOSNET
:
333 IcmpErr
= ICMP_ERR_UNREACH_NET
;
337 case ICMP_CODE_UNREACH_HOST_UNKNOWN
:
338 case ICMP_CODE_UNREACH_ISOLATED
:
339 case ICMP_CODE_UNREACH_HOST_PROHIB
:
340 case ICMP_CODE_UNREACH_TOSHOST
:
341 IcmpErr
= ICMP_ERR_UNREACH_HOST
;
351 case ICMP_TYPE_TIMXCEED
:
356 IcmpErr
= (UINT8
) (Code
+ ICMP_ERR_TIMXCEED_INTRANS
);
360 case ICMP_TYPE_PARAMPROB
:
365 IcmpErr
= ICMP_ERR_PARAMPROB
;
369 case ICMP_TYPE_SOURCEQUENCH
:
374 IcmpErr
= ICMP_ERR_QUENCH
;
383 // Notify user the ICMP pkt only containing payload except
384 // IP and ICMP header
386 PayLoadHdr
= (UINT8
*) ((UINT8
*) IpHdr
+ EFI_IP4_HEADER_LEN (IpHdr
));
387 TrimBytes
= (UINT32
) (PayLoadHdr
- (UINT8
*) IcmpHdr
);
389 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
392 // If the input packet has invalid format, and TrimBytes is larger than
393 // the packet size, the NetbufTrim might trim the packet to zero.
395 if (Pkt
->TotalSize
!= 0) {
396 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
403 This function handles ICMPv6 packets. It is the worker function of
406 @param[in] IpIo Pointer to the IP_IO instance.
407 @param[in, out] Pkt Pointer to the ICMPv6 packet.
408 @param[in] Session Pointer to the net session of this ICMPv6 packet.
410 @retval EFI_SUCCESS The ICMPv6 packet is handled successfully.
411 @retval EFI_ABORTED This type of ICMPv6 packet is not supported.
418 IN EFI_NET_SESSION_DATA
*Session
421 IP6_ICMP_ERROR_HEAD
*IcmpHdr
;
422 EFI_IP6_HEADER
*IpHdr
;
431 ASSERT (IpIo
!= NULL
);
432 ASSERT (Pkt
!= NULL
);
433 ASSERT (Session
!= NULL
);
434 ASSERT (IpIo
->IpVersion
== IP_VERSION_6
);
437 // Check the ICMPv6 packet length.
439 if (Pkt
->TotalSize
< sizeof (IP6_ICMP_ERROR_HEAD
)) {
444 IcmpHdr
= NET_PROTO_HDR (Pkt
, IP6_ICMP_ERROR_HEAD
);
445 Type
= IcmpHdr
->Head
.Type
;
446 Code
= IcmpHdr
->Head
.Code
;
449 // Analyze the ICMPv6 Error in this ICMPv6 packet
452 case ICMP_V6_DEST_UNREACHABLE
:
454 case ICMP_V6_NO_ROUTE_TO_DEST
:
455 case ICMP_V6_BEYOND_SCOPE
:
456 case ICMP_V6_ROUTE_REJECTED
:
457 IcmpErr
= ICMP6_ERR_UNREACH_NET
;
461 case ICMP_V6_COMM_PROHIBITED
:
462 case ICMP_V6_ADDR_UNREACHABLE
:
463 case ICMP_V6_SOURCE_ADDR_FAILED
:
464 IcmpErr
= ICMP6_ERR_UNREACH_HOST
;
468 case ICMP_V6_PORT_UNREACHABLE
:
469 IcmpErr
= ICMP6_ERR_UNREACH_PORT
;
479 case ICMP_V6_PACKET_TOO_BIG
:
484 IcmpErr
= ICMP6_ERR_PACKAGE_TOOBIG
;
488 case ICMP_V6_TIME_EXCEEDED
:
493 IcmpErr
= (UINT8
) (ICMP6_ERR_TIMXCEED_HOPLIMIT
+ Code
);
497 case ICMP_V6_PARAMETER_PROBLEM
:
502 IcmpErr
= (UINT8
) (ICMP6_ERR_PARAMPROB_HEADER
+ Code
);
512 // Notify user the ICMPv6 packet only containing payload except
513 // IPv6 basic header, extension header and ICMP header
516 IpHdr
= (EFI_IP6_HEADER
*) (&IcmpHdr
->IpHead
);
517 NextHeader
= IpHdr
->NextHeader
;
518 PayLoadHdr
= (UINT8
*) ((UINT8
*) IcmpHdr
+ sizeof (IP6_ICMP_ERROR_HEAD
));
522 switch (NextHeader
) {
523 case EFI_IP_PROTO_UDP
:
524 case EFI_IP_PROTO_TCP
:
525 case EFI_IP_PROTO_ICMP
:
526 case IP6_NO_NEXT_HEADER
:
532 case IP6_DESTINATION
:
534 // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
535 // the first 8 octets.
537 NextHeader
= *(PayLoadHdr
);
538 PayLoadHdr
= (UINT8
*) (PayLoadHdr
+ (*(PayLoadHdr
+ 1) + 1) * 8);
544 // The Fragment Header Length is 8 octets.
546 NextHeader
= *(PayLoadHdr
);
547 PayLoadHdr
= (UINT8
*) (PayLoadHdr
+ 8);
557 TrimBytes
= (UINT32
) (PayLoadHdr
- (UINT8
*) IcmpHdr
);
559 NetbufTrim (Pkt
, TrimBytes
, TRUE
);
562 // If the input packet has invalid format, and TrimBytes is larger than
563 // the packet size, the NetbufTrim might trim the packet to zero.
565 if (Pkt
->TotalSize
!= 0) {
566 IpIo
->PktRcvdNotify (EFI_ICMP_ERROR
, IcmpErr
, Session
, Pkt
, IpIo
->RcvdContext
);
573 This function handles ICMP packets.
575 @param[in] IpIo Pointer to the IP_IO instance.
576 @param[in, out] Pkt Pointer to the ICMP packet.
577 @param[in] Session Pointer to the net session of this ICMP packet.
579 @retval EFI_SUCCESS The ICMP packet is handled successfully.
580 @retval EFI_ABORTED This type of ICMP packet is not supported.
581 @retval EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
588 IN EFI_NET_SESSION_DATA
*Session
592 if (IpIo
->IpVersion
== IP_VERSION_4
) {
594 return IpIoIcmpv4Handler (IpIo
, Pkt
, Session
);
596 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
598 return IpIoIcmpv6Handler (IpIo
, Pkt
, Session
);
602 return EFI_UNSUPPORTED
;
608 Free function for receive token of IP_IO. It is used to
609 signal the recycle event to notify IP to recycle the
612 @param[in] Event The event to be signaled.
621 gBS
->SignalEvent ((EFI_EVENT
) Event
);
626 Create a send entry to wrap a packet before sending
629 @param[in, out] IpIo Pointer to the IP_IO instance.
630 @param[in, out] Pkt Pointer to the packet.
631 @param[in] Sender Pointer to the IP sender.
632 @param[in] Context Pointer to the context.
633 @param[in] NotifyData Pointer to the notify data.
634 @param[in] Dest Pointer to the destination IP address.
635 @param[in] Override Pointer to the overriden IP_IO data.
637 @return Pointer to the data structure created to wrap the packet. If any error occurs,
645 IN IP_IO_IP_PROTOCOL Sender
,
646 IN VOID
*Context OPTIONAL
,
647 IN VOID
*NotifyData OPTIONAL
,
648 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
649 IN IP_IO_OVERRIDE
*Override
652 IP_IO_SEND_ENTRY
*SndEntry
;
655 NET_FRAGMENT
*ExtFragment
;
656 UINT32 FragmentCount
;
657 IP_IO_OVERRIDE
*OverrideData
;
658 IP_IO_IP_TX_DATA
*TxData
;
659 EFI_IP4_TRANSMIT_DATA
*Ip4TxData
;
660 EFI_IP6_TRANSMIT_DATA
*Ip6TxData
;
662 if ((IpIo
->IpVersion
!= IP_VERSION_4
) && (IpIo
->IpVersion
!= IP_VERSION_6
)) {
671 // Allocate resource for SndEntry
673 SndEntry
= AllocatePool (sizeof (IP_IO_SEND_ENTRY
));
674 if (NULL
== SndEntry
) {
678 Status
= gBS
->CreateEvent (
685 if (EFI_ERROR (Status
)) {
689 FragmentCount
= Pkt
->BlockOpNum
;
692 // Allocate resource for TxData
694 TxData
= (IP_IO_IP_TX_DATA
*) AllocatePool (
695 sizeof (IP_IO_IP_TX_DATA
) + sizeof (NET_FRAGMENT
) * (FragmentCount
- 1)
698 if (NULL
== TxData
) {
703 // Build a fragment table to contain the fragments in the packet.
705 if (IpIo
->IpVersion
== IP_VERSION_4
) {
706 ExtFragment
= (NET_FRAGMENT
*) TxData
->Ip4TxData
.FragmentTable
;
708 ExtFragment
= (NET_FRAGMENT
*) TxData
->Ip6TxData
.FragmentTable
;
711 NetbufBuildExt (Pkt
, ExtFragment
, &FragmentCount
);
715 // Allocate resource for OverrideData if needed
717 if (NULL
!= Override
) {
719 OverrideData
= AllocateCopyPool (sizeof (IP_IO_OVERRIDE
), Override
);
720 if (NULL
== OverrideData
) {
726 // Set other fields of TxData except the fragment table
728 if (IpIo
->IpVersion
== IP_VERSION_4
) {
730 Ip4TxData
= &TxData
->Ip4TxData
;
732 IP4_COPY_ADDRESS (&Ip4TxData
->DestinationAddress
, Dest
);
734 Ip4TxData
->OverrideData
= &OverrideData
->Ip4OverrideData
;
735 Ip4TxData
->OptionsLength
= 0;
736 Ip4TxData
->OptionsBuffer
= NULL
;
737 Ip4TxData
->TotalDataLength
= Pkt
->TotalSize
;
738 Ip4TxData
->FragmentCount
= FragmentCount
;
741 // Set the fields of SndToken
743 SndEntry
->SndToken
.Ip4Token
.Event
= Event
;
744 SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
= Ip4TxData
;
747 Ip6TxData
= &TxData
->Ip6TxData
;
750 CopyMem (&Ip6TxData
->DestinationAddress
, Dest
, sizeof (EFI_IPv6_ADDRESS
));
752 ZeroMem (&Ip6TxData
->DestinationAddress
, sizeof (EFI_IPv6_ADDRESS
));
755 Ip6TxData
->OverrideData
= &OverrideData
->Ip6OverrideData
;
756 Ip6TxData
->DataLength
= Pkt
->TotalSize
;
757 Ip6TxData
->FragmentCount
= FragmentCount
;
758 Ip6TxData
->ExtHdrsLength
= 0;
759 Ip6TxData
->ExtHdrs
= NULL
;
762 // Set the fields of SndToken
764 SndEntry
->SndToken
.Ip6Token
.Event
= Event
;
765 SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
= Ip6TxData
;
769 // Set the fields of SndEntry
771 SndEntry
->IpIo
= IpIo
;
772 SndEntry
->Ip
= Sender
;
773 SndEntry
->Context
= Context
;
774 SndEntry
->NotifyData
= NotifyData
;
779 InsertTailList (&IpIo
->PendingSndList
, &SndEntry
->Entry
);
785 if (OverrideData
!= NULL
) {
786 FreePool (OverrideData
);
789 if (TxData
!= NULL
) {
793 if (SndEntry
!= NULL
) {
798 gBS
->CloseEvent (Event
);
806 Destroy the SndEntry.
808 This function pairs with IpIoCreateSndEntry().
810 @param[in] SndEntry Pointer to the send entry to be destroyed.
814 IpIoDestroySndEntry (
815 IN IP_IO_SEND_ENTRY
*SndEntry
819 IP_IO_IP_TX_DATA
*TxData
;
820 IP_IO_OVERRIDE
*Override
;
822 if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_4
) {
823 Event
= SndEntry
->SndToken
.Ip4Token
.Event
;
824 TxData
= (IP_IO_IP_TX_DATA
*) SndEntry
->SndToken
.Ip4Token
.Packet
.TxData
;
825 Override
= (IP_IO_OVERRIDE
*) TxData
->Ip4TxData
.OverrideData
;
826 } else if (SndEntry
->IpIo
->IpVersion
== IP_VERSION_6
) {
827 Event
= SndEntry
->SndToken
.Ip6Token
.Event
;
828 TxData
= (IP_IO_IP_TX_DATA
*) SndEntry
->SndToken
.Ip6Token
.Packet
.TxData
;
829 Override
= (IP_IO_OVERRIDE
*) TxData
->Ip6TxData
.OverrideData
;
834 gBS
->CloseEvent (Event
);
838 if (NULL
!= Override
) {
842 NetbufFree (SndEntry
->Pkt
);
844 RemoveEntryList (&SndEntry
->Entry
);
851 Notify function for IP transmit token.
853 @param[in] Context The context passed in by the event notifier.
858 IpIoTransmitHandlerDpc (
863 IP_IO_SEND_ENTRY
*SndEntry
;
866 SndEntry
= (IP_IO_SEND_ENTRY
*) Context
;
868 IpIo
= SndEntry
->IpIo
;
870 if (IpIo
->IpVersion
== IP_VERSION_4
) {
871 Status
= SndEntry
->SndToken
.Ip4Token
.Status
;
872 } else if (IpIo
->IpVersion
== IP_VERSION_6
){
873 Status
= SndEntry
->SndToken
.Ip6Token
.Status
;
878 if ((IpIo
->PktSentNotify
!= NULL
) && (SndEntry
->NotifyData
!= NULL
)) {
879 IpIo
->PktSentNotify (
887 IpIoDestroySndEntry (SndEntry
);
892 Notify function for IP transmit token.
894 @param[in] Event The event signaled.
895 @param[in] Context The context passed in by the event notifier.
900 IpIoTransmitHandler (
906 // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
908 QueueDpc (TPL_CALLBACK
, IpIoTransmitHandlerDpc
, Context
);
913 The dummy handler for the dummy IP receive token.
915 @param[in] Context The context passed in by the event notifier.
920 IpIoDummyHandlerDpc (
924 IP_IO_IP_INFO
*IpInfo
;
926 EFI_EVENT RecycleEvent
;
928 IpInfo
= (IP_IO_IP_INFO
*) Context
;
930 if ((IpInfo
->IpVersion
!= IP_VERSION_4
) && (IpInfo
->IpVersion
!= IP_VERSION_6
)) {
936 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
937 Status
= IpInfo
->DummyRcvToken
.Ip4Token
.Status
;
939 if (IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
!= NULL
) {
940 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip4Token
.Packet
.RxData
->RecycleSignal
;
943 Status
= IpInfo
->DummyRcvToken
.Ip6Token
.Status
;
945 if (IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
!= NULL
) {
946 RecycleEvent
= IpInfo
->DummyRcvToken
.Ip6Token
.Packet
.RxData
->RecycleSignal
;
952 if (EFI_ABORTED
== Status
) {
954 // The reception is actively aborted by the consumer, directly return.
957 } else if (EFI_SUCCESS
== Status
) {
959 // Recycle the RxData.
961 ASSERT (RecycleEvent
!= NULL
);
963 gBS
->SignalEvent (RecycleEvent
);
967 // Continue the receive.
969 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
970 IpInfo
->Ip
.Ip4
->Receive (
972 &IpInfo
->DummyRcvToken
.Ip4Token
975 IpInfo
->Ip
.Ip6
->Receive (
977 &IpInfo
->DummyRcvToken
.Ip6Token
984 This function add IpIoDummyHandlerDpc to the end of the DPC queue.
986 @param[in] Event The event signaled.
987 @param[in] Context The context passed in by the event notifier.
998 // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
1000 QueueDpc (TPL_CALLBACK
, IpIoDummyHandlerDpc
, Context
);
1005 Notify function for the IP receive token, used to process
1006 the received IP packets.
1008 @param[in] Context The context passed in by the event notifier.
1013 IpIoListenHandlerDpc (
1019 IP_IO_IP_RX_DATA
*RxData
;
1020 EFI_NET_SESSION_DATA Session
;
1023 IpIo
= (IP_IO
*) Context
;
1025 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1026 Status
= IpIo
->RcvToken
.Ip4Token
.Status
;
1027 RxData
= (IP_IO_IP_RX_DATA
*) IpIo
->RcvToken
.Ip4Token
.Packet
.RxData
;
1028 } else if (IpIo
->IpVersion
== IP_VERSION_6
) {
1029 Status
= IpIo
->RcvToken
.Ip6Token
.Status
;
1030 RxData
= (IP_IO_IP_RX_DATA
*) IpIo
->RcvToken
.Ip6Token
.Packet
.RxData
;
1035 if (EFI_ABORTED
== Status
) {
1037 // The reception is actively aborted by the consumer, directly return.
1042 if ((EFI_SUCCESS
!= Status
) && (EFI_ICMP_ERROR
!= Status
)) {
1044 // Only process the normal packets and the icmp error packets.
1046 if (RxData
!= NULL
) {
1054 // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).
1056 ASSERT (RxData
!= NULL
);
1057 if (RxData
== NULL
) {
1061 if (NULL
== IpIo
->PktRcvdNotify
) {
1065 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1066 ASSERT (RxData
->Ip4RxData
.Header
!= NULL
);
1067 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
))) {
1069 // The source address is a broadcast address, discard it.
1073 if ((EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
) != 0) &&
1074 (IpIo
->SubnetMask
!= 0) &&
1075 IP4_NET_EQUAL (IpIo
->StationIp
, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
) &&
1076 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
)) {
1078 // The source address doesn't match StationIp and it's not a unicast IP address, discard it.
1083 if (RxData
->Ip4RxData
.DataLength
== 0) {
1085 // Discard zero length data payload packet.
1091 // The fragment should always be valid for non-zero length packet.
1093 ASSERT (RxData
->Ip4RxData
.FragmentCount
!= 0);
1096 // Create a netbuffer representing IPv4 packet
1098 Pkt
= NetbufFromExt (
1099 (NET_FRAGMENT
*) RxData
->Ip4RxData
.FragmentTable
,
1100 RxData
->Ip4RxData
.FragmentCount
,
1104 RxData
->Ip4RxData
.RecycleSignal
1111 // Create a net session
1113 Session
.Source
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
);
1114 Session
.Dest
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->DestinationAddress
);
1115 Session
.IpHdr
.Ip4Hdr
= RxData
->Ip4RxData
.Header
;
1116 Session
.IpHdrLen
= RxData
->Ip4RxData
.HeaderLength
;
1117 Session
.IpVersion
= IP_VERSION_4
;
1119 ASSERT (RxData
->Ip6RxData
.Header
!= NULL
);
1120 if (!NetIp6IsValidUnicast(&RxData
->Ip6RxData
.Header
->SourceAddress
)) {
1124 if (RxData
->Ip6RxData
.DataLength
== 0) {
1126 // Discard zero length data payload packet.
1132 // The fragment should always be valid for non-zero length packet.
1134 ASSERT (RxData
->Ip6RxData
.FragmentCount
!= 0);
1137 // Create a netbuffer representing IPv6 packet
1139 Pkt
= NetbufFromExt (
1140 (NET_FRAGMENT
*) RxData
->Ip6RxData
.FragmentTable
,
1141 RxData
->Ip6RxData
.FragmentCount
,
1145 RxData
->Ip6RxData
.RecycleSignal
1152 // Create a net session
1156 &RxData
->Ip6RxData
.Header
->SourceAddress
,
1157 sizeof(EFI_IPv6_ADDRESS
)
1161 &RxData
->Ip6RxData
.Header
->DestinationAddress
,
1162 sizeof(EFI_IPv6_ADDRESS
)
1164 Session
.IpHdr
.Ip6Hdr
= RxData
->Ip6RxData
.Header
;
1165 Session
.IpHdrLen
= RxData
->Ip6RxData
.HeaderLength
;
1166 Session
.IpVersion
= IP_VERSION_6
;
1169 if (EFI_SUCCESS
== Status
) {
1171 IpIo
->PktRcvdNotify (EFI_SUCCESS
, 0, &Session
, Pkt
, IpIo
->RcvdContext
);
1174 // Status is EFI_ICMP_ERROR
1176 Status
= IpIoIcmpHandler (IpIo
, Pkt
, &Session
);
1177 if (EFI_ERROR (Status
)) {
1186 if (IpIo
->IpVersion
== IP_VERSION_4
){
1187 gBS
->SignalEvent (RxData
->Ip4RxData
.RecycleSignal
);
1189 gBS
->SignalEvent (RxData
->Ip6RxData
.RecycleSignal
);
1194 if (IpIo
->IpVersion
== IP_VERSION_4
){
1195 IpIo
->Ip
.Ip4
->Receive (IpIo
->Ip
.Ip4
, &(IpIo
->RcvToken
.Ip4Token
));
1197 IpIo
->Ip
.Ip6
->Receive (IpIo
->Ip
.Ip6
, &(IpIo
->RcvToken
.Ip6Token
));
1202 This function add IpIoListenHandlerDpc to the end of the DPC queue.
1204 @param[in] Event The event signaled.
1205 @param[in] Context The context passed in by the event notifier.
1216 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1218 QueueDpc (TPL_CALLBACK
, IpIoListenHandlerDpc
, Context
);
1223 Create a new IP_IO instance.
1225 If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1227 This function uses IP4/IP6 service binding protocol in Controller to create
1228 an IP4/IP6 child (aka IP4/IP6 instance).
1230 @param[in] Image The image handle of the driver or application that
1232 @param[in] Controller The controller handle that has IP4 or IP6 service
1233 binding protocol installed.
1234 @param[in] IpVersion The version of the IP protocol to use, either
1237 @return Pointer to a newly created IP_IO instance, or NULL if failed.
1243 IN EFI_HANDLE Image
,
1244 IN EFI_HANDLE Controller
,
1252 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1254 IpIo
= AllocateZeroPool (sizeof (IP_IO
));
1259 InitializeListHead (&(IpIo
->PendingSndList
));
1260 InitializeListHead (&(IpIo
->IpList
));
1261 IpIo
->Controller
= Controller
;
1262 IpIo
->Image
= Image
;
1263 IpIo
->IpVersion
= IpVersion
;
1266 Status
= gBS
->CreateEvent (
1273 if (EFI_ERROR (Status
)) {
1277 if (IpVersion
== IP_VERSION_4
) {
1278 IpIo
->RcvToken
.Ip4Token
.Event
= Event
;
1280 IpIo
->RcvToken
.Ip6Token
.Event
= Event
;
1284 // Create an IP child and open IP protocol
1286 Status
= IpIoCreateIpChildOpenProtocol (
1291 (VOID
**) & (IpIo
->Ip
)
1293 if (EFI_ERROR (Status
)) {
1301 if (Event
!= NULL
) {
1302 gBS
->CloseEvent (Event
);
1305 gBS
->FreePool (IpIo
);
1312 Open an IP_IO instance for use.
1314 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1316 This function is called after IpIoCreate(). It is used for configuring the IP
1317 instance and register the callbacks and their context data for sending and
1318 receiving IP packets.
1320 @param[in, out] IpIo Pointer to an IP_IO instance that needs
1322 @param[in] OpenData The configuration data and callbacks for
1325 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
1327 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
1329 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported.
1330 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1331 @retval Others Error condition occurred.
1338 IN IP_IO_OPEN_DATA
*OpenData
1344 if (IpIo
== NULL
|| OpenData
== NULL
) {
1345 return EFI_INVALID_PARAMETER
;
1348 if (IpIo
->IsConfigured
) {
1349 return EFI_ACCESS_DENIED
;
1352 IpVersion
= IpIo
->IpVersion
;
1354 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1359 if (IpVersion
== IP_VERSION_4
){
1361 // RawData mode is no supported.
1363 ASSERT (!OpenData
->IpConfigData
.Ip4CfgData
.RawData
);
1364 if (OpenData
->IpConfigData
.Ip4CfgData
.RawData
) {
1365 return EFI_UNSUPPORTED
;
1368 if (!OpenData
->IpConfigData
.Ip4CfgData
.UseDefaultAddress
) {
1369 IpIo
->StationIp
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.StationAddress
);
1370 IpIo
->SubnetMask
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.SubnetMask
);
1373 Status
= IpIo
->Ip
.Ip4
->Configure (
1375 &OpenData
->IpConfigData
.Ip4CfgData
1379 Status
= IpIo
->Ip
.Ip6
->Configure (
1381 &OpenData
->IpConfigData
.Ip6CfgData
1385 if (EFI_ERROR (Status
)) {
1390 // @bug To delete the default route entry in this Ip, if it is:
1391 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1394 if (IpVersion
== IP_VERSION_4
){
1395 Status
= IpIo
->Ip
.Ip4
->Routes (
1403 if (EFI_ERROR (Status
) && (EFI_NOT_FOUND
!= Status
)) {
1408 IpIo
->PktRcvdNotify
= OpenData
->PktRcvdNotify
;
1409 IpIo
->PktSentNotify
= OpenData
->PktSentNotify
;
1411 IpIo
->RcvdContext
= OpenData
->RcvdContext
;
1412 IpIo
->SndContext
= OpenData
->SndContext
;
1414 if (IpVersion
== IP_VERSION_4
){
1415 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip4CfgData
.DefaultProtocol
;
1418 // start to listen incoming packet
1420 Status
= IpIo
->Ip
.Ip4
->Receive (
1422 &(IpIo
->RcvToken
.Ip4Token
)
1424 if (EFI_ERROR (Status
)) {
1425 IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1431 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip6CfgData
.DefaultProtocol
;
1432 Status
= IpIo
->Ip
.Ip6
->Receive (
1434 &(IpIo
->RcvToken
.Ip6Token
)
1436 if (EFI_ERROR (Status
)) {
1437 IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1442 IpIo
->IsConfigured
= TRUE
;
1443 InsertTailList (&mActiveIpIoList
, &IpIo
->Entry
);
1450 Stop an IP_IO instance.
1452 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1454 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1455 the pending send/receive tokens will be canceled.
1457 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1459 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1460 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1461 @retval Others Error condition occurred.
1471 IP_IO_IP_INFO
*IpInfo
;
1475 return EFI_INVALID_PARAMETER
;
1478 if (!IpIo
->IsConfigured
) {
1482 IpVersion
= IpIo
->IpVersion
;
1484 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1487 // Remove the IpIo from the active IpIo list.
1489 RemoveEntryList (&IpIo
->Entry
);
1492 // Configure NULL Ip
1494 if (IpVersion
== IP_VERSION_4
) {
1495 Status
= IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1497 Status
= IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1499 if (EFI_ERROR (Status
)) {
1503 IpIo
->IsConfigured
= FALSE
;
1506 // Detroy the Ip List used by IpIo
1509 while (!IsListEmpty (&(IpIo
->IpList
))) {
1510 IpInfo
= NET_LIST_HEAD (&(IpIo
->IpList
), IP_IO_IP_INFO
, Entry
);
1512 IpIoRemoveIp (IpIo
, IpInfo
);
1516 // All pending send tokens should be flushed by resetting the IP instances.
1518 ASSERT (IsListEmpty (&IpIo
->PendingSndList
));
1521 // Close the receive event.
1523 if (IpVersion
== IP_VERSION_4
){
1524 gBS
->CloseEvent (IpIo
->RcvToken
.Ip4Token
.Event
);
1526 gBS
->CloseEvent (IpIo
->RcvToken
.Ip6Token
.Event
);
1534 Destroy an IP_IO instance.
1536 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1537 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1539 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1542 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1543 @retval Others Error condition occurred.
1557 Status
= IpIoStop (IpIo
);
1558 if (EFI_ERROR (Status
)) {
1563 // Close the IP protocol and destroy the child.
1565 Status
= IpIoCloseProtocolDestroyIpChild (
1571 if (EFI_ERROR (Status
)) {
1575 gBS
->FreePool (IpIo
);
1582 Send out an IP packet.
1584 This function is called after IpIoOpen(). The data to be sent is wrapped in
1585 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1586 overriden by Sender. Other sending configs, like source address and gateway
1587 address etc., are specified in OverrideData.
1589 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1591 @param[in, out] Pkt Pointer to the IP packet to be sent.
1592 @param[in] Sender The IP protocol instance used for sending.
1593 @param[in] Context Optional context data.
1594 @param[in] NotifyData Optional notify data.
1595 @param[in] Dest The destination IP address to send this packet to.
1596 This parameter is optional when using IPv6.
1597 @param[in] OverrideData The data to override some configuration of the IP
1598 instance used for sending.
1600 @retval EFI_SUCCESS The operation is completed successfully.
1601 @retval EFI_INVALID_PARAMETER The input parameter is not correct.
1602 @retval EFI_NOT_STARTED The IpIo is not configured.
1603 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1604 @retval Others Error condition occurred.
1611 IN OUT NET_BUF
*Pkt
,
1612 IN IP_IO_IP_INFO
*Sender OPTIONAL
,
1613 IN VOID
*Context OPTIONAL
,
1614 IN VOID
*NotifyData OPTIONAL
,
1615 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
1616 IN IP_IO_OVERRIDE
*OverrideData OPTIONAL
1620 IP_IO_IP_PROTOCOL Ip
;
1621 IP_IO_SEND_ENTRY
*SndEntry
;
1623 if ((IpIo
== NULL
) || (Pkt
== NULL
)) {
1624 return EFI_INVALID_PARAMETER
;
1627 if ((IpIo
->IpVersion
== IP_VERSION_4
) && (Dest
== NULL
)) {
1628 return EFI_INVALID_PARAMETER
;
1631 if (!IpIo
->IsConfigured
) {
1632 return EFI_NOT_STARTED
;
1635 Ip
= (NULL
== Sender
) ? IpIo
->Ip
: Sender
->Ip
;
1638 // create a new SndEntry
1640 SndEntry
= IpIoCreateSndEntry (IpIo
, Pkt
, Ip
, Context
, NotifyData
, Dest
, OverrideData
);
1641 if (NULL
== SndEntry
) {
1642 return EFI_OUT_OF_RESOURCES
;
1648 if (IpIo
->IpVersion
== IP_VERSION_4
){
1649 Status
= Ip
.Ip4
->Transmit (
1651 &SndEntry
->SndToken
.Ip4Token
1654 Status
= Ip
.Ip6
->Transmit (
1656 &SndEntry
->SndToken
.Ip6Token
1660 if (EFI_ERROR (Status
)) {
1661 IpIoDestroySndEntry (SndEntry
);
1669 Cancel the IP transmit token which wraps this Packet.
1671 If IpIo is NULL, then ASSERT().
1672 If Packet is NULL, then ASSERT().
1674 @param[in] IpIo Pointer to the IP_IO instance.
1675 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1686 IP_IO_SEND_ENTRY
*SndEntry
;
1687 IP_IO_IP_PROTOCOL Ip
;
1689 ASSERT ((IpIo
!= NULL
) && (Packet
!= NULL
));
1691 NET_LIST_FOR_EACH (Node
, &IpIo
->PendingSndList
) {
1693 SndEntry
= NET_LIST_USER_STRUCT (Node
, IP_IO_SEND_ENTRY
, Entry
);
1695 if (SndEntry
->Pkt
== Packet
) {
1699 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1702 &SndEntry
->SndToken
.Ip4Token
1707 &SndEntry
->SndToken
.Ip6Token
1719 Add a new IP instance for sending data.
1721 If IpIo is NULL, then ASSERT().
1722 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1724 The function is used to add the IP_IO to the IP_IO sending list. The caller
1725 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1728 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1729 instance for sending purpose.
1731 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1741 IP_IO_IP_INFO
*IpInfo
;
1744 ASSERT (IpIo
!= NULL
);
1745 ASSERT ((IpIo
->IpVersion
== IP_VERSION_4
) || (IpIo
->IpVersion
== IP_VERSION_6
));
1747 IpInfo
= AllocatePool (sizeof (IP_IO_IP_INFO
));
1748 if (IpInfo
== NULL
) {
1753 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1756 InitializeListHead (&IpInfo
->Entry
);
1757 IpInfo
->ChildHandle
= NULL
;
1758 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1759 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1762 IpInfo
->IpVersion
= IpIo
->IpVersion
;
1765 // Create the IP instance and open the IP protocol.
1767 Status
= IpIoCreateIpChildOpenProtocol (
1770 &IpInfo
->ChildHandle
,
1772 (VOID
**) &IpInfo
->Ip
1774 if (EFI_ERROR (Status
)) {
1779 // Create the event for the DummyRcvToken.
1781 Status
= gBS
->CreateEvent (
1788 if (EFI_ERROR (Status
)) {
1789 goto ReleaseIpChild
;
1792 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1793 IpInfo
->DummyRcvToken
.Ip4Token
.Event
= Event
;
1795 IpInfo
->DummyRcvToken
.Ip6Token
.Event
= Event
;
1799 // Link this IpInfo into the IpIo.
1801 InsertTailList (&IpIo
->IpList
, &IpInfo
->Entry
);
1807 IpIoCloseProtocolDestroyIpChild (
1810 IpInfo
->ChildHandle
,
1816 gBS
->FreePool (IpInfo
);
1823 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1826 If IpInfo is NULL, then ASSERT().
1827 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1829 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1830 @param[in, out] IpConfigData The IP configure data used to configure the IP
1831 instance, if NULL the IP instance is reset. If
1832 UseDefaultAddress is set to TRUE, and the configure
1833 operation succeeds, the default address information
1834 is written back in this IpConfigData.
1836 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1837 or no need to reconfigure it.
1838 @retval Others Configuration fails.
1844 IN OUT IP_IO_IP_INFO
*IpInfo
,
1845 IN OUT VOID
*IpConfigData OPTIONAL
1849 IP_IO_IP_PROTOCOL Ip
;
1851 EFI_IP4_MODE_DATA Ip4ModeData
;
1852 EFI_IP6_MODE_DATA Ip6ModeData
;
1854 ASSERT (IpInfo
!= NULL
);
1856 if (IpInfo
->RefCnt
> 1) {
1858 // This IP instance is shared, don't reconfigure it until it has only one
1859 // consumer. Currently, only the tcp children cloned from their passive parent
1860 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1861 // let the last consumer clean the IP instance.
1866 IpVersion
= IpInfo
->IpVersion
;
1867 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1871 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1872 Status
= Ip
.Ip4
->Configure (Ip
.Ip4
, IpConfigData
);
1874 Status
= Ip
.Ip6
->Configure (Ip
.Ip6
, IpConfigData
);
1877 if (EFI_ERROR (Status
)) {
1881 if (IpConfigData
!= NULL
) {
1882 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1884 if (((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->UseDefaultAddress
) {
1885 Status
= Ip
.Ip4
->GetModeData (
1891 if (EFI_ERROR (Status
)) {
1892 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1896 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
, &Ip4ModeData
.ConfigData
.StationAddress
);
1897 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
, &Ip4ModeData
.ConfigData
.SubnetMask
);
1902 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1906 &IpInfo
->PreMask
.SubnetMask
,
1907 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
,
1911 Status
= Ip
.Ip4
->Receive (
1913 &IpInfo
->DummyRcvToken
.Ip4Token
1915 if (EFI_ERROR (Status
)) {
1916 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1919 Status
= Ip
.Ip6
->GetModeData (
1925 if (EFI_ERROR (Status
)) {
1926 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1930 if (Ip6ModeData
.IsConfigured
) {
1932 &((EFI_IP6_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1933 &Ip6ModeData
.ConfigData
.StationAddress
,
1934 sizeof (EFI_IPv6_ADDRESS
)
1937 if (Ip6ModeData
.AddressList
!= NULL
) {
1938 FreePool (Ip6ModeData
.AddressList
);
1941 if (Ip6ModeData
.GroupTable
!= NULL
) {
1942 FreePool (Ip6ModeData
.GroupTable
);
1945 if (Ip6ModeData
.RouteTable
!= NULL
) {
1946 FreePool (Ip6ModeData
.RouteTable
);
1949 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1950 FreePool (Ip6ModeData
.NeighborCache
);
1953 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1954 FreePool (Ip6ModeData
.PrefixTable
);
1957 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1958 FreePool (Ip6ModeData
.IcmpTypeList
);
1962 Status
= EFI_NO_MAPPING
;
1968 &Ip6ModeData
.ConfigData
.StationAddress
,
1969 sizeof (EFI_IPv6_ADDRESS
)
1972 Status
= Ip
.Ip6
->Receive (
1974 &IpInfo
->DummyRcvToken
.Ip6Token
1976 if (EFI_ERROR (Status
)) {
1977 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1982 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1984 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1985 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1993 Destroy an IP instance maintained in IpIo->IpList for
1996 If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
1998 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1999 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
2000 will be dstroyed if the RefCnt is zero.
2002 @param[in] IpIo Pointer to the IP_IO instance.
2003 @param[in] IpInfo Pointer to the IpInfo to be removed.
2010 IN IP_IO_IP_INFO
*IpInfo
2016 if (IpIo
== NULL
|| IpInfo
== NULL
) {
2020 ASSERT (IpInfo
->RefCnt
> 0);
2022 NET_PUT_REF (IpInfo
);
2024 if (IpInfo
->RefCnt
> 0) {
2029 IpVersion
= IpIo
->IpVersion
;
2031 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
2033 RemoveEntryList (&IpInfo
->Entry
);
2035 if (IpVersion
== IP_VERSION_4
){
2036 IpInfo
->Ip
.Ip4
->Configure (
2040 IpIoCloseProtocolDestroyIpChild (
2043 IpInfo
->ChildHandle
,
2047 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip4Token
.Event
);
2051 IpInfo
->Ip
.Ip6
->Configure (
2056 IpIoCloseProtocolDestroyIpChild (
2059 IpInfo
->ChildHandle
,
2063 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip6Token
.Event
);
2071 Find the first IP protocol maintained in IpIo whose local
2072 address is the same as Src.
2074 This function is called when the caller needs the IpIo to send data to the
2075 specified Src. The IpIo was added previously by IpIoAddIp().
2077 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
2078 @param[in] IpVersion The version of the IP protocol to use, either
2080 @param[in] Src The local IP address.
2082 @return Pointer to the IP protocol can be used for sending purpose and its local
2083 address is the same with Src. NULL if failed.
2089 IN OUT IP_IO
**IpIo
,
2091 IN EFI_IP_ADDRESS
*Src
2094 LIST_ENTRY
*IpIoEntry
;
2096 LIST_ENTRY
*IpInfoEntry
;
2097 IP_IO_IP_INFO
*IpInfo
;
2099 if (IpIo
== NULL
|| Src
== NULL
) {
2103 if ((IpVersion
!= IP_VERSION_4
) && (IpVersion
!= IP_VERSION_6
)) {
2107 NET_LIST_FOR_EACH (IpIoEntry
, &mActiveIpIoList
) {
2108 IpIoPtr
= NET_LIST_USER_STRUCT (IpIoEntry
, IP_IO
, Entry
);
2110 if (((*IpIo
!= NULL
) && (*IpIo
!= IpIoPtr
)) || (IpIoPtr
->IpVersion
!= IpVersion
)) {
2114 NET_LIST_FOR_EACH (IpInfoEntry
, &IpIoPtr
->IpList
) {
2115 IpInfo
= NET_LIST_USER_STRUCT (IpInfoEntry
, IP_IO_IP_INFO
, Entry
);
2116 if (IpInfo
->IpVersion
== IP_VERSION_4
){
2118 if (EFI_IP4_EQUAL (&IpInfo
->Addr
.v4
, &Src
->v4
)) {
2125 if (EFI_IP6_EQUAL (&IpInfo
->Addr
.v6
, &Src
->v6
)) {
2141 Get the ICMP error map information.
2143 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2144 are not NULL, this routine will fill them.
2146 @param[in] IcmpError IcmpError Type.
2147 @param[in] IpVersion The version of the IP protocol to use,
2148 either IPv4 or IPv6.
2149 @param[out] IsHard If TRUE, indicates that it is a hard error.
2150 @param[out] Notify If TRUE, SockError needs to be notified.
2152 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code.
2153 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2158 IpIoGetIcmpErrStatus (
2161 OUT BOOLEAN
*IsHard OPTIONAL
,
2162 OUT BOOLEAN
*Notify OPTIONAL
2165 if (IpVersion
== IP_VERSION_4
) {
2166 ASSERT (IcmpError
<= ICMP_ERR_PARAMPROB
);
2168 if (IsHard
!= NULL
) {
2169 *IsHard
= mIcmpErrMap
[IcmpError
].IsHard
;
2172 if (Notify
!= NULL
) {
2173 *Notify
= mIcmpErrMap
[IcmpError
].Notify
;
2176 switch (IcmpError
) {
2177 case ICMP_ERR_UNREACH_NET
:
2178 return EFI_NETWORK_UNREACHABLE
;
2180 case ICMP_ERR_TIMXCEED_INTRANS
:
2181 case ICMP_ERR_TIMXCEED_REASS
:
2182 case ICMP_ERR_UNREACH_HOST
:
2183 return EFI_HOST_UNREACHABLE
;
2185 case ICMP_ERR_UNREACH_PROTOCOL
:
2186 return EFI_PROTOCOL_UNREACHABLE
;
2188 case ICMP_ERR_UNREACH_PORT
:
2189 return EFI_PORT_UNREACHABLE
;
2191 case ICMP_ERR_MSGSIZE
:
2192 case ICMP_ERR_UNREACH_SRCFAIL
:
2193 case ICMP_ERR_QUENCH
:
2194 case ICMP_ERR_PARAMPROB
:
2195 return EFI_ICMP_ERROR
;
2199 return EFI_UNSUPPORTED
;
2202 } else if (IpVersion
== IP_VERSION_6
) {
2204 ASSERT (IcmpError
<= ICMP6_ERR_PARAMPROB_IPV6OPTION
);
2206 if (IsHard
!= NULL
) {
2207 *IsHard
= mIcmp6ErrMap
[IcmpError
].IsHard
;
2210 if (Notify
!= NULL
) {
2211 *Notify
= mIcmp6ErrMap
[IcmpError
].Notify
;
2214 switch (IcmpError
) {
2215 case ICMP6_ERR_UNREACH_NET
:
2216 return EFI_NETWORK_UNREACHABLE
;
2218 case ICMP6_ERR_UNREACH_HOST
:
2219 case ICMP6_ERR_TIMXCEED_HOPLIMIT
:
2220 case ICMP6_ERR_TIMXCEED_REASS
:
2221 return EFI_HOST_UNREACHABLE
;
2223 case ICMP6_ERR_UNREACH_PROTOCOL
:
2224 return EFI_PROTOCOL_UNREACHABLE
;
2226 case ICMP6_ERR_UNREACH_PORT
:
2227 return EFI_PORT_UNREACHABLE
;
2229 case ICMP6_ERR_PACKAGE_TOOBIG
:
2230 case ICMP6_ERR_PARAMPROB_HEADER
:
2231 case ICMP6_ERR_PARAMPROB_NEXHEADER
:
2232 case ICMP6_ERR_PARAMPROB_IPV6OPTION
:
2233 return EFI_ICMP_ERROR
;
2237 return EFI_UNSUPPORTED
;
2242 // Should never be here
2245 return EFI_UNSUPPORTED
;
2251 Refresh the remote peer's Neighbor Cache entries.
2253 This function is called when the caller needs the IpIo to refresh the existing
2254 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2255 node has recently received a confirmation that packets sent recently to the
2256 neighbor were received by its IP layer.
2258 @param[in] IpIo Pointer to an IP_IO instance
2259 @param[in] Neighbor The IP address of the neighbor
2260 @param[in] Timeout Time in 100-ns units that this entry will
2261 remain in the neighbor cache. A value of
2262 zero means that the entry is permanent.
2263 A value of non-zero means that the entry is
2264 dynamic and will be deleted after Timeout.
2266 @retval EFI_SUCCESS The operation is completed successfully.
2267 @retval EFI_NOT_STARTED The IpIo is not configured.
2268 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2269 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2271 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh.
2272 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2277 IpIoRefreshNeighbor (
2279 IN EFI_IP_ADDRESS
*Neighbor
,
2283 EFI_IP6_PROTOCOL
*Ip
;
2285 if (!IpIo
->IsConfigured
) {
2286 return EFI_NOT_STARTED
;
2289 if (IpIo
->IpVersion
!= IP_VERSION_6
) {
2290 return EFI_UNSUPPORTED
;
2295 return Ip
->Neighbors (Ip
, FALSE
, &Neighbor
->v6
, NULL
, Timeout
, TRUE
);