4 (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2005 - 2017, 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 NULL,
638 @return resource limit occurred.
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
)) || (NULL
== RxData
)) {
1044 // @bug Only process the normal packets and the icmp error packets, if RxData is NULL
1045 // @bug with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although
1046 // @bug this should be a bug of the low layer (IP).
1051 if (NULL
== IpIo
->PktRcvdNotify
) {
1055 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1056 ASSERT (RxData
->Ip4RxData
.Header
!= NULL
);
1057 if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
))) {
1059 // The source address is a broadcast address, discard it.
1063 if ((EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
) != 0) &&
1064 (IpIo
->SubnetMask
!= 0) &&
1065 IP4_NET_EQUAL (IpIo
->StationIp
, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
) &&
1066 !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA
*) RxData
)->Header
->SourceAddress
), IpIo
->SubnetMask
)) {
1068 // The source address is not zero and it's not a unicast IP address, discard it.
1073 if (RxData
->Ip4RxData
.DataLength
== 0) {
1075 // Discard zero length data payload packet.
1081 // The fragment should always be valid for non-zero length packet.
1083 ASSERT (RxData
->Ip4RxData
.FragmentCount
!= 0);
1086 // Create a netbuffer representing IPv4 packet
1088 Pkt
= NetbufFromExt (
1089 (NET_FRAGMENT
*) RxData
->Ip4RxData
.FragmentTable
,
1090 RxData
->Ip4RxData
.FragmentCount
,
1094 RxData
->Ip4RxData
.RecycleSignal
1101 // Create a net session
1103 Session
.Source
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->SourceAddress
);
1104 Session
.Dest
.Addr
[0] = EFI_IP4 (RxData
->Ip4RxData
.Header
->DestinationAddress
);
1105 Session
.IpHdr
.Ip4Hdr
= RxData
->Ip4RxData
.Header
;
1106 Session
.IpHdrLen
= RxData
->Ip4RxData
.HeaderLength
;
1107 Session
.IpVersion
= IP_VERSION_4
;
1109 ASSERT (RxData
->Ip6RxData
.Header
!= NULL
);
1110 if (!NetIp6IsValidUnicast(&RxData
->Ip6RxData
.Header
->SourceAddress
)) {
1114 if (RxData
->Ip6RxData
.DataLength
== 0) {
1116 // Discard zero length data payload packet.
1122 // The fragment should always be valid for non-zero length packet.
1124 ASSERT (RxData
->Ip6RxData
.FragmentCount
!= 0);
1127 // Create a netbuffer representing IPv6 packet
1129 Pkt
= NetbufFromExt (
1130 (NET_FRAGMENT
*) RxData
->Ip6RxData
.FragmentTable
,
1131 RxData
->Ip6RxData
.FragmentCount
,
1135 RxData
->Ip6RxData
.RecycleSignal
1142 // Create a net session
1146 &RxData
->Ip6RxData
.Header
->SourceAddress
,
1147 sizeof(EFI_IPv6_ADDRESS
)
1151 &RxData
->Ip6RxData
.Header
->DestinationAddress
,
1152 sizeof(EFI_IPv6_ADDRESS
)
1154 Session
.IpHdr
.Ip6Hdr
= RxData
->Ip6RxData
.Header
;
1155 Session
.IpHdrLen
= RxData
->Ip6RxData
.HeaderLength
;
1156 Session
.IpVersion
= IP_VERSION_6
;
1159 if (EFI_SUCCESS
== Status
) {
1161 IpIo
->PktRcvdNotify (EFI_SUCCESS
, 0, &Session
, Pkt
, IpIo
->RcvdContext
);
1164 // Status is EFI_ICMP_ERROR
1166 Status
= IpIoIcmpHandler (IpIo
, Pkt
, &Session
);
1167 if (EFI_ERROR (Status
)) {
1176 if (IpIo
->IpVersion
== IP_VERSION_4
){
1177 gBS
->SignalEvent (RxData
->Ip4RxData
.RecycleSignal
);
1179 gBS
->SignalEvent (RxData
->Ip6RxData
.RecycleSignal
);
1184 if (IpIo
->IpVersion
== IP_VERSION_4
){
1185 IpIo
->Ip
.Ip4
->Receive (IpIo
->Ip
.Ip4
, &(IpIo
->RcvToken
.Ip4Token
));
1187 IpIo
->Ip
.Ip6
->Receive (IpIo
->Ip
.Ip6
, &(IpIo
->RcvToken
.Ip6Token
));
1192 This function add IpIoListenHandlerDpc to the end of the DPC queue.
1194 @param[in] Event The event signaled.
1195 @param[in] Context The context passed in by the event notifier.
1206 // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
1208 QueueDpc (TPL_CALLBACK
, IpIoListenHandlerDpc
, Context
);
1213 Create a new IP_IO instance.
1215 This function uses IP4/IP6 service binding protocol in Controller to create
1216 an IP4/IP6 child (aka IP4/IP6 instance).
1218 @param[in] Image The image handle of the driver or application that
1220 @param[in] Controller The controller handle that has IP4 or IP6 service
1221 binding protocol installed.
1222 @param[in] IpVersion The version of the IP protocol to use, either
1225 @return Pointer to a newly created IP_IO instance, or NULL if failed.
1231 IN EFI_HANDLE Image
,
1232 IN EFI_HANDLE Controller
,
1240 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1242 IpIo
= AllocateZeroPool (sizeof (IP_IO
));
1247 InitializeListHead (&(IpIo
->PendingSndList
));
1248 InitializeListHead (&(IpIo
->IpList
));
1249 IpIo
->Controller
= Controller
;
1250 IpIo
->Image
= Image
;
1251 IpIo
->IpVersion
= IpVersion
;
1254 Status
= gBS
->CreateEvent (
1261 if (EFI_ERROR (Status
)) {
1265 if (IpVersion
== IP_VERSION_4
) {
1266 IpIo
->RcvToken
.Ip4Token
.Event
= Event
;
1268 IpIo
->RcvToken
.Ip6Token
.Event
= Event
;
1272 // Create an IP child and open IP protocol
1274 Status
= IpIoCreateIpChildOpenProtocol (
1279 (VOID
**)&(IpIo
->Ip
)
1281 if (EFI_ERROR (Status
)) {
1289 if (Event
!= NULL
) {
1290 gBS
->CloseEvent (Event
);
1293 gBS
->FreePool (IpIo
);
1300 Open an IP_IO instance for use.
1302 This function is called after IpIoCreate(). It is used for configuring the IP
1303 instance and register the callbacks and their context data for sending and
1304 receiving IP packets.
1306 @param[in, out] IpIo Pointer to an IP_IO instance that needs
1308 @param[in] OpenData The configuration data and callbacks for
1311 @retval EFI_SUCCESS The IP_IO instance opened with OpenData
1313 @retval EFI_ACCESS_DENIED The IP_IO instance is configured, avoid to
1315 @retval EFI_UNSUPPORTED IPv4 RawData mode is no supported.
1316 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1317 @retval Others Error condition occurred.
1324 IN IP_IO_OPEN_DATA
*OpenData
1330 if (IpIo
== NULL
|| OpenData
== NULL
) {
1331 return EFI_INVALID_PARAMETER
;
1334 if (IpIo
->IsConfigured
) {
1335 return EFI_ACCESS_DENIED
;
1338 IpVersion
= IpIo
->IpVersion
;
1340 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1345 if (IpVersion
== IP_VERSION_4
){
1347 // RawData mode is no supported.
1349 ASSERT (!OpenData
->IpConfigData
.Ip4CfgData
.RawData
);
1350 if (OpenData
->IpConfigData
.Ip4CfgData
.RawData
) {
1351 return EFI_UNSUPPORTED
;
1354 if (!OpenData
->IpConfigData
.Ip4CfgData
.UseDefaultAddress
) {
1355 IpIo
->StationIp
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.StationAddress
);
1356 IpIo
->SubnetMask
= EFI_NTOHL (OpenData
->IpConfigData
.Ip4CfgData
.SubnetMask
);
1359 Status
= IpIo
->Ip
.Ip4
->Configure (
1361 &OpenData
->IpConfigData
.Ip4CfgData
1365 Status
= IpIo
->Ip
.Ip6
->Configure (
1367 &OpenData
->IpConfigData
.Ip6CfgData
1371 if (EFI_ERROR (Status
)) {
1376 // @bug To delete the default route entry in this Ip, if it is:
1377 // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
1380 if (IpVersion
== IP_VERSION_4
){
1381 Status
= IpIo
->Ip
.Ip4
->Routes (
1389 if (EFI_ERROR (Status
) && (EFI_NOT_FOUND
!= Status
)) {
1394 IpIo
->PktRcvdNotify
= OpenData
->PktRcvdNotify
;
1395 IpIo
->PktSentNotify
= OpenData
->PktSentNotify
;
1397 IpIo
->RcvdContext
= OpenData
->RcvdContext
;
1398 IpIo
->SndContext
= OpenData
->SndContext
;
1400 if (IpVersion
== IP_VERSION_4
){
1401 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip4CfgData
.DefaultProtocol
;
1404 // start to listen incoming packet
1406 Status
= IpIo
->Ip
.Ip4
->Receive (
1408 &(IpIo
->RcvToken
.Ip4Token
)
1410 if (EFI_ERROR (Status
)) {
1411 IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1417 IpIo
->Protocol
= OpenData
->IpConfigData
.Ip6CfgData
.DefaultProtocol
;
1418 Status
= IpIo
->Ip
.Ip6
->Receive (
1420 &(IpIo
->RcvToken
.Ip6Token
)
1422 if (EFI_ERROR (Status
)) {
1423 IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1428 IpIo
->IsConfigured
= TRUE
;
1429 InsertTailList (&mActiveIpIoList
, &IpIo
->Entry
);
1438 Stop an IP_IO instance.
1440 This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
1441 the pending send/receive tokens will be canceled.
1443 @param[in, out] IpIo Pointer to the IP_IO instance that needs to stop.
1445 @retval EFI_SUCCESS The IP_IO instance stopped successfully.
1446 @retval EFI_INVALID_PARAMETER Invalid input parameter.
1447 @retval Others Error condition occurred.
1457 IP_IO_IP_INFO
*IpInfo
;
1461 return EFI_INVALID_PARAMETER
;
1464 if (!IpIo
->IsConfigured
) {
1468 IpVersion
= IpIo
->IpVersion
;
1470 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1473 // Remove the IpIo from the active IpIo list.
1475 RemoveEntryList (&IpIo
->Entry
);
1478 // Configure NULL Ip
1480 if (IpVersion
== IP_VERSION_4
) {
1481 Status
= IpIo
->Ip
.Ip4
->Configure (IpIo
->Ip
.Ip4
, NULL
);
1483 Status
= IpIo
->Ip
.Ip6
->Configure (IpIo
->Ip
.Ip6
, NULL
);
1485 if (EFI_ERROR (Status
)) {
1489 IpIo
->IsConfigured
= FALSE
;
1492 // Detroy the Ip List used by IpIo
1495 while (!IsListEmpty (&(IpIo
->IpList
))) {
1496 IpInfo
= NET_LIST_HEAD (&(IpIo
->IpList
), IP_IO_IP_INFO
, Entry
);
1498 IpIoRemoveIp (IpIo
, IpInfo
);
1502 // All pending send tokens should be flushed by resetting the IP instances.
1504 ASSERT (IsListEmpty (&IpIo
->PendingSndList
));
1507 // Close the receive event.
1509 if (IpVersion
== IP_VERSION_4
){
1510 gBS
->CloseEvent (IpIo
->RcvToken
.Ip4Token
.Event
);
1512 gBS
->CloseEvent (IpIo
->RcvToken
.Ip6Token
.Event
);
1520 Destroy an IP_IO instance.
1522 This function is paired with IpIoCreate(). The IP_IO will be closed first.
1523 Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
1525 @param[in, out] IpIo Pointer to the IP_IO instance that needs to be
1528 @retval EFI_SUCCESS The IP_IO instance destroyed successfully.
1529 @retval Others Error condition occurred.
1543 Status
= IpIoStop (IpIo
);
1544 if (EFI_ERROR (Status
)) {
1549 // Close the IP protocol and destroy the child.
1551 Status
= IpIoCloseProtocolDestroyIpChild (
1557 if (EFI_ERROR (Status
)) {
1561 gBS
->FreePool (IpIo
);
1568 Send out an IP packet.
1570 This function is called after IpIoOpen(). The data to be sent are wrapped in
1571 Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
1572 overriden by Sender. Other sending configs, like source address and gateway
1573 address etc., are specified in OverrideData.
1575 @param[in, out] IpIo Pointer to an IP_IO instance used for sending IP
1577 @param[in, out] Pkt Pointer to the IP packet to be sent.
1578 @param[in] Sender The IP protocol instance used for sending.
1579 @param[in] Context Optional context data.
1580 @param[in] NotifyData Optional notify data.
1581 @param[in] Dest The destination IP address to send this packet to.
1582 This parameter is optional when using IPv6.
1583 @param[in] OverrideData The data to override some configuration of the IP
1584 instance used for sending.
1586 @retval EFI_SUCCESS The operation is completed successfully.
1587 @retval EFI_INVALID_PARAMETER The input parameter is not correct.
1588 @retval EFI_NOT_STARTED The IpIo is not configured.
1589 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
1590 @retval Others Error condition occurred.
1597 IN OUT NET_BUF
*Pkt
,
1598 IN IP_IO_IP_INFO
*Sender OPTIONAL
,
1599 IN VOID
*Context OPTIONAL
,
1600 IN VOID
*NotifyData OPTIONAL
,
1601 IN EFI_IP_ADDRESS
*Dest OPTIONAL
,
1602 IN IP_IO_OVERRIDE
*OverrideData OPTIONAL
1606 IP_IO_IP_PROTOCOL Ip
;
1607 IP_IO_SEND_ENTRY
*SndEntry
;
1609 if ((IpIo
== NULL
) || (Pkt
== NULL
)) {
1610 return EFI_INVALID_PARAMETER
;
1613 if ((IpIo
->IpVersion
== IP_VERSION_4
) && (Dest
== NULL
)) {
1614 return EFI_INVALID_PARAMETER
;
1617 if (!IpIo
->IsConfigured
) {
1618 return EFI_NOT_STARTED
;
1621 Ip
= (NULL
== Sender
) ? IpIo
->Ip
: Sender
->Ip
;
1624 // create a new SndEntry
1626 SndEntry
= IpIoCreateSndEntry (IpIo
, Pkt
, Ip
, Context
, NotifyData
, Dest
, OverrideData
);
1627 if (NULL
== SndEntry
) {
1628 return EFI_OUT_OF_RESOURCES
;
1634 if (IpIo
->IpVersion
== IP_VERSION_4
){
1635 Status
= Ip
.Ip4
->Transmit (
1637 &SndEntry
->SndToken
.Ip4Token
1640 Status
= Ip
.Ip6
->Transmit (
1642 &SndEntry
->SndToken
.Ip6Token
1646 if (EFI_ERROR (Status
)) {
1647 IpIoDestroySndEntry (SndEntry
);
1655 Cancel the IP transmit token which wraps this Packet.
1657 @param[in] IpIo Pointer to the IP_IO instance.
1658 @param[in] Packet Pointer to the packet of NET_BUF to cancel.
1669 IP_IO_SEND_ENTRY
*SndEntry
;
1670 IP_IO_IP_PROTOCOL Ip
;
1672 ASSERT ((IpIo
!= NULL
) && (Packet
!= NULL
));
1674 NET_LIST_FOR_EACH (Node
, &IpIo
->PendingSndList
) {
1676 SndEntry
= NET_LIST_USER_STRUCT (Node
, IP_IO_SEND_ENTRY
, Entry
);
1678 if (SndEntry
->Pkt
== Packet
) {
1682 if (IpIo
->IpVersion
== IP_VERSION_4
) {
1685 &SndEntry
->SndToken
.Ip4Token
1690 &SndEntry
->SndToken
.Ip6Token
1702 Add a new IP instance for sending data.
1704 The function is used to add the IP_IO to the IP_IO sending list. The caller
1705 can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
1708 @param[in, out] IpIo Pointer to a IP_IO instance to add a new IP
1709 instance for sending purpose.
1711 @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
1721 IP_IO_IP_INFO
*IpInfo
;
1724 ASSERT (IpIo
!= NULL
);
1726 IpInfo
= AllocatePool (sizeof (IP_IO_IP_INFO
));
1727 if (IpInfo
== NULL
) {
1732 // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
1735 InitializeListHead (&IpInfo
->Entry
);
1736 IpInfo
->ChildHandle
= NULL
;
1737 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1738 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1741 IpInfo
->IpVersion
= IpIo
->IpVersion
;
1744 // Create the IP instance and open the IP protocol.
1746 Status
= IpIoCreateIpChildOpenProtocol (
1749 &IpInfo
->ChildHandle
,
1751 (VOID
**) &IpInfo
->Ip
1753 if (EFI_ERROR (Status
)) {
1758 // Create the event for the DummyRcvToken.
1760 Status
= gBS
->CreateEvent (
1767 if (EFI_ERROR (Status
)) {
1768 goto ReleaseIpChild
;
1771 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1772 IpInfo
->DummyRcvToken
.Ip4Token
.Event
= Event
;
1774 IpInfo
->DummyRcvToken
.Ip6Token
.Event
= Event
;
1778 // Link this IpInfo into the IpIo.
1780 InsertTailList (&IpIo
->IpList
, &IpInfo
->Entry
);
1786 IpIoCloseProtocolDestroyIpChild (
1789 IpInfo
->ChildHandle
,
1795 gBS
->FreePool (IpInfo
);
1802 Configure the IP instance of this IpInfo and start the receiving if IpConfigData
1805 @param[in, out] IpInfo Pointer to the IP_IO_IP_INFO instance.
1806 @param[in, out] IpConfigData The IP configure data used to configure the IP
1807 instance, if NULL the IP instance is reset. If
1808 UseDefaultAddress is set to TRUE, and the configure
1809 operation succeeds, the default address information
1810 is written back in this IpConfigData.
1812 @retval EFI_SUCCESS The IP instance of this IpInfo is configured successfully
1813 or no need to reconfigure it.
1814 @retval Others Configuration fails.
1820 IN OUT IP_IO_IP_INFO
*IpInfo
,
1821 IN OUT VOID
*IpConfigData OPTIONAL
1825 IP_IO_IP_PROTOCOL Ip
;
1827 EFI_IP4_MODE_DATA Ip4ModeData
;
1828 EFI_IP6_MODE_DATA Ip6ModeData
;
1830 ASSERT (IpInfo
!= NULL
);
1832 if (IpInfo
->RefCnt
> 1) {
1834 // This IP instance is shared, don't reconfigure it until it has only one
1835 // consumer. Currently, only the tcp children cloned from their passive parent
1836 // will share the same IP. So this cases only happens while IpConfigData is NULL,
1837 // let the last consumer clean the IP instance.
1842 IpVersion
= IpInfo
->IpVersion
;
1843 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
1847 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1848 Status
= Ip
.Ip4
->Configure (Ip
.Ip4
, IpConfigData
);
1850 Status
= Ip
.Ip6
->Configure (Ip
.Ip6
, IpConfigData
);
1853 if (EFI_ERROR (Status
)) {
1857 if (IpConfigData
!= NULL
) {
1858 if (IpInfo
->IpVersion
== IP_VERSION_4
) {
1860 if (((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->UseDefaultAddress
) {
1861 Status
= Ip
.Ip4
->GetModeData (
1867 if (EFI_ERROR (Status
)) {
1868 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1872 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
, &Ip4ModeData
.ConfigData
.StationAddress
);
1873 IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
, &Ip4ModeData
.ConfigData
.SubnetMask
);
1878 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1882 &IpInfo
->PreMask
.SubnetMask
,
1883 &((EFI_IP4_CONFIG_DATA
*) IpConfigData
)->SubnetMask
,
1887 Status
= Ip
.Ip4
->Receive (
1889 &IpInfo
->DummyRcvToken
.Ip4Token
1891 if (EFI_ERROR (Status
)) {
1892 Ip
.Ip4
->Configure (Ip
.Ip4
, NULL
);
1895 Status
= Ip
.Ip6
->GetModeData (
1901 if (EFI_ERROR (Status
)) {
1902 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1906 if (Ip6ModeData
.IsConfigured
) {
1908 &((EFI_IP6_CONFIG_DATA
*) IpConfigData
)->StationAddress
,
1909 &Ip6ModeData
.ConfigData
.StationAddress
,
1910 sizeof (EFI_IPv6_ADDRESS
)
1913 if (Ip6ModeData
.AddressList
!= NULL
) {
1914 FreePool (Ip6ModeData
.AddressList
);
1917 if (Ip6ModeData
.GroupTable
!= NULL
) {
1918 FreePool (Ip6ModeData
.GroupTable
);
1921 if (Ip6ModeData
.RouteTable
!= NULL
) {
1922 FreePool (Ip6ModeData
.RouteTable
);
1925 if (Ip6ModeData
.NeighborCache
!= NULL
) {
1926 FreePool (Ip6ModeData
.NeighborCache
);
1929 if (Ip6ModeData
.PrefixTable
!= NULL
) {
1930 FreePool (Ip6ModeData
.PrefixTable
);
1933 if (Ip6ModeData
.IcmpTypeList
!= NULL
) {
1934 FreePool (Ip6ModeData
.IcmpTypeList
);
1938 Status
= EFI_NO_MAPPING
;
1944 &Ip6ModeData
.ConfigData
.StationAddress
,
1945 sizeof (EFI_IPv6_ADDRESS
)
1948 Status
= Ip
.Ip6
->Receive (
1950 &IpInfo
->DummyRcvToken
.Ip6Token
1952 if (EFI_ERROR (Status
)) {
1953 Ip
.Ip6
->Configure (Ip
.Ip6
, NULL
);
1958 // The IP instance is reset, set the stored Addr and SubnetMask to zero.
1960 ZeroMem (&IpInfo
->Addr
, sizeof (IpInfo
->Addr
));
1961 ZeroMem (&IpInfo
->PreMask
, sizeof (IpInfo
->PreMask
));
1971 Destroy an IP instance maintained in IpIo->IpList for
1974 This function pairs with IpIoAddIp(). The IpInfo is previously created by
1975 IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
1976 will be dstroyed if the RefCnt is zero.
1978 @param[in] IpIo Pointer to the IP_IO instance.
1979 @param[in] IpInfo Pointer to the IpInfo to be removed.
1986 IN IP_IO_IP_INFO
*IpInfo
1992 if (IpIo
== NULL
|| IpInfo
== NULL
) {
1996 ASSERT (IpInfo
->RefCnt
> 0);
1998 NET_PUT_REF (IpInfo
);
2000 if (IpInfo
->RefCnt
> 0) {
2005 IpVersion
= IpIo
->IpVersion
;
2007 ASSERT ((IpVersion
== IP_VERSION_4
) || (IpVersion
== IP_VERSION_6
));
2009 RemoveEntryList (&IpInfo
->Entry
);
2011 if (IpVersion
== IP_VERSION_4
){
2012 IpInfo
->Ip
.Ip4
->Configure (
2016 IpIoCloseProtocolDestroyIpChild (
2019 IpInfo
->ChildHandle
,
2023 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip4Token
.Event
);
2027 IpInfo
->Ip
.Ip6
->Configure (
2032 IpIoCloseProtocolDestroyIpChild (
2035 IpInfo
->ChildHandle
,
2039 gBS
->CloseEvent (IpInfo
->DummyRcvToken
.Ip6Token
.Event
);
2047 Find the first IP protocol maintained in IpIo whose local
2048 address is the same as Src.
2050 This function is called when the caller needs the IpIo to send data to the
2051 specified Src. The IpIo was added previously by IpIoAddIp().
2053 @param[in, out] IpIo Pointer to the pointer of the IP_IO instance.
2054 @param[in] IpVersion The version of the IP protocol to use, either
2056 @param[in] Src The local IP address.
2058 @return Pointer to the IP protocol can be used for sending purpose and its local
2059 address is the same with Src. NULL if failed.
2065 IN OUT IP_IO
**IpIo
,
2067 IN EFI_IP_ADDRESS
*Src
2070 LIST_ENTRY
*IpIoEntry
;
2072 LIST_ENTRY
*IpInfoEntry
;
2073 IP_IO_IP_INFO
*IpInfo
;
2075 if (IpIo
== NULL
|| Src
== NULL
) {
2079 if ((IpVersion
!= IP_VERSION_4
) && (IpVersion
!= IP_VERSION_6
)) {
2083 NET_LIST_FOR_EACH (IpIoEntry
, &mActiveIpIoList
) {
2084 IpIoPtr
= NET_LIST_USER_STRUCT (IpIoEntry
, IP_IO
, Entry
);
2086 if (((*IpIo
!= NULL
) && (*IpIo
!= IpIoPtr
)) || (IpIoPtr
->IpVersion
!= IpVersion
)) {
2090 NET_LIST_FOR_EACH (IpInfoEntry
, &IpIoPtr
->IpList
) {
2091 IpInfo
= NET_LIST_USER_STRUCT (IpInfoEntry
, IP_IO_IP_INFO
, Entry
);
2092 if (IpInfo
->IpVersion
== IP_VERSION_4
){
2094 if (EFI_IP4_EQUAL (&IpInfo
->Addr
.v4
, &Src
->v4
)) {
2101 if (EFI_IP6_EQUAL (&IpInfo
->Addr
.v6
, &Src
->v6
)) {
2118 Get the ICMP error map information.
2120 The ErrorStatus will be returned. The IsHard and Notify are optional. If they
2121 are not NULL, this routine will fill them.
2123 @param[in] IcmpError IcmpError Type.
2124 @param[in] IpVersion The version of the IP protocol to use,
2125 either IPv4 or IPv6.
2126 @param[out] IsHard If TRUE, indicates that it is a hard error.
2127 @param[out] Notify If TRUE, SockError needs to be notified.
2129 @retval EFI_UNSUPPORTED Unrecognizable ICMP error code.
2130 @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
2135 IpIoGetIcmpErrStatus (
2138 OUT BOOLEAN
*IsHard OPTIONAL
,
2139 OUT BOOLEAN
*Notify OPTIONAL
2142 if (IpVersion
== IP_VERSION_4
) {
2143 ASSERT (IcmpError
<= ICMP_ERR_PARAMPROB
);
2145 if (IsHard
!= NULL
) {
2146 *IsHard
= mIcmpErrMap
[IcmpError
].IsHard
;
2149 if (Notify
!= NULL
) {
2150 *Notify
= mIcmpErrMap
[IcmpError
].Notify
;
2153 switch (IcmpError
) {
2154 case ICMP_ERR_UNREACH_NET
:
2155 return EFI_NETWORK_UNREACHABLE
;
2157 case ICMP_ERR_TIMXCEED_INTRANS
:
2158 case ICMP_ERR_TIMXCEED_REASS
:
2159 case ICMP_ERR_UNREACH_HOST
:
2160 return EFI_HOST_UNREACHABLE
;
2162 case ICMP_ERR_UNREACH_PROTOCOL
:
2163 return EFI_PROTOCOL_UNREACHABLE
;
2165 case ICMP_ERR_UNREACH_PORT
:
2166 return EFI_PORT_UNREACHABLE
;
2168 case ICMP_ERR_MSGSIZE
:
2169 case ICMP_ERR_UNREACH_SRCFAIL
:
2170 case ICMP_ERR_QUENCH
:
2171 case ICMP_ERR_PARAMPROB
:
2172 return EFI_ICMP_ERROR
;
2176 return EFI_UNSUPPORTED
;
2179 } else if (IpVersion
== IP_VERSION_6
) {
2181 ASSERT (IcmpError
<= ICMP6_ERR_PARAMPROB_IPV6OPTION
);
2183 if (IsHard
!= NULL
) {
2184 *IsHard
= mIcmp6ErrMap
[IcmpError
].IsHard
;
2187 if (Notify
!= NULL
) {
2188 *Notify
= mIcmp6ErrMap
[IcmpError
].Notify
;
2191 switch (IcmpError
) {
2192 case ICMP6_ERR_UNREACH_NET
:
2193 return EFI_NETWORK_UNREACHABLE
;
2195 case ICMP6_ERR_UNREACH_HOST
:
2196 case ICMP6_ERR_TIMXCEED_HOPLIMIT
:
2197 case ICMP6_ERR_TIMXCEED_REASS
:
2198 return EFI_HOST_UNREACHABLE
;
2200 case ICMP6_ERR_UNREACH_PROTOCOL
:
2201 return EFI_PROTOCOL_UNREACHABLE
;
2203 case ICMP6_ERR_UNREACH_PORT
:
2204 return EFI_PORT_UNREACHABLE
;
2206 case ICMP6_ERR_PACKAGE_TOOBIG
:
2207 case ICMP6_ERR_PARAMPROB_HEADER
:
2208 case ICMP6_ERR_PARAMPROB_NEXHEADER
:
2209 case ICMP6_ERR_PARAMPROB_IPV6OPTION
:
2210 return EFI_ICMP_ERROR
;
2214 return EFI_UNSUPPORTED
;
2219 // Should never be here
2222 return EFI_UNSUPPORTED
;
2228 Refresh the remote peer's Neighbor Cache entries.
2230 This function is called when the caller needs the IpIo to refresh the existing
2231 IPv6 neighbor cache entries since the neighbor is considered reachable by the
2232 node has recently received a confirmation that packets sent recently to the
2233 neighbor were received by its IP layer.
2235 @param[in] IpIo Pointer to an IP_IO instance
2236 @param[in] Neighbor The IP address of the neighbor
2237 @param[in] Timeout Time in 100-ns units that this entry will
2238 remain in the neighbor cache. A value of
2239 zero means that the entry is permanent.
2240 A value of non-zero means that the entry is
2241 dynamic and will be deleted after Timeout.
2243 @retval EFI_SUCCESS The operation is completed successfully.
2244 @retval EFI_NOT_STARTED The IpIo is not configured.
2245 @retval EFI_INVALID_PARAMETER Neighbor Address is invalid.
2246 @retval EFI_NOT_FOUND The neighbor cache entry is not in the
2248 @retval EFI_UNSUPPORTED IP version is IPv4, which doesn't support neighbor cache refresh.
2249 @retval EFI_OUT_OF_RESOURCES Failed due to resource limit.
2253 IpIoRefreshNeighbor (
2255 IN EFI_IP_ADDRESS
*Neighbor
,
2259 EFI_IP6_PROTOCOL
*Ip
;
2261 if (!IpIo
->IsConfigured
) {
2262 return EFI_NOT_STARTED
;
2265 if (IpIo
->IpVersion
!= IP_VERSION_6
) {
2266 return EFI_UNSUPPORTED
;
2271 return Ip
->Neighbors (Ip
, FALSE
, &Neighbor
->v6
, NULL
, Timeout
, TRUE
);