mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-29 18:23:45 +01:00 
			
		
		
		
	1. Do not use tab characters 2. No trailing white space in one line 3. All files must end with CRLF Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com>
		
			
				
	
	
		
			2298 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2298 lines
		
	
	
		
			59 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   IpIo Library.
 | |
| 
 | |
| (C) Copyright 2014 Hewlett-Packard Development Company, L.P.<BR>
 | |
| Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| **/
 | |
| 
 | |
| #include <Uefi.h>
 | |
| 
 | |
| #include <Protocol/Udp4.h>
 | |
| 
 | |
| #include <Library/IpIoLib.h>
 | |
| #include <Library/BaseLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/UefiBootServicesTableLib.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/DpcLib.h>
 | |
| 
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED LIST_ENTRY  mActiveIpIoList = {
 | |
|   &mActiveIpIoList,
 | |
|   &mActiveIpIoList
 | |
| };
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP4_CONFIG_DATA  mIp4IoDefaultIpConfigData = {
 | |
|   EFI_IP_PROTO_UDP,
 | |
|   FALSE,
 | |
|   TRUE,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   {{0, 0, 0, 0}},
 | |
|   {{0, 0, 0, 0}},
 | |
|   0,
 | |
|   255,
 | |
|   FALSE,
 | |
|   FALSE,
 | |
|   0,
 | |
|   0
 | |
| };
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED EFI_IP6_CONFIG_DATA  mIp6IoDefaultIpConfigData = {
 | |
|   EFI_IP_PROTO_UDP,
 | |
|   FALSE,
 | |
|   TRUE,
 | |
|   FALSE,
 | |
|   {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
 | |
|   {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
 | |
|   0,
 | |
|   255,
 | |
|   0,
 | |
|   0,
 | |
|   0
 | |
| };
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmpErrMap[10] = {
 | |
|   {FALSE, TRUE }, // ICMP_ERR_UNREACH_NET
 | |
|   {FALSE, TRUE }, // ICMP_ERR_UNREACH_HOST
 | |
|   {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PROTOCOL
 | |
|   {TRUE,  TRUE }, // ICMP_ERR_UNREACH_PORT
 | |
|   {TRUE,  TRUE }, // ICMP_ERR_MSGSIZE
 | |
|   {FALSE, TRUE }, // ICMP_ERR_UNREACH_SRCFAIL
 | |
|   {FALSE, TRUE }, // ICMP_ERR_TIMXCEED_INTRANS
 | |
|   {FALSE, TRUE }, // ICMP_ERR_TIMEXCEED_REASS
 | |
|   {FALSE, FALSE}, // ICMP_ERR_QUENCH
 | |
|   {FALSE, TRUE }  // ICMP_ERR_PARAMPROB
 | |
| };
 | |
| 
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED ICMP_ERROR_INFO  mIcmp6ErrMap[10] = {
 | |
|   {FALSE, TRUE}, // ICMP6_ERR_UNREACH_NET
 | |
|   {FALSE, TRUE}, // ICMP6_ERR_UNREACH_HOST
 | |
|   {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PROTOCOL
 | |
|   {TRUE,  TRUE}, // ICMP6_ERR_UNREACH_PORT
 | |
|   {TRUE,  TRUE}, // ICMP6_ERR_PACKAGE_TOOBIG
 | |
|   {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_HOPLIMIT
 | |
|   {FALSE, TRUE}, // ICMP6_ERR_TIMXCEED_REASS
 | |
|   {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_HEADER
 | |
|   {FALSE, TRUE}, // ICMP6_ERR_PARAMPROB_NEXHEADER
 | |
|   {FALSE, TRUE}  // ICMP6_ERR_PARAMPROB_IPV6OPTION
 | |
| };
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Notify function for IP transmit token.
 | |
| 
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoTransmitHandlerDpc (
 | |
|   IN VOID      *Context
 | |
|   );
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Notify function for IP transmit token.
 | |
| 
 | |
|   @param[in]  Event                 The event signaled.
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoTransmitHandler (
 | |
|   IN EFI_EVENT Event,
 | |
|   IN VOID      *Context
 | |
|   );
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function create an IP child ,open the IP protocol, and return the opened
 | |
|   IP protocol as Interface.
 | |
| 
 | |
|   @param[in]    ControllerHandle   The controller handle.
 | |
|   @param[in]    ImageHandle        The image handle.
 | |
|   @param[in]    ChildHandle        Pointer to the buffer to save the IP child handle.
 | |
|   @param[in]    IpVersion          The version of the IP protocol to use, either
 | |
|                                    IPv4 or IPv6.
 | |
|   @param[out]   Interface          Pointer used to get the IP protocol interface.
 | |
| 
 | |
|   @retval       EFI_SUCCESS        The IP child is created and the IP protocol
 | |
|                                    interface is retrieved.
 | |
|   @retval       EFI_UNSUPPORTED    Upsupported IpVersion.
 | |
|   @retval       Others             The required operation failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpIoCreateIpChildOpenProtocol (
 | |
|   IN  EFI_HANDLE  ControllerHandle,
 | |
|   IN  EFI_HANDLE  ImageHandle,
 | |
|   IN  EFI_HANDLE  *ChildHandle,
 | |
|   IN  UINT8       IpVersion,
 | |
|   OUT VOID        **Interface
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_GUID    *ServiceBindingGuid;
 | |
|   EFI_GUID    *IpProtocolGuid;
 | |
| 
 | |
|   if (IpVersion == IP_VERSION_4) {
 | |
|     ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
 | |
|     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
 | |
|   } else if (IpVersion == IP_VERSION_6){
 | |
|     ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
 | |
|     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
 | |
|   } else {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create an IP child.
 | |
|   //
 | |
|   Status = NetLibCreateServiceChild (
 | |
|              ControllerHandle,
 | |
|              ImageHandle,
 | |
|              ServiceBindingGuid,
 | |
|              ChildHandle
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open the IP protocol installed on the *ChildHandle.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   *ChildHandle,
 | |
|                   IpProtocolGuid,
 | |
|                   Interface,
 | |
|                   ImageHandle,
 | |
|                   ControllerHandle,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // On failure, destroy the IP child.
 | |
|     //
 | |
|     NetLibDestroyServiceChild (
 | |
|       ControllerHandle,
 | |
|       ImageHandle,
 | |
|       ServiceBindingGuid,
 | |
|       *ChildHandle
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function close the previously openned IP protocol and destroy the IP child.
 | |
| 
 | |
|   @param[in]  ControllerHandle    The controller handle.
 | |
|   @param[in]  ImageHandle         The image handle.
 | |
|   @param[in]  ChildHandle         The child handle of the IP child.
 | |
|   @param[in]  IpVersion           The version of the IP protocol to use, either
 | |
|                                   IPv4 or IPv6.
 | |
| 
 | |
|   @retval     EFI_SUCCESS         The IP protocol is closed and the relevant IP child
 | |
|                                   is destroyed.
 | |
|   @retval     EFI_UNSUPPORTED     Upsupported IpVersion.
 | |
|   @retval     Others              The required operation failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpIoCloseProtocolDestroyIpChild (
 | |
|   IN EFI_HANDLE  ControllerHandle,
 | |
|   IN EFI_HANDLE  ImageHandle,
 | |
|   IN EFI_HANDLE  ChildHandle,
 | |
|   IN UINT8       IpVersion
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   EFI_GUID    *ServiceBindingGuid;
 | |
|   EFI_GUID    *IpProtocolGuid;
 | |
| 
 | |
|   if (IpVersion == IP_VERSION_4) {
 | |
|     ServiceBindingGuid = &gEfiIp4ServiceBindingProtocolGuid;
 | |
|     IpProtocolGuid     = &gEfiIp4ProtocolGuid;
 | |
|   } else if (IpVersion == IP_VERSION_6) {
 | |
|     ServiceBindingGuid = &gEfiIp6ServiceBindingProtocolGuid;
 | |
|     IpProtocolGuid     = &gEfiIp6ProtocolGuid;
 | |
|   } else {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close the previously openned IP protocol.
 | |
|   //
 | |
|   Status = gBS->CloseProtocol (
 | |
|                   ChildHandle,
 | |
|                   IpProtocolGuid,
 | |
|                   ImageHandle,
 | |
|                   ControllerHandle
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Destroy the IP child.
 | |
|   //
 | |
|   return NetLibDestroyServiceChild (
 | |
|            ControllerHandle,
 | |
|            ImageHandle,
 | |
|            ServiceBindingGuid,
 | |
|            ChildHandle
 | |
|            );
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function handles ICMPv4 packets. It is the worker function of
 | |
|   IpIoIcmpHandler.
 | |
| 
 | |
|   @param[in]       IpIo            Pointer to the IP_IO instance.
 | |
|   @param[in, out]  Pkt             Pointer to the ICMPv4 packet.
 | |
|   @param[in]       Session         Pointer to the net session of this ICMPv4 packet.
 | |
| 
 | |
|   @retval          EFI_SUCCESS     The ICMPv4 packet is handled successfully.
 | |
|   @retval          EFI_ABORTED     This type of ICMPv4 packet is not supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpIoIcmpv4Handler (
 | |
|   IN     IP_IO                *IpIo,
 | |
|   IN OUT NET_BUF              *Pkt,
 | |
|   IN     EFI_NET_SESSION_DATA *Session
 | |
|   )
 | |
| {
 | |
|   IP4_ICMP_ERROR_HEAD  *IcmpHdr;
 | |
|   EFI_IP4_HEADER       *IpHdr;
 | |
|   UINT8                IcmpErr;
 | |
|   UINT8                *PayLoadHdr;
 | |
|   UINT8                Type;
 | |
|   UINT8                Code;
 | |
|   UINT32               TrimBytes;
 | |
| 
 | |
|   ASSERT (IpIo != NULL);
 | |
|   ASSERT (Pkt != NULL);
 | |
|   ASSERT (Session != NULL);
 | |
|   ASSERT (IpIo->IpVersion == IP_VERSION_4);
 | |
| 
 | |
|   //
 | |
|   // Check the ICMP packet length.
 | |
|   //
 | |
|   if (Pkt->TotalSize < sizeof (IP4_ICMP_ERROR_HEAD)) {
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   IcmpHdr = NET_PROTO_HDR (Pkt, IP4_ICMP_ERROR_HEAD);
 | |
|   IpHdr   = (EFI_IP4_HEADER *) (&IcmpHdr->IpHead);
 | |
| 
 | |
|   if (Pkt->TotalSize < ICMP_ERRLEN (IpHdr)) {
 | |
| 
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   Type = IcmpHdr->Head.Type;
 | |
|   Code = IcmpHdr->Head.Code;
 | |
| 
 | |
|   //
 | |
|   // Analyze the ICMP Error in this ICMP pkt
 | |
|   //
 | |
|   switch (Type) {
 | |
|   case ICMP_TYPE_UNREACH:
 | |
|     switch (Code) {
 | |
|     case ICMP_CODE_UNREACH_NET:
 | |
|     case ICMP_CODE_UNREACH_HOST:
 | |
|     case ICMP_CODE_UNREACH_PROTOCOL:
 | |
|     case ICMP_CODE_UNREACH_PORT:
 | |
|     case ICMP_CODE_UNREACH_SRCFAIL:
 | |
|       IcmpErr = (UINT8) (ICMP_ERR_UNREACH_NET + Code);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case ICMP_CODE_UNREACH_NEEDFRAG:
 | |
|       IcmpErr = ICMP_ERR_MSGSIZE;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case ICMP_CODE_UNREACH_NET_UNKNOWN:
 | |
|     case ICMP_CODE_UNREACH_NET_PROHIB:
 | |
|     case ICMP_CODE_UNREACH_TOSNET:
 | |
|       IcmpErr = ICMP_ERR_UNREACH_NET;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case ICMP_CODE_UNREACH_HOST_UNKNOWN:
 | |
|     case ICMP_CODE_UNREACH_ISOLATED:
 | |
|     case ICMP_CODE_UNREACH_HOST_PROHIB:
 | |
|     case ICMP_CODE_UNREACH_TOSHOST:
 | |
|       IcmpErr = ICMP_ERR_UNREACH_HOST;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case ICMP_TYPE_TIMXCEED:
 | |
|     if (Code > 1) {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     IcmpErr = (UINT8) (Code + ICMP_ERR_TIMXCEED_INTRANS);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case ICMP_TYPE_PARAMPROB:
 | |
|     if (Code > 1) {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     IcmpErr = ICMP_ERR_PARAMPROB;
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case ICMP_TYPE_SOURCEQUENCH:
 | |
|     if (Code != 0) {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     IcmpErr = ICMP_ERR_QUENCH;
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Notify user the ICMP pkt only containing payload except
 | |
|   // IP and ICMP header
 | |
|   //
 | |
|   PayLoadHdr = (UINT8 *) ((UINT8 *) IpHdr + EFI_IP4_HEADER_LEN (IpHdr));
 | |
|   TrimBytes  = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
 | |
| 
 | |
|   NetbufTrim (Pkt, TrimBytes, TRUE);
 | |
| 
 | |
|   //
 | |
|   // If the input packet has invalid format, and TrimBytes is larger than
 | |
|   // the packet size, the NetbufTrim might trim the packet to zero.
 | |
|   //
 | |
|   if (Pkt->TotalSize != 0) {
 | |
|     IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function handles ICMPv6 packets. It is the worker function of
 | |
|   IpIoIcmpHandler.
 | |
| 
 | |
|   @param[in]       IpIo            Pointer to the IP_IO instance.
 | |
|   @param[in, out]  Pkt             Pointer to the ICMPv6 packet.
 | |
|   @param[in]       Session         Pointer to the net session of this ICMPv6 packet.
 | |
| 
 | |
|   @retval          EFI_SUCCESS     The ICMPv6 packet is handled successfully.
 | |
|   @retval          EFI_ABORTED     This type of ICMPv6 packet is not supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpIoIcmpv6Handler (
 | |
|   IN     IP_IO                *IpIo,
 | |
|   IN OUT NET_BUF              *Pkt,
 | |
|   IN     EFI_NET_SESSION_DATA *Session
 | |
|   )
 | |
| {
 | |
|   IP6_ICMP_ERROR_HEAD  *IcmpHdr;
 | |
|   EFI_IP6_HEADER       *IpHdr;
 | |
|   UINT8                IcmpErr;
 | |
|   UINT8                *PayLoadHdr;
 | |
|   UINT8                Type;
 | |
|   UINT8                Code;
 | |
|   UINT8                NextHeader;
 | |
|   UINT32               TrimBytes;
 | |
|   BOOLEAN              Flag;
 | |
| 
 | |
|   ASSERT (IpIo != NULL);
 | |
|   ASSERT (Pkt != NULL);
 | |
|   ASSERT (Session != NULL);
 | |
|   ASSERT (IpIo->IpVersion == IP_VERSION_6);
 | |
| 
 | |
|   //
 | |
|   // Check the ICMPv6 packet length.
 | |
|   //
 | |
|   if (Pkt->TotalSize < sizeof (IP6_ICMP_ERROR_HEAD)) {
 | |
| 
 | |
|     return EFI_ABORTED;
 | |
|   }
 | |
| 
 | |
|   IcmpHdr = NET_PROTO_HDR (Pkt, IP6_ICMP_ERROR_HEAD);
 | |
|   Type    = IcmpHdr->Head.Type;
 | |
|   Code    = IcmpHdr->Head.Code;
 | |
| 
 | |
|   //
 | |
|   // Analyze the ICMPv6 Error in this ICMPv6 packet
 | |
|   //
 | |
|   switch (Type) {
 | |
|   case ICMP_V6_DEST_UNREACHABLE:
 | |
|     switch (Code) {
 | |
|     case ICMP_V6_NO_ROUTE_TO_DEST:
 | |
|     case ICMP_V6_BEYOND_SCOPE:
 | |
|     case ICMP_V6_ROUTE_REJECTED:
 | |
|       IcmpErr = ICMP6_ERR_UNREACH_NET;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case ICMP_V6_COMM_PROHIBITED:
 | |
|     case ICMP_V6_ADDR_UNREACHABLE:
 | |
|     case ICMP_V6_SOURCE_ADDR_FAILED:
 | |
|       IcmpErr = ICMP6_ERR_UNREACH_HOST;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case ICMP_V6_PORT_UNREACHABLE:
 | |
|       IcmpErr = ICMP6_ERR_UNREACH_PORT;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|      default:
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case ICMP_V6_PACKET_TOO_BIG:
 | |
|     if (Code >= 1) {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     IcmpErr = ICMP6_ERR_PACKAGE_TOOBIG;
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case ICMP_V6_TIME_EXCEEDED:
 | |
|     if (Code > 1) {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     IcmpErr = (UINT8) (ICMP6_ERR_TIMXCEED_HOPLIMIT + Code);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case ICMP_V6_PARAMETER_PROBLEM:
 | |
|     if (Code > 3) {
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|     IcmpErr = (UINT8) (ICMP6_ERR_PARAMPROB_HEADER + Code);
 | |
| 
 | |
|     break;
 | |
| 
 | |
|    default:
 | |
| 
 | |
|      return EFI_ABORTED;
 | |
|    }
 | |
| 
 | |
|   //
 | |
|   // Notify user the ICMPv6 packet only containing payload except
 | |
|   // IPv6 basic header, extension header and ICMP header
 | |
|   //
 | |
| 
 | |
|   IpHdr      = (EFI_IP6_HEADER *) (&IcmpHdr->IpHead);
 | |
|   NextHeader = IpHdr->NextHeader;
 | |
|   PayLoadHdr = (UINT8 *) ((UINT8 *) IcmpHdr + sizeof (IP6_ICMP_ERROR_HEAD));
 | |
|   Flag       = TRUE;
 | |
| 
 | |
|   do {
 | |
|     switch (NextHeader) {
 | |
|     case EFI_IP_PROTO_UDP:
 | |
|     case EFI_IP_PROTO_TCP:
 | |
|     case EFI_IP_PROTO_ICMP:
 | |
|     case IP6_NO_NEXT_HEADER:
 | |
|       Flag = FALSE;
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case IP6_HOP_BY_HOP:
 | |
|     case IP6_DESTINATION:
 | |
|       //
 | |
|       // The Hdr Ext Len is 8-bit unsigned integer in 8-octet units, not including
 | |
|       // the first 8 octets.
 | |
|       //
 | |
|       NextHeader = *(PayLoadHdr);
 | |
|       PayLoadHdr = (UINT8 *) (PayLoadHdr + (*(PayLoadHdr + 1) + 1) * 8);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     case IP6_FRAGMENT:
 | |
|       //
 | |
|       // The Fragment Header Length is 8 octets.
 | |
|       //
 | |
|       NextHeader = *(PayLoadHdr);
 | |
|       PayLoadHdr = (UINT8 *) (PayLoadHdr + 8);
 | |
| 
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
| 
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
|   } while (Flag);
 | |
| 
 | |
|   TrimBytes = (UINT32) (PayLoadHdr - (UINT8 *) IcmpHdr);
 | |
| 
 | |
|   NetbufTrim (Pkt, TrimBytes, TRUE);
 | |
| 
 | |
|   //
 | |
|   // If the input packet has invalid format, and TrimBytes is larger than
 | |
|   // the packet size, the NetbufTrim might trim the packet to zero.
 | |
|   //
 | |
|   if (Pkt->TotalSize != 0) {
 | |
|     IpIo->PktRcvdNotify (EFI_ICMP_ERROR, IcmpErr, Session, Pkt, IpIo->RcvdContext);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function handles ICMP packets.
 | |
| 
 | |
|   @param[in]       IpIo            Pointer to the IP_IO instance.
 | |
|   @param[in, out]  Pkt             Pointer to the ICMP packet.
 | |
|   @param[in]       Session         Pointer to the net session of this ICMP packet.
 | |
| 
 | |
|   @retval          EFI_SUCCESS     The ICMP packet is handled successfully.
 | |
|   @retval          EFI_ABORTED     This type of ICMP packet is not supported.
 | |
|   @retval          EFI_UNSUPPORTED The IP protocol version in IP_IO is not supported.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IpIoIcmpHandler (
 | |
|   IN     IP_IO                *IpIo,
 | |
|   IN OUT NET_BUF              *Pkt,
 | |
|   IN     EFI_NET_SESSION_DATA *Session
 | |
|   )
 | |
| {
 | |
| 
 | |
|   if (IpIo->IpVersion == IP_VERSION_4) {
 | |
| 
 | |
|     return IpIoIcmpv4Handler (IpIo, Pkt, Session);
 | |
| 
 | |
|   } else if (IpIo->IpVersion == IP_VERSION_6) {
 | |
| 
 | |
|     return IpIoIcmpv6Handler (IpIo, Pkt, Session);
 | |
| 
 | |
|   } else {
 | |
| 
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Free function for receive token of IP_IO. It is used to
 | |
|   signal the recycle event to notify IP to recycle the
 | |
|   data buffer.
 | |
| 
 | |
|   @param[in]  Event                 The event to be signaled.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoExtFree (
 | |
|   IN VOID  *Event
 | |
|   )
 | |
| {
 | |
|   gBS->SignalEvent ((EFI_EVENT) Event);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Create a send entry to wrap a packet before sending
 | |
|   out it through IP.
 | |
| 
 | |
|   @param[in, out]  IpIo                 Pointer to the IP_IO instance.
 | |
|   @param[in, out]  Pkt                  Pointer to the packet.
 | |
|   @param[in]       Sender               Pointer to the IP sender.
 | |
|   @param[in]       Context              Pointer to the context.
 | |
|   @param[in]       NotifyData           Pointer to the notify data.
 | |
|   @param[in]       Dest                 Pointer to the destination IP address.
 | |
|   @param[in]       Override             Pointer to the overriden IP_IO data.
 | |
| 
 | |
|   @return Pointer to the data structure created to wrap the packet. If any error occurs,
 | |
|           then return NULL.
 | |
| 
 | |
| **/
 | |
| IP_IO_SEND_ENTRY *
 | |
| IpIoCreateSndEntry (
 | |
|   IN OUT IP_IO             *IpIo,
 | |
|   IN OUT NET_BUF           *Pkt,
 | |
|   IN     IP_IO_IP_PROTOCOL Sender,
 | |
|   IN     VOID              *Context    OPTIONAL,
 | |
|   IN     VOID              *NotifyData OPTIONAL,
 | |
|   IN     EFI_IP_ADDRESS    *Dest       OPTIONAL,
 | |
|   IN     IP_IO_OVERRIDE    *Override
 | |
|   )
 | |
| {
 | |
|   IP_IO_SEND_ENTRY          *SndEntry;
 | |
|   EFI_EVENT                 Event;
 | |
|   EFI_STATUS                Status;
 | |
|   NET_FRAGMENT              *ExtFragment;
 | |
|   UINT32                    FragmentCount;
 | |
|   IP_IO_OVERRIDE            *OverrideData;
 | |
|   IP_IO_IP_TX_DATA          *TxData;
 | |
|   EFI_IP4_TRANSMIT_DATA     *Ip4TxData;
 | |
|   EFI_IP6_TRANSMIT_DATA     *Ip6TxData;
 | |
| 
 | |
|   if ((IpIo->IpVersion != IP_VERSION_4) && (IpIo->IpVersion != IP_VERSION_6)) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Event        = NULL;
 | |
|   TxData       = NULL;
 | |
|   OverrideData = NULL;
 | |
| 
 | |
|   //
 | |
|   // Allocate resource for SndEntry
 | |
|   //
 | |
|   SndEntry = AllocatePool (sizeof (IP_IO_SEND_ENTRY));
 | |
|   if (NULL == SndEntry) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   IpIoTransmitHandler,
 | |
|                   SndEntry,
 | |
|                   &Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   FragmentCount = Pkt->BlockOpNum;
 | |
| 
 | |
|   //
 | |
|   // Allocate resource for TxData
 | |
|   //
 | |
|   TxData = (IP_IO_IP_TX_DATA *) AllocatePool (
 | |
|     sizeof (IP_IO_IP_TX_DATA) + sizeof (NET_FRAGMENT) * (FragmentCount - 1)
 | |
|     );
 | |
| 
 | |
|   if (NULL == TxData) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Build a fragment table to contain the fragments in the packet.
 | |
|   //
 | |
|   if (IpIo->IpVersion == IP_VERSION_4) {
 | |
|     ExtFragment = (NET_FRAGMENT *) TxData->Ip4TxData.FragmentTable;
 | |
|   } else {
 | |
|     ExtFragment = (NET_FRAGMENT *) TxData->Ip6TxData.FragmentTable;
 | |
|   }
 | |
| 
 | |
|   NetbufBuildExt (Pkt, ExtFragment, &FragmentCount);
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Allocate resource for OverrideData if needed
 | |
|   //
 | |
|   if (NULL != Override) {
 | |
| 
 | |
|     OverrideData = AllocateCopyPool (sizeof (IP_IO_OVERRIDE), Override);
 | |
|     if (NULL == OverrideData) {
 | |
|       goto ON_ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set other fields of TxData except the fragment table
 | |
|   //
 | |
|   if (IpIo->IpVersion == IP_VERSION_4) {
 | |
| 
 | |
|     Ip4TxData = &TxData->Ip4TxData;
 | |
| 
 | |
|     IP4_COPY_ADDRESS (&Ip4TxData->DestinationAddress, Dest);
 | |
| 
 | |
|     Ip4TxData->OverrideData    = &OverrideData->Ip4OverrideData;
 | |
|     Ip4TxData->OptionsLength   = 0;
 | |
|     Ip4TxData->OptionsBuffer   = NULL;
 | |
|     Ip4TxData->TotalDataLength = Pkt->TotalSize;
 | |
|     Ip4TxData->FragmentCount   = FragmentCount;
 | |
| 
 | |
|     //
 | |
|     // Set the fields of SndToken
 | |
|     //
 | |
|     SndEntry->SndToken.Ip4Token.Event         = Event;
 | |
|     SndEntry->SndToken.Ip4Token.Packet.TxData = Ip4TxData;
 | |
|   } else {
 | |
| 
 | |
|     Ip6TxData = &TxData->Ip6TxData;
 | |
| 
 | |
|     if (Dest != NULL) {
 | |
|       CopyMem (&Ip6TxData->DestinationAddress, Dest, sizeof (EFI_IPv6_ADDRESS));
 | |
|     } else {
 | |
|       ZeroMem (&Ip6TxData->DestinationAddress, sizeof (EFI_IPv6_ADDRESS));
 | |
|     }
 | |
| 
 | |
|     Ip6TxData->OverrideData  = &OverrideData->Ip6OverrideData;
 | |
|     Ip6TxData->DataLength    = Pkt->TotalSize;
 | |
|     Ip6TxData->FragmentCount = FragmentCount;
 | |
|     Ip6TxData->ExtHdrsLength = 0;
 | |
|     Ip6TxData->ExtHdrs       = NULL;
 | |
| 
 | |
|     //
 | |
|     // Set the fields of SndToken
 | |
|     //
 | |
|     SndEntry->SndToken.Ip6Token.Event         = Event;
 | |
|     SndEntry->SndToken.Ip6Token.Packet.TxData = Ip6TxData;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Set the fields of SndEntry
 | |
|   //
 | |
|   SndEntry->IpIo        = IpIo;
 | |
|   SndEntry->Ip          = Sender;
 | |
|   SndEntry->Context     = Context;
 | |
|   SndEntry->NotifyData  = NotifyData;
 | |
| 
 | |
|   SndEntry->Pkt         = Pkt;
 | |
|   NET_GET_REF (Pkt);
 | |
| 
 | |
|   InsertTailList (&IpIo->PendingSndList, &SndEntry->Entry);
 | |
| 
 | |
|   return SndEntry;
 | |
| 
 | |
| ON_ERROR:
 | |
| 
 | |
|   if (OverrideData != NULL) {
 | |
|     FreePool (OverrideData);
 | |
|   }
 | |
| 
 | |
|   if (TxData != NULL) {
 | |
|     FreePool (TxData);
 | |
|   }
 | |
| 
 | |
|   if (SndEntry != NULL) {
 | |
|     FreePool (SndEntry);
 | |
|   }
 | |
| 
 | |
|   if (Event != NULL) {
 | |
|     gBS->CloseEvent (Event);
 | |
|   }
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Destroy the SndEntry.
 | |
| 
 | |
|   This function pairs with IpIoCreateSndEntry().
 | |
| 
 | |
|   @param[in]  SndEntry              Pointer to the send entry to be destroyed.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| IpIoDestroySndEntry (
 | |
|   IN IP_IO_SEND_ENTRY  *SndEntry
 | |
|   )
 | |
| {
 | |
|   EFI_EVENT         Event;
 | |
|   IP_IO_IP_TX_DATA  *TxData;
 | |
|   IP_IO_OVERRIDE    *Override;
 | |
| 
 | |
|   if (SndEntry->IpIo->IpVersion == IP_VERSION_4) {
 | |
|     Event              = SndEntry->SndToken.Ip4Token.Event;
 | |
|     TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip4Token.Packet.TxData;
 | |
|     Override           = (IP_IO_OVERRIDE *) TxData->Ip4TxData.OverrideData;
 | |
|   } else if (SndEntry->IpIo->IpVersion == IP_VERSION_6) {
 | |
|     Event              = SndEntry->SndToken.Ip6Token.Event;
 | |
|     TxData             = (IP_IO_IP_TX_DATA *) SndEntry->SndToken.Ip6Token.Packet.TxData;
 | |
|     Override           = (IP_IO_OVERRIDE *) TxData->Ip6TxData.OverrideData;
 | |
|   } else {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (Event);
 | |
| 
 | |
|   FreePool (TxData);
 | |
| 
 | |
|   if (NULL != Override) {
 | |
|     FreePool (Override);
 | |
|   }
 | |
| 
 | |
|   NetbufFree (SndEntry->Pkt);
 | |
| 
 | |
|   RemoveEntryList (&SndEntry->Entry);
 | |
| 
 | |
|   FreePool (SndEntry);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Notify function for IP transmit token.
 | |
| 
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoTransmitHandlerDpc (
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   IP_IO             *IpIo;
 | |
|   IP_IO_SEND_ENTRY  *SndEntry;
 | |
|   EFI_STATUS        Status;
 | |
| 
 | |
|   SndEntry  = (IP_IO_SEND_ENTRY *) Context;
 | |
| 
 | |
|   IpIo      = SndEntry->IpIo;
 | |
| 
 | |
|   if (IpIo->IpVersion == IP_VERSION_4) {
 | |
|     Status = SndEntry->SndToken.Ip4Token.Status;
 | |
|   } else if (IpIo->IpVersion == IP_VERSION_6){
 | |
|     Status = SndEntry->SndToken.Ip6Token.Status;
 | |
|   } else {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   if ((IpIo->PktSentNotify != NULL) && (SndEntry->NotifyData != NULL)) {
 | |
|     IpIo->PktSentNotify (
 | |
|             Status,
 | |
|             SndEntry->Context,
 | |
|             SndEntry->Ip,
 | |
|             SndEntry->NotifyData
 | |
|             );
 | |
|   }
 | |
| 
 | |
|   IpIoDestroySndEntry (SndEntry);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Notify function for IP transmit token.
 | |
| 
 | |
|   @param[in]  Event                 The event signaled.
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoTransmitHandler (
 | |
|   IN EFI_EVENT Event,
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Request IpIoTransmitHandlerDpc as a DPC at TPL_CALLBACK
 | |
|   //
 | |
|   QueueDpc (TPL_CALLBACK, IpIoTransmitHandlerDpc, Context);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   The dummy handler for the dummy IP receive token.
 | |
| 
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoDummyHandlerDpc (
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   IP_IO_IP_INFO             *IpInfo;
 | |
|   EFI_STATUS                 Status;
 | |
|   EFI_EVENT                  RecycleEvent;
 | |
| 
 | |
|   IpInfo      = (IP_IO_IP_INFO *) Context;
 | |
| 
 | |
|   if ((IpInfo->IpVersion != IP_VERSION_4) && (IpInfo->IpVersion != IP_VERSION_6)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   RecycleEvent = NULL;
 | |
| 
 | |
|   if (IpInfo->IpVersion == IP_VERSION_4) {
 | |
|     Status = IpInfo->DummyRcvToken.Ip4Token.Status;
 | |
| 
 | |
|     if (IpInfo->DummyRcvToken.Ip4Token.Packet.RxData != NULL) {
 | |
|       RecycleEvent = IpInfo->DummyRcvToken.Ip4Token.Packet.RxData->RecycleSignal;
 | |
|     }
 | |
|   } else {
 | |
|     Status = IpInfo->DummyRcvToken.Ip6Token.Status;
 | |
| 
 | |
|     if (IpInfo->DummyRcvToken.Ip6Token.Packet.RxData != NULL) {
 | |
|       RecycleEvent = IpInfo->DummyRcvToken.Ip6Token.Packet.RxData->RecycleSignal;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| 
 | |
| 
 | |
|   if (EFI_ABORTED == Status) {
 | |
|     //
 | |
|     // The reception is actively aborted by the consumer, directly return.
 | |
|     //
 | |
|     return;
 | |
|   } else if (EFI_SUCCESS == Status) {
 | |
|     //
 | |
|     // Recycle the RxData.
 | |
|     //
 | |
|     ASSERT (RecycleEvent != NULL);
 | |
| 
 | |
|     gBS->SignalEvent (RecycleEvent);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Continue the receive.
 | |
|   //
 | |
|   if (IpInfo->IpVersion == IP_VERSION_4) {
 | |
|     IpInfo->Ip.Ip4->Receive (
 | |
|                       IpInfo->Ip.Ip4,
 | |
|                       &IpInfo->DummyRcvToken.Ip4Token
 | |
|                       );
 | |
|   } else {
 | |
|     IpInfo->Ip.Ip6->Receive (
 | |
|                       IpInfo->Ip.Ip6,
 | |
|                       &IpInfo->DummyRcvToken.Ip6Token
 | |
|                       );
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   This function add IpIoDummyHandlerDpc to the end of the DPC queue.
 | |
| 
 | |
|   @param[in]  Event                 The event signaled.
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoDummyHandler (
 | |
|   IN EFI_EVENT Event,
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Request IpIoDummyHandlerDpc as a DPC at TPL_CALLBACK
 | |
|   //
 | |
|   QueueDpc (TPL_CALLBACK, IpIoDummyHandlerDpc, Context);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Notify function for the IP receive token, used to process
 | |
|   the received IP packets.
 | |
| 
 | |
|   @param[in]  Context               The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoListenHandlerDpc (
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   IP_IO                 *IpIo;
 | |
|   EFI_STATUS            Status;
 | |
|   IP_IO_IP_RX_DATA      *RxData;
 | |
|   EFI_NET_SESSION_DATA  Session;
 | |
|   NET_BUF               *Pkt;
 | |
| 
 | |
|   IpIo = (IP_IO *) Context;
 | |
| 
 | |
|   if (IpIo->IpVersion == IP_VERSION_4) {
 | |
|     Status = IpIo->RcvToken.Ip4Token.Status;
 | |
|     RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip4Token.Packet.RxData;
 | |
|   } else if (IpIo->IpVersion == IP_VERSION_6) {
 | |
|     Status = IpIo->RcvToken.Ip6Token.Status;
 | |
|     RxData = (IP_IO_IP_RX_DATA *) IpIo->RcvToken.Ip6Token.Packet.RxData;
 | |
|   } else {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (EFI_ABORTED == Status) {
 | |
|     //
 | |
|     // The reception is actively aborted by the consumer, directly return.
 | |
|     //
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if ((EFI_SUCCESS != Status) && (EFI_ICMP_ERROR != Status)) {
 | |
|     //
 | |
|     // Only process the normal packets and the icmp error packets.
 | |
|     //
 | |
|     if (RxData != NULL) {
 | |
|       goto CleanUp;
 | |
|     } else {
 | |
|       goto Resume;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // if RxData is NULL with Status == EFI_SUCCESS or EFI_ICMP_ERROR, this should be a code issue in the low layer (IP).
 | |
|   //
 | |
|   ASSERT (RxData != NULL);
 | |
|   if (RxData == NULL) {
 | |
|     goto Resume;
 | |
|   }
 | |
| 
 | |
|   if (NULL == IpIo->PktRcvdNotify) {
 | |
|     goto CleanUp;
 | |
|   }
 | |
| 
 | |
|   if (IpIo->IpVersion == IP_VERSION_4) {
 | |
|     ASSERT (RxData->Ip4RxData.Header != NULL);
 | |
|     if (IP4_IS_LOCAL_BROADCAST (EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress))) {
 | |
|       //
 | |
|       // The source address is a broadcast address, discard it.
 | |
|       //
 | |
|       goto CleanUp;
 | |
|     }
 | |
|     if ((EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress) != 0) &&
 | |
|         (IpIo->SubnetMask != 0) &&
 | |
|         IP4_NET_EQUAL (IpIo->StationIp, EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask) &&
 | |
|         !NetIp4IsUnicast (EFI_NTOHL (((EFI_IP4_RECEIVE_DATA *) RxData)->Header->SourceAddress), IpIo->SubnetMask)) {
 | |
|       //
 | |
|       // The source address doesn't match StationIp and it's not a unicast IP address, discard it.
 | |
|       //
 | |
|       goto CleanUp;
 | |
|     }
 | |
| 
 | |
|     if (RxData->Ip4RxData.DataLength == 0) {
 | |
|       //
 | |
|       // Discard zero length data payload packet.
 | |
|       //
 | |
|       goto CleanUp;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // The fragment should always be valid for non-zero length packet.
 | |
|     //
 | |
|     ASSERT (RxData->Ip4RxData.FragmentCount != 0);
 | |
| 
 | |
|     //
 | |
|     // Create a netbuffer representing IPv4 packet
 | |
|     //
 | |
|     Pkt = NetbufFromExt (
 | |
|             (NET_FRAGMENT *) RxData->Ip4RxData.FragmentTable,
 | |
|             RxData->Ip4RxData.FragmentCount,
 | |
|             0,
 | |
|             0,
 | |
|             IpIoExtFree,
 | |
|             RxData->Ip4RxData.RecycleSignal
 | |
|             );
 | |
|     if (NULL == Pkt) {
 | |
|       goto CleanUp;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Create a net session
 | |
|     //
 | |
|     Session.Source.Addr[0] = EFI_IP4 (RxData->Ip4RxData.Header->SourceAddress);
 | |
|     Session.Dest.Addr[0]   = EFI_IP4 (RxData->Ip4RxData.Header->DestinationAddress);
 | |
|     Session.IpHdr.Ip4Hdr   = RxData->Ip4RxData.Header;
 | |
|     Session.IpHdrLen       = RxData->Ip4RxData.HeaderLength;
 | |
|     Session.IpVersion      = IP_VERSION_4;
 | |
|   } else {
 | |
|     ASSERT (RxData->Ip6RxData.Header != NULL);
 | |
|     if (!NetIp6IsValidUnicast(&RxData->Ip6RxData.Header->SourceAddress)) {
 | |
|       goto CleanUp;
 | |
|     }
 | |
| 
 | |
|     if (RxData->Ip6RxData.DataLength == 0) {
 | |
|       //
 | |
|       // Discard zero length data payload packet.
 | |
|       //
 | |
|       goto CleanUp;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // The fragment should always be valid for non-zero length packet.
 | |
|     //
 | |
|     ASSERT (RxData->Ip6RxData.FragmentCount != 0);
 | |
| 
 | |
|     //
 | |
|     // Create a netbuffer representing IPv6 packet
 | |
|     //
 | |
|     Pkt = NetbufFromExt (
 | |
|             (NET_FRAGMENT *) RxData->Ip6RxData.FragmentTable,
 | |
|             RxData->Ip6RxData.FragmentCount,
 | |
|             0,
 | |
|             0,
 | |
|             IpIoExtFree,
 | |
|             RxData->Ip6RxData.RecycleSignal
 | |
|             );
 | |
|     if (NULL == Pkt) {
 | |
|       goto CleanUp;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Create a net session
 | |
|     //
 | |
|     CopyMem (
 | |
|       &Session.Source,
 | |
|       &RxData->Ip6RxData.Header->SourceAddress,
 | |
|       sizeof(EFI_IPv6_ADDRESS)
 | |
|       );
 | |
|     CopyMem (
 | |
|       &Session.Dest,
 | |
|       &RxData->Ip6RxData.Header->DestinationAddress,
 | |
|       sizeof(EFI_IPv6_ADDRESS)
 | |
|       );
 | |
|     Session.IpHdr.Ip6Hdr = RxData->Ip6RxData.Header;
 | |
|     Session.IpHdrLen     = RxData->Ip6RxData.HeaderLength;
 | |
|     Session.IpVersion    = IP_VERSION_6;
 | |
|   }
 | |
| 
 | |
|   if (EFI_SUCCESS == Status) {
 | |
| 
 | |
|     IpIo->PktRcvdNotify (EFI_SUCCESS, 0, &Session, Pkt, IpIo->RcvdContext);
 | |
|   } else {
 | |
|     //
 | |
|     // Status is EFI_ICMP_ERROR
 | |
|     //
 | |
|     Status = IpIoIcmpHandler (IpIo, Pkt, &Session);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       NetbufFree (Pkt);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   goto Resume;
 | |
| 
 | |
| CleanUp:
 | |
| 
 | |
|   if (IpIo->IpVersion == IP_VERSION_4){
 | |
|     gBS->SignalEvent (RxData->Ip4RxData.RecycleSignal);
 | |
|   } else {
 | |
|     gBS->SignalEvent (RxData->Ip6RxData.RecycleSignal);
 | |
|   }
 | |
| 
 | |
| Resume:
 | |
| 
 | |
|   if (IpIo->IpVersion == IP_VERSION_4){
 | |
|     IpIo->Ip.Ip4->Receive (IpIo->Ip.Ip4, &(IpIo->RcvToken.Ip4Token));
 | |
|   } else {
 | |
|     IpIo->Ip.Ip6->Receive (IpIo->Ip.Ip6, &(IpIo->RcvToken.Ip6Token));
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function add IpIoListenHandlerDpc to the end of the DPC queue.
 | |
| 
 | |
|   @param[in]  Event                The event signaled.
 | |
|   @param[in]  Context              The context passed in by the event notifier.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoListenHandler (
 | |
|   IN EFI_EVENT Event,
 | |
|   IN VOID      *Context
 | |
|   )
 | |
| {
 | |
|   //
 | |
|   // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK
 | |
|   //
 | |
|   QueueDpc (TPL_CALLBACK, IpIoListenHandlerDpc, Context);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Create a new IP_IO instance.
 | |
| 
 | |
|   If IpVersion is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
 | |
| 
 | |
|   This function uses IP4/IP6 service binding protocol in Controller to create
 | |
|   an IP4/IP6 child (aka IP4/IP6 instance).
 | |
| 
 | |
|   @param[in]  Image             The image handle of the driver or application that
 | |
|                                 consumes IP_IO.
 | |
|   @param[in]  Controller        The controller handle that has IP4 or IP6 service
 | |
|                                 binding protocol installed.
 | |
|   @param[in]  IpVersion         The version of the IP protocol to use, either
 | |
|                                 IPv4 or IPv6.
 | |
| 
 | |
|   @return Pointer to a newly created IP_IO instance, or NULL if failed.
 | |
| 
 | |
| **/
 | |
| IP_IO *
 | |
| EFIAPI
 | |
| IpIoCreate (
 | |
|   IN EFI_HANDLE Image,
 | |
|   IN EFI_HANDLE Controller,
 | |
|   IN UINT8      IpVersion
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   IP_IO       *IpIo;
 | |
|   EFI_EVENT   Event;
 | |
| 
 | |
|   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 | |
| 
 | |
|   IpIo = AllocateZeroPool (sizeof (IP_IO));
 | |
|   if (NULL == IpIo) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   InitializeListHead (&(IpIo->PendingSndList));
 | |
|   InitializeListHead (&(IpIo->IpList));
 | |
|   IpIo->Controller  = Controller;
 | |
|   IpIo->Image       = Image;
 | |
|   IpIo->IpVersion   = IpVersion;
 | |
|   Event             = NULL;
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   IpIoListenHandler,
 | |
|                   IpIo,
 | |
|                   &Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ReleaseIpIo;
 | |
|   }
 | |
| 
 | |
|   if (IpVersion == IP_VERSION_4) {
 | |
|     IpIo->RcvToken.Ip4Token.Event = Event;
 | |
|   } else {
 | |
|     IpIo->RcvToken.Ip6Token.Event = Event;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create an IP child and open IP protocol
 | |
|   //
 | |
|   Status = IpIoCreateIpChildOpenProtocol (
 | |
|              Controller,
 | |
|              Image,
 | |
|              &IpIo->ChildHandle,
 | |
|              IpVersion,
 | |
|              (VOID **) & (IpIo->Ip)
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ReleaseIpIo;
 | |
|   }
 | |
| 
 | |
|   return IpIo;
 | |
| 
 | |
| ReleaseIpIo:
 | |
| 
 | |
|   if (Event != NULL) {
 | |
|     gBS->CloseEvent (Event);
 | |
|   }
 | |
| 
 | |
|   gBS->FreePool (IpIo);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Open an IP_IO instance for use.
 | |
| 
 | |
|   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
 | |
| 
 | |
|   This function is called after IpIoCreate(). It is used for configuring the IP
 | |
|   instance and register the callbacks and their context data for sending and
 | |
|   receiving IP packets.
 | |
| 
 | |
|   @param[in, out]  IpIo               Pointer to an IP_IO instance that needs
 | |
|                                       to open.
 | |
|   @param[in]       OpenData           The configuration data and callbacks for
 | |
|                                       the IP_IO instance.
 | |
| 
 | |
|   @retval          EFI_SUCCESS            The IP_IO instance opened with OpenData
 | |
|                                           successfully.
 | |
|   @retval          EFI_ACCESS_DENIED      The IP_IO instance is configured, avoid to
 | |
|                                           reopen it.
 | |
|   @retval          EFI_UNSUPPORTED        IPv4 RawData mode is no supported.
 | |
|   @retval          EFI_INVALID_PARAMETER  Invalid input parameter.
 | |
|   @retval          Others                 Error condition occurred.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoOpen (
 | |
|   IN OUT IP_IO           *IpIo,
 | |
|   IN     IP_IO_OPEN_DATA *OpenData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   UINT8             IpVersion;
 | |
| 
 | |
|   if (IpIo == NULL || OpenData == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (IpIo->IsConfigured) {
 | |
|     return EFI_ACCESS_DENIED;
 | |
|   }
 | |
| 
 | |
|   IpVersion = IpIo->IpVersion;
 | |
| 
 | |
|   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 | |
| 
 | |
|   //
 | |
|   // configure ip
 | |
|   //
 | |
|   if (IpVersion == IP_VERSION_4){
 | |
|     //
 | |
|     // RawData mode is no supported.
 | |
|     //
 | |
|     ASSERT (!OpenData->IpConfigData.Ip4CfgData.RawData);
 | |
|     if (OpenData->IpConfigData.Ip4CfgData.RawData) {
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|     if (!OpenData->IpConfigData.Ip4CfgData.UseDefaultAddress) {
 | |
|       IpIo->StationIp = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.StationAddress);
 | |
|       IpIo->SubnetMask = EFI_NTOHL (OpenData->IpConfigData.Ip4CfgData.SubnetMask);
 | |
|     }
 | |
| 
 | |
|     Status = IpIo->Ip.Ip4->Configure (
 | |
|                              IpIo->Ip.Ip4,
 | |
|                              &OpenData->IpConfigData.Ip4CfgData
 | |
|                              );
 | |
|   } else {
 | |
| 
 | |
|     Status = IpIo->Ip.Ip6->Configure (
 | |
|                              IpIo->Ip.Ip6,
 | |
|                              &OpenData->IpConfigData.Ip6CfgData
 | |
|                              );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // @bug To delete the default route entry in this Ip, if it is:
 | |
|   // @bug (0.0.0.0, 0.0.0.0, 0.0.0.0). Delete this statement if Ip modified
 | |
|   // @bug its code
 | |
|   //
 | |
|   if (IpVersion == IP_VERSION_4){
 | |
|     Status = IpIo->Ip.Ip4->Routes (
 | |
|                              IpIo->Ip.Ip4,
 | |
|                              TRUE,
 | |
|                              &mZeroIp4Addr,
 | |
|                              &mZeroIp4Addr,
 | |
|                              &mZeroIp4Addr
 | |
|                              );
 | |
| 
 | |
|     if (EFI_ERROR (Status) && (EFI_NOT_FOUND != Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   IpIo->PktRcvdNotify = OpenData->PktRcvdNotify;
 | |
|   IpIo->PktSentNotify = OpenData->PktSentNotify;
 | |
| 
 | |
|   IpIo->RcvdContext   = OpenData->RcvdContext;
 | |
|   IpIo->SndContext    = OpenData->SndContext;
 | |
| 
 | |
|   if (IpVersion == IP_VERSION_4){
 | |
|     IpIo->Protocol = OpenData->IpConfigData.Ip4CfgData.DefaultProtocol;
 | |
| 
 | |
|     //
 | |
|     // start to listen incoming packet
 | |
|     //
 | |
|     Status = IpIo->Ip.Ip4->Receive (
 | |
|                              IpIo->Ip.Ip4,
 | |
|                              &(IpIo->RcvToken.Ip4Token)
 | |
|                              );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
| 
 | |
|     IpIo->Protocol = OpenData->IpConfigData.Ip6CfgData.DefaultProtocol;
 | |
|     Status = IpIo->Ip.Ip6->Receive (
 | |
|                              IpIo->Ip.Ip6,
 | |
|                              &(IpIo->RcvToken.Ip6Token)
 | |
|                              );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   IpIo->IsConfigured = TRUE;
 | |
|   InsertTailList (&mActiveIpIoList, &IpIo->Entry);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop an IP_IO instance.
 | |
| 
 | |
|   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
 | |
| 
 | |
|   This function is paired with IpIoOpen(). The IP_IO will be unconfigured and all
 | |
|   the pending send/receive tokens will be canceled.
 | |
| 
 | |
|   @param[in, out]  IpIo            Pointer to the IP_IO instance that needs to stop.
 | |
| 
 | |
|   @retval          EFI_SUCCESS            The IP_IO instance stopped successfully.
 | |
|   @retval          EFI_INVALID_PARAMETER  Invalid input parameter.
 | |
|   @retval          Others                 Error condition occurred.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoStop (
 | |
|   IN OUT IP_IO *IpIo
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   IP_IO_IP_INFO     *IpInfo;
 | |
|   UINT8             IpVersion;
 | |
| 
 | |
|   if (IpIo == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (!IpIo->IsConfigured) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   IpVersion = IpIo->IpVersion;
 | |
| 
 | |
|   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 | |
| 
 | |
|   //
 | |
|   // Remove the IpIo from the active IpIo list.
 | |
|   //
 | |
|   RemoveEntryList (&IpIo->Entry);
 | |
| 
 | |
|   //
 | |
|   // Configure NULL Ip
 | |
|   //
 | |
|   if (IpVersion == IP_VERSION_4) {
 | |
|     Status = IpIo->Ip.Ip4->Configure (IpIo->Ip.Ip4, NULL);
 | |
|   } else {
 | |
|     Status = IpIo->Ip.Ip6->Configure (IpIo->Ip.Ip6, NULL);
 | |
|   }
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   IpIo->IsConfigured = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Detroy the Ip List used by IpIo
 | |
|   //
 | |
| 
 | |
|   while (!IsListEmpty (&(IpIo->IpList))) {
 | |
|     IpInfo = NET_LIST_HEAD (&(IpIo->IpList), IP_IO_IP_INFO, Entry);
 | |
| 
 | |
|     IpIoRemoveIp (IpIo, IpInfo);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // All pending send tokens should be flushed by resetting the IP instances.
 | |
|   //
 | |
|   ASSERT (IsListEmpty (&IpIo->PendingSndList));
 | |
| 
 | |
|   //
 | |
|   // Close the receive event.
 | |
|   //
 | |
|   if (IpVersion == IP_VERSION_4){
 | |
|     gBS->CloseEvent (IpIo->RcvToken.Ip4Token.Event);
 | |
|   } else {
 | |
|     gBS->CloseEvent (IpIo->RcvToken.Ip6Token.Event);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Destroy an IP_IO instance.
 | |
| 
 | |
|   This function is paired with IpIoCreate(). The IP_IO will be closed first.
 | |
|   Resource will be freed afterwards. See IpIoCloseProtocolDestroyIpChild().
 | |
| 
 | |
|   @param[in, out]  IpIo         Pointer to the IP_IO instance that needs to be
 | |
|                                 destroyed.
 | |
| 
 | |
|   @retval          EFI_SUCCESS  The IP_IO instance destroyed successfully.
 | |
|   @retval          Others       Error condition occurred.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoDestroy (
 | |
|   IN OUT IP_IO *IpIo
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
| 
 | |
|   //
 | |
|   // Stop the IpIo.
 | |
|   //
 | |
|   Status = IpIoStop (IpIo);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Close the IP protocol and destroy the child.
 | |
|   //
 | |
|   Status = IpIoCloseProtocolDestroyIpChild (
 | |
|              IpIo->Controller,
 | |
|              IpIo->Image,
 | |
|              IpIo->ChildHandle,
 | |
|              IpIo->IpVersion
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   gBS->FreePool (IpIo);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Send out an IP packet.
 | |
| 
 | |
|   This function is called after IpIoOpen(). The data to be sent is wrapped in
 | |
|   Pkt. The IP instance wrapped in IpIo is used for sending by default but can be
 | |
|   overriden by Sender. Other sending configs, like source address and gateway
 | |
|   address etc., are specified in OverrideData.
 | |
| 
 | |
|   @param[in, out]  IpIo                  Pointer to an IP_IO instance used for sending IP
 | |
|                                          packet.
 | |
|   @param[in, out]  Pkt                   Pointer to the IP packet to be sent.
 | |
|   @param[in]       Sender                The IP protocol instance used for sending.
 | |
|   @param[in]       Context               Optional context data.
 | |
|   @param[in]       NotifyData            Optional notify data.
 | |
|   @param[in]       Dest                  The destination IP address to send this packet to.
 | |
|                                          This parameter is optional when using IPv6.
 | |
|   @param[in]       OverrideData          The data to override some configuration of the IP
 | |
|                                          instance used for sending.
 | |
| 
 | |
|   @retval          EFI_SUCCESS           The operation is completed successfully.
 | |
|   @retval          EFI_INVALID_PARAMETER The input parameter is not correct.
 | |
|   @retval          EFI_NOT_STARTED       The IpIo is not configured.
 | |
|   @retval          EFI_OUT_OF_RESOURCES  Failed due to resource limit.
 | |
|   @retval          Others                Error condition occurred.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoSend (
 | |
|   IN OUT IP_IO          *IpIo,
 | |
|   IN OUT NET_BUF        *Pkt,
 | |
|   IN     IP_IO_IP_INFO  *Sender        OPTIONAL,
 | |
|   IN     VOID           *Context       OPTIONAL,
 | |
|   IN     VOID           *NotifyData    OPTIONAL,
 | |
|   IN     EFI_IP_ADDRESS *Dest          OPTIONAL,
 | |
|   IN     IP_IO_OVERRIDE *OverrideData  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   IP_IO_IP_PROTOCOL Ip;
 | |
|   IP_IO_SEND_ENTRY  *SndEntry;
 | |
| 
 | |
|   if ((IpIo == NULL) || (Pkt == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((IpIo->IpVersion == IP_VERSION_4) && (Dest == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (!IpIo->IsConfigured) {
 | |
|     return EFI_NOT_STARTED;
 | |
|   }
 | |
| 
 | |
|   Ip = (NULL == Sender) ? IpIo->Ip : Sender->Ip;
 | |
| 
 | |
|   //
 | |
|   // create a new SndEntry
 | |
|   //
 | |
|   SndEntry = IpIoCreateSndEntry (IpIo, Pkt, Ip, Context, NotifyData, Dest, OverrideData);
 | |
|   if (NULL == SndEntry) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Send this Packet
 | |
|   //
 | |
|   if (IpIo->IpVersion == IP_VERSION_4){
 | |
|     Status = Ip.Ip4->Transmit (
 | |
|                        Ip.Ip4,
 | |
|                        &SndEntry->SndToken.Ip4Token
 | |
|                        );
 | |
|   } else {
 | |
|     Status = Ip.Ip6->Transmit (
 | |
|                        Ip.Ip6,
 | |
|                        &SndEntry->SndToken.Ip6Token
 | |
|                        );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     IpIoDestroySndEntry (SndEntry);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Cancel the IP transmit token which wraps this Packet.
 | |
| 
 | |
|   If IpIo is NULL, then ASSERT().
 | |
|   If Packet is NULL, then ASSERT().
 | |
| 
 | |
|   @param[in]  IpIo                  Pointer to the IP_IO instance.
 | |
|   @param[in]  Packet                Pointer to the packet of NET_BUF to cancel.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoCancelTxToken (
 | |
|   IN IP_IO  *IpIo,
 | |
|   IN VOID   *Packet
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY        *Node;
 | |
|   IP_IO_SEND_ENTRY  *SndEntry;
 | |
|   IP_IO_IP_PROTOCOL Ip;
 | |
| 
 | |
|   ASSERT ((IpIo != NULL) && (Packet != NULL));
 | |
| 
 | |
|   NET_LIST_FOR_EACH (Node, &IpIo->PendingSndList) {
 | |
| 
 | |
|     SndEntry = NET_LIST_USER_STRUCT (Node, IP_IO_SEND_ENTRY, Entry);
 | |
| 
 | |
|     if (SndEntry->Pkt == Packet) {
 | |
| 
 | |
|       Ip = SndEntry->Ip;
 | |
| 
 | |
|       if (IpIo->IpVersion == IP_VERSION_4) {
 | |
|         Ip.Ip4->Cancel (
 | |
|                   Ip.Ip4,
 | |
|                   &SndEntry->SndToken.Ip4Token
 | |
|                   );
 | |
|       } else {
 | |
|         Ip.Ip6->Cancel (
 | |
|                   Ip.Ip6,
 | |
|                   &SndEntry->SndToken.Ip6Token
 | |
|                   );
 | |
|       }
 | |
| 
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Add a new IP instance for sending data.
 | |
| 
 | |
|   If IpIo is NULL, then ASSERT().
 | |
|   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
 | |
| 
 | |
|   The function is used to add the IP_IO to the IP_IO sending list. The caller
 | |
|   can later use IpIoFindSender() to get the IP_IO and call IpIoSend() to send
 | |
|   data.
 | |
| 
 | |
|   @param[in, out]  IpIo               Pointer to a IP_IO instance to add a new IP
 | |
|                                       instance for sending purpose.
 | |
| 
 | |
|   @return Pointer to the created IP_IO_IP_INFO structure, NULL if failed.
 | |
| 
 | |
| **/
 | |
| IP_IO_IP_INFO *
 | |
| EFIAPI
 | |
| IpIoAddIp (
 | |
|   IN OUT IP_IO  *IpIo
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
|   IP_IO_IP_INFO  *IpInfo;
 | |
|   EFI_EVENT      Event;
 | |
| 
 | |
|   ASSERT (IpIo != NULL);
 | |
|   ASSERT ((IpIo->IpVersion == IP_VERSION_4) || (IpIo->IpVersion == IP_VERSION_6));
 | |
| 
 | |
|   IpInfo = AllocatePool (sizeof (IP_IO_IP_INFO));
 | |
|   if (IpInfo == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Init this IpInfo, set the Addr and SubnetMask to 0 before we configure the IP
 | |
|   // instance.
 | |
|   //
 | |
|   InitializeListHead (&IpInfo->Entry);
 | |
|   IpInfo->ChildHandle = NULL;
 | |
|   ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
 | |
|   ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
 | |
| 
 | |
|   IpInfo->RefCnt    = 1;
 | |
|   IpInfo->IpVersion = IpIo->IpVersion;
 | |
| 
 | |
|   //
 | |
|   // Create the IP instance and open the IP protocol.
 | |
|   //
 | |
|   Status = IpIoCreateIpChildOpenProtocol (
 | |
|              IpIo->Controller,
 | |
|              IpIo->Image,
 | |
|              &IpInfo->ChildHandle,
 | |
|              IpInfo->IpVersion,
 | |
|              (VOID **) &IpInfo->Ip
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ReleaseIpInfo;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create the event for the DummyRcvToken.
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   IpIoDummyHandler,
 | |
|                   IpInfo,
 | |
|                   &Event
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ReleaseIpChild;
 | |
|   }
 | |
| 
 | |
|   if (IpInfo->IpVersion == IP_VERSION_4) {
 | |
|     IpInfo->DummyRcvToken.Ip4Token.Event = Event;
 | |
|   } else {
 | |
|     IpInfo->DummyRcvToken.Ip6Token.Event = Event;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Link this IpInfo into the IpIo.
 | |
|   //
 | |
|   InsertTailList (&IpIo->IpList, &IpInfo->Entry);
 | |
| 
 | |
|   return IpInfo;
 | |
| 
 | |
| ReleaseIpChild:
 | |
| 
 | |
|   IpIoCloseProtocolDestroyIpChild (
 | |
|     IpIo->Controller,
 | |
|     IpIo->Image,
 | |
|     IpInfo->ChildHandle,
 | |
|     IpInfo->IpVersion
 | |
|     );
 | |
| 
 | |
| ReleaseIpInfo:
 | |
| 
 | |
|   gBS->FreePool (IpInfo);
 | |
| 
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Configure the IP instance of this IpInfo and start the receiving if IpConfigData
 | |
|   is not NULL.
 | |
| 
 | |
|   If IpInfo is NULL, then ASSERT().
 | |
|   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
 | |
| 
 | |
|   @param[in, out]  IpInfo          Pointer to the IP_IO_IP_INFO instance.
 | |
|   @param[in, out]  IpConfigData    The IP configure data used to configure the IP
 | |
|                                    instance, if NULL the IP instance is reset. If
 | |
|                                    UseDefaultAddress is set to TRUE, and the configure
 | |
|                                    operation succeeds, the default address information
 | |
|                                    is written back in this IpConfigData.
 | |
| 
 | |
|   @retval          EFI_SUCCESS     The IP instance of this IpInfo is configured successfully
 | |
|                                    or no need to reconfigure it.
 | |
|   @retval          Others          Configuration fails.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoConfigIp (
 | |
|   IN OUT IP_IO_IP_INFO        *IpInfo,
 | |
|   IN OUT VOID                 *IpConfigData OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS         Status;
 | |
|   IP_IO_IP_PROTOCOL  Ip;
 | |
|   UINT8              IpVersion;
 | |
|   EFI_IP4_MODE_DATA  Ip4ModeData;
 | |
|   EFI_IP6_MODE_DATA  Ip6ModeData;
 | |
| 
 | |
|   ASSERT (IpInfo != NULL);
 | |
| 
 | |
|   if (IpInfo->RefCnt > 1) {
 | |
|     //
 | |
|     // This IP instance is shared, don't reconfigure it until it has only one
 | |
|     // consumer. Currently, only the tcp children cloned from their passive parent
 | |
|     // will share the same IP. So this cases only happens while IpConfigData is NULL,
 | |
|     // let the last consumer clean the IP instance.
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   IpVersion = IpInfo->IpVersion;
 | |
|   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 | |
| 
 | |
|   Ip = IpInfo->Ip;
 | |
| 
 | |
|   if (IpInfo->IpVersion == IP_VERSION_4) {
 | |
|     Status = Ip.Ip4->Configure (Ip.Ip4, IpConfigData);
 | |
|   } else {
 | |
|     Status = Ip.Ip6->Configure (Ip.Ip6, IpConfigData);
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (IpConfigData != NULL) {
 | |
|     if (IpInfo->IpVersion == IP_VERSION_4) {
 | |
| 
 | |
|       if (((EFI_IP4_CONFIG_DATA *) IpConfigData)->UseDefaultAddress) {
 | |
|         Status = Ip.Ip4->GetModeData (
 | |
|                            Ip.Ip4,
 | |
|                            &Ip4ModeData,
 | |
|                            NULL,
 | |
|                            NULL
 | |
|                            );
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           Ip.Ip4->Configure (Ip.Ip4, NULL);
 | |
|           return Status;
 | |
|         }
 | |
| 
 | |
|         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->StationAddress, &Ip4ModeData.ConfigData.StationAddress);
 | |
|         IP4_COPY_ADDRESS (&((EFI_IP4_CONFIG_DATA*) IpConfigData)->SubnetMask, &Ip4ModeData.ConfigData.SubnetMask);
 | |
|       }
 | |
| 
 | |
|       CopyMem (
 | |
|         &IpInfo->Addr.Addr,
 | |
|         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->StationAddress,
 | |
|         sizeof (IP4_ADDR)
 | |
|         );
 | |
|       CopyMem (
 | |
|         &IpInfo->PreMask.SubnetMask,
 | |
|         &((EFI_IP4_CONFIG_DATA *) IpConfigData)->SubnetMask,
 | |
|         sizeof (IP4_ADDR)
 | |
|         );
 | |
| 
 | |
|       Status = Ip.Ip4->Receive (
 | |
|                          Ip.Ip4,
 | |
|                          &IpInfo->DummyRcvToken.Ip4Token
 | |
|                          );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Ip.Ip4->Configure (Ip.Ip4, NULL);
 | |
|       }
 | |
|     } else {
 | |
|       Status = Ip.Ip6->GetModeData (
 | |
|                          Ip.Ip6,
 | |
|                          &Ip6ModeData,
 | |
|                          NULL,
 | |
|                          NULL
 | |
|                          );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Ip.Ip6->Configure (Ip.Ip6, NULL);
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       if (Ip6ModeData.IsConfigured) {
 | |
|         CopyMem (
 | |
|           &((EFI_IP6_CONFIG_DATA *) IpConfigData)->StationAddress,
 | |
|           &Ip6ModeData.ConfigData.StationAddress,
 | |
|           sizeof (EFI_IPv6_ADDRESS)
 | |
|           );
 | |
| 
 | |
|         if (Ip6ModeData.AddressList != NULL) {
 | |
|           FreePool (Ip6ModeData.AddressList);
 | |
|         }
 | |
| 
 | |
|         if (Ip6ModeData.GroupTable != NULL) {
 | |
|           FreePool (Ip6ModeData.GroupTable);
 | |
|         }
 | |
| 
 | |
|         if (Ip6ModeData.RouteTable != NULL) {
 | |
|           FreePool (Ip6ModeData.RouteTable);
 | |
|         }
 | |
| 
 | |
|         if (Ip6ModeData.NeighborCache != NULL) {
 | |
|           FreePool (Ip6ModeData.NeighborCache);
 | |
|         }
 | |
| 
 | |
|         if (Ip6ModeData.PrefixTable != NULL) {
 | |
|           FreePool (Ip6ModeData.PrefixTable);
 | |
|         }
 | |
| 
 | |
|         if (Ip6ModeData.IcmpTypeList != NULL) {
 | |
|           FreePool (Ip6ModeData.IcmpTypeList);
 | |
|         }
 | |
| 
 | |
|       } else {
 | |
|         Status = EFI_NO_MAPPING;
 | |
|         return Status;
 | |
|       }
 | |
| 
 | |
|       CopyMem (
 | |
|         &IpInfo->Addr,
 | |
|         &Ip6ModeData.ConfigData.StationAddress,
 | |
|         sizeof (EFI_IPv6_ADDRESS)
 | |
|         );
 | |
| 
 | |
|       Status = Ip.Ip6->Receive (
 | |
|                          Ip.Ip6,
 | |
|                          &IpInfo->DummyRcvToken.Ip6Token
 | |
|                          );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Ip.Ip6->Configure (Ip.Ip6, NULL);
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // The IP instance is reset, set the stored Addr and SubnetMask to zero.
 | |
|     //
 | |
|     ZeroMem (&IpInfo->Addr, sizeof (IpInfo->Addr));
 | |
|     ZeroMem (&IpInfo->PreMask, sizeof (IpInfo->PreMask));
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Destroy an IP instance maintained in IpIo->IpList for
 | |
|   sending purpose.
 | |
| 
 | |
|   If Ip version is not IP_VERSION_4 or IP_VERSION_6, then ASSERT().
 | |
| 
 | |
|   This function pairs with IpIoAddIp(). The IpInfo is previously created by
 | |
|   IpIoAddIp(). The IP_IO_IP_INFO::RefCnt is decremented and the IP instance
 | |
|   will be dstroyed if the RefCnt is zero.
 | |
| 
 | |
|   @param[in]  IpIo                  Pointer to the IP_IO instance.
 | |
|   @param[in]  IpInfo                Pointer to the IpInfo to be removed.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| IpIoRemoveIp (
 | |
|   IN IP_IO            *IpIo,
 | |
|   IN IP_IO_IP_INFO    *IpInfo
 | |
|   )
 | |
| {
 | |
| 
 | |
|   UINT8               IpVersion;
 | |
| 
 | |
|   if (IpIo == NULL || IpInfo == NULL) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   ASSERT (IpInfo->RefCnt > 0);
 | |
| 
 | |
|   NET_PUT_REF (IpInfo);
 | |
| 
 | |
|   if (IpInfo->RefCnt > 0) {
 | |
| 
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   IpVersion = IpIo->IpVersion;
 | |
| 
 | |
|   ASSERT ((IpVersion == IP_VERSION_4) || (IpVersion == IP_VERSION_6));
 | |
| 
 | |
|   RemoveEntryList (&IpInfo->Entry);
 | |
| 
 | |
|   if (IpVersion == IP_VERSION_4){
 | |
|     IpInfo->Ip.Ip4->Configure (
 | |
|                       IpInfo->Ip.Ip4,
 | |
|                       NULL
 | |
|                       );
 | |
|     IpIoCloseProtocolDestroyIpChild (
 | |
|       IpIo->Controller,
 | |
|       IpIo->Image,
 | |
|       IpInfo->ChildHandle,
 | |
|       IP_VERSION_4
 | |
|       );
 | |
| 
 | |
|     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip4Token.Event);
 | |
| 
 | |
|   } else {
 | |
| 
 | |
|     IpInfo->Ip.Ip6->Configure (
 | |
|                       IpInfo->Ip.Ip6,
 | |
|                       NULL
 | |
|                       );
 | |
| 
 | |
|     IpIoCloseProtocolDestroyIpChild (
 | |
|       IpIo->Controller,
 | |
|       IpIo->Image,
 | |
|       IpInfo->ChildHandle,
 | |
|       IP_VERSION_6
 | |
|       );
 | |
| 
 | |
|     gBS->CloseEvent (IpInfo->DummyRcvToken.Ip6Token.Event);
 | |
|   }
 | |
| 
 | |
|   FreePool (IpInfo);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Find the first IP protocol maintained in IpIo whose local
 | |
|   address is the same as Src.
 | |
| 
 | |
|   This function is called when the caller needs the IpIo to send data to the
 | |
|   specified Src. The IpIo was added previously by IpIoAddIp().
 | |
| 
 | |
|   @param[in, out]  IpIo              Pointer to the pointer of the IP_IO instance.
 | |
|   @param[in]       IpVersion         The version of the IP protocol to use, either
 | |
|                                      IPv4 or IPv6.
 | |
|   @param[in]       Src               The local IP address.
 | |
| 
 | |
|   @return Pointer to the IP protocol can be used for sending purpose and its local
 | |
|           address is the same with Src. NULL if failed.
 | |
| 
 | |
| **/
 | |
| IP_IO_IP_INFO *
 | |
| EFIAPI
 | |
| IpIoFindSender (
 | |
|   IN OUT IP_IO           **IpIo,
 | |
|   IN     UINT8           IpVersion,
 | |
|   IN     EFI_IP_ADDRESS  *Src
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY      *IpIoEntry;
 | |
|   IP_IO           *IpIoPtr;
 | |
|   LIST_ENTRY      *IpInfoEntry;
 | |
|   IP_IO_IP_INFO   *IpInfo;
 | |
| 
 | |
|   if (IpIo == NULL || Src == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   if ((IpVersion != IP_VERSION_4) && (IpVersion != IP_VERSION_6)) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   NET_LIST_FOR_EACH (IpIoEntry, &mActiveIpIoList) {
 | |
|     IpIoPtr = NET_LIST_USER_STRUCT (IpIoEntry, IP_IO, Entry);
 | |
| 
 | |
|     if (((*IpIo != NULL) && (*IpIo != IpIoPtr)) || (IpIoPtr->IpVersion != IpVersion)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     NET_LIST_FOR_EACH (IpInfoEntry, &IpIoPtr->IpList) {
 | |
|       IpInfo = NET_LIST_USER_STRUCT (IpInfoEntry, IP_IO_IP_INFO, Entry);
 | |
|       if (IpInfo->IpVersion == IP_VERSION_4){
 | |
| 
 | |
|         if (EFI_IP4_EQUAL (&IpInfo->Addr.v4, &Src->v4)) {
 | |
|           *IpIo = IpIoPtr;
 | |
|           return IpInfo;
 | |
|         }
 | |
| 
 | |
|       } else {
 | |
| 
 | |
|         if (EFI_IP6_EQUAL (&IpInfo->Addr.v6, &Src->v6)) {
 | |
|           *IpIo = IpIoPtr;
 | |
|           return IpInfo;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No match.
 | |
|   //
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Get the ICMP error map information.
 | |
| 
 | |
|   The ErrorStatus will be returned. The IsHard and Notify are optional. If they
 | |
|   are not NULL, this routine will fill them.
 | |
| 
 | |
|   @param[in]   IcmpError             IcmpError Type.
 | |
|   @param[in]   IpVersion             The version of the IP protocol to use,
 | |
|                                      either IPv4 or IPv6.
 | |
|   @param[out]  IsHard                If TRUE, indicates that it is a hard error.
 | |
|   @param[out]  Notify                If TRUE, SockError needs to be notified.
 | |
| 
 | |
|   @retval EFI_UNSUPPORTED            Unrecognizable ICMP error code.
 | |
|   @return ICMP Error Status, such as EFI_NETWORK_UNREACHABLE.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoGetIcmpErrStatus (
 | |
|   IN  UINT8       IcmpError,
 | |
|   IN  UINT8       IpVersion,
 | |
|   OUT BOOLEAN     *IsHard  OPTIONAL,
 | |
|   OUT BOOLEAN     *Notify  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   if (IpVersion == IP_VERSION_4 ) {
 | |
|     ASSERT (IcmpError <= ICMP_ERR_PARAMPROB);
 | |
| 
 | |
|     if (IsHard != NULL) {
 | |
|       *IsHard = mIcmpErrMap[IcmpError].IsHard;
 | |
|     }
 | |
| 
 | |
|     if (Notify != NULL) {
 | |
|       *Notify = mIcmpErrMap[IcmpError].Notify;
 | |
|     }
 | |
| 
 | |
|     switch (IcmpError) {
 | |
|     case ICMP_ERR_UNREACH_NET:
 | |
|       return  EFI_NETWORK_UNREACHABLE;
 | |
| 
 | |
|     case ICMP_ERR_TIMXCEED_INTRANS:
 | |
|     case ICMP_ERR_TIMXCEED_REASS:
 | |
|     case ICMP_ERR_UNREACH_HOST:
 | |
|       return  EFI_HOST_UNREACHABLE;
 | |
| 
 | |
|     case ICMP_ERR_UNREACH_PROTOCOL:
 | |
|       return  EFI_PROTOCOL_UNREACHABLE;
 | |
| 
 | |
|     case ICMP_ERR_UNREACH_PORT:
 | |
|       return  EFI_PORT_UNREACHABLE;
 | |
| 
 | |
|     case ICMP_ERR_MSGSIZE:
 | |
|     case ICMP_ERR_UNREACH_SRCFAIL:
 | |
|     case ICMP_ERR_QUENCH:
 | |
|     case ICMP_ERR_PARAMPROB:
 | |
|       return  EFI_ICMP_ERROR;
 | |
| 
 | |
|     default:
 | |
|       ASSERT (FALSE);
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|   } else if (IpVersion == IP_VERSION_6) {
 | |
| 
 | |
|     ASSERT (IcmpError <= ICMP6_ERR_PARAMPROB_IPV6OPTION);
 | |
| 
 | |
|     if (IsHard != NULL) {
 | |
|       *IsHard = mIcmp6ErrMap[IcmpError].IsHard;
 | |
|     }
 | |
| 
 | |
|     if (Notify != NULL) {
 | |
|       *Notify = mIcmp6ErrMap[IcmpError].Notify;
 | |
|     }
 | |
| 
 | |
|     switch (IcmpError) {
 | |
|     case ICMP6_ERR_UNREACH_NET:
 | |
|       return EFI_NETWORK_UNREACHABLE;
 | |
| 
 | |
|     case ICMP6_ERR_UNREACH_HOST:
 | |
|     case ICMP6_ERR_TIMXCEED_HOPLIMIT:
 | |
|     case ICMP6_ERR_TIMXCEED_REASS:
 | |
|       return EFI_HOST_UNREACHABLE;
 | |
| 
 | |
|     case ICMP6_ERR_UNREACH_PROTOCOL:
 | |
|       return EFI_PROTOCOL_UNREACHABLE;
 | |
| 
 | |
|     case ICMP6_ERR_UNREACH_PORT:
 | |
|       return EFI_PORT_UNREACHABLE;
 | |
| 
 | |
|     case ICMP6_ERR_PACKAGE_TOOBIG:
 | |
|     case ICMP6_ERR_PARAMPROB_HEADER:
 | |
|     case ICMP6_ERR_PARAMPROB_NEXHEADER:
 | |
|     case ICMP6_ERR_PARAMPROB_IPV6OPTION:
 | |
|       return EFI_ICMP_ERROR;
 | |
| 
 | |
|     default:
 | |
|       ASSERT (FALSE);
 | |
|       return EFI_UNSUPPORTED;
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
|     //
 | |
|     // Should never be here
 | |
|     //
 | |
|     ASSERT (FALSE);
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Refresh the remote peer's Neighbor Cache entries.
 | |
| 
 | |
|   This function is called when the caller needs the IpIo to refresh the existing
 | |
|   IPv6 neighbor cache entries since the neighbor is considered reachable by the
 | |
|   node has recently received a confirmation that packets sent recently to the
 | |
|   neighbor were received by its IP layer.
 | |
| 
 | |
|   @param[in]   IpIo                  Pointer to an IP_IO instance
 | |
|   @param[in]   Neighbor              The IP address of the neighbor
 | |
|   @param[in]   Timeout               Time in 100-ns units that this entry will
 | |
|                                      remain in the neighbor cache. A value of
 | |
|                                      zero means that the entry is permanent.
 | |
|                                      A value of non-zero means that the entry is
 | |
|                                      dynamic and will be deleted after Timeout.
 | |
| 
 | |
|   @retval      EFI_SUCCESS           The operation is completed successfully.
 | |
|   @retval      EFI_NOT_STARTED       The IpIo is not configured.
 | |
|   @retval      EFI_INVALID_PARAMETER Neighbor Address is invalid.
 | |
|   @retval      EFI_NOT_FOUND         The neighbor cache entry is not in the
 | |
|                                      neighbor table.
 | |
|   @retval      EFI_UNSUPPORTED       IP version is IPv4, which doesn't support neighbor cache refresh.
 | |
|   @retval      EFI_OUT_OF_RESOURCES  Failed due to resource limit.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IpIoRefreshNeighbor (
 | |
|   IN IP_IO           *IpIo,
 | |
|   IN EFI_IP_ADDRESS  *Neighbor,
 | |
|   IN UINT32          Timeout
 | |
|   )
 | |
| {
 | |
|   EFI_IP6_PROTOCOL  *Ip;
 | |
| 
 | |
|   if (!IpIo->IsConfigured) {
 | |
|     return EFI_NOT_STARTED;
 | |
|   }
 | |
| 
 | |
|   if (IpIo->IpVersion != IP_VERSION_6) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Ip = IpIo->Ip.Ip6;
 | |
| 
 | |
|   return Ip->Neighbors (Ip, FALSE, &Neighbor->v6, NULL, Timeout, TRUE);
 | |
| }
 | |
| 
 |