Add a TcpIo library to facilitate usage of TCP service.
authortye1 <tye1@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 14 Dec 2010 03:19:21 +0000 (03:19 +0000)
committertye1 <tye1@6f19259b-4bc3-4df7-8a09-765794883524>
Tue, 14 Dec 2010 03:19:21 +0000 (03:19 +0000)
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11162 6f19259b-4bc3-4df7-8a09-765794883524

MdeModulePkg/Include/Library/TcpIoLib.h [new file with mode: 0644]
MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c [new file with mode: 0644]
MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf [new file with mode: 0644]
MdeModulePkg/MdeModulePkg.dec
MdeModulePkg/MdeModulePkg.dsc

diff --git a/MdeModulePkg/Include/Library/TcpIoLib.h b/MdeModulePkg/Include/Library/TcpIoLib.h
new file mode 100644 (file)
index 0000000..050f14b
--- /dev/null
@@ -0,0 +1,252 @@
+/** @file\r
+  This library is used to share code between UEFI network stack modules.\r
+  It provides the helper routines to access TCP service.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at<BR>\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/
+
+#ifndef _TCP_IO_H_
+#define _TCP_IO_H_\r
+\r
+\r
+#include <Protocol/Tcp4.h>\r
+#include <Protocol/Tcp6.h>\r
+\r
+#include <Library/NetLib.h>
+\r
+#define TCP_VERSION_4 IP_VERSION_4\r
+#define TCP_VERSION_6 IP_VERSION_6\r
+\r
+///
+/// 10 seconds
+///
+#define TCP_GET_MAPPING_TIMEOUT 100000000U\r
+\r
+\r
+typedef struct {\r
+  EFI_IPv4_ADDRESS          LocalIp;\r
+  EFI_IPv4_ADDRESS          SubnetMask;\r
+  EFI_IPv4_ADDRESS          Gateway;\r
+\r
+  UINT16                    StationPort;\r
+  EFI_IPv4_ADDRESS          RemoteIp;\r
+  UINT16                    RemotePort;\r
+  BOOLEAN                   ActiveFlag;\r
+} TCP4_IO_CONFIG_DATA;
+\r
+typedef struct {
+  UINT16                    StationPort;\r
+  EFI_IPv6_ADDRESS          RemoteIp;\r
+  UINT16                    RemotePort;
+  BOOLEAN                   ActiveFlag;\r
+} TCP6_IO_CONFIG_DATA;\r
+\r
+typedef union {\r
+  TCP4_IO_CONFIG_DATA       Tcp4IoConfigData;\r
+  TCP6_IO_CONFIG_DATA       Tcp6IoConfigData;\r
+} TCP_IO_CONFIG_DATA;\r
+\r
+typedef union {\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+} TCP_IO_PROTOCOL;\r
+\r
+typedef union {\r
+  EFI_TCP4_CONNECTION_TOKEN Tcp4Token;\r
+  EFI_TCP6_CONNECTION_TOKEN Tcp6Token;\r
+} TCP_IO_CONNECTION_TOKEN;\r
+\r
+typedef union {\r
+  EFI_TCP4_IO_TOKEN         Tcp4Token;\r
+  EFI_TCP6_IO_TOKEN         Tcp6Token;\r
+} TCP_IO_IO_TOKEN;\r
+\r
+typedef union {\r
+  EFI_TCP4_CLOSE_TOKEN      Tcp4Token;\r
+  EFI_TCP6_CLOSE_TOKEN      Tcp6Token;\r
+} TCP_IO_CLOSE_TOKEN;\r
+\r
+typedef union {\r
+  EFI_TCP4_LISTEN_TOKEN     Tcp4Token;\r
+  EFI_TCP6_LISTEN_TOKEN     Tcp6Token;\r
+} TCP_IO_LISTEN_TOKEN;\r
+\r
+\r
+typedef struct {\r
+  UINT8                     TcpVersion;\r
+  EFI_HANDLE                Image;\r
+  EFI_HANDLE                Controller;\r
+  EFI_HANDLE                Handle;\r
+  \r
+  TCP_IO_PROTOCOL           Tcp;\r
+  TCP_IO_PROTOCOL           NewTcp;\r
+  TCP_IO_CONNECTION_TOKEN   ConnToken;\r
+  TCP_IO_IO_TOKEN           TxToken;\r
+  TCP_IO_IO_TOKEN           RxToken;\r
+  TCP_IO_CLOSE_TOKEN        CloseToken;\r
+  TCP_IO_LISTEN_TOKEN       ListenToken;\r
+  \r
+  BOOLEAN                   IsConnDone;\r
+  BOOLEAN                   IsTxDone;\r
+  BOOLEAN                   IsRxDone;\r
+  BOOLEAN                   IsCloseDone;\r
+  BOOLEAN                   IsListenDone;\r
+} TCP_IO;\r
+\r
+/**\r
+  Create a TCP socket with the specified configuration data. \r
+\r
+  @param[in]  Image      The handle of the driver image.\r
+  @param[in]  Controller The handle of the controller.\r
+  @param[in]  TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.\r
+  @param[in]  ConfigData The Tcp configuration data.\r
+  @param[out] TcpIo      The TcpIo.\r
+  \r
+  @retval EFI_SUCCESS            The TCP socket is created and configured.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not
+                                 supported in the implementation.\r
+  @retval Others                 Failed to create the TCP socket or configure it.\r
+\r
+**/\r
+EFI_STATUS
+EFIAPI\r
+TcpIoCreateSocket (
+  IN EFI_HANDLE             Image,
+  IN EFI_HANDLE             Controller,\r
+  IN UINT8                  TcpVersion,
+  IN TCP_IO_CONFIG_DATA     *ConfigData,
+  OUT TCP_IO                *TcpIo
+  );
+
+/**
+  Destroy the socket. 
+
+  @param[in]  TcpIo The TcpIo which wraps the socket to be destroyed.
+
+**/
+VOID
+EFIAPI\r
+TcpIoDestroySocket (
+  IN TCP_IO                 *TcpIo
+  );
+
+/**\r
+  Connect to the other endpoint of the TCP socket.\r
+\r
+  @param[in, out]  TcpIo     The TcpIo wrapping the TCP socket.\r
+  @param[in]       Timeout   The time to wait for connection done.\r
+  \r
+  @retval EFI_SUCCESS            Connect to the other endpoint of the TCP socket\r
+                                 successfully.\r
+  @retval EFI_TIMEOUT            Failed to connect to the other endpoint of the\r
+                                 TCP socket in the specified time period.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not\r
+                                 supported in the implementation.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS
+EFIAPI\r
+TcpIoConnect (
+  IN OUT TCP_IO             *TcpIo,
+  IN     EFI_EVENT          Timeout
+  );
+\r
+/**\r
+  Accept the incomding request from the other endpoint of the TCP socket.\r
+\r
+  @param[in, out]  TcpIo     The TcpIo wrapping the TCP socket.\r
+  @param[in]       Timeout   The time to wait for connection done.\r
+\r
+  \r
+  @retval EFI_SUCCESS            Connect to the other endpoint of the TCP socket\r
+                                 successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not\r
+                                 supported in the implementation.\r
+\r
+  @retval EFI_TIMEOUT            Failed to connect to the other endpoint of the\r
+                                 TCP socket in the specified time period.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcpIoAccept (\r
+  IN OUT TCP_IO             *TcpIo,\r
+  IN     EFI_EVENT          Timeout\r
+  );\r
+  
+/**
+  Reset the socket.
+
+  @param[in, out]  TcpIo The TcpIo wrapping the TCP socket.
+
+**/
+VOID
+EFIAPI\r
+TcpIoReset (
+  IN OUT TCP_IO             *TcpIo
+  );
+
+/**\r
+  Transmit the Packet to the other endpoint of the socket.\r
+\r
+  @param[in]   TcpIo           The TcpIo wrapping the TCP socket.\r
+  @param[in]   Packet          The packet to transmit.\r
+  \r
+  @retval EFI_SUCCESS            The packet is trasmitted.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not\r
+                                 supported in the implementation.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS
+EFIAPI\r
+TcpIoTransmit (
+  IN TCP_IO                 *TcpIo,
+  IN NET_BUF                *Packet
+  );
+
+/**\r
+  Receive data from the socket.\r
+\r
+  @param[in, out]  TcpIo       The TcpIo which wraps the socket to be destroyed.\r
+  @param[in]       Packet      The buffer to hold the data copy from the socket rx buffer.\r
+  @param[in]       AsyncMode   Is this receive asyncronous or not.\r
+  @param[in]       Timeout     The time to wait for receiving the amount of data the Packet\r
+                               can hold.\r
+\r
+  @retval EFI_SUCCESS            The required amount of data is received from the socket.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate momery.\r
+  @retval EFI_TIMEOUT            Failed to receive the required amount of data in the\r
+                                 specified time period.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS
+EFIAPI\r
+TcpIoReceive (
+  IN OUT TCP_IO             *TcpIo,
+  IN     NET_BUF            *Packet,
+  IN     BOOLEAN            AsyncMode,
+  IN     EFI_EVENT          Timeout
+  );
+\r
+#endif\r
+\r
diff --git a/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c b/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.c
new file mode 100644 (file)
index 0000000..48120b4
--- /dev/null
@@ -0,0 +1,993 @@
+/** @file\r
+  This library is used to share code between UEFI network stack modules.\r
+  It provides the helper routines to access TCP service.\r
+\r
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution.  The full text of the license may be found at<BR>\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+\r
+#include <Library/TcpIoLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+\r
+/**
+  The common notify function associated with various TcpIo events. \r
+
+  @param[in]  Event   The event signaled.
+  @param[in]  Context The context.
+
+**/
+VOID
+EFIAPI
+TcpIoCommonNotify (\r
+  IN EFI_EVENT  Event,
+  IN VOID       *Context
+  )
+{\r
+  if ((Event == NULL) || (Context == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  *((BOOLEAN *) Context) = TRUE;
+}\r
+\r
+/**
+  The internal function for delay configuring TCP6 when IP6 driver is still in DAD.\r
+
+  @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.\r
+  @retval Others                 Failed to finish the operation.\r
+\r
+**/
+EFI_STATUS
+TcpIoGetMapping (\r
+  IN EFI_TCP6_PROTOCOL    *Tcp6,
+  IN EFI_TCP6_CONFIG_DATA *Tcp6ConfigData
+  )
+{
+  EFI_STATUS              Status;
+  EFI_EVENT               Event;
+\r
+  if ((Tcp6 == NULL) || (Tcp6ConfigData == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  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\r
+                  );
+
+  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;
+}\r
+\r
+/**\r
+  Create a TCP socket with the specified configuration data. \r
+\r
+  @param[in]  Image      The handle of the driver image.\r
+  @param[in]  Controller The handle of the controller.\r
+  @param[in]  TcpVersion The version of Tcp, TCP_VERSION_4 or TCP_VERSION_6.\r
+  @param[in]  ConfigData The Tcp configuration data.\r
+  @param[out] TcpIo      The TcpIo.\r
+  \r
+  @retval EFI_SUCCESS            The TCP socket is created and configured.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not
+                                 supported in the implementation.\r
+  @retval Others                 Failed to create the TCP socket or configure it.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcpIoCreateSocket (\r
+  IN EFI_HANDLE             Image,\r
+  IN EFI_HANDLE             Controller,\r
+  IN UINT8                  TcpVersion,\r
+  IN TCP_IO_CONFIG_DATA     *ConfigData,\r
+  OUT TCP_IO                *TcpIo\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_EVENT                 Event;\r
+  EFI_GUID                  *ServiceBindingGuid;\r
+  EFI_GUID                  *ProtocolGuid;\r
+  VOID                      **Interface;\r
+  EFI_TCP4_OPTION           ControlOption;\r
+  EFI_TCP4_CONFIG_DATA      Tcp4ConfigData;\r
+  EFI_TCP4_ACCESS_POINT     *AccessPoint4;\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_CONFIG_DATA      Tcp6ConfigData;\r
+  EFI_TCP6_ACCESS_POINT     *AccessPoint6;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+\r
+  if ((Image == NULL) || (Controller == NULL) || (ConfigData == NULL) || (TcpIo == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Tcp4 = NULL;\r
+  Tcp6 = NULL;\r
+\r
+  ZeroMem (TcpIo, sizeof (TCP_IO));\r
+\r
+  if (TcpVersion == TCP_VERSION_4) {\r
+    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+    ProtocolGuid       = &gEfiTcp4ProtocolGuid;\r
+    Interface          = (VOID **) (&TcpIo->Tcp.Tcp4);\r
+  } else if (TcpVersion == TCP_VERSION_6) {\r
+    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+    ProtocolGuid       = &gEfiTcp6ProtocolGuid;\r
+    Interface          = (VOID **) (&TcpIo->Tcp.Tcp6);\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  TcpIo->TcpVersion = TcpVersion;\r
+\r
+  //\r
+  // Create the TCP child instance and get the TCP protocol.\r
+  //  \r
+  Status = NetLibCreateServiceChild (
+             Controller,
+             Image,
+             ServiceBindingGuid,\r
+             &TcpIo->Handle\r
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = gBS->OpenProtocol (
+                  TcpIo->Handle,\r
+                  ProtocolGuid,\r
+                  Interface,\r
+                  Image,
+                  Controller,
+                  EFI_OPEN_PROTOCOL_BY_DRIVER
+                  );
+  if (EFI_ERROR (Status) || (*Interface == NULL)) {\r
+    goto ON_ERROR;
+  }\r
+\r
+  if (TcpVersion == TCP_VERSION_4) {\r
+    Tcp4             = TcpIo->Tcp.Tcp4;\r
+  } else {\r
+    Tcp6             = TcpIo->Tcp.Tcp6;\r
+  }\r
+
+  TcpIo->Image       = Image;\r
+  TcpIo->Controller  = Controller;\r
+
+  //
+  // 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;
+\r
+  if (TcpVersion == TCP_VERSION_4) {\r
+    Tcp4ConfigData.TypeOfService        = 8;\r
+    Tcp4ConfigData.TimeToLive           = 255;\r
+    Tcp4ConfigData.ControlOption        = &ControlOption;\r
+\r
+    AccessPoint4                        = &Tcp4ConfigData.AccessPoint;\r
+\r
+    ZeroMem (AccessPoint4, sizeof (EFI_TCP4_ACCESS_POINT));\r
+    AccessPoint4->StationPort           = ConfigData->Tcp4IoConfigData.StationPort;\r
+    AccessPoint4->RemotePort            = ConfigData->Tcp4IoConfigData.RemotePort;\r
+    AccessPoint4->ActiveFlag            = ConfigData->Tcp4IoConfigData.ActiveFlag;\r
+\r
+    CopyMem (\r
+      &AccessPoint4->StationAddress,\r
+      &ConfigData->Tcp4IoConfigData.LocalIp,\r
+      sizeof (EFI_IPv4_ADDRESS)\r
+      );\r
+    CopyMem (\r
+      &AccessPoint4->SubnetMask,\r
+      &ConfigData->Tcp4IoConfigData.SubnetMask,\r
+      sizeof (EFI_IPv4_ADDRESS)\r
+      );\r
+    CopyMem (\r
+      &AccessPoint4->RemoteAddress,\r
+      &ConfigData->Tcp4IoConfigData.RemoteIp,\r
+      sizeof (EFI_IPv4_ADDRESS)\r
+      );\r
+\r
+    ASSERT (Tcp4 != NULL);\r
+\r
+    //\r
+    // Configure the TCP4 protocol.\r
+    //\r
+    Status = Tcp4->Configure (Tcp4, &Tcp4ConfigData);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+\r
+    if (!EFI_IP4_EQUAL (&ConfigData->Tcp4IoConfigData.Gateway, &mZeroIp4Addr)) {\r
+      //\r
+      // The gateway is not zero. Add the default route manually.\r
+      //\r
+      Status = Tcp4->Routes (\r
+                       Tcp4,\r
+                       FALSE,\r
+                       &mZeroIp4Addr,\r
+                       &mZeroIp4Addr,\r
+                       &ConfigData->Tcp4IoConfigData.Gateway\r
+                       );\r
+      if (EFI_ERROR (Status)) {\r
+        goto ON_ERROR;\r
+      }\r
+    }\r
+  } else {\r
+    Tcp6ConfigData.TrafficClass         = 0;\r
+    Tcp6ConfigData.HopLimit             = 255;\r
+    Tcp6ConfigData.ControlOption        = (EFI_TCP6_OPTION *) &ControlOption;\r
+\r
+    AccessPoint6                        = &Tcp6ConfigData.AccessPoint;\r
+\r
+    ZeroMem (AccessPoint6, sizeof (EFI_TCP6_ACCESS_POINT));\r
+    AccessPoint6->StationPort           = ConfigData->Tcp6IoConfigData.StationPort;\r
+    AccessPoint6->RemotePort            = ConfigData->Tcp6IoConfigData.RemotePort;\r
+    AccessPoint6->ActiveFlag            = ConfigData->Tcp6IoConfigData.ActiveFlag;\r
+\r
+    IP6_COPY_ADDRESS (&AccessPoint6->RemoteAddress, &ConfigData->Tcp6IoConfigData.RemoteIp);\r
+\r
+\r
+    ASSERT (Tcp6 != NULL);\r
+    //\r
+    // Configure the TCP6 protocol.\r
+    //\r
+    Status = Tcp6->Configure (Tcp6, &Tcp6ConfigData);\r
+    if (Status == EFI_NO_MAPPING) {\r
+      Status = TcpIoGetMapping (Tcp6, &Tcp6ConfigData);\r
+    }\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto ON_ERROR;\r
+    }\r
+  }\r
+\r
+  //
+  // Create events for variuos asynchronous operations.
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  TcpIoCommonNotify,\r
+                  &TcpIo->IsConnDone,\r
+                  &Event\r
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }\r
+\r
+  TcpIo->ConnToken.Tcp4Token.CompletionToken.Event = Event;\r
+\r
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  TcpIoCommonNotify,\r
+                  &TcpIo->IsListenDone,\r
+                  &Event\r
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }\r
+\r
+  TcpIo->ListenToken.Tcp4Token.CompletionToken.Event = Event;\r
+\r
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  TcpIoCommonNotify,\r
+                  &TcpIo->IsTxDone,\r
+                  &Event\r
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+\r
+  TcpIo->TxToken.Tcp4Token.CompletionToken.Event = Event;\r
+\r
+\r
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  TcpIoCommonNotify,\r
+                  &TcpIo->IsRxDone,\r
+                  &Event\r
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+\r
+  TcpIo->RxToken.Tcp4Token.CompletionToken.Event = Event;\r
+\r
+  Status = gBS->CreateEvent (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  TcpIoCommonNotify,\r
+                  &TcpIo->IsCloseDone,\r
+                  &Event\r
+                  );
+  if (EFI_ERROR (Status)) {
+    goto ON_ERROR;
+  }
+\r
+  TcpIo->CloseToken.Tcp4Token.CompletionToken.Event = Event;\r
+\r
+\r
+  return EFI_SUCCESS;\r
+
+ON_ERROR:
+\r
+  TcpIoDestroySocket (TcpIo);\r
+
+  return Status;\r
+}\r
+  \r
+/**\r
+  Destroy the socket. \r
+\r
+  @param[in]  TcpIo The TcpIo which wraps the socket to be destroyed.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TcpIoDestroySocket (\r
+  IN TCP_IO                 *TcpIo\r
+  )\r
+{\r
+  EFI_EVENT                 Event;\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+  UINT8                     TcpVersion;\r
+  EFI_GUID                  *ServiceBindingGuid;\r
+  EFI_GUID                  *ProtocolGuid;\r
+  EFI_HANDLE                ChildHandle;\r
+\r
+  if (TcpIo == NULL) {\r
+    return ;\r
+  }\r
+\r
+  TcpVersion = TcpIo->TcpVersion;\r
+\r
+  if ((TcpVersion != TCP_VERSION_4) && (TcpVersion != TCP_VERSION_6)) {\r
+    return ;\r
+  }\r
+\r
+  Event = TcpIo->ConnToken.Tcp4Token.CompletionToken.Event;\r
+\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
+  }\r
+\r
+  Event = TcpIo->ListenToken.Tcp4Token.CompletionToken.Event;\r
+\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
+  }\r
+\r
+  Event = TcpIo->TxToken.Tcp4Token.CompletionToken.Event;\r
+\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
+  }\r
+\r
+  Event = TcpIo->RxToken.Tcp4Token.CompletionToken.Event;\r
+\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
+  }\r
+\r
+  Event = TcpIo->CloseToken.Tcp4Token.CompletionToken.Event;\r
+\r
+  if (Event != NULL) {\r
+    gBS->CloseEvent (Event);\r
+  }\r
+\r
+  Tcp4 = NULL;\r
+  Tcp6 = NULL;\r
+\r
+\r
+  if (TcpVersion == TCP_VERSION_4) {\r
+    ServiceBindingGuid = &gEfiTcp4ServiceBindingProtocolGuid;\r
+    ProtocolGuid       = &gEfiTcp4ProtocolGuid;\r
+    Tcp4 = TcpIo->Tcp.Tcp4;\r
+    if (Tcp4 != NULL) {\r
+      Tcp4->Configure (Tcp4, NULL);\r
+    }\r
+  } else {\r
+    ServiceBindingGuid = &gEfiTcp6ServiceBindingProtocolGuid;\r
+    ProtocolGuid       = &gEfiTcp6ProtocolGuid;\r
+    Tcp6 = TcpIo->Tcp.Tcp6;\r
+    if (Tcp6 != NULL) {\r
+      Tcp6->Configure (Tcp6, NULL);\r
+    }\r
+  }\r
+\r
+  if ((Tcp4 != NULL) || (Tcp6 != NULL)) {\r
+\r
+    gBS->CloseProtocol (
+           TcpIo->Handle,\r
+           ProtocolGuid,\r
+           TcpIo->Image,\r
+           TcpIo->Controller\r
+           );\r
+  }\r
+\r
+  ChildHandle = NULL;\r
+\r
+  if (TcpIo->IsListenDone) {\r
+    if (TcpVersion == TCP_VERSION_4) {\r
+      Tcp4 = TcpIo->NewTcp.Tcp4;\r
+      if (Tcp4 != NULL) {\r
+        Tcp4->Configure (Tcp4, NULL);\r
+        ChildHandle = TcpIo->ListenToken.Tcp4Token.NewChildHandle;\r
+      }\r
+    } else {\r
+      Tcp6 = TcpIo->NewTcp.Tcp6;\r
+      if (Tcp6 != NULL) {\r
+        Tcp6->Configure (Tcp6, NULL);\r
+        ChildHandle = TcpIo->ListenToken.Tcp6Token.NewChildHandle;\r
+      }\r
+    }\r
+\r
+    if (ChildHandle != NULL) {\r
+\r
+      gBS->CloseProtocol (\r
+             ChildHandle,\r
+             ProtocolGuid,\r
+             TcpIo->Image,\r
+             TcpIo->Controller\r
+             );\r
+    }\r
+  }\r
+\r
+  NetLibDestroyServiceChild (
+    TcpIo->Controller,\r
+    TcpIo->Image,\r
+    ServiceBindingGuid,\r
+    TcpIo->Handle\r
+    );\r
+}\r
+\r
+/**\r
+  Connect to the other endpoint of the TCP socket.\r
+\r
+  @param[in, out]  TcpIo     The TcpIo wrapping the TCP socket.\r
+  @param[in]       Timeout   The time to wait for connection done.\r
+  \r
+  @retval EFI_SUCCESS            Connect to the other endpoint of the TCP socket\r
+                                 successfully.\r
+  @retval EFI_TIMEOUT            Failed to connect to the other endpoint of the\r
+                                 TCP socket in the specified time period.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not\r
+                                 supported in the implementation.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcpIoConnect (\r
+  IN OUT TCP_IO             *TcpIo,\r
+  IN     EFI_EVENT          Timeout\r
+  )\r
+{\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+  EFI_STATUS                Status;\r
+\r
+  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TcpIo->IsConnDone = FALSE;\r
+\r
+  Tcp4 = NULL;\r
+  Tcp6 = NULL;\r
+\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+    Tcp4   = TcpIo->Tcp.Tcp4;\r
+    Status = Tcp4->Connect (Tcp4, &TcpIo->ConnToken.Tcp4Token);\r
+  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
+    Tcp6   = TcpIo->Tcp.Tcp6;\r
+    Status = Tcp6->Connect (Tcp6, &TcpIo->ConnToken.Tcp6Token);\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  while (!TcpIo->IsConnDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {\r
+    if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+      Tcp4->Poll (Tcp4);\r
+    } else {\r
+      Tcp6->Poll (Tcp6);\r
+    }\r
+  }
+
+  if (!TcpIo->IsConnDone) {\r
+    Status = EFI_TIMEOUT;
+  } else {\r
+    Status = TcpIo->ConnToken.Tcp4Token.CompletionToken.Status;\r
+  }\r
+
+  return Status;\r
+}\r
+\r
+/**\r
+  Accept the incomding request from the other endpoint of the TCP socket.\r
+\r
+  @param[in, out]  TcpIo     The TcpIo wrapping the TCP socket.\r
+  @param[in]       Timeout   The time to wait for connection done.\r
+\r
+  \r
+  @retval EFI_SUCCESS            Connect to the other endpoint of the TCP socket\r
+                                 successfully.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not\r
+                                 supported in the implementation.\r
+\r
+  @retval EFI_TIMEOUT            Failed to connect to the other endpoint of the\r
+                                 TCP socket in the specified time period.                      \r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcpIoAccept (\r
+  IN OUT TCP_IO             *TcpIo,\r
+  IN     EFI_EVENT          Timeout\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_GUID                  *ProtocolGuid;\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+\r
+  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  TcpIo->IsListenDone = FALSE;\r
+\r
+  Tcp4 = NULL;\r
+  Tcp6 = NULL;\r
+\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+    Tcp4   = TcpIo->Tcp.Tcp4;\r
+    Status = Tcp4->Accept (Tcp4, &TcpIo->ListenToken.Tcp4Token);\r
+  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
+    Tcp6   = TcpIo->Tcp.Tcp6;\r
+    Status = Tcp6->Accept (Tcp6, &TcpIo->ListenToken.Tcp6Token);\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }\r
+\r
+  while (!TcpIo->IsListenDone && EFI_ERROR (gBS->CheckEvent (Timeout))) {\r
+    if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+      Tcp4->Poll (Tcp4);\r
+    } else {\r
+      Tcp6->Poll (Tcp6);\r
+    }\r
+  }
+\r
+  if (!TcpIo->IsListenDone) {\r
+    Status = EFI_TIMEOUT;
+  } else {\r
+    Status = TcpIo->ListenToken.Tcp4Token.CompletionToken.Status;\r
+  }\r
+\r
+  //
+  // The new TCP instance handle created for the established connection is 
+  // in ListenToken.
+  //
+  if (!EFI_ERROR (Status)) {\r
+    if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+      ProtocolGuid = &gEfiTcp4ProtocolGuid;\r
+    } else {\r
+      ProtocolGuid = &gEfiTcp6ProtocolGuid;\r
+    }\r
+    \r
+    Status = gBS->OpenProtocol (
+                    TcpIo->ListenToken.Tcp4Token.NewChildHandle,\r
+                    ProtocolGuid,\r
+                    (VOID **) (&TcpIo->NewTcp.Tcp4),\r
+                    TcpIo->Image,\r
+                    TcpIo->Controller,\r
+                    EFI_OPEN_PROTOCOL_BY_DRIVER
+                    );
+
+  }
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Reset the socket.\r
+\r
+  @param[in, out]  TcpIo The TcpIo wrapping the TCP socket.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+TcpIoReset (\r
+  IN OUT TCP_IO             *TcpIo\r
+  )\r
+{\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+  EFI_STATUS                Status;\r
+\r
+  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)) {\r
+    return ;\r
+  }\r
+\r
+  TcpIo->IsCloseDone = FALSE;\r
+  Tcp4               = NULL;\r
+  Tcp6               = NULL;\r
+\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) { \r
+    TcpIo->CloseToken.Tcp4Token.AbortOnClose = TRUE;\r
+    Tcp4 = TcpIo->Tcp.Tcp4;\r
+    Status = Tcp4->Close (Tcp4, &TcpIo->CloseToken.Tcp4Token);\r
+  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
+    TcpIo->CloseToken.Tcp6Token.AbortOnClose = TRUE;\r
+    Tcp6 = TcpIo->Tcp.Tcp6;\r
+    Status = Tcp6->Close (Tcp6, &TcpIo->CloseToken.Tcp6Token);\r
+  } else {\r
+    return ;\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {
+    return ;
+  }
+
+  while (!TcpIo->IsCloseDone) {\r
+    if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+      Tcp4->Poll (Tcp4);\r
+    } else {\r
+      Tcp6->Poll (Tcp6);\r
+    }\r
+  }\r
+}\r
+\r
+  \r
+/**\r
+  Transmit the Packet to the other endpoint of the socket.\r
+\r
+  @param[in]   TcpIo           The TcpIo wrapping the TCP socket.\r
+  @param[in]   Packet          The packet to transmit.\r
+  \r
+  @retval EFI_SUCCESS            The packet is trasmitted.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_UNSUPPORTED        One or more of the control options are not\r
+                                 supported in the implementation.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcpIoTransmit (\r
+  IN TCP_IO                 *TcpIo,\r
+  IN NET_BUF                *Packet\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  VOID                      *Data;\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+  UINTN                     Size;\r
+\r
+  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+\r
+    Size = sizeof (EFI_TCP4_TRANSMIT_DATA) + \r
+           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);\r
+  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
+    Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +\r
+           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  Data = AllocatePool (Size);\r
+  if (Data == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;
+  }\r
+\r
+  ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push        = TRUE;\r
+  ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent      = FALSE;\r
+  ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;\r
+\r
+  //
+  // Build the fragment table.
+  //
+  ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;\r
+\r
+  NetbufBuildExt (\r
+    Packet,\r
+    (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],\r
+    &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount\r
+    );\r
+\r
+  Tcp4   = NULL;\r
+  Tcp6   = NULL;\r
+  Status = EFI_DEVICE_ERROR;\r
+\r
+  //
+  // Trasnmit the packet.
+  //\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+    TcpIo->TxToken.Tcp4Token.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;\r
+    Tcp4    = TcpIo->Tcp.Tcp4;\r
+    if (TcpIo->IsListenDone) {\r
+      Tcp4 = TcpIo->NewTcp.Tcp4;\r
+    }\r
+\r
+    if (Tcp4 == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+    \r
+    Status  = Tcp4->Transmit (Tcp4, &TcpIo->TxToken.Tcp4Token);\r
+  } else {\r
+    TcpIo->TxToken.Tcp6Token.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;\r
+    Tcp6    = TcpIo->Tcp.Tcp6;\r
+    if (TcpIo->IsListenDone) {\r
+      Tcp6 = TcpIo->NewTcp.Tcp6;\r
+    }\r
+\r
+    if (Tcp6 == NULL) {\r
+      goto ON_EXIT;\r
+    }\r
+\r
+    Status  = Tcp6->Transmit (Tcp6, &TcpIo->TxToken.Tcp6Token);\r
+  }\r
+\r
+  if (EFI_ERROR (Status)) {
+    goto ON_EXIT;
+  }
+
+  while (!TcpIo->IsTxDone) {\r
+    if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+      Tcp4->Poll (Tcp4);\r
+    } else {\r
+      Tcp6->Poll (Tcp6);\r
+    }\r
+  }
+
+  TcpIo->IsTxDone  = FALSE;\r
+  Status           = TcpIo->TxToken.Tcp4Token.CompletionToken.Status;\r
+\r
+ON_EXIT:
+
+  FreePool (Data);\r
+
+  return Status;\r
+}\r
+\r
+/**\r
+  Receive data from the socket.\r
+\r
+  @param[in, out]  TcpIo       The TcpIo which wraps the socket to be destroyed.\r
+  @param[in]       Packet      The buffer to hold the data copy from the socket rx buffer.\r
+  @param[in]       AsyncMode   Is this receive asyncronous or not.\r
+  @param[in]       Timeout     The time to wait for receiving the amount of data the Packet\r
+                               can hold.\r
+\r
+  @retval EFI_SUCCESS            The required amount of data is received from the socket.\r
+  @retval EFI_INVALID_PARAMETER  One or more parameters are invalid.\r
+  @retval EFI_DEVICE_ERROR       An unexpected network or system error occurred.\r
+  @retval EFI_OUT_OF_RESOURCES   Failed to allocate momery.\r
+  @retval EFI_TIMEOUT            Failed to receive the required amount of data in the\r
+                                 specified time period.\r
+  @retval Others                 Other errors as indicated.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TcpIoReceive (\r
+  IN OUT TCP_IO             *TcpIo,\r
+  IN     NET_BUF            *Packet,\r
+  IN     BOOLEAN            AsyncMode,\r
+  IN     EFI_EVENT          Timeout\r
+  )\r
+{\r
+  EFI_TCP4_PROTOCOL         *Tcp4;\r
+  EFI_TCP6_PROTOCOL         *Tcp6;\r
+  EFI_TCP4_RECEIVE_DATA     RxData;\r
+  EFI_STATUS                Status;\r
+  NET_FRAGMENT              *Fragment;\r
+  UINT32                    FragmentCount;\r
+  UINT32                    CurrentFragment;\r
+\r
+  if ((TcpIo == NULL) || (TcpIo->Tcp.Tcp4 == NULL)|| (Packet == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Tcp4 = NULL;\r
+  Tcp6 = NULL;\r
+\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+    TcpIo->RxToken.Tcp4Token.Packet.RxData = &RxData;\r
+    Tcp4 = TcpIo->Tcp.Tcp4;\r
+\r
+    if (TcpIo->IsListenDone) {\r
+      Tcp4 = TcpIo->NewTcp.Tcp4;\r
+    }\r
+\r
+    if (Tcp4 == NULL) {\r
+      return EFI_DEVICE_ERROR;\r
+    }\r
+\r
+  } else if (TcpIo->TcpVersion == TCP_VERSION_6) {\r
+    TcpIo->RxToken.Tcp6Token.Packet.RxData = (EFI_TCP6_RECEIVE_DATA *) &RxData;\r
+    Tcp6 = TcpIo->Tcp.Tcp6;\r
+\r
+    if (TcpIo->IsListenDone) {\r
+      Tcp6 = TcpIo->NewTcp.Tcp6;\r
+    }\r
+\r
+    if (Tcp6 == NULL) {\r
+      return EFI_DEVICE_ERROR; \r
+    }\r
+\r
+  } else {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  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);
+\r
+  RxData.FragmentCount          = 1;\r
+  CurrentFragment               = 0;\r
+  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;
+\r
+    if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+      Status = Tcp4->Receive (Tcp4, &TcpIo->RxToken.Tcp4Token);\r
+    } else {\r
+      Status = Tcp6->Receive (Tcp6, &TcpIo->RxToken.Tcp6Token);\r
+    }\r
+    \r
+    if (EFI_ERROR (Status)) {
+      goto ON_EXIT;
+    }
+    \r
+    while (!TcpIo->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+      //\r
+      // Poll until some data is received or an error occurs.\r
+      //\r
+      if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+        Tcp4->Poll (Tcp4);\r
+      } else {\r
+        Tcp6->Poll (Tcp6);\r
+      }\r
+    }\r
+
+    if (!TcpIo->IsRxDone) {\r
+      //
+      // Timeout occurs, cancel the receive request.
+      //
+      if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+        Tcp4->Cancel (Tcp4, &TcpIo->RxToken.Tcp4Token.CompletionToken);\r
+      } else {\r
+        Tcp6->Cancel (Tcp6, &TcpIo->RxToken.Tcp6Token.CompletionToken);\r
+      }\r
+
+      Status = EFI_TIMEOUT;
+      goto ON_EXIT;
+    } else {
+      TcpIo->IsRxDone = FALSE;\r
+    }\r
+\r
+    Status = TcpIo->RxToken.Tcp4Token.CompletionToken.Status;\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      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:
+\r
+  if (TcpIo->TcpVersion == TCP_VERSION_4) {\r
+    TcpIo->RxToken.Tcp4Token.Packet.RxData = NULL;\r
+  } else {\r
+    TcpIo->RxToken.Tcp6Token.Packet.RxData = NULL;\r
+  }\r
+\r
+  FreePool (Fragment);\r
+
+  return Status;\r
+}\r
diff --git a/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf b/MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf
new file mode 100644 (file)
index 0000000..808b98b
--- /dev/null
@@ -0,0 +1,53 @@
+## @file\r
+#  Instance of TcpIoLib.\r
+#\r
+#  This module provides TCP services by consuming EFI TCP Service Binding Protocol and\r
+#  EFI TCP Protocol.\r
+#  \r
+# Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
+# This program and the accompanying materials\r
+# are licensed and made available under the terms and conditions of the BSD License\r
+# which accompanies this distribution.  The full text of the license may be found at\r
+# http://opensource.org/licenses/bsd-license.php\r
+#\r
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+#\r
+##\r
+\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = DxeTcpIoLib\r
+  FILE_GUID                      = D4608509-1AB0-4cc7-827A-AB8E1E7BD3E6\r
+  MODULE_TYPE                    = DXE_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  LIBRARY_CLASS                  = TcpIoLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER\r
+\r
+#\r
+# The following information is for reference only and not required by the build tools.\r
+#\r
+#  VALID_ARCHITECTURES           = IA32 X64 IPF EBC\r
+#\r
+\r
+[Sources]\r
+  DxeTcpIoLib.c\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+\r
+\r
+[LibraryClasses]\r
+  TcpIoLib\r
+  BaseLib\r
+  DebugLib\r
+  UefiBootServicesTableLib\r
+  MemoryAllocationLib\r
+  BaseMemoryLib\r
+\r
+[Protocols]\r
+  gEfiTcp4ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiTcp4ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiTcp6ServiceBindingProtocolGuid            # PROTOCOL ALWAYS_CONSUMED\r
+  gEfiTcp6ProtocolGuid                          # PROTOCOL ALWAYS_CONSUMED\r
index 0530f91..8cf4b75 100644 (file)
   #   This library is only intended to be used by UEFI network stack modules.\r
   UdpIoLib|Include/Library/UdpIoLib.h\r
 \r
+  ##  @libraryclass  The helper routines to access TCP service.\r
+  #   This library is only intended to be used by UEFI network stack modules.\r
+  TcpIoLib|Include/Library/TcpIoLib.h\r
+\r
   ##  @libraryclass  Defines a set of methods to reset whole system.\r
   ResetSystemLib|Include/Library/ResetSystemLib.h\r
 \r
index d8a3826..86ad3f5 100644 (file)
@@ -68,6 +68,7 @@
   NetLib|MdeModulePkg/Library/DxeNetLib/DxeNetLib.inf\r
   IpIoLib|MdeModulePkg/Library/DxeIpIoLib/DxeIpIoLib.inf\r
   UdpIoLib|MdeModulePkg/Library/DxeUdpIoLib/DxeUdpIoLib.inf\r
+  TcpIoLib|MdeModulePkg/Library/DxeTcpIoLib/DxeTcpIoLib.inf\r
   DpcLib|MdeModulePkg/Library/DxeDpcLib/DxeDpcLib.inf\r
   SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf\r
   TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf\r