git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@4693 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			551 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			551 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*++
 | 
						|
 | 
						|
Copyright (c) 2004 - 2007, Intel Corporation
 | 
						|
All rights reserved. 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.
 | 
						|
 | 
						|
Module Name:
 | 
						|
 | 
						|
  IScsiTcp4Io.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
--*/
 | 
						|
 | 
						|
#include "IScsiImpl.h"
 | 
						|
 | 
						|
VOID
 | 
						|
EFIAPI
 | 
						|
Tcp4IoCommonNotify (
 | 
						|
  IN EFI_EVENT  Event,
 | 
						|
  IN VOID       *Context
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  The common notify function associated with various Tcp4Io events. 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Event   - The event signaled.
 | 
						|
  Contect - The context.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  *((BOOLEAN *) Context) = TRUE;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
Tcp4IoCreateSocket (
 | 
						|
  IN EFI_HANDLE           Image,
 | 
						|
  IN EFI_HANDLE           Controller,
 | 
						|
  IN TCP4_IO_CONFIG_DATA  *ConfigData,
 | 
						|
  IN TCP4_IO              *Tcp4Io
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Create a TCP socket with the specified configuration data. 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Image      - The handle of the driver image.
 | 
						|
  Controller - The handle of the controller.
 | 
						|
  ConfigData - The Tcp4 configuration data.
 | 
						|
  Tcp4Io     - The Tcp4Io.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS - The TCP socket is created and configured.
 | 
						|
  other       - Failed to create the TCP socket or configure it.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  EFI_TCP4_PROTOCOL     *Tcp4;
 | 
						|
  EFI_TCP4_CONFIG_DATA  Tcp4ConfigData;
 | 
						|
  EFI_TCP4_OPTION       ControlOption;
 | 
						|
  EFI_TCP4_ACCESS_POINT *AccessPoint;
 | 
						|
 | 
						|
  Tcp4Io->Handle = NULL;
 | 
						|
  Tcp4Io->ConnToken.CompletionToken.Event = NULL;
 | 
						|
  Tcp4Io->TxToken.CompletionToken.Event = NULL;
 | 
						|
  Tcp4Io->RxToken.CompletionToken.Event = NULL;
 | 
						|
  Tcp4Io->CloseToken.CompletionToken.Event = NULL;
 | 
						|
  Tcp4 = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create the TCP4 child instance and get the TCP4 protocol.
 | 
						|
  //
 | 
						|
  Status = NetLibCreateServiceChild (
 | 
						|
            Controller,
 | 
						|
            Image,
 | 
						|
            &gEfiTcp4ServiceBindingProtocolGuid,
 | 
						|
            &Tcp4Io->Handle
 | 
						|
            );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->OpenProtocol (
 | 
						|
                  Tcp4Io->Handle,
 | 
						|
                  &gEfiTcp4ProtocolGuid,
 | 
						|
                  (VOID **)&Tcp4Io->Tcp4,
 | 
						|
                  Image,
 | 
						|
                  Controller,
 | 
						|
                  EFI_OPEN_PROTOCOL_BY_DRIVER
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Tcp4Io->Image       = Image;
 | 
						|
  Tcp4Io->Controller  = Controller;
 | 
						|
  Tcp4                = Tcp4Io->Tcp4;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
 | 
						|
  Tcp4ConfigData.TypeOfService          = 8;
 | 
						|
  Tcp4ConfigData.TimeToLive             = 255;
 | 
						|
  Tcp4ConfigData.ControlOption          = &ControlOption;
 | 
						|
 | 
						|
  AccessPoint = &Tcp4ConfigData.AccessPoint;
 | 
						|
 | 
						|
  AccessPoint->UseDefaultAddress = FALSE;
 | 
						|
  AccessPoint->StationPort = 0;
 | 
						|
  AccessPoint->RemotePort = ConfigData->RemotePort;
 | 
						|
  AccessPoint->ActiveFlag = TRUE;
 | 
						|
 | 
						|
  CopyMem (&AccessPoint->StationAddress, &ConfigData->LocalIp, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
  CopyMem (&AccessPoint->SubnetMask, &ConfigData->SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
  CopyMem (&AccessPoint->RemoteAddress, &ConfigData->RemoteIp, sizeof (EFI_IPv4_ADDRESS));
 | 
						|
 | 
						|
  //
 | 
						|
  // Configure the TCP4 protocol.
 | 
						|
  //
 | 
						|
  Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!EFI_IP4_EQUAL (&ConfigData->Gateway, &mZeroIp4Addr)) {
 | 
						|
    //
 | 
						|
    // the gateway is not zero, add the default route by hand
 | 
						|
    //
 | 
						|
    Status = Tcp4->Routes (Tcp4, FALSE, &mZeroIp4Addr, &mZeroIp4Addr, &ConfigData->Gateway);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_ERROR;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Create events for variuos asynchronous operations.
 | 
						|
  //
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  Tcp4IoCommonNotify,
 | 
						|
                  &Tcp4Io->IsConnDone,
 | 
						|
                  &Tcp4Io->ConnToken.CompletionToken.Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  Tcp4IoCommonNotify,
 | 
						|
                  &Tcp4Io->IsTxDone,
 | 
						|
                  &Tcp4Io->TxToken.CompletionToken.Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  Tcp4IoCommonNotify,
 | 
						|
                  &Tcp4Io->IsRxDone,
 | 
						|
                  &Tcp4Io->RxToken.CompletionToken.Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->CreateEvent (
 | 
						|
                  EFI_EVENT_NOTIFY_SIGNAL,
 | 
						|
                  TPL_NOTIFY,
 | 
						|
                  Tcp4IoCommonNotify,
 | 
						|
                  &Tcp4Io->IsCloseDone,
 | 
						|
                  &Tcp4Io->CloseToken.CompletionToken.Event
 | 
						|
                  );
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Tcp4Io->IsTxDone  = FALSE;
 | 
						|
  Tcp4Io->IsRxDone  = FALSE;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
 | 
						|
  if (Tcp4Io->RxToken.CompletionToken.Event != NULL) {
 | 
						|
    gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Tcp4Io->TxToken.CompletionToken.Event != NULL) {
 | 
						|
    gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Tcp4Io->ConnToken.CompletionToken.Event != NULL) {
 | 
						|
    gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
 | 
						|
  }
 | 
						|
 | 
						|
  if (Tcp4 != NULL) {
 | 
						|
    Tcp4->Configure (Tcp4, NULL);
 | 
						|
 | 
						|
    gBS->CloseProtocol (
 | 
						|
          Tcp4Io->Handle,
 | 
						|
          &gEfiTcp4ProtocolGuid,
 | 
						|
          Image,
 | 
						|
          Controller
 | 
						|
          );
 | 
						|
  }
 | 
						|
 | 
						|
  NetLibDestroyServiceChild (
 | 
						|
    Controller,
 | 
						|
    Image,
 | 
						|
    &gEfiTcp4ServiceBindingProtocolGuid,
 | 
						|
    Tcp4Io->Handle
 | 
						|
    );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
Tcp4IoDestroySocket (
 | 
						|
  IN TCP4_IO  *Tcp4Io
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Destroy the socket. 
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Tcp4Io - The Tcp4Io which wraps the socket to be destroyeds.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_TCP4_PROTOCOL *Tcp4;
 | 
						|
 | 
						|
  Tcp4 = Tcp4Io->Tcp4;
 | 
						|
 | 
						|
  Tcp4->Configure (Tcp4, NULL);
 | 
						|
 | 
						|
  gBS->CloseEvent (Tcp4Io->TxToken.CompletionToken.Event);
 | 
						|
  gBS->CloseEvent (Tcp4Io->RxToken.CompletionToken.Event);
 | 
						|
  gBS->CloseEvent (Tcp4Io->ConnToken.CompletionToken.Event);
 | 
						|
 | 
						|
  gBS->CloseProtocol (
 | 
						|
        Tcp4Io->Handle,
 | 
						|
        &gEfiTcp4ProtocolGuid,
 | 
						|
        Tcp4Io->Image,
 | 
						|
        Tcp4Io->Controller
 | 
						|
        );
 | 
						|
 | 
						|
  NetLibDestroyServiceChild (
 | 
						|
    Tcp4Io->Controller,
 | 
						|
    Tcp4Io->Image,
 | 
						|
    &gEfiTcp4ServiceBindingProtocolGuid,
 | 
						|
    Tcp4Io->Handle
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
Tcp4IoConnect (
 | 
						|
  IN TCP4_IO    *Tcp4Io,
 | 
						|
  IN EFI_EVENT  Timeout
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Connect to the other endpoint of the TCP socket.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Tcp4Io  - The Tcp4Io wrapping the TCP socket.
 | 
						|
  Timeout - The time to wait for connection done.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_TCP4_PROTOCOL *Tcp4;
 | 
						|
  EFI_STATUS        Status;
 | 
						|
 | 
						|
  Tcp4Io->IsConnDone  = FALSE;
 | 
						|
  Tcp4                = Tcp4Io->Tcp4;
 | 
						|
  Status              = Tcp4->Connect (Tcp4, &Tcp4Io->ConnToken);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!Tcp4Io->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {
 | 
						|
    Tcp4->Poll (Tcp4);
 | 
						|
  }
 | 
						|
 | 
						|
  if (!Tcp4Io->IsConnDone) {
 | 
						|
    Status = EFI_TIMEOUT;
 | 
						|
  } else {
 | 
						|
    Status = Tcp4Io->ConnToken.CompletionToken.Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
VOID
 | 
						|
Tcp4IoReset (
 | 
						|
  IN TCP4_IO  *Tcp4Io
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Reset the socket.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Tcp4Io - The Tcp4Io wrapping the TCP socket.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  None.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_STATUS        Status;
 | 
						|
  EFI_TCP4_PROTOCOL *Tcp4;
 | 
						|
 | 
						|
  Tcp4Io->CloseToken.AbortOnClose = TRUE;
 | 
						|
  Tcp4Io->IsCloseDone             = FALSE;
 | 
						|
 | 
						|
  Tcp4 = Tcp4Io->Tcp4;
 | 
						|
  Status = Tcp4->Close (Tcp4, &Tcp4Io->CloseToken);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!Tcp4Io->IsCloseDone) {
 | 
						|
    Tcp4->Poll (Tcp4);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
Tcp4IoTransmit (
 | 
						|
  IN TCP4_IO  *Tcp4Io,
 | 
						|
  IN NET_BUF  *Packet
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Transmit the Packet to the other endpoint of the socket.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Tcp4Io - The Tcp4Io wrapping the TCP socket.
 | 
						|
  Packet - The packet to transmit
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS          - The packet is trasmitted.
 | 
						|
  EFI_OUT_OF_RESOURCES - Failed to allocate memory.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_TCP4_TRANSMIT_DATA  *TxData;
 | 
						|
  EFI_TCP4_PROTOCOL       *Tcp4;
 | 
						|
  EFI_STATUS              Status;
 | 
						|
 | 
						|
  TxData = AllocatePool (sizeof (EFI_TCP4_TRANSMIT_DATA) + (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA));
 | 
						|
  if (TxData == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  TxData->Push        = TRUE;
 | 
						|
  TxData->Urgent      = FALSE;
 | 
						|
  TxData->DataLength  = Packet->TotalSize;
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the fragment table.
 | 
						|
  //
 | 
						|
  TxData->FragmentCount = Packet->BlockOpNum;
 | 
						|
  NetbufBuildExt (Packet, (NET_FRAGMENT *) &TxData->FragmentTable[0], &TxData->FragmentCount);
 | 
						|
 | 
						|
  Tcp4Io->TxToken.Packet.TxData = TxData;
 | 
						|
 | 
						|
  //
 | 
						|
  // Trasnmit the packet.
 | 
						|
  //
 | 
						|
  Tcp4    = Tcp4Io->Tcp4;
 | 
						|
  Status  = Tcp4->Transmit (Tcp4, &Tcp4Io->TxToken);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  while (!Tcp4Io->IsTxDone) {
 | 
						|
    Tcp4->Poll (Tcp4);
 | 
						|
  }
 | 
						|
 | 
						|
  Tcp4Io->IsTxDone  = FALSE;
 | 
						|
 | 
						|
  Status            = Tcp4Io->TxToken.CompletionToken.Status;
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
 | 
						|
  gBS->FreePool (TxData);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
EFI_STATUS
 | 
						|
Tcp4IoReceive (
 | 
						|
  IN TCP4_IO    *Tcp4Io,
 | 
						|
  IN NET_BUF    *Packet,
 | 
						|
  IN BOOLEAN    AsyncMode,
 | 
						|
  IN EFI_EVENT  Timeout
 | 
						|
  )
 | 
						|
/*++
 | 
						|
 | 
						|
Routine Description:
 | 
						|
 | 
						|
  Receive data from the socket.
 | 
						|
 | 
						|
Arguments:
 | 
						|
 | 
						|
  Tcp4Io    - The Tcp4Io which wraps the socket to be destroyeds.
 | 
						|
  Packet    - The buffer to hold the data copy from the soket rx buffer.
 | 
						|
  AsyncMode - Is this receive asyncronous or not.
 | 
						|
  Timeout   - The time to wait for receiving the amount of data the Packet
 | 
						|
              can hold.
 | 
						|
 | 
						|
Returns:
 | 
						|
 | 
						|
  EFI_SUCCESS          - The required amount of data is received from the socket.
 | 
						|
  EFI_OUT_OF_RESOURCES - Failed to allocate momery.
 | 
						|
  EFI_TIMEOUT          - Failed to receive the required amount of data in the
 | 
						|
                         specified time period.
 | 
						|
 | 
						|
--*/
 | 
						|
{
 | 
						|
  EFI_TCP4_PROTOCOL     *Tcp4;
 | 
						|
  EFI_TCP4_RECEIVE_DATA RxData;
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  NET_FRAGMENT          *Fragment;
 | 
						|
  UINT32                FragmentCount;
 | 
						|
  UINT32                CurrentFragment;
 | 
						|
 | 
						|
  FragmentCount = Packet->BlockOpNum;
 | 
						|
  Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
 | 
						|
  if (Fragment == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Build the fragment table.
 | 
						|
  //
 | 
						|
  NetbufBuildExt (Packet, Fragment, &FragmentCount);
 | 
						|
 | 
						|
  RxData.FragmentCount          = 1;
 | 
						|
  Tcp4Io->RxToken.Packet.RxData = &RxData;
 | 
						|
  CurrentFragment               = 0;
 | 
						|
  Tcp4                          = Tcp4Io->Tcp4;
 | 
						|
  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;
 | 
						|
 | 
						|
    Status = Tcp4->Receive (Tcp4, &Tcp4Io->RxToken);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto ON_EXIT;
 | 
						|
    }
 | 
						|
 | 
						|
    while (!Tcp4Io->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
 | 
						|
      //
 | 
						|
      // Poll until some data is received or something error happens.
 | 
						|
      //
 | 
						|
      Tcp4->Poll (Tcp4);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!Tcp4Io->IsRxDone) {
 | 
						|
      //
 | 
						|
      // Timeout occurs, cancel the receive request.
 | 
						|
      //
 | 
						|
      Tcp4->Cancel (Tcp4, &Tcp4Io->RxToken.CompletionToken);
 | 
						|
 | 
						|
      Status = EFI_TIMEOUT;
 | 
						|
      goto ON_EXIT;
 | 
						|
    } else {
 | 
						|
      Tcp4Io->IsRxDone = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Tcp4Io->RxToken.CompletionToken.Status)) {
 | 
						|
      Status = Tcp4Io->RxToken.CompletionToken.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:
 | 
						|
 | 
						|
  gBS->FreePool (Fragment);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 |