mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-11-04 05:25:45 +01:00 
			
		
		
		
	Signed-off-by: Tian, Hot <hot.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15155 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1008 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1008 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This library is used to share code between UEFI network stack modules.
 | 
						|
  It provides the helper routines to access TCP service.
 | 
						|
 | 
						|
Copyright (c) 2010 - 2011, 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<BR>
 | 
						|
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 <Library/TcpIoLib.h>
 | 
						|
#include <Library/BaseLib.h>
 | 
						|
#include <Library/DebugLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/BaseMemoryLib.h>
 | 
						|
 | 
						|
/**
 | 
						|
  The common notify function associated with various TcpIo events. 
 | 
						|
 | 
						|
  @param[in]  Event   The event signaled.
 | 
						|
  @param[in]  Context The context.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TcpIoCommonNotify (
 | 
						|
  IN EFI_EVENT  Event,
 | 
						|
  IN VOID       *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  if ((Event == NULL) || (Context == NULL)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  *((BOOLEAN *) Context) = TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The internal function for delay configuring TCP6 when IP6 driver is still in DAD.
 | 
						|
 | 
						|
  @param[in]  Tcp6               The EFI_TCP6_PROTOCOL protocol instance.
 | 
						|
  @param[in]  Tcp6ConfigData     The Tcp6 configuration data.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The operational settings successfully
 | 
						|
                                 completed.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
  @retval Others                 Failed to finish the operation.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
TcpIoGetMapping (
 | 
						|
  IN EFI_TCP6_PROTOCOL    *Tcp6,
 | 
						|
  IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS              Status;
 | 
						|
  EFI_EVENT               Event;
 | 
						|
 | 
						|
  if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Event  = NULL;
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_TIMER,
 | 
						|
                  TPL_CALLBACK,
 | 
						|
                  NULL,
 | 
						|
                  NULL,
 | 
						|
                  &Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->SetTimer (
 | 
						|
                  Event,
 | 
						|
                  TimerRelative,
 | 
						|
                  TCP_GET_MAPPING_TIMEOUT
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  while (EFI_ERROR (gBS->CheckEvent (Event))) {
 | 
						|
 | 
						|
    Tcp6->Poll (Tcp6);
 | 
						|
 | 
						|
    Status = Tcp6->Configure (Tcp6, Tcp6ConfigData);
 | 
						|
 | 
						|
    if (!EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
 | 
						|
  if (Event != NULL) {
 | 
						|
    gBS->CloseEvent (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create a TCP socket with the specified configuration data. 
 | 
						|
 | 
						|
  @param[in]  Image      The handle of the driver image.
 | 
						|
  @param[in]  Controller The handle of the controller.
 | 
						|
  @param[in]  TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.
 | 
						|
  @param[in]  ConfigData The Tcp configuration data.
 | 
						|
  @param[out] TcpIo      The TcpIo.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS            The TCP socket is created and configured.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
  @retval EFI_UNSUPPORTED        One or more of the control options are not
 | 
						|
                                 supported in the implementation.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
 | 
						|
  @retval Others                 Failed to create the TCP socket or configure it.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpIoCreateSocket (
 | 
						|
  IN EFI_HANDLE             Image,
 | 
						|
  IN EFI_HANDLE             Controller,
 | 
						|
  IN UINT8                  TcpVersion,
 | 
						|
  IN TCP_IO_CONFIG_DATA     *ConfigData,
 | 
						|
  OUT TCP_IO                *TcpIo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_EVENT                 Event;
 | 
						|
  EFI_GUID                  *ServiceBindingGuid;
 | 
						|
  EFI_GUID                  *ProtocolGuid;
 | 
						|
  VOID                      **Interface;
 | 
						|
  EFI_TCP4_OPTION           ControlOption;
 | 
						|
  EFI_TCP4_CONFIG_DATA      Tcp4ConfigData;
 | 
						|
  EFI_TCP4_ACCESS_POINT     *AccessPoint4;
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_CONFIG_DATA      Tcp6ConfigData;
 | 
						|
  EFI_TCP6_ACCESS_POINT     *AccessPoint6;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
  EFI_TCP4_RECEIVE_DATA     *RxData;
 | 
						|
 | 
						|
  if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Tcp4 = NULL;
 | 
						|
  Tcp6 = NULL;
 | 
						|
 | 
						|
  ZeroMem (TcpIo, sizeof (TCP_IO));
 | 
						|
 | 
						|
  if (TcpVersion == TCP_VERSION_4) {
 | 
						|
    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
 | 
						|
    ProtocolGuid       = &gEfiTcp4ProtocolGuid;
 | 
						|
    Interface          = (VOID **) (&TcpIo->Tcp.Tcp4);
 | 
						|
  } else if (TcpVersion == TCP_VERSION_6) {
 | 
						|
    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
 | 
						|
    ProtocolGuid       = &gEfiTcp6ProtocolGuid;
 | 
						|
    Interface          = (VOID **) (&TcpIo->Tcp.Tcp6);
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->TcpVersion = TcpVersion;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create the TCP child instance and get the TCP protocol.
 | 
						|
  //  
 | 
						|
  Status = NetLibCreateServiceChild (
 | 
						|
             Controller,
 | 
						|
             Image,
 | 
						|
             ServiceBindingGuid,
 | 
						|
             &TcpIo->Handle
 | 
						|
             );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  TcpIo->Handle,
 | 
						|
                  ProtocolGuid,
 | 
						|
                  Interface,
 | 
						|
                  Image,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status) || (*Interface == NULL)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (TcpVersion == TCP_VERSION_4) {
 | 
						|
    Tcp4             = TcpIo->Tcp.Tcp4;
 | 
						|
  } else {
 | 
						|
    Tcp6             = TcpIo->Tcp.Tcp6;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->Image       = Image;
 | 
						|
  TcpIo->Controller  = Controller;
 | 
						|
 | 
						|
  //
 | 
						|
  // Set the configuration parameters.
 | 
						|
  //
 | 
						|
  ControlOption.ReceiveBufferSize       = 0x200000;
 | 
						|
  ControlOption.SendBufferSize          = 0x200000;
 | 
						|
  ControlOption.MaxSynBackLog           = 0;
 | 
						|
  ControlOption.ConnectionTimeout       = 0;
 | 
						|
  ControlOption.DataRetries             = 6;
 | 
						|
  ControlOption.FinTimeout              = 0;
 | 
						|
  ControlOption.TimeWaitTimeout         = 0;
 | 
						|
  ControlOption.KeepAliveProbes         = 4;
 | 
						|
  ControlOption.KeepAliveTime           = 0;
 | 
						|
  ControlOption.KeepAliveInterval       = 0;
 | 
						|
  ControlOption.EnableNagle             = FALSE;
 | 
						|
  ControlOption.EnableTimeStamp         = FALSE;
 | 
						|
  ControlOption.EnableWindowScaling     = TRUE;
 | 
						|
  ControlOption.EnableSelectiveAck      = FALSE;
 | 
						|
  ControlOption.EnablePathMtuDiscovery  = FALSE;
 | 
						|
 | 
						|
  if (TcpVersion == TCP_VERSION_4) {
 | 
						|
    Tcp4ConfigData.TypeOfService        = 8;
 | 
						|
    Tcp4ConfigData.TimeToLive           = 255;
 | 
						|
    Tcp4ConfigData.ControlOption        = &ControlOption;
 | 
						|
 | 
						|
    AccessPoint4                        = &Tcp4ConfigData.AccessPoint;
 | 
						|
 | 
						|
    ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT));
 | 
						|
    AccessPoint4->StationPort           = ConfigData->Tcp4IoConfigData.StationPort;
 | 
						|
    AccessPoint4->RemotePort            = ConfigData->Tcp4IoConfigData.RemotePort;
 | 
						|
    AccessPoint4->ActiveFlag            = ConfigData->Tcp4IoConfigData.ActiveFlag;
 | 
						|
 | 
						|
    CopyMem (
 | 
						|
      &AccessPoint4->StationAddress,
 | 
						|
      &ConfigData->Tcp4IoConfigData.LocalIp,
 | 
						|
      sizeof (EFI_IPv4_ADDRESS)
 | 
						|
      );
 | 
						|
    CopyMem (
 | 
						|
      &AccessPoint4->SubnetMask,
 | 
						|
      &ConfigData->Tcp4IoConfigData.SubnetMask,
 | 
						|
      sizeof (EFI_IPv4_ADDRESS)
 | 
						|
      );
 | 
						|
    CopyMem (
 | 
						|
      &AccessPoint4->RemoteAddress,
 | 
						|
      &ConfigData->Tcp4IoConfigData.RemoteIp,
 | 
						|
      sizeof (EFI_IPv4_ADDRESS)
 | 
						|
      );
 | 
						|
 | 
						|
    ASSERT (Tcp4 != NULL);
 | 
						|
 | 
						|
    //
 | 
						|
    // Configure the TCP4 protocol.
 | 
						|
    //
 | 
						|
    Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
    if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) {
 | 
						|
      //
 | 
						|
      // The gateway is not zero. Add the default route manually.
 | 
						|
      //
 | 
						|
      Status = Tcp4->Routes (
 | 
						|
                       Tcp4,
 | 
						|
                       FALSE,
 | 
						|
                       &mZeroIp4Addr,
 | 
						|
                       &mZeroIp4Addr,
 | 
						|
                       &ConfigData->Tcp4IoConfigData.Gateway
 | 
						|
                       );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        goto ON_ERROR;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Tcp6ConfigData.TrafficClass         = 0;
 | 
						|
    Tcp6ConfigData.HopLimit             = 255;
 | 
						|
    Tcp6ConfigData.ControlOption        = (EFI_TCP6_OPTION *) &ControlOption;
 | 
						|
 | 
						|
    AccessPoint6                        = &Tcp6ConfigData.AccessPoint;
 | 
						|
 | 
						|
    ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT));
 | 
						|
    AccessPoint6->StationPort           = ConfigData->Tcp6IoConfigData.StationPort;
 | 
						|
    AccessPoint6->RemotePort            = ConfigData->Tcp6IoConfigData.RemotePort;
 | 
						|
    AccessPoint6->ActiveFlag            = ConfigData->Tcp6IoConfigData.ActiveFlag;
 | 
						|
 | 
						|
    IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp);
 | 
						|
 | 
						|
 | 
						|
    ASSERT (Tcp6 != NULL);
 | 
						|
    //
 | 
						|
    // Configure the TCP6 protocol.
 | 
						|
    //
 | 
						|
    Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData);
 | 
						|
    if (Status == EFI_NO_MAPPING) {
 | 
						|
      Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData);
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Create events for variuos asynchronous operations.
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TcpIoCommonNotify,
 | 
						|
                  &TcpIo->IsConnDone,
 | 
						|
                  &Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event;
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TcpIoCommonNotify,
 | 
						|
                  &TcpIo->IsListenDone,
 | 
						|
                  &Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event;
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TcpIoCommonNotify,
 | 
						|
                  &TcpIo->IsTxDone,
 | 
						|
                  &Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event;
 | 
						|
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TcpIoCommonNotify,
 | 
						|
                  &TcpIo->IsRxDone,
 | 
						|
                  &Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event;
 | 
						|
 | 
						|
  RxData = (EFI_TCP4_RECEIVE_DATA *) AllocateZeroPool (sizeof (EFI_TCP4_RECEIVE_DATA));
 | 
						|
  if (RxData == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->RxToken.Tcp4Token.Packet.RxData = RxData;
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EVT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  TcpIoCommonNotify,
 | 
						|
                  &TcpIo->IsCloseDone,
 | 
						|
                  &Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event;
 | 
						|
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  TcpIoDestroySocket (TcpIo);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
  
 | 
						|
/**
 | 
						|
  Destroy the socket. 
 | 
						|
 | 
						|
  @param[in]  TcpIo The TcpIo which wraps the socket to be destroyed.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TcpIoDestroySocket (
 | 
						|
  IN TCP_IO                 *TcpIo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_EVENT                 Event;
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
  UINT8                     TcpVersion;
 | 
						|
  EFI_GUID                  *ServiceBindingGuid;
 | 
						|
  EFI_GUID                  *ProtocolGuid;
 | 
						|
  EFI_HANDLE                ChildHandle;
 | 
						|
 | 
						|
  if (TcpIo == NULL) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpVersion = TcpIo->TcpVersion;
 | 
						|
 | 
						|
  if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event;
 | 
						|
 | 
						|
  if (Event != NULL) {
 | 
						|
    gBS->CloseEvent (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event;
 | 
						|
 | 
						|
  if (Event != NULL) {
 | 
						|
    gBS->CloseEvent (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event;
 | 
						|
 | 
						|
  if (Event != NULL) {
 | 
						|
    gBS->CloseEvent (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event;
 | 
						|
 | 
						|
  if (Event != NULL) {
 | 
						|
    gBS->CloseEvent (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event;
 | 
						|
 | 
						|
  if (Event != NULL) {
 | 
						|
    gBS->CloseEvent (Event);
 | 
						|
  }
 | 
						|
 | 
						|
  if (TcpIo->RxToken.Tcp4Token.Packet.RxData != NULL) {
 | 
						|
    FreePool (TcpIo->RxToken.Tcp4Token.Packet.RxData);
 | 
						|
  }
 | 
						|
 | 
						|
  Tcp4 = NULL;
 | 
						|
  Tcp6 = NULL;
 | 
						|
 | 
						|
 | 
						|
  if (TcpVersion == TCP_VERSION_4) {
 | 
						|
    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;
 | 
						|
    ProtocolGuid       = &gEfiTcp4ProtocolGuid;
 | 
						|
    Tcp4 = TcpIo->Tcp.Tcp4;
 | 
						|
    if (Tcp4 != NULL) {
 | 
						|
      Tcp4->Configure (Tcp4, NULL);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;
 | 
						|
    ProtocolGuid       = &gEfiTcp6ProtocolGuid;
 | 
						|
    Tcp6 = TcpIo->Tcp.Tcp6;
 | 
						|
    if (Tcp6 != NULL) {
 | 
						|
      Tcp6->Configure (Tcp6, NULL);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Tcp4 != NULL) || (Tcp6 != NULL)) {
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
           TcpIo->Handle,
 | 
						|
           ProtocolGuid,
 | 
						|
           TcpIo->Image,
 | 
						|
           TcpIo->Controller
 | 
						|
           );
 | 
						|
  }
 | 
						|
 | 
						|
  ChildHandle = NULL;
 | 
						|
 | 
						|
  if (TcpIo->IsListenDone) {
 | 
						|
    if (TcpVersion == TCP_VERSION_4) {
 | 
						|
      Tcp4 = TcpIo->NewTcp.Tcp4;
 | 
						|
      if (Tcp4 != NULL) {
 | 
						|
        Tcp4->Configure (Tcp4, NULL);
 | 
						|
        ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      Tcp6 = TcpIo->NewTcp.Tcp6;
 | 
						|
      if (Tcp6 != NULL) {
 | 
						|
        Tcp6->Configure (Tcp6, NULL);
 | 
						|
        ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (ChildHandle != NULL) {
 | 
						|
 | 
						|
      gBS->CloseProtocol (
 | 
						|
             ChildHandle,
 | 
						|
             ProtocolGuid,
 | 
						|
             TcpIo->Image,
 | 
						|
             TcpIo->Controller
 | 
						|
             );
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  NetLibDestroyServiceChild (
 | 
						|
    TcpIo->Controller,
 | 
						|
    TcpIo->Image,
 | 
						|
    ServiceBindingGuid,
 | 
						|
    TcpIo->Handle
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Connect to the other endpoint of the TCP socket.
 | 
						|
 | 
						|
  @param[in, out]  TcpIo     The TcpIo wrapping the TCP socket.
 | 
						|
  @param[in]       Timeout   The time to wait for connection done.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS            Connect to the other endpoint of the TCP socket
 | 
						|
                                 successfully.
 | 
						|
  @retval EFI_TIMEOUT            Failed to connect to the other endpoint of the
 | 
						|
                                 TCP socket in the specified time period.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
  @retval EFI_UNSUPPORTED        One or more of the control options are not
 | 
						|
                                 supported in the implementation.
 | 
						|
  @retval Others                 Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpIoConnect (
 | 
						|
  IN OUT TCP_IO             *TcpIo,
 | 
						|
  IN     EFI_EVENT          Timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->IsConnDone = FALSE;
 | 
						|
 | 
						|
  Tcp4 = NULL;
 | 
						|
  Tcp6 = NULL;
 | 
						|
 | 
						|
  if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
    Tcp4   = TcpIo->Tcp.Tcp4;
 | 
						|
    Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token);
 | 
						|
  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
 | 
						|
    Tcp6   = TcpIo->Tcp.Tcp6;
 | 
						|
    Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token);
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!TcpIo->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
 | 
						|
    if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
      Tcp4->Poll (Tcp4);
 | 
						|
    } else {
 | 
						|
      Tcp6->Poll (Tcp6);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!TcpIo->IsConnDone) {
 | 
						|
    Status = EFI_TIMEOUT;
 | 
						|
  } else {
 | 
						|
    Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Accept the incomding request from the other endpoint of the TCP socket.
 | 
						|
 | 
						|
  @param[in, out]  TcpIo     The TcpIo wrapping the TCP socket.
 | 
						|
  @param[in]       Timeout   The time to wait for connection done.
 | 
						|
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS            Connect to the other endpoint of the TCP socket
 | 
						|
                                 successfully.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
  @retval EFI_UNSUPPORTED        One or more of the control options are not
 | 
						|
                                 supported in the implementation.
 | 
						|
 | 
						|
  @retval EFI_TIMEOUT            Failed to connect to the other endpoint of the
 | 
						|
                                 TCP socket in the specified time period.                      
 | 
						|
  @retval Others                 Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpIoAccept (
 | 
						|
  IN OUT TCP_IO             *TcpIo,
 | 
						|
  IN     EFI_EVENT          Timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  EFI_GUID                  *ProtocolGuid;
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
 | 
						|
  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->IsListenDone = FALSE;
 | 
						|
 | 
						|
  Tcp4 = NULL;
 | 
						|
  Tcp6 = NULL;
 | 
						|
 | 
						|
  if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
    Tcp4   = TcpIo->Tcp.Tcp4;
 | 
						|
    Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token);
 | 
						|
  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
 | 
						|
    Tcp6   = TcpIo->Tcp.Tcp6;
 | 
						|
    Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token);
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!TcpIo->IsListenDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
 | 
						|
    if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
      Tcp4->Poll (Tcp4);
 | 
						|
    } else {
 | 
						|
      Tcp6->Poll (Tcp6);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!TcpIo->IsListenDone) {
 | 
						|
    Status = EFI_TIMEOUT;
 | 
						|
  } else {
 | 
						|
    Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // The new TCP instance handle created for the established connection is 
 | 
						|
  // in ListenToken.
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
      ProtocolGuid = &gEfiTcp4ProtocolGuid;
 | 
						|
    } else {
 | 
						|
      ProtocolGuid = &gEfiTcp6ProtocolGuid;
 | 
						|
    }
 | 
						|
    
 | 
						|
    Status = gBS->OpenProtocol (
 | 
						|
                    TcpIo->ListenToken.Tcp4Token.NewChildHandle,
 | 
						|
                    ProtocolGuid,
 | 
						|
                    (VOID **) (&TcpIo->NewTcp.Tcp4),
 | 
						|
                    TcpIo->Image,
 | 
						|
                    TcpIo->Controller,
 | 
						|
                    EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                    );
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Reset the socket.
 | 
						|
 | 
						|
  @param[in, out]  TcpIo The TcpIo wrapping the TCP socket.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
TcpIoReset (
 | 
						|
  IN OUT TCP_IO             *TcpIo
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->IsCloseDone = FALSE;
 | 
						|
  Tcp4               = NULL;
 | 
						|
  Tcp6               = NULL;
 | 
						|
 | 
						|
  if (TcpIo->TcpVersion == TCP_VERSION_4) { 
 | 
						|
    TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE;
 | 
						|
    Tcp4 = TcpIo->Tcp.Tcp4;
 | 
						|
    Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token);
 | 
						|
  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
 | 
						|
    TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE;
 | 
						|
    Tcp6 = TcpIo->Tcp.Tcp6;
 | 
						|
    Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token);
 | 
						|
  } else {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!TcpIo->IsCloseDone) {
 | 
						|
    if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
      Tcp4->Poll (Tcp4);
 | 
						|
    } else {
 | 
						|
      Tcp6->Poll (Tcp6);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
  
 | 
						|
/**
 | 
						|
  Transmit the Packet to the other endpoint of the socket.
 | 
						|
 | 
						|
  @param[in]   TcpIo           The TcpIo wrapping the TCP socket.
 | 
						|
  @param[in]   Packet          The packet to transmit.
 | 
						|
  
 | 
						|
  @retval EFI_SUCCESS            The packet is trasmitted.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
  @retval EFI_UNSUPPORTED        One or more of the control options are not
 | 
						|
                                 supported in the implementation.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.
 | 
						|
  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.
 | 
						|
  @retval Others                 Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpIoTransmit (
 | 
						|
  IN TCP_IO                 *TcpIo,
 | 
						|
  IN NET_BUF                *Packet
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  VOID                      *Data;
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
  UINTN                     Size;
 | 
						|
 | 
						|
  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
 | 
						|
    Size = sizeof (EFI_TCP4_TRANSMIT_DATA) + 
 | 
						|
           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
 | 
						|
  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
 | 
						|
    Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
 | 
						|
           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  Data = AllocatePool (Size);
 | 
						|
  if (Data == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push        = TRUE;
 | 
						|
  ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
 | 
						|
  ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the fragment table.
 | 
						|
  //
 | 
						|
  ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
 | 
						|
 | 
						|
  NetbufBuildExt (
 | 
						|
    Packet,
 | 
						|
    (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
 | 
						|
    &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
 | 
						|
    );
 | 
						|
 | 
						|
  Tcp4   = NULL;
 | 
						|
  Tcp6   = NULL;
 | 
						|
  Status = EFI_DEVICE_ERROR;
 | 
						|
 | 
						|
  //
 | 
						|
  // Trasnmit the packet.
 | 
						|
  //
 | 
						|
  if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
    TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
 | 
						|
    Tcp4    = TcpIo->Tcp.Tcp4;
 | 
						|
    if (TcpIo->IsListenDone) {
 | 
						|
      Tcp4 = TcpIo->NewTcp.Tcp4;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tcp4 == NULL) {
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
    
 | 
						|
    Status  = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token);
 | 
						|
  } else {
 | 
						|
    TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
 | 
						|
    Tcp6    = TcpIo->Tcp.Tcp6;
 | 
						|
    if (TcpIo->IsListenDone) {
 | 
						|
      Tcp6 = TcpIo->NewTcp.Tcp6;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tcp6 == NULL) {
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    Status  = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token);
 | 
						|
  }
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!TcpIo->IsTxDone) {
 | 
						|
    if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
      Tcp4->Poll (Tcp4);
 | 
						|
    } else {
 | 
						|
      Tcp6->Poll (Tcp6);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  TcpIo->IsTxDone  = FALSE;
 | 
						|
  Status           = TcpIo->TxToken.Tcp4Token.CompletionToken.Status;
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
 | 
						|
  FreePool (Data);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Receive data from the socket.
 | 
						|
 | 
						|
  @param[in, out]  TcpIo       The TcpIo which wraps the socket to be destroyed.
 | 
						|
  @param[in]       Packet      The buffer to hold the data copy from the socket rx buffer.
 | 
						|
  @param[in]       AsyncMode   Is this receive asyncronous or not.
 | 
						|
  @param[in]       Timeout     The time to wait for receiving the amount of data the Packet
 | 
						|
                               can hold.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS            The required amount of data is received from the socket.
 | 
						|
  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.
 | 
						|
  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES   Failed to allocate momery.
 | 
						|
  @retval EFI_TIMEOUT            Failed to receive the required amount of data in the
 | 
						|
                                 specified time period.
 | 
						|
  @retval Others                 Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
TcpIoReceive (
 | 
						|
  IN OUT TCP_IO             *TcpIo,
 | 
						|
  IN     NET_BUF            *Packet,
 | 
						|
  IN     BOOLEAN            AsyncMode,
 | 
						|
  IN     EFI_EVENT          Timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_TCP4_PROTOCOL         *Tcp4;
 | 
						|
  EFI_TCP6_PROTOCOL         *Tcp6;
 | 
						|
  EFI_TCP4_RECEIVE_DATA     *RxData;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  NET_FRAGMENT              *Fragment;
 | 
						|
  UINT32                    FragmentCount;
 | 
						|
  UINT32                    CurrentFragment;
 | 
						|
 | 
						|
  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  RxData = TcpIo->RxToken.Tcp4Token.Packet.RxData;
 | 
						|
  if (RxData == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Tcp4 = NULL;
 | 
						|
  Tcp6 = NULL;
 | 
						|
 | 
						|
  if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
    Tcp4 = TcpIo->Tcp.Tcp4;
 | 
						|
 | 
						|
    if (TcpIo->IsListenDone) {
 | 
						|
      Tcp4 = TcpIo->NewTcp.Tcp4;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tcp4 == NULL) {
 | 
						|
      return EFI_DEVICE_ERROR;
 | 
						|
    }
 | 
						|
 | 
						|
  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {
 | 
						|
    Tcp6 = TcpIo->Tcp.Tcp6;
 | 
						|
 | 
						|
    if (TcpIo->IsListenDone) {
 | 
						|
      Tcp6 = TcpIo->NewTcp.Tcp6;
 | 
						|
    }
 | 
						|
 | 
						|
    if (Tcp6 == NULL) {
 | 
						|
      return EFI_DEVICE_ERROR; 
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  FragmentCount = Packet->BlockOpNum;
 | 
						|
  Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
 | 
						|
  if (Fragment == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Build the fragment table.
 | 
						|
  //
 | 
						|
  NetbufBuildExt (Packet, Fragment, &FragmentCount);
 | 
						|
 | 
						|
  RxData->FragmentCount         = 1;
 | 
						|
  CurrentFragment               = 0;
 | 
						|
  Status                        = EFI_SUCCESS;
 | 
						|
 | 
						|
  while (CurrentFragment < FragmentCount) {
 | 
						|
    RxData->DataLength                       = Fragment[CurrentFragment].Len;
 | 
						|
    RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
 | 
						|
    RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
 | 
						|
 | 
						|
    if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
      Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token);
 | 
						|
    } else {
 | 
						|
      Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token);
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
    
 | 
						|
    while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
 | 
						|
      //
 | 
						|
      // Poll until some data is received or an error occurs.
 | 
						|
      //
 | 
						|
      if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
        Tcp4->Poll (Tcp4);
 | 
						|
      } else {
 | 
						|
        Tcp6->Poll (Tcp6);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!TcpIo->IsRxDone) {
 | 
						|
      //
 | 
						|
      // Timeout occurs, cancel the receive request.
 | 
						|
      //
 | 
						|
      if (TcpIo->TcpVersion == TCP_VERSION_4) {
 | 
						|
        Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken);
 | 
						|
      } else {
 | 
						|
        Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken);
 | 
						|
      }
 | 
						|
 | 
						|
      Status = EFI_TIMEOUT;
 | 
						|
      goto ON_EXIT;
 | 
						|
    } else {
 | 
						|
      TcpIo->IsRxDone = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status;
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    Fragment[CurrentFragment].Len -= RxData->FragmentTable[0].FragmentLength;
 | 
						|
    if (Fragment[CurrentFragment].Len == 0) {
 | 
						|
      CurrentFragment++;
 | 
						|
    } else {
 | 
						|
      Fragment[CurrentFragment].Bulk += RxData->FragmentTable[0].FragmentLength;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
 | 
						|
  if (Fragment != NULL) {
 | 
						|
    FreePool (Fragment);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |