]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StdLib/EfiSocketLib/Tcp4.c
Add Socket Libraries.
[mirror_edk2.git] / StdLib / EfiSocketLib / Tcp4.c
diff --git a/StdLib/EfiSocketLib/Tcp4.c b/StdLib/EfiSocketLib/Tcp4.c
new file mode 100644 (file)
index 0000000..2840dd7
--- /dev/null
@@ -0,0 +1,3415 @@
+/** @file\r
+  Implement the TCP4 driver support for the socket layer.\r
+\r
+  Copyright (c) 2011, Intel Corporation\r
+  All rights reserved. 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
+#include "Socket.h"\r
+\r
+\r
+/**\r
+  Accept a network connection.\r
+\r
+  The SocketAccept routine waits for a network connection to the socket.\r
+  It is able to return the remote network address to the caller if\r
+  requested.\r
+\r
+  @param [in] pSocket   Address of the socket structure.\r
+\r
+  @param [in] pSockAddr       Address of a buffer to receive the remote\r
+                              network address.\r
+\r
+  @param [in, out] pSockAddrLength  Length in bytes of the address buffer.\r
+                                    On output specifies the length of the\r
+                                    remote network address.\r
+\r
+  @retval EFI_SUCCESS   Remote address is available\r
+  @retval Others        Remote address not available\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpAccept4 (\r
+  IN DT_SOCKET * pSocket,\r
+  IN struct sockaddr * pSockAddr,\r
+  IN OUT socklen_t * pSockAddrLength\r
+  )\r
+{\r
+  DT_PORT * pPort;\r
+  struct sockaddr_in * pRemoteAddress;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  UINT32 RemoteAddress;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Validate the socket length\r
+  //\r
+  pRemoteAddress = (struct sockaddr_in *) pSockAddr;\r
+  if (( NULL == pSockAddrLength )\r
+    || ( sizeof ( *pRemoteAddress ) > *pSockAddrLength )) {\r
+    //\r
+    //  Invalid socket address\r
+    //\r
+    Status = EFI_INVALID_PARAMETER;\r
+    pSocket->errno = EINVAL;\r
+    DEBUG (( DEBUG_ACCEPT,\r
+              "ERROR - Invalid address length\r\n" ));\r
+  }\r
+  else {\r
+    //\r
+    //  Assume success\r
+    //\r
+    Status = EFI_SUCCESS;\r
+\r
+    //\r
+    //  Locate the address context\r
+    //\r
+    pPort = pSocket->pPortList;\r
+    pTcp4 = &pPort->Context.Tcp4;\r
+\r
+    //\r
+    //  Fill-in the remote address structure\r
+    //\r
+    ZeroMem ( pRemoteAddress, sizeof ( *pRemoteAddress ));\r
+    pRemoteAddress->sin_len = sizeof ( *pRemoteAddress );\r
+    pRemoteAddress->sin_family = AF_INET;\r
+    pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
+    RemoteAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];\r
+    RemoteAddress <<= 8;\r
+    RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];\r
+    RemoteAddress <<= 8;\r
+    RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];\r
+    RemoteAddress <<= 8;\r
+    RemoteAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];\r
+    pRemoteAddress->sin_addr.s_addr = RemoteAddress;\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Bind a name to a socket.\r
+\r
+  The ::TcpBind4 routine connects a name to a TCP4 stack on the local machine.\r
+\r
+  @param [in] pSocket   Address of the socket structure.\r
+\r
+  @param [in] pSockAddr Address of a sockaddr structure that contains the\r
+                        connection point on the local machine.  An IPv4 address\r
+                        of INADDR_ANY specifies that the connection is made to\r
+                        all of the network stacks on the platform.  Specifying a\r
+                        specific IPv4 address restricts the connection to the\r
+                        network stack supporting that address.  Specifying zero\r
+                        for the port causes the network layer to assign a port\r
+                        number from the dynamic range.  Specifying a specific\r
+                        port number causes the network layer to use that port.\r
+\r
+  @param [in] SockAddrLen   Specifies the length in bytes of the sockaddr structure.\r
+\r
+  @retval EFI_SUCCESS - Socket successfully created\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpBind4 (\r
+  IN DT_SOCKET * pSocket,\r
+  IN const struct sockaddr * pSockAddr,\r
+  IN socklen_t SockAddrLength\r
+  )\r
+{\r
+  EFI_HANDLE ChildHandle;\r
+  DT_LAYER * pLayer;\r
+  DT_PORT * pPort;\r
+  DT_SERVICE * pService;\r
+  CONST struct sockaddr_in * pIp4Address;\r
+  EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;\r
+  EFI_STATUS Status;\r
+  EFI_STATUS TempStatus;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  pSocket->errno = 0;\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Validate the address length\r
+  //\r
+  pIp4Address = (CONST struct sockaddr_in *) pSockAddr;\r
+  if ( SockAddrLength >= ( sizeof ( *pIp4Address )\r
+                           - sizeof ( pIp4Address->sin_zero ))) {\r
+\r
+    //\r
+    //  Walk the list of services\r
+    //\r
+    pLayer = &mEslLayer;\r
+    pService = pLayer->pTcp4List;\r
+    while ( NULL != pService ) {\r
+      //\r
+      //  Create the TCP port\r
+      //\r
+      pTcp4Service = pService->pInterface;\r
+      ChildHandle = NULL;\r
+      Status = pTcp4Service->CreateChild ( pTcp4Service,\r
+                                           &ChildHandle );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
+                  "0x%08x: Tcp4 port handle created\r\n",\r
+                  ChildHandle ));\r
+\r
+        //\r
+        //  Open the port\r
+        //\r
+        Status = EslTcpPortAllocate4 ( pSocket,\r
+                                       pService,\r
+                                       ChildHandle,\r
+                                       (UINT8 *) &pIp4Address->sin_addr.s_addr,\r
+                                       SwapBytes16 ( pIp4Address->sin_port ),\r
+                                       DEBUG_BIND,\r
+                                       &pPort );\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
+                  "ERROR - Failed to open Tcp4 port handle, Status: %r\r\n",\r
+                  Status ));\r
+        ChildHandle = NULL;\r
+      }\r
+\r
+      //\r
+      //  Close the port if necessary\r
+      //\r
+      if (( EFI_ERROR ( Status )) && ( NULL != ChildHandle )) {\r
+        TempStatus = pTcp4Service->DestroyChild ( pTcp4Service,\r
+                                                  ChildHandle );\r
+        if ( !EFI_ERROR ( TempStatus )) {\r
+          DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
+                    "0x%08x: Tcp4 port handle destroyed\r\n",\r
+                    ChildHandle ));\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,\r
+                    "ERROR - Failed to destroy the Tcp4 port handle 0x%08x, Status: %r\r\n",\r
+                    ChildHandle,\r
+                    TempStatus ));\r
+          ASSERT ( EFI_SUCCESS == TempStatus );\r
+        }\r
+      }\r
+\r
+      //\r
+      //  Set the next service\r
+      //\r
+      pService = pService->pNext;\r
+    }\r
+\r
+    //\r
+    //  Verify that at least one network connection was found\r
+    //\r
+    if ( NULL == pSocket->pPortList ) {\r
+      DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
+                "Socket address %d.%d.%d.%d (0x%08x) is not available!\r\n",\r
+                ( pIp4Address->sin_addr.s_addr >> 24 ) & 0xff,\r
+                ( pIp4Address->sin_addr.s_addr >> 16 ) & 0xff,\r
+                ( pIp4Address->sin_addr.s_addr >> 8 ) & 0xff,\r
+                pIp4Address->sin_addr.s_addr & 0xff,\r
+                pIp4Address->sin_addr.s_addr ));\r
+      pSocket->errno = EADDRNOTAVAIL;\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_BIND,\r
+              "ERROR - Invalid TCP4 address length: %d\r\n",\r
+              SockAddrLength ));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    pSocket->errno = EINVAL;\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Attempt to connect to a remote TCP port\r
+\r
+  @param [in] pSocket         Address of the socket structure.\r
+\r
+  @retval EFI_SUCCESS   The connection was successfully established.\r
+  @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
+  @retval Others        The connection attempt failed.\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpConnectAttempt4 (\r
+  IN DT_SOCKET * pSocket\r
+  )\r
+{\r
+  DT_PORT * pPort;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  //  Determine if any more local adapters are available\r
+  //\r
+  pPort = pSocket->pPortList;\r
+  if ( NULL != pPort ) {\r
+    //\r
+    //  Configure the port\r
+    //\r
+    pTcp4 = &pPort->Context.Tcp4;\r
+    pTcp4->ConfigData.AccessPoint.ActiveFlag = TRUE;\r
+    pTcp4->ConfigData.TimeToLive = 255;\r
+    pTcp4Protocol = pTcp4->pProtocol;\r
+    Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
+                                        &pTcp4->ConfigData );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_CONNECT,\r
+                "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",\r
+                Status ));\r
+      switch ( Status ) {\r
+      case EFI_ACCESS_DENIED:\r
+        pSocket->errno = EACCES;\r
+        break;\r
+    \r
+      default:\r
+      case EFI_DEVICE_ERROR:\r
+        pSocket->errno = EIO;\r
+        break;\r
+    \r
+      case EFI_INVALID_PARAMETER:\r
+        pSocket->errno = EADDRNOTAVAIL;\r
+        break;\r
+    \r
+      case EFI_NO_MAPPING:\r
+        pSocket->errno = EAFNOSUPPORT;\r
+        break;\r
+    \r
+      case EFI_OUT_OF_RESOURCES:\r
+        pSocket->errno = ENOBUFS;\r
+        break;\r
+    \r
+      case EFI_UNSUPPORTED:\r
+        pSocket->errno = EOPNOTSUPP;\r
+        break;\r
+      }\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_CONNECT,\r
+                "0x%08x: Port configured\r\n",\r
+                pPort ));\r
+      pTcp4->bConfigured = TRUE;\r
+\r
+      //\r
+      //  Attempt the connection to the remote system\r
+      //\r
+      Status = pTcp4Protocol->Connect ( pTcp4Protocol,\r
+                                        &pTcp4->ConnectToken );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        //  Connection in progress\r
+        //\r
+        pSocket->errno = EINPROGRESS;\r
+        Status = EFI_NOT_READY;\r
+        DEBUG (( DEBUG_CONNECT,\r
+                  "0x%08x: Port attempting connection to %d.%d.%d.%d:%d\r\n",\r
+                  pPort,\r
+                  pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
+                  pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1],\r
+                  pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2],\r
+                  pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3],\r
+                  pTcp4->ConfigData.AccessPoint.RemotePort ));\r
+      }\r
+      else {\r
+        //\r
+        //  Connection error\r
+        //\r
+        pSocket->errno = EINVAL;\r
+        DEBUG (( DEBUG_CONNECT,\r
+                  "ERROR - Port 0x%08x not connected, Status: %r\r\n",\r
+                  pPort,\r
+                  Status ));\r
+      }\r
+    }\r
+  }\r
+  else {\r
+    //\r
+    //  No more local adapters available\r
+    //\r
+    pSocket->errno = ENETUNREACH;\r
+    Status = EFI_NO_RESPONSE;\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the remote connection attempt\r
+\r
+  A connection attempt to a remote system has just completed when\r
+  this routine is invoked.  Release the port in the case of an\r
+  error and start a connection attempt on the next port.  If the\r
+  connection attempt was successful, then release all of the other\r
+  ports.\r
+\r
+  @param  Event         The connect completion event\r
+\r
+  @param  pPort         The DT_PORT structure address\r
+\r
+**/\r
+VOID\r
+EslTcpConnectComplete4 (\r
+  IN EFI_EVENT Event,\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  BOOLEAN bRemoveFirstPort;\r
+  BOOLEAN bRemovePorts;\r
+  DT_PORT * pNextPort;\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Locate the TCP context\r
+  //\r
+  pSocket = pPort->pSocket;\r
+  pTcp4 = &pPort->Context.Tcp4;\r
+\r
+  //\r
+  //  Get the connection status\r
+  //\r
+  bRemoveFirstPort = FALSE;\r
+  bRemovePorts = FALSE;\r
+  Status = pTcp4->ConnectToken.CompletionToken.Status;\r
+  pSocket->ConnectStatus = Status;\r
+  if ( !EFI_ERROR ( Status )) {\r
+    //\r
+    //  The connection was successful\r
+    //\r
+    DEBUG (( DEBUG_CONNECT,\r
+              "0x%08x: Port connected to %d.%d.%d.%d:%d\r\n",\r
+              pPort,\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],\r
+              pTcp4->ConfigData.AccessPoint.RemotePort ));\r
+\r
+    //\r
+    //  Remove the rest of the ports\r
+    //\r
+    bRemovePorts = TRUE;\r
+  }\r
+  else {\r
+    //\r
+    //  The connection failed\r
+    //\r
+    DEBUG (( DEBUG_CONNECT,\r
+              "0x%08x: Port connection to %d.%d.%d.%d:%d failed, Status: %r\r\n",\r
+              pPort,\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [0],\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [1],\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [2],\r
+              pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr [3],\r
+              pTcp4->ConfigData.AccessPoint.RemotePort,\r
+              Status ));\r
+\r
+    //\r
+    //  Close the current port\r
+    //\r
+    Status = EslTcpPortClose4 ( pPort );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_CONNECT,\r
+              "0x%08x: Port closed\r\n",\r
+              pPort ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_CONNECT,\r
+                "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
+                pPort,\r
+                Status ));\r
+    }\r
+\r
+    //\r
+    //  Try to connect using the next port\r
+    //\r
+    Status = EslTcpConnectAttempt4 ( pSocket );\r
+    if ( EFI_NOT_READY != Status ) {\r
+      pSocket->ConnectStatus = Status;\r
+      bRemoveFirstPort = TRUE;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Remove the ports if necessary\r
+  //\r
+  if ( bRemoveFirstPort || bRemovePorts ) {\r
+    //\r
+    //  Remove the first port if necessary\r
+    //\r
+    pPort = pSocket->pPortList;\r
+    if (( !bRemoveFirstPort ) && ( NULL != pPort )) {\r
+      pPort = pPort->pLinkSocket;\r
+    }\r
+\r
+    //\r
+    //  Remove the rest of the list\r
+    //\r
+    while ( NULL != pPort ) {\r
+      pNextPort = pPort->pLinkSocket;\r
+      EslTcpPortClose4 ( pPort );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        DEBUG (( DEBUG_CONNECT,\r
+                "0x%08x: Port closed\r\n",\r
+                pPort ));\r
+      }\r
+      else {\r
+        DEBUG (( DEBUG_CONNECT,\r
+                  "ERROR - Failed to close port 0x%08x, Status: %r\r\n",\r
+                  pPort,\r
+                  Status ));\r
+      }\r
+      pPort = pNextPort;\r
+    }\r
+\r
+    //\r
+    //  Notify the poll routine\r
+    //\r
+    pSocket->bConnected = TRUE;\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Poll for completion of the connection attempt.\r
+\r
+  The ::TcpConnectPoll4 routine determines when the connection\r
+  attempt transitions from being in process to being complete.\r
+\r
+  @param [in] pSocket         Address of the socket structure.\r
+\r
+  @retval EFI_SUCCESS   The connection was successfully established.\r
+  @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
+  @retval Others        The connection attempt failed.\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpConnectPoll4 (\r
+  IN DT_SOCKET * pSocket\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Determine if the connection is complete\r
+  //\r
+  if ( !pSocket->bConnected ) {\r
+    //\r
+    //  Not connected\r
+    //\r
+    pSocket->errno = EAGAIN;\r
+    Status = EFI_NOT_READY;\r
+  }\r
+  else {\r
+    //\r
+    //  The connection processing is complete\r
+    //\r
+    pSocket->bConnected = FALSE;\r
+\r
+    //\r
+    //  Translate the connection status\r
+    //\r
+    Status = pSocket->ConnectStatus;\r
+    switch ( Status ) {\r
+    default:\r
+    case EFI_DEVICE_ERROR:\r
+      pSocket->errno = EIO;\r
+      break;\r
+\r
+    case EFI_ABORTED:\r
+      pSocket->errno = ECONNREFUSED;\r
+      break;\r
+\r
+    case EFI_INVALID_PARAMETER:\r
+      pSocket->errno = EINVAL;\r
+      break;\r
+\r
+    case EFI_NO_MAPPING:\r
+    case EFI_NO_RESPONSE:\r
+      pSocket->errno = EHOSTUNREACH;\r
+      break;\r
+\r
+    case EFI_NO_MEDIA:\r
+      pSocket->errno = ENETDOWN;\r
+      break;\r
+\r
+    case EFI_OUT_OF_RESOURCES:\r
+      pSocket->errno = ENOMEM;\r
+      break;\r
+\r
+    case EFI_SUCCESS:\r
+      pSocket->errno = 0;\r
+      pSocket->bConfigured = TRUE;\r
+      break;\r
+\r
+    case EFI_TIMEOUT:\r
+      pSocket->errno = ETIMEDOUT;\r
+      break;\r
+\r
+    case EFI_UNSUPPORTED:\r
+      pSocket->errno = ENOTSUP;\r
+      break;\r
+\r
+    case 0x80000069:\r
+      pSocket->errno = ECONNRESET;\r
+      break;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the initialization status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Connect to a remote system via the network.\r
+\r
+  The ::TcpConnectStart4= routine starts the connection processing\r
+  for a TCP4 port.\r
+\r
+  @param [in] pSocket         Address of the socket structure.\r
+\r
+  @param [in] pSockAddr       Network address of the remote system.\r
+    \r
+  @param [in] SockAddrLength  Length in bytes of the network address.\r
+  \r
+  @retval EFI_SUCCESS   The connection was successfully established.\r
+  @retval EFI_NOT_READY The connection is in progress, call this routine again.\r
+  @retval Others        The connection attempt failed.\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpConnectStart4 (\r
+  IN DT_SOCKET * pSocket,\r
+  IN const struct sockaddr * pSockAddr,\r
+  IN socklen_t SockAddrLength\r
+  )\r
+{\r
+  struct sockaddr_in LocalAddress;\r
+  DT_PORT * pPort;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  CONST struct sockaddr_in * pIp4Address;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Validate the address length\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  pIp4Address = (CONST struct sockaddr_in *) pSockAddr;\r
+  if ( SockAddrLength >= ( sizeof ( *pIp4Address )\r
+                           - sizeof ( pIp4Address->sin_zero ))) {\r
+    //\r
+    //  Determine if BIND was already called\r
+    //\r
+    if ( NULL == pSocket->pPortList ) {\r
+      //\r
+      //  Allow any local port\r
+      //\r
+      ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
+      LocalAddress.sin_len = sizeof ( LocalAddress );\r
+      LocalAddress.sin_family = AF_INET;\r
+      Status = EslSocketBind ( &pSocket->SocketProtocol,\r
+                               (struct sockaddr *)&LocalAddress,\r
+                               LocalAddress.sin_len,\r
+                               &pSocket->errno );\r
+    }\r
+    if ( NULL != pSocket->pPortList ) {\r
+      //\r
+      //  Walk the list of ports\r
+      //\r
+      pPort = pSocket->pPortList;\r
+      while ( NULL != pPort ) {\r
+        //\r
+        //  Set the remote address\r
+        //\r
+        pTcp4 = &pPort->Context.Tcp4;\r
+        *(UINT32 *)&pTcp4->ConfigData.AccessPoint.RemoteAddress = pIp4Address->sin_addr.s_addr;\r
+        pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pIp4Address->sin_port );\r
+\r
+        //\r
+        //  Set the next port\r
+        //\r
+        pPort = pPort->pLinkSocket;\r
+      }\r
+      \r
+      //\r
+      //  Attempt a connection using the first adapter\r
+      //\r
+      Status = EslTcpConnectAttempt4 ( pSocket );\r
+    }\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_CONNECT,\r
+              "ERROR - Invalid TCP4 address length: %d\r\n",\r
+              SockAddrLength ));\r
+    Status = EFI_INVALID_PARAMETER;\r
+    pSocket->errno = EINVAL;\r
+  }\r
+\r
+  //\r
+  //  Return the initialization status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Initialize the TCP4 service.\r
+\r
+  This routine initializes the TCP4 service after its service binding\r
+  protocol was located on a controller.\r
+\r
+  @param [in] pService        DT_SERVICE structure address\r
+\r
+  @retval EFI_SUCCESS         The service was properly initialized\r
+  @retval other               A failure occurred during the service initialization\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EslTcpInitialize4 (\r
+  IN DT_SERVICE * pService\r
+  )\r
+{\r
+  DT_LAYER * pLayer;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Identify the service\r
+  //\r
+  pService->NetworkType = NETWORK_TYPE_TCP4;\r
+\r
+  //\r
+  //  Connect this service to the service list\r
+  //\r
+  pLayer = &mEslLayer;\r
+  pService->pNext = pLayer->pTcp4List;\r
+  pLayer->pTcp4List = pService;\r
+\r
+  //\r
+  //  Assume the list is empty\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Return the initialization status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the local socket address\r
+\r
+  @param [in] pSocket             Address of the socket structure.\r
+\r
+  @param [out] pAddress           Network address to receive the local system address\r
+\r
+  @param [in,out] pAddressLength  Length of the local network address structure\r
+\r
+  @retval EFI_SUCCESS - Address available\r
+  @retval Other - Failed to get the address\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpGetLocalAddress4 (\r
+  IN DT_SOCKET * pSocket,\r
+  OUT struct sockaddr * pAddress,\r
+  IN OUT socklen_t * pAddressLength\r
+  )\r
+{\r
+  socklen_t LengthInBytes;\r
+  DT_PORT * pPort;\r
+  struct sockaddr_in * pLocalAddress;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Verify that there is just a single connection\r
+  //\r
+  pPort = pSocket->pPortList;\r
+  if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
+    //\r
+    //  Verify the address length\r
+    //\r
+    LengthInBytes = sizeof ( struct sockaddr_in );\r
+    if ( LengthInBytes <= * pAddressLength ) {\r
+      //\r
+      //  Return the local address\r
+      //\r
+      pTcp4 = &pPort->Context.Tcp4;\r
+      pLocalAddress = (struct sockaddr_in *)pAddress;\r
+      ZeroMem ( pLocalAddress, LengthInBytes );\r
+      pLocalAddress->sin_family = AF_INET;\r
+      pLocalAddress->sin_len = (uint8_t)LengthInBytes;\r
+      pLocalAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.StationPort );\r
+      CopyMem ( &pLocalAddress->sin_addr,\r
+                &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],\r
+                sizeof ( pLocalAddress->sin_addr ));\r
+      pSocket->errno = 0;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    else {\r
+      pSocket->errno = EINVAL;\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  else {\r
+    pSocket->errno = ENOTCONN;\r
+    Status = EFI_NOT_STARTED;\r
+  }\r
+  \r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Get the remote socket address\r
+\r
+  @param [in] pSocket             Address of the socket structure.\r
+\r
+  @param [out] pAddress           Network address to receive the remote system address\r
+\r
+  @param [in,out] pAddressLength  Length of the remote network address structure\r
+\r
+  @retval EFI_SUCCESS - Address available\r
+  @retval Other - Failed to get the address\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpGetRemoteAddress4 (\r
+  IN DT_SOCKET * pSocket,\r
+  OUT struct sockaddr * pAddress,\r
+  IN OUT socklen_t * pAddressLength\r
+  )\r
+{\r
+  socklen_t LengthInBytes;\r
+  DT_PORT * pPort;\r
+  struct sockaddr_in * pRemoteAddress;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Verify that there is just a single connection\r
+  //\r
+  pPort = pSocket->pPortList;\r
+  if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
+    //\r
+    //  Verify the address length\r
+    //\r
+    LengthInBytes = sizeof ( struct sockaddr_in );\r
+    if ( LengthInBytes <= * pAddressLength ) {\r
+      //\r
+      //  Return the local address\r
+      //\r
+      pTcp4 = &pPort->Context.Tcp4;\r
+      pRemoteAddress = (struct sockaddr_in *)pAddress;\r
+      ZeroMem ( pRemoteAddress, LengthInBytes );\r
+      pRemoteAddress->sin_family = AF_INET;\r
+      pRemoteAddress->sin_len = (uint8_t)LengthInBytes;\r
+      pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
+      CopyMem ( &pRemoteAddress->sin_addr,\r
+                &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
+                sizeof ( pRemoteAddress->sin_addr ));\r
+      pSocket->errno = 0;\r
+      Status = EFI_SUCCESS;\r
+    }\r
+    else {\r
+      pSocket->errno = EINVAL;\r
+      Status = EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+  else {\r
+    pSocket->errno = ENOTCONN;\r
+    Status = EFI_NOT_STARTED;\r
+  }\r
+  \r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Establish the known port to listen for network connections.\r
+\r
+  The ::Tcp4Listen routine places the port into a state that enables connection\r
+  attempts.  Connections are placed into FIFO order in a queue to be serviced\r
+  by the application.  The application calls the ::Tcp4Accept routine to remove\r
+  the next connection from the queue and get the associated socket.  The\r
+  <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>\r
+  documentation for the listen routine is available online for reference.\r
+\r
+  @param [in] pSocket     Address of the socket structure.\r
+\r
+  @retval EFI_SUCCESS - Socket successfully created\r
+  @retval Other - Failed to enable the socket for listen\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpListen4 (\r
+  IN DT_SOCKET * pSocket\r
+  )\r
+{\r
+  DT_PORT * pNextPort;\r
+  DT_PORT * pPort;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Use for/break instead of goto\r
+  //\r
+  for ( ; ; ) {\r
+    //\r
+    //  Assume no ports are available\r
+    //\r
+    pSocket->errno = EOPNOTSUPP;\r
+    Status = EFI_NOT_READY;\r
+\r
+    //\r
+    //  Walk the list of ports\r
+    //\r
+    pPort = pSocket->pPortList;\r
+    while ( NULL != pPort ) {\r
+      //\r
+      //  Assume success\r
+      //\r
+      pSocket->errno = 0;\r
+\r
+      //\r
+      //  Use for/break insteak of goto\r
+      //\r
+      for ( ; ; ) {\r
+        //\r
+        //  Create the listen completion event\r
+        //\r
+        pTcp4 = &pPort->Context.Tcp4;\r
+        Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
+                                    TPL_SOCKETS,\r
+                                    (EFI_EVENT_NOTIFY)EslTcpListenComplete4,\r
+                                    pPort,\r
+                                    &pTcp4->ListenToken.CompletionToken.Event );\r
+        if ( EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
+                    "ERROR - Failed to create the listen completion event, Status: %r\r\n",\r
+                    Status ));\r
+          pSocket->errno = ENOMEM;\r
+          break;\r
+        }\r
+        DEBUG (( DEBUG_POOL,\r
+                  "0x%08x: Created listen completion event\r\n",\r
+                  pTcp4->ListenToken.CompletionToken.Event ));\r
+\r
+        //\r
+        //  Configure the port\r
+        //\r
+        pTcp4Protocol = pTcp4->pProtocol;\r
+        Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
+                                            &pTcp4->ConfigData );\r
+        if ( EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_LISTEN,\r
+                    "ERROR - Failed to configure the Tcp4 port, Status: %r\r\n",\r
+                    Status ));\r
+          switch ( Status ) {\r
+          case EFI_ACCESS_DENIED:\r
+            pSocket->errno = EACCES;\r
+            break;\r
+\r
+          default:\r
+          case EFI_DEVICE_ERROR:\r
+            pSocket->errno = EIO;\r
+            break;\r
+\r
+          case EFI_INVALID_PARAMETER:\r
+            pSocket->errno = EADDRNOTAVAIL;\r
+            break;\r
+\r
+          case EFI_NO_MAPPING:\r
+            pSocket->errno = EAFNOSUPPORT;\r
+            break;\r
+\r
+          case EFI_OUT_OF_RESOURCES:\r
+            pSocket->errno = ENOBUFS;\r
+            break;\r
+\r
+          case EFI_UNSUPPORTED:\r
+            pSocket->errno = EOPNOTSUPP;\r
+            break;\r
+          }\r
+          break;\r
+        }\r
+        DEBUG (( DEBUG_LISTEN,\r
+                  "0x%08x: Port configured\r\n",\r
+                  pPort ));\r
+        pTcp4->bConfigured = TRUE;\r
+\r
+        //\r
+        //  Start the listen operation on the port\r
+        //\r
+        Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
+                                         &pTcp4->ListenToken );\r
+        if ( EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_LISTEN,\r
+                    "ERROR - Failed Tcp4 accept, Status: %r\r\n",\r
+                    Status ));\r
+          switch ( Status ) {\r
+          case EFI_ACCESS_DENIED:\r
+            pSocket->errno = EACCES;\r
+            break;\r
+\r
+          default:\r
+          case EFI_DEVICE_ERROR:\r
+            pSocket->errno = EIO;\r
+            break;\r
+\r
+          case EFI_INVALID_PARAMETER:\r
+            pSocket->errno = EADDRNOTAVAIL;\r
+            break;\r
+\r
+          case EFI_NOT_STARTED:\r
+            pSocket->errno = ENETDOWN;\r
+            break;\r
+\r
+          case EFI_OUT_OF_RESOURCES:\r
+            pSocket->errno = ENOBUFS;\r
+            break;\r
+          }\r
+          break;\r
+        }\r
+        DEBUG (( DEBUG_LISTEN,\r
+                  "0x%08x: Listen pending on Port\r\n",\r
+                  pPort ));\r
+\r
+        //\r
+        //  Listen is pending on this port\r
+        //\r
+        break;\r
+      }\r
+\r
+      //\r
+      //  Get the next port\r
+      //\r
+      pNextPort = pPort->pLinkSocket;\r
+\r
+      //\r
+      //  Close the port upon error\r
+      //\r
+      if ( EFI_ERROR ( Status ))\r
+      {\r
+        EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );\r
+      }\r
+\r
+      //\r
+      //  Set the next port\r
+      //\r
+      pPort = pNextPort;\r
+    }\r
+    \r
+    //\r
+    //  Determine if any ports are in the listen state\r
+    //\r
+    if ( NULL == pSocket->pPortList ) {\r
+      //\r
+      //  No ports in the listen state\r
+      //\r
+      pSocket->MaxFifoDepth = 0;\r
+\r
+      //\r
+      //  Return the last error detected\r
+      //\r
+      break;\r
+    }\r
+\r
+    //\r
+    //  Mark the socket as configured\r
+    //\r
+    pSocket->bConfigured = TRUE;\r
+\r
+    //\r
+    //  All done\r
+    //\r
+    DEBUG (( DEBUG_LISTEN,\r
+              "0x%08x: pSocket - Listen pending on socket\r\n",\r
+              pSocket ));\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the connection attempt\r
+\r
+  A system has initiated a connection attempt with a socket in the\r
+  listen state.  Attempt to complete the connection.\r
+\r
+  @param  Event         The listen completion event\r
+\r
+  @param  pPort         The DT_PORT structure address\r
+\r
+**/\r
+VOID\r
+EslTcpListenComplete4 (\r
+  IN EFI_EVENT Event,\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  EFI_HANDLE ChildHandle;\r
+  EFI_TCP4_CONFIG_DATA * pConfigData;\r
+  DT_LAYER * pLayer;\r
+  DT_PORT * pNewPort;\r
+  DT_SOCKET * pNewSocket;\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+  EFI_HANDLE TcpPortHandle;\r
+  EFI_STATUS TempStatus;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Determine if this connection fits into the connection FIFO\r
+  //\r
+  pSocket = pPort->pSocket;\r
+  TcpPortHandle = pPort->Context.Tcp4.ListenToken.NewChildHandle;\r
+  if (( SOCKET_STATE_LISTENING == pSocket->State )\r
+    && ( pSocket->MaxFifoDepth > pSocket->FifoDepth )) {\r
+    //\r
+    //  Allocate a socket for this connection\r
+    //\r
+    ChildHandle = NULL;\r
+    pLayer = &mEslLayer;\r
+    Status = EslSocketAllocate ( &ChildHandle,\r
+                                 DEBUG_CONNECTION,\r
+                                 &pNewSocket );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      //\r
+      //  Clone the socket parameters\r
+      //\r
+      pNewSocket->Domain = pSocket->Domain;\r
+      pNewSocket->Protocol = pSocket->Protocol;\r
+      pNewSocket->Type = pSocket->Type;\r
+\r
+      //\r
+      //  Allocate a port for this connection\r
+      //\r
+      pTcp4 = &pPort->Context.Tcp4;\r
+      Status = EslTcpPortAllocate4 ( pNewSocket,\r
+                                     pPort->pService,\r
+                                     TcpPortHandle,\r
+                                     &pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0],\r
+                                     0,\r
+                                     DEBUG_CONNECTION,\r
+                                     &pNewPort );\r
+      if ( !EFI_ERROR ( Status )) {\r
+        //\r
+        //  Restart the listen operation on the port\r
+        //\r
+        pTcp4Protocol = pTcp4->pProtocol;\r
+        Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
+                                         &pTcp4->ListenToken );\r
+\r
+        //\r
+        //  Close the TCP port using SocketClose\r
+        //\r
+        TcpPortHandle = NULL;\r
+        pTcp4 = &pNewPort->Context.Tcp4;\r
+        pTcp4->bConfigured = TRUE;\r
+\r
+        //\r
+        //  Check for an accept call error\r
+        //\r
+        if ( !EFI_ERROR ( Status )) {\r
+          //\r
+          //  Get the port configuration\r
+          //\r
+          pConfigData = &pTcp4->ConfigData;\r
+          pConfigData->ControlOption = &pTcp4->Option;\r
+          pTcp4Protocol = pTcp4->pProtocol;\r
+          Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,\r
+                                                NULL,\r
+                                                pConfigData,\r
+                                                NULL,\r
+                                                NULL,\r
+                                                NULL );\r
+          if ( !EFI_ERROR ( Status )) {\r
+            //\r
+            //  Add the new socket to the connection FIFO\r
+            //\r
+            if ( NULL == pSocket->pFifoTail ) {\r
+              //\r
+              //  First connection\r
+              //\r
+              pSocket->pFifoHead = pNewSocket;\r
+            }\r
+            else {\r
+              //\r
+              //  Add to end of list.\r
+              //\r
+              pSocket->pFifoTail->pNextConnection = pNewSocket;\r
+            }\r
+            pSocket->pFifoTail = pNewSocket;\r
+            pSocket->FifoDepth += 1;\r
+\r
+            //\r
+            //  Update the socket state\r
+            //\r
+            pNewSocket->State = SOCKET_STATE_IN_FIFO;\r
+\r
+            //\r
+            //  Log the connection\r
+            //\r
+            DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
+                      "0x%08x: Socket on port %d.%d.%d.%d:%d connected to %d.%d.%d.%d:%d\r\n",\r
+                      pNewSocket,\r
+                      pConfigData->AccessPoint.StationAddress.Addr[0],\r
+                      pConfigData->AccessPoint.StationAddress.Addr[1],\r
+                      pConfigData->AccessPoint.StationAddress.Addr[2],\r
+                      pConfigData->AccessPoint.StationAddress.Addr[3],\r
+                      pConfigData->AccessPoint.StationPort,\r
+                      pConfigData->AccessPoint.RemoteAddress.Addr[0],\r
+                      pConfigData->AccessPoint.RemoteAddress.Addr[1],\r
+                      pConfigData->AccessPoint.RemoteAddress.Addr[2],\r
+                      pConfigData->AccessPoint.RemoteAddress.Addr[3],\r
+                      pConfigData->AccessPoint.RemotePort ));\r
+            DEBUG (( DEBUG_CONNECTION | DEBUG_INFO,\r
+                      "0x%08x: Listen socket adding socket 0x%08x to FIFO, depth: %d\r\n",\r
+                      pSocket,\r
+                      pNewSocket,\r
+                      pSocket->FifoDepth ));\r
+\r
+            //\r
+            //  Start the receive operation\r
+            //\r
+            EslTcpRxStart4 ( pNewPort );\r
+          }\r
+          else {\r
+            DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,\r
+                      "ERROR - GetModeData failed on port 0x%08x, Status: %r\r\n",\r
+                      pNewPort,\r
+                      Status ));\r
+          }\r
+        }\r
+        else {\r
+          //\r
+          //  The listen failed on this port\r
+          //\r
+          DEBUG (( DEBUG_LISTEN | DEBUG_INFO,\r
+                    "ERROR - Listen failed on port 0x%08x, Status: %r\r\n",\r
+                    pPort,\r
+                    Status ));\r
+\r
+          //\r
+          //  Close the listening port\r
+          //\r
+          EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );\r
+        }\r
+      }\r
+\r
+      //\r
+      //  Done with the socket if necessary\r
+      //\r
+      if ( EFI_ERROR ( Status )) {\r
+        TempStatus = EslSocketCloseStart ( &pNewSocket->SocketProtocol,\r
+                                           TRUE,\r
+                                           &pSocket->errno );\r
+        ASSERT ( EFI_SUCCESS == TempStatus );\r
+      }\r
+    }\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_CONNECTION,\r
+              "0x%08x: Socket FIFO full, connection refused\r\n",\r
+              pSocket ));\r
+\r
+    //\r
+    //  The FIFO is full or the socket is in the wrong state\r
+    //\r
+    Status = EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  //\r
+  //  Close the connection if necessary\r
+  //\r
+  if (( EFI_ERROR ( Status ))\r
+    && ( NULL == TcpPortHandle )) {\r
+    //\r
+    // TODO: Finish this code path\r
+    //  The new connection does not fit into the connection FIFO\r
+    //\r
+    //  Process:\r
+    //    Call close\r
+    //    Release the resources\r
+    \r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Allocate and initialize a DT_PORT structure.\r
+\r
+  @param [in] pSocket     Address of the socket structure.\r
+  @param [in] pService    Address of the DT_SERVICE structure.\r
+  @param [in] ChildHandle TCP4 child handle\r
+  @param [in] pIpAddress  Buffer containing IP4 network address of the local host\r
+  @param [in] PortNumber  Tcp4 port number\r
+  @param [in] DebugFlags  Flags for debug messages\r
+  @param [out] ppPort     Buffer to receive new DT_PORT structure address\r
+\r
+  @retval EFI_SUCCESS - Socket successfully created\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpPortAllocate4 (\r
+  IN DT_SOCKET * pSocket,\r
+  IN DT_SERVICE * pService,\r
+  IN EFI_HANDLE ChildHandle,\r
+  IN CONST UINT8 * pIpAddress,\r
+  IN UINT16 PortNumber,\r
+  IN UINTN DebugFlags,\r
+  OUT DT_PORT ** ppPort\r
+  )\r
+{\r
+  UINTN LengthInBytes;\r
+  EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
+  DT_LAYER * pLayer;\r
+  DT_PORT * pPort;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Use for/break instead of goto\r
+  for ( ; ; ) {\r
+    //\r
+    //  Allocate a port structure\r
+    //\r
+    pLayer = &mEslLayer;\r
+    LengthInBytes = sizeof ( *pPort );\r
+    Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
+                                 LengthInBytes,\r
+                                 (VOID **)&pPort );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+                "ERROR - Failed to allocate the port structure, Status: %r\r\n",\r
+                Status ));\r
+      pSocket->errno = ENOMEM;\r
+      pPort = NULL;\r
+      break;\r
+    }\r
+    DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+              "0x%08x: Allocate pPort, %d bytes\r\n",\r
+              pPort,\r
+              LengthInBytes ));\r
+\r
+    //\r
+    //  Initialize the port\r
+    //\r
+    ZeroMem ( pPort, LengthInBytes );\r
+    pPort->Signature = PORT_SIGNATURE;\r
+    pPort->pService = pService;\r
+    pPort->pSocket = pSocket;\r
+    pPort->pfnCloseStart = EslTcpPortCloseStart4;\r
+    pPort->DebugFlags = DebugFlags;\r
+\r
+    //\r
+    //  Allocate the receive event\r
+    //\r
+    pTcp4 = &pPort->Context.Tcp4;\r
+    Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,\r
+                                 TPL_SOCKETS,\r
+                                 (EFI_EVENT_NOTIFY)EslTcpRxComplete4,\r
+                                 pPort,\r
+                                 &pTcp4->RxToken.CompletionToken.Event);\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to create the receive event, Status: %r\r\n",\r
+                Status ));\r
+      pSocket->errno = ENOMEM;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_RX | DEBUG_POOL,\r
+              "0x%08x: Created receive event\r\n",\r
+              pTcp4->RxToken.CompletionToken.Event ));\r
+\r
+    //\r
+    //  Allocate the urgent transmit event\r
+    //\r
+    Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,\r
+                                 TPL_SOCKETS,\r
+                                 (EFI_EVENT_NOTIFY)EslTcpTxOobComplete4,\r
+                                 pPort,\r
+                                 &pTcp4->TxOobToken.CompletionToken.Event);\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to create the urgent transmit event, Status: %r\r\n",\r
+                Status ));\r
+      pSocket->errno = ENOMEM;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
+              "0x%08x: Created urgent transmit event\r\n",\r
+              pTcp4->TxOobToken.CompletionToken.Event ));\r
+\r
+    //\r
+    //  Allocate the normal transmit event\r
+    //\r
+    Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,\r
+                                 TPL_SOCKETS,\r
+                                 (EFI_EVENT_NOTIFY)EslTcpTxComplete4,\r
+                                 pPort,\r
+                                 &pTcp4->TxToken.CompletionToken.Event);\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to create the normal transmit event, Status: %r\r\n",\r
+                Status ));\r
+      pSocket->errno = ENOMEM;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
+              "0x%08x: Created normal transmit event\r\n",\r
+              pTcp4->TxToken.CompletionToken.Event ));\r
+\r
+    //\r
+    //  Allocate the close event\r
+    //\r
+    Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,\r
+                                 TPL_SOCKETS,\r
+                                 (EFI_EVENT_NOTIFY)EslTcpPortCloseComplete4,\r
+                                 pPort,\r
+                                 &pTcp4->CloseToken.CompletionToken.Event);\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to create the close event, Status: %r\r\n",\r
+                Status ));\r
+      pSocket->errno = ENOMEM;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
+              "0x%08x: Created close event\r\n",\r
+              pTcp4->CloseToken.CompletionToken.Event ));\r
+\r
+    //\r
+    //  Allocate the connection event\r
+    //\r
+    Status = gBS->CreateEvent (  EVT_NOTIFY_SIGNAL,\r
+                                 TPL_SOCKETS,\r
+                                 (EFI_EVENT_NOTIFY)EslTcpConnectComplete4,\r
+                                 pPort,\r
+                                 &pTcp4->ConnectToken.CompletionToken.Event);\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to create the connect event, Status: %r\r\n",\r
+                Status ));\r
+      pSocket->errno = ENOMEM;\r
+      break;\r
+    }\r
+    DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
+              "0x%08x: Created connect event\r\n",\r
+              pTcp4->ConnectToken.CompletionToken.Event ));\r
+\r
+    //\r
+    //  Open the port protocol\r
+    //\r
+    Status = gBS->OpenProtocol (\r
+                    ChildHandle,\r
+                    &gEfiTcp4ProtocolGuid,\r
+                    (VOID **) &pTcp4->pProtocol,\r
+                    pLayer->ImageHandle,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL );\r
+    if ( EFI_ERROR ( Status )) {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to open gEfiTcp4ProtocolGuid on controller 0x%08x\r\n",\r
+                pTcp4->Handle ));\r
+      pSocket->errno = EEXIST;\r
+      break;\r
+    }\r
+    DEBUG (( DebugFlags,\r
+              "0x%08x: gEfiTcp4ProtocolGuid opened on controller 0x%08x\r\n",\r
+              pTcp4->pProtocol,\r
+              ChildHandle ));\r
+\r
+    //\r
+    //  Set the port address\r
+    //\r
+    pTcp4->Handle = ChildHandle;\r
+    pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
+    pAccessPoint->StationPort = PortNumber;\r
+    if (( 0 == pIpAddress[0])\r
+      && ( 0 == pIpAddress[1])\r
+      && ( 0 == pIpAddress[2])\r
+      && ( 0 == pIpAddress[3])) {\r
+      pAccessPoint->UseDefaultAddress = TRUE;\r
+    }\r
+    else {\r
+      pAccessPoint->StationAddress.Addr[0] = pIpAddress[0];\r
+      pAccessPoint->StationAddress.Addr[1] = pIpAddress[1];\r
+      pAccessPoint->StationAddress.Addr[2] = pIpAddress[2];\r
+      pAccessPoint->StationAddress.Addr[3] = pIpAddress[3];\r
+      pAccessPoint->SubnetMask.Addr[0] = 0xff;\r
+      pAccessPoint->SubnetMask.Addr[1] = 0xff;\r
+      pAccessPoint->SubnetMask.Addr[2] = 0xff;\r
+      pAccessPoint->SubnetMask.Addr[3] = 0xff;\r
+    }\r
+    pAccessPoint->ActiveFlag = FALSE;\r
+    pTcp4->ConfigData.TimeToLive = 255;\r
+\r
+    //\r
+    //  Verify the socket layer synchronization\r
+    //\r
+    VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+    //\r
+    //  Add this port to the socket\r
+    //\r
+    pPort->pLinkSocket = pSocket->pPortList;\r
+    pSocket->pPortList = pPort;\r
+    DEBUG (( DebugFlags,\r
+              "0x%08x: Socket adding port: 0x%08x\r\n",\r
+              pSocket,\r
+              pPort ));\r
+\r
+    //\r
+    //  Add this port to the service\r
+    //\r
+    pPort->pLinkService = pService->pPortList;\r
+    pService->pPortList = pPort;\r
+\r
+    //\r
+    //  Return the port\r
+    //\r
+    *ppPort = pPort;\r
+    break;\r
+  }\r
+\r
+  //\r
+  //  Clean up after the error if necessary\r
+  //\r
+  if (( EFI_ERROR ( Status )) && ( NULL != pPort )) {\r
+    //\r
+    //  Close the port\r
+    //\r
+    EslTcpPortClose4 ( pPort );\r
+  }\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Close a TCP4 port.\r
+\r
+  This routine releases the resources allocated by\r
+  ::TcpPortAllocate4().\r
+  \r
+  @param [in] pPort       Address of the port structure.\r
+\r
+  @retval EFI_SUCCESS     The port is closed\r
+  @retval other           Port close error\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpPortClose4 (\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  UINTN DebugFlags;\r
+  DT_LAYER * pLayer;\r
+  DT_PACKET * pPacket;\r
+  DT_PORT * pPreviousPort;\r
+  DT_SERVICE * pService;\r
+  DT_SOCKET * pSocket;\r
+  EFI_SERVICE_BINDING_PROTOCOL * pTcp4Service;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Locate the port in the socket list\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  pLayer = &mEslLayer;\r
+  DebugFlags = pPort->DebugFlags;\r
+  pSocket = pPort->pSocket;\r
+  pPreviousPort = pSocket->pPortList;\r
+  if ( pPreviousPort == pPort ) {\r
+    //\r
+    //  Remove this port from the head of the socket list\r
+    //\r
+    pSocket->pPortList = pPort->pLinkSocket;\r
+  }\r
+  else {\r
+    //\r
+    //  Locate the port in the middle of the socket list\r
+    //\r
+    while (( NULL != pPreviousPort )\r
+      && ( pPreviousPort->pLinkSocket != pPort )) {\r
+      pPreviousPort = pPreviousPort->pLinkSocket;\r
+    }\r
+    if ( NULL != pPreviousPort ) {\r
+      //\r
+      //  Remove the port from the middle of the socket list\r
+      //\r
+      pPreviousPort->pLinkSocket = pPort->pLinkSocket;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Locate the port in the service list\r
+  //\r
+  pService = pPort->pService;\r
+  pPreviousPort = pService->pPortList;\r
+  if ( pPreviousPort == pPort ) {\r
+    //\r
+    //  Remove this port from the head of the service list\r
+    //\r
+    pService->pPortList = pPort->pLinkService;\r
+  }\r
+  else {\r
+    //\r
+    //  Locate the port in the middle of the service list\r
+    //\r
+    while (( NULL != pPreviousPort )\r
+      && ( pPreviousPort->pLinkService != pPort )) {\r
+      pPreviousPort = pPreviousPort->pLinkService;\r
+    }\r
+    if ( NULL != pPreviousPort ) {\r
+      //\r
+      //  Remove the port from the middle of the service list\r
+      //\r
+      pPreviousPort->pLinkService = pPort->pLinkService;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Empty the urgent receive queue\r
+  //\r
+  pTcp4 = &pPort->Context.Tcp4;\r
+  while ( NULL != pSocket->pRxOobPacketListHead ) {\r
+    pPacket = pSocket->pRxOobPacketListHead;\r
+    pSocket->pRxOobPacketListHead = pPacket->pNext;\r
+    pSocket->RxOobBytes -= pPacket->Op.Tcp4Rx.ValidBytes;\r
+    EslSocketPacketFree ( pPacket, DEBUG_RX );\r
+  }\r
+  pSocket->pRxOobPacketListTail = NULL;\r
+  ASSERT ( 0 == pSocket->RxOobBytes );\r
+\r
+  //\r
+  //  Empty the receive queue\r
+  //\r
+  while ( NULL != pSocket->pRxPacketListHead ) {\r
+    pPacket = pSocket->pRxPacketListHead;\r
+    pSocket->pRxPacketListHead = pPacket->pNext;\r
+    pSocket->RxBytes -= pPacket->Op.Tcp4Rx.ValidBytes;\r
+    EslSocketPacketFree ( pPacket, DEBUG_RX );\r
+  }\r
+  pSocket->pRxPacketListTail = NULL;\r
+  ASSERT ( 0 == pSocket->RxBytes );\r
+\r
+  //\r
+  //  Empty the receive free queue\r
+  //\r
+  while ( NULL != pSocket->pRxFree ) {\r
+    pPacket = pSocket->pRxFree;\r
+    pSocket->pRxFree = pPacket->pNext;\r
+    EslSocketPacketFree ( pPacket, DEBUG_RX );\r
+  }\r
+\r
+  //\r
+  //  Done with the connect event\r
+  //\r
+  if ( NULL != pTcp4->ConnectToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Closed connect event\r\n",\r
+                pTcp4->ConnectToken.CompletionToken.Event ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close the connect event, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the close event\r
+  //\r
+  if ( NULL != pTcp4->CloseToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( pTcp4->CloseToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Closed close event\r\n",\r
+                pTcp4->CloseToken.CompletionToken.Event ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close the close event, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the listen completion event\r
+  //\r
+  if ( NULL != pTcp4->ListenToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( pTcp4->ListenToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Closed listen completion event\r\n",\r
+                pTcp4->ListenToken.CompletionToken.Event ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close the listen completion event, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the receive event\r
+  //\r
+  if ( NULL != pTcp4->RxToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( pTcp4->RxToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Closed receive event\r\n",\r
+                pTcp4->RxToken.CompletionToken.Event ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close the receive event, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the normal transmit event\r
+  //\r
+  if ( NULL != pTcp4->TxToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( pTcp4->TxToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Closed normal transmit event\r\n",\r
+                pTcp4->TxToken.CompletionToken.Event ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close the normal transmit event, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the urgent transmit event\r
+  //\r
+  if ( NULL != pTcp4->TxOobToken.CompletionToken.Event ) {\r
+    Status = gBS->CloseEvent ( pTcp4->TxOobToken.CompletionToken.Event );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Closed urgent transmit event\r\n",\r
+                pTcp4->TxOobToken.CompletionToken.Event ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close the urgent transmit event, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the TCP protocol\r
+  //\r
+  pTcp4Service = pService->pInterface;\r
+  if ( NULL != pTcp4->pProtocol ) {\r
+    Status = gBS->CloseProtocol ( pTcp4->Handle,\r
+                                  &gEfiTcp4ProtocolGuid,\r
+                                  pLayer->ImageHandle,\r
+                                  NULL );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags,\r
+                "0x%08x: gEfiTcp4ProtocolGuid closed on controller 0x%08x\r\n",\r
+                pTcp4->pProtocol,\r
+                pTcp4->Handle ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags,\r
+                "ERROR - Failed to close gEfiTcp4ProtocolGuid opened on controller 0x%08x, Status: %r\r\n",\r
+                pTcp4->Handle,\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Done with the TCP port\r
+  //\r
+  if ( NULL != pTcp4->Handle ) {\r
+    Status = pTcp4Service->DestroyChild ( pTcp4Service,\r
+                                          pTcp4->Handle );\r
+    if ( !EFI_ERROR ( Status )) {\r
+      DEBUG (( DebugFlags | DEBUG_POOL,\r
+                "0x%08x: Tcp4 port handle destroyed\r\n",\r
+                pTcp4->Handle ));\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
+                "ERROR - Failed to destroy the Tcp4 port handle, Status: %r\r\n",\r
+                Status ));\r
+      ASSERT ( EFI_SUCCESS == Status );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Release the port structure\r
+  //\r
+  Status = gBS->FreePool ( pPort );\r
+  if ( !EFI_ERROR ( Status )) {\r
+    DEBUG (( DebugFlags | DEBUG_POOL,\r
+              "0x%08x: Free pPort, %d bytes\r\n",\r
+              pPort,\r
+              sizeof ( *pPort )));\r
+  }\r
+  else {\r
+    DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
+              "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",\r
+              pPort,\r
+              Status ));\r
+    ASSERT ( EFI_SUCCESS == Status );\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the port close completion\r
+\r
+  @param  Event         The close completion event\r
+\r
+  @param  pPort         The DT_PORT structure address\r
+\r
+**/\r
+VOID\r
+EslTcpPortCloseComplete4 (\r
+  IN EFI_EVENT Event,\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Update the port state\r
+  //\r
+  pPort->State = PORT_STATE_CLOSE_DONE;\r
+\r
+  //\r
+  //  Release the resources once the receive operation completes\r
+  //\r
+  Status = EslTcpPortCloseRxDone4 ( pPort );\r
+  DBG_EXIT_STATUS ( Status );\r
+}\r
+\r
+\r
+/**\r
+  Start the close operation on a TCP4 port, state 1.\r
+\r
+  Closing a port goes through the following states:\r
+  1. Port close starting - Mark the port as closing and wait for transmission to complete\r
+  2. Port TX close done - Transmissions complete, close the port and abort the receives\r
+  3. Port RX close done - Receive operations complete, close the port\r
+  4. Port closed - Release the port resources\r
+  \r
+  @param [in] pPort       Address of the port structure.\r
+  @param [in] bCloseNow   Set TRUE to abort active transfers\r
+  @param [in] DebugFlags  Flags for debug messages\r
+\r
+  @retval EFI_SUCCESS         The port is closed, not normally returned\r
+  @retval EFI_NOT_READY       The port has started the closing process\r
+  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
+                              most likely the routine was called already.\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpPortCloseStart4 (\r
+  IN DT_PORT * pPort,\r
+  IN BOOLEAN bCloseNow,\r
+  IN UINTN DebugFlags\r
+  )\r
+{\r
+  DT_SOCKET * pSocket;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Mark the port as closing\r
+  //\r
+  Status = EFI_ALREADY_STARTED;\r
+  pSocket = pPort->pSocket;\r
+  pSocket->errno = EALREADY;\r
+  if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {\r
+\r
+    //\r
+    //  Update the port state\r
+    //\r
+    pPort->State = PORT_STATE_CLOSE_STARTED;\r
+    DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+              "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",\r
+              pPort ));\r
+    pPort->bCloseNow = bCloseNow;\r
+    pPort->DebugFlags = DebugFlags;\r
+\r
+    //\r
+    //  Determine if transmits are complete\r
+    //\r
+    Status = EslTcpPortCloseTxDone4 ( pPort );\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Port close state 3\r
+\r
+  Continue the close operation after the receive is complete.\r
+\r
+  @param [in] pPort       Address of the port structure.\r
+\r
+  @retval EFI_SUCCESS         The port is closed\r
+  @retval EFI_NOT_READY       The port is still closing\r
+  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
+                              most likely the routine was called already.\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpPortCloseRxDone4 (\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  PORT_STATE PortState;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Verify that the port is closing\r
+  //\r
+  Status = EFI_ALREADY_STARTED;\r
+  PortState = pPort->State;\r
+  if (( PORT_STATE_CLOSE_TX_DONE == PortState )\r
+    || ( PORT_STATE_CLOSE_DONE == PortState )) {\r
+    //\r
+    //  Determine if the receive operation is pending\r
+    //\r
+    Status = EFI_NOT_READY;\r
+    pTcp4 = &pPort->Context.Tcp4;\r
+    if ( NULL == pTcp4->pReceivePending ) {\r
+      //\r
+      //  The receive operation is complete\r
+      //  Update the port state\r
+      //\r
+      pPort->State = PORT_STATE_CLOSE_RX_DONE;\r
+      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+                "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",\r
+                pPort ));\r
+\r
+      //\r
+      //  Determine if the close operation has completed\r
+      //\r
+      if ( PORT_STATE_CLOSE_DONE == PortState ) {\r
+        //\r
+        //  The close operation has completed\r
+        //  Release the port resources\r
+        //\r
+        Status = EslTcpPortClose4 ( pPort );\r
+      }\r
+      else\r
+      {\r
+        DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+                  "0x%08x: Port Close: Close operation still pending!\r\n",\r
+                  pPort ));\r
+      }\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+                "0x%08x: Port Close: Receive still pending!\r\n",\r
+                pPort ));\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Port close state 2\r
+\r
+  Continue the close operation after the transmission is complete.\r
+\r
+  @param [in] pPort       Address of the port structure.\r
+\r
+  @retval EFI_SUCCESS         The port is closed, not normally returned\r
+  @retval EFI_NOT_READY       The port is still closing\r
+  @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
+                              most likely the routine was called already.\r
+\r
+**/\r
+EFI_STATUS\r
+EslTcpPortCloseTxDone4 (\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  All transmissions are complete or must be stopped\r
+  //  Mark the port as TX complete\r
+  //\r
+  Status = EFI_ALREADY_STARTED;\r
+  if ( PORT_STATE_CLOSE_STARTED == pPort->State ) {\r
+    //\r
+    //  Verify that the transmissions are complete\r
+    //\r
+    pSocket = pPort->pSocket;\r
+    if ( pPort->bCloseNow\r
+         || ( EFI_SUCCESS != pSocket->TxError )\r
+         || (( 0 == pSocket->TxOobBytes )\r
+                && ( 0 == pSocket->TxBytes ))) {\r
+      //\r
+      //  Start the close operation on the port\r
+      //\r
+      pTcp4 = &pPort->Context.Tcp4;\r
+      pTcp4->CloseToken.AbortOnClose = FALSE;\r
+      pTcp4Protocol = pTcp4->pProtocol;\r
+      if ( !pTcp4->bConfigured ) {\r
+        //\r
+        //  Skip the close operation since the port is not\r
+        //  configured\r
+        //\r
+        //  Update the port state\r
+        //\r
+        pPort->State = PORT_STATE_CLOSE_DONE;\r
+        DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+                  "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",\r
+                  pPort ));\r
+        Status = EFI_SUCCESS;\r
+      }\r
+      else {\r
+        //\r
+        //  Close the configured port\r
+        //\r
+        Status = pTcp4Protocol->Close ( pTcp4Protocol,\r
+                                        &pTcp4->CloseToken );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
+                    "0x%08x: Port close started\r\n",\r
+                    pPort ));\r
+\r
+          //\r
+          //  Update the port state\r
+          //\r
+          pPort->State = PORT_STATE_CLOSE_TX_DONE;\r
+          DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+                    "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",\r
+                    pPort ));\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_ERROR | pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
+                   "ERROR - Close failed on port 0x%08x, Status: %r\r\n",\r
+                   pPort,\r
+                   Status ));\r
+          ASSERT ( EFI_SUCCESS == Status );\r
+        }\r
+      }\r
+\r
+      //\r
+      //  Determine if the receive operation is pending\r
+      //\r
+      if ( !EFI_ERROR ( Status )) {\r
+        Status = EslTcpPortCloseRxDone4 ( pPort );\r
+      }\r
+    }\r
+    else {\r
+      //\r
+      //  Transmissions are still active, exit\r
+      //\r
+      DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+                "0x%08x: Port Close: Transmits are still pending!\r\n",\r
+                pPort ));\r
+      Status = EFI_NOT_READY;\r
+      pSocket->errno = EAGAIN;\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Receive data from a network connection.\r
+\r
+\r
+  @param [in] pSocket         Address of a DT_SOCKET structure\r
+  \r
+  @param [in] Flags           Message control flags\r
+  \r
+  @param [in] BufferLength    Length of the the buffer\r
+  \r
+  @param [in] pBuffer         Address of a buffer to receive the data.\r
+  \r
+  @param [in] pDataLength     Number of received data bytes in the buffer.\r
+\r
+  @param [out] pAddress       Network address to receive the remote system address\r
+\r
+  @param [in,out] pAddressLength  Length of the remote network address structure\r
+\r
+  @retval EFI_SUCCESS - Socket data successfully received\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpReceive4 (\r
+  IN DT_SOCKET * pSocket,\r
+  IN INT32 Flags,\r
+  IN size_t BufferLength,\r
+  IN UINT8 * pBuffer,\r
+  OUT size_t * pDataLength,\r
+  OUT struct sockaddr * pAddress,\r
+  IN OUT socklen_t * pAddressLength\r
+  )\r
+{\r
+  socklen_t AddressLength;\r
+  size_t BytesToCopy;\r
+  in_addr_t IpAddress;\r
+  size_t LengthInBytes;\r
+  DT_PACKET * pPacket;\r
+  DT_PORT * pPort;\r
+  DT_PACKET ** ppQueueHead;\r
+  DT_PACKET ** ppQueueTail;\r
+  struct sockaddr_in * pRemoteAddress;\r
+  size_t * pRxDataBytes;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  struct sockaddr_in RemoteAddress;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Assume failure\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+  pSocket->errno = ENOTCONN;\r
+\r
+  //\r
+  //  Verify that the socket is connected\r
+  //\r
+  if (( SOCKET_STATE_CONNECTED == pSocket->State )\r
+    || ( PORT_STATE_RX_ERROR == pSocket->State )) {\r
+    //\r
+    //  Locate the port\r
+    //\r
+    pPort = pSocket->pPortList;\r
+    if ( NULL != pPort ) {\r
+      //\r
+      //  Determine the queue head\r
+      //\r
+      pTcp4 = &pPort->Context.Tcp4;\r
+      if ( 0 != ( Flags & MSG_OOB )) {\r
+        ppQueueHead = &pSocket->pRxOobPacketListHead;\r
+        ppQueueTail = &pSocket->pRxOobPacketListTail;\r
+        pRxDataBytes = &pSocket->RxOobBytes;\r
+      }\r
+      else {\r
+        ppQueueHead = &pSocket->pRxPacketListHead;\r
+        ppQueueTail = &pSocket->pRxPacketListTail;\r
+        pRxDataBytes = &pSocket->RxBytes;\r
+      }\r
+\r
+      //\r
+      //  Determine if there is any data on the queue\r
+      //\r
+      pPacket = *ppQueueHead;\r
+      if ( NULL != pPacket ) {\r
+        //\r
+        //  Validate the return address parameters\r
+        //\r
+        if (( NULL == pAddress ) || ( NULL != pAddressLength )) {\r
+          //\r
+          //  Return the remote system address if requested\r
+          //\r
+          if ( NULL != pAddress ) {\r
+            //\r
+            //  Build the remote address\r
+            //\r
+            ZeroMem ( &RemoteAddress, sizeof ( RemoteAddress ));\r
+            RemoteAddress.sin_len = sizeof ( RemoteAddress );\r
+            RemoteAddress.sin_family = AF_INET;\r
+            IpAddress = pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3];\r
+            IpAddress <<= 8;\r
+            IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2];\r
+            IpAddress <<= 8;\r
+            IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1];\r
+            IpAddress <<= 8;\r
+            IpAddress |= pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0];\r
+            RemoteAddress.sin_addr.s_addr = IpAddress;\r
+            RemoteAddress.sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
+\r
+            //\r
+            //  Copy the address\r
+            //\r
+            pRemoteAddress = (struct sockaddr_in *)pAddress;\r
+            AddressLength = sizeof ( *pRemoteAddress );\r
+            if ( AddressLength > *pAddressLength ) {\r
+              AddressLength = *pAddressLength;\r
+            }\r
+            CopyMem ( pRemoteAddress,\r
+                      &RemoteAddress,\r
+                      AddressLength );\r
+\r
+            //\r
+            //  Update the address length\r
+            //\r
+            *pAddressLength = AddressLength;\r
+          }\r
+\r
+          //\r
+          //  Copy the received data\r
+          //\r
+          LengthInBytes = 0;\r
+          do {\r
+            //\r
+            //  Determine the amount of received data\r
+            //\r
+            BytesToCopy = pPacket->Op.Tcp4Rx.ValidBytes;\r
+            if (( BufferLength - LengthInBytes ) < BytesToCopy ) {\r
+              BytesToCopy = BufferLength - LengthInBytes;\r
+            }\r
+            LengthInBytes += BytesToCopy;\r
+\r
+            //\r
+            //  Move the data into the buffer\r
+            //\r
+            DEBUG (( DEBUG_RX,\r
+                      "0x%08x: Port copy packet 0x%08x data into 0x%08x, 0x%08x bytes\r\n",\r
+                      pPort,\r
+                      pPacket,\r
+                      pBuffer,\r
+                      BytesToCopy ));\r
+            CopyMem ( pBuffer, pPacket->Op.Tcp4Rx.pBuffer, BytesToCopy );\r
+\r
+            //\r
+            //  Determine if the data is being read\r
+            //\r
+            if ( 0 == ( Flags & MSG_PEEK )) {\r
+              //\r
+              //  Account for the bytes consumed\r
+              //\r
+              pPacket->Op.Tcp4Rx.pBuffer += BytesToCopy;\r
+              pPacket->Op.Tcp4Rx.ValidBytes -= BytesToCopy;\r
+              *pRxDataBytes -= BytesToCopy;\r
+              DEBUG (( DEBUG_RX,\r
+                        "0x%08x: Port account for 0x%08x bytes\r\n",\r
+                        pPort,\r
+                        BytesToCopy ));\r
+\r
+              //\r
+              //  Determine if the entire packet was consumed\r
+              //\r
+              if (( 0 == pPacket->Op.Tcp4Rx.ValidBytes )\r
+                || ( SOCK_STREAM != pSocket->Type )) {\r
+                //\r
+                //  All done with this packet\r
+                //  Account for any discarded data\r
+                //\r
+                *pRxDataBytes -= pPacket->Op.Tcp4Rx.ValidBytes;\r
+                if ( 0 != pPacket->Op.Tcp4Rx.ValidBytes ) {\r
+                  DEBUG (( DEBUG_RX,\r
+                            "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",\r
+                            pPort,\r
+                            pPacket->Op.Tcp4Rx.ValidBytes ));\r
+                }\r
+\r
+                //\r
+                //  Remove this packet from the queue\r
+                //\r
+                *ppQueueHead = pPacket->pNext;\r
+                if ( NULL == *ppQueueHead ) {\r
+                  *ppQueueTail = NULL;\r
+                }\r
+\r
+                //\r
+                //  Move the packet to the free queue\r
+                //\r
+                pPacket->pNext = pSocket->pRxFree;\r
+                pSocket->pRxFree = pPacket;\r
+                DEBUG (( DEBUG_RX,\r
+                          "0x%08x: Port freeing packet 0x%08x\r\n",\r
+                          pPort,\r
+                          pPacket ));\r
+\r
+                //\r
+                //  Restart this receive operation if necessary\r
+                //\r
+                if (( NULL == pTcp4->pReceivePending )\r
+                  && ( MAX_RX_DATA > pSocket->RxBytes )) {\r
+                    EslTcpRxStart4 ( pPort );\r
+                }\r
+              }\r
+            }\r
+\r
+            //\r
+            //  Get the next packet\r
+            //\r
+            pPacket = *ppQueueHead;\r
+          } while (( SOCK_STREAM == pSocket->Type )\r
+                && ( NULL != pPacket )\r
+                && ( 0 == ( Flags & MSG_PEEK ))\r
+                && ( BufferLength > LengthInBytes ));\r
+\r
+          //\r
+          //  Return the data length\r
+          //\r
+          *pDataLength = LengthInBytes;\r
+\r
+          //\r
+          //  Successful operation\r
+          //\r
+          Status = EFI_SUCCESS;\r
+          pSocket->errno = 0;\r
+        }\r
+        else {\r
+          //\r
+          //  Bad return address pointer and length\r
+          //\r
+          Status = EFI_INVALID_PARAMETER;\r
+          pSocket->errno = EINVAL;\r
+        }\r
+      }\r
+      else {\r
+        //\r
+        //  The queue is empty\r
+        //  Determine if it is time to return the receive error\r
+        //\r
+        if ( EFI_ERROR ( pSocket->RxError )\r
+          && ( NULL == pSocket->pRxPacketListHead )\r
+          && ( NULL == pSocket->pRxOobPacketListHead )) {\r
+          Status = pSocket->RxError;\r
+          switch ( Status ) {\r
+          default:\r
+            pSocket->errno = EIO;\r
+            break;\r
+          \r
+          case EFI_CONNECTION_FIN:\r
+            pSocket->errno = ESHUTDOWN;\r
+            break;\r
+\r
+          case EFI_CONNECTION_REFUSED:\r
+            pSocket->errno = ECONNREFUSED;\r
+            break;\r
+\r
+          case EFI_CONNECTION_RESET:\r
+            pSocket->errno = ECONNRESET;\r
+            break;\r
+\r
+          case EFI_HOST_UNREACHABLE:\r
+            pSocket->errno = EHOSTUNREACH;\r
+            break;\r
+          \r
+          case EFI_NETWORK_UNREACHABLE:\r
+            pSocket->errno = ENETUNREACH;\r
+            break;\r
+          \r
+          case EFI_PORT_UNREACHABLE:\r
+            pSocket->errno = EPROTONOSUPPORT;\r
+            break;\r
+          \r
+          case EFI_PROTOCOL_UNREACHABLE:\r
+            pSocket->errno = ENOPROTOOPT;\r
+            break;\r
+          }\r
+          pSocket->RxError = EFI_SUCCESS;\r
+        }\r
+        else {\r
+          Status = EFI_NOT_READY;\r
+          pSocket->errno = EAGAIN;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Cancel the receive operations\r
+\r
+  @param [in] pSocket         Address of a DT_SOCKET structure\r
+  \r
+  @retval EFI_SUCCESS - The cancel was successful\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpRxCancel4 (\r
+  IN DT_SOCKET * pSocket\r
+  )\r
+{\r
+  DT_PACKET * pPacket;\r
+  DT_PORT * pPort;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Assume failure\r
+  //\r
+  Status = EFI_NOT_FOUND;\r
+\r
+  //\r
+  //  Locate the port\r
+  //\r
+  pPort = pSocket->pPortList;\r
+  if ( NULL != pPort ) {\r
+    //\r
+    //  Determine if a receive is pending\r
+    //\r
+    pTcp4 = &pPort->Context.Tcp4;\r
+    pPacket = pTcp4->pReceivePending;\r
+    if ( NULL != pPacket ) {\r
+      //\r
+      //  Attempt to cancel the receive operation\r
+      //\r
+      pTcp4Protocol = pTcp4->pProtocol;\r
+      Status = pTcp4Protocol->Cancel ( pTcp4Protocol,\r
+                                       &pTcp4->RxToken.CompletionToken );\r
+      if ( EFI_NOT_FOUND == Status ) {\r
+        //\r
+        //  The receive is complete\r
+        //\r
+        Status = EFI_SUCCESS;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the receive completion\r
+\r
+  Buffer the data that was just received.\r
+\r
+  @param  Event         The receive completion event\r
+\r
+  @param  pPort         The DT_PORT structure address\r
+\r
+**/\r
+VOID\r
+EslTcpRxComplete4 (\r
+  IN EFI_EVENT Event,\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  BOOLEAN bUrgent;\r
+  size_t LengthInBytes;\r
+  DT_PACKET * pPacket;\r
+  DT_PACKET * pPrevious;\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Mark this receive complete\r
+  //\r
+  pTcp4 = &pPort->Context.Tcp4;\r
+  pPacket = pTcp4->pReceivePending;\r
+  pTcp4->pReceivePending = NULL;\r
+\r
+  //\r
+  //  Determine if this receive was successful\r
+  //\r
+  pSocket = pPort->pSocket;\r
+  Status = pTcp4->RxToken.CompletionToken.Status;\r
+  if (( !EFI_ERROR ( Status )) && ( !pSocket->bRxDisable )) {\r
+    //\r
+    //  Set the buffer size and address\r
+    //\r
+    pPacket->Op.Tcp4Rx.pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;\r
+    LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
+    pPacket->Op.Tcp4Rx.ValidBytes = LengthInBytes;\r
+    pPacket->pNext = NULL;\r
+\r
+    //\r
+    //  Queue this packet\r
+    //\r
+    bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;\r
+    if ( bUrgent ) {\r
+      //\r
+      //  Add packet to the urgent list\r
+      //\r
+      pPrevious = pSocket->pRxOobPacketListTail;\r
+      if ( NULL == pPrevious ) {\r
+        pSocket->pRxOobPacketListHead = pPacket;\r
+      }\r
+      else {\r
+        pPrevious->pNext = pPacket;\r
+      }\r
+      pSocket->pRxOobPacketListTail = pPacket;\r
+\r
+      //\r
+      //  Account for the urgent data\r
+      //\r
+      pSocket->RxOobBytes += LengthInBytes;\r
+    }\r
+    else {\r
+      //\r
+      //  Add packet to the normal list\r
+      //\r
+      pPrevious = pSocket->pRxPacketListTail;\r
+      if ( NULL == pPrevious ) {\r
+        pSocket->pRxPacketListHead = pPacket;\r
+      }\r
+      else {\r
+        pPrevious->pNext = pPacket;\r
+      }\r
+      pSocket->pRxPacketListTail = pPacket;\r
+\r
+      //\r
+      //  Account for the normal data\r
+      //\r
+      pSocket->RxBytes += LengthInBytes;\r
+    }\r
+\r
+    //\r
+    //  Log the received data\r
+    //\r
+    DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+              "0x%08x: Packet queued on port 0x%08x with 0x%08x bytes of %s data\r\n",\r
+              pPacket,\r
+              pPort,\r
+              LengthInBytes,\r
+              bUrgent ? L"urgent" : L"normal" ));\r
+\r
+    //\r
+    //  Attempt to restart this receive operation\r
+    //\r
+    if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
+      EslTcpRxStart4 ( pPort );\r
+    }\r
+    else {\r
+      DEBUG (( DEBUG_RX,\r
+                "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
+                pPort,\r
+                pSocket->RxBytes ));\r
+    }\r
+  }\r
+  else\r
+  {\r
+    DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+              "ERROR - Receiving packet 0x%08x, on port 0x%08x, Status:%r\r\n",\r
+              pPacket,\r
+              pPort,\r
+              Status ));\r
+\r
+    //\r
+    //  Receive error, free the packet save the error\r
+    //\r
+    EslSocketPacketFree ( pPacket, DEBUG_RX );\r
+    if ( !EFI_ERROR ( pSocket->RxError )) {\r
+      pSocket->RxError = Status;\r
+    }\r
+\r
+    //\r
+    //  Update the port state\r
+    //\r
+    if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
+      EslTcpPortCloseRxDone4 ( pPort );\r
+    }\r
+    else {\r
+      if ( EFI_ERROR ( Status )) {\r
+        pPort->State = PORT_STATE_RX_ERROR;\r
+      }\r
+    }\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Start a receive operation\r
+\r
+  @param [in] pPort       Address of the DT_PORT structure.\r
+\r
+ **/\r
+VOID\r
+EslTcpRxStart4 (\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  size_t LengthInBytes;\r
+  DT_PACKET * pPacket;\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Determine if a receive is already pending\r
+  //\r
+  Status = EFI_SUCCESS;\r
+  pPacket = NULL;\r
+  pSocket = pPort->pSocket;\r
+  pTcp4 = &pPort->Context.Tcp4;\r
+  if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
+    if (( NULL == pTcp4->pReceivePending )\r
+      && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
+      //\r
+      //  Determine if there are any free packets\r
+      //\r
+      pPacket = pSocket->pRxFree;\r
+      LengthInBytes = sizeof ( pPacket->Op.Tcp4Rx.Buffer );\r
+      if ( NULL != pPacket ) {\r
+        //\r
+        //  Remove this packet from the free list\r
+        //\r
+        pSocket->pRxFree = pPacket->pNext;\r
+        DEBUG (( DEBUG_RX,\r
+                  "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
+                  pPort,\r
+                  pPacket ));\r
+      }\r
+      else {\r
+        //\r
+        //  Allocate a packet structure\r
+        //\r
+        Status = EslSocketPacketAllocate ( &pPacket,\r
+                                           sizeof ( pPacket->Op.Tcp4Rx ),\r
+                                           DEBUG_RX );\r
+        if ( EFI_ERROR ( Status )) {\r
+          pPacket = NULL;\r
+          DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
+                    "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",\r
+                    pPort,\r
+                    Status ));\r
+        }\r
+      }\r
+\r
+      //\r
+      //  Determine if a packet is available\r
+      //\r
+      if ( NULL != pPacket ) {\r
+        //\r
+        //  Initialize the buffer for receive\r
+        //\r
+        pTcp4->RxToken.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;\r
+        pPacket->Op.Tcp4Rx.RxData.DataLength = (UINT32) LengthInBytes;\r
+        pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;\r
+        pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentLength = (UINT32) LengthInBytes;\r
+        pPacket->Op.Tcp4Rx.RxData.FragmentTable [0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer [0];\r
+        pTcp4->pReceivePending = pPacket;\r
+\r
+        //\r
+        //  Start the receive on the packet\r
+        //\r
+        pTcp4Protocol = pTcp4->pProtocol;\r
+        Status = pTcp4Protocol->Receive ( pTcp4Protocol,\r
+                                          &pTcp4->RxToken );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+                    "0x%08x: Packet receive pending on port 0x%08x\r\n",\r
+                    pPacket,\r
+                    pPort ));\r
+        }\r
+        else {\r
+          DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+                    "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",\r
+                    pPort,\r
+                    Status ));\r
+          pTcp4->pReceivePending = NULL;\r
+          if ( !EFI_ERROR ( pSocket->RxError )) {\r
+            //\r
+            //  Save the error status\r
+            //\r
+            pSocket->RxError = Status;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Shutdown the TCP4 service.\r
+\r
+  This routine undoes the work performed by ::TcpInitialize4.\r
+\r
+  @param [in] pService        DT_SERVICE structure address\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EslTcpShutdown4 (\r
+  IN DT_SERVICE * pService\r
+  )\r
+{\r
+  DT_LAYER * pLayer;\r
+  DT_PORT * pPort;\r
+  DT_SERVICE * pPreviousService;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Verify the socket layer synchronization\r
+  //\r
+  VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+  //\r
+  //  Walk the list of ports\r
+  //\r
+  do {\r
+    pPort = pService->pPortList;\r
+    if ( NULL != pPort ) {\r
+      //\r
+      //  Remove the port from the port list\r
+      //\r
+      pService->pPortList = pPort->pLinkService;\r
+\r
+      //\r
+      //  Close the port\r
+      // TODO: Fix this\r
+      //\r
+//      pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );\r
+    }\r
+  } while ( NULL != pPort );\r
+\r
+  //\r
+  //  Remove the service from the service list\r
+  //\r
+  pLayer = &mEslLayer;\r
+  pPreviousService = pLayer->pTcp4List;\r
+  if ( pService == pPreviousService ) {\r
+    //\r
+    //  Remove the service from the beginning of the list\r
+    //\r
+    pLayer->pTcp4List = pService->pNext;\r
+  }\r
+  else {\r
+    //\r
+    //  Remove the service from the middle of the list\r
+    //\r
+    while ( NULL != pPreviousService ) {\r
+      if ( pService == pPreviousService->pNext ) {\r
+        pPreviousService->pNext = pService->pNext;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Determine if the socket is configured.\r
+\r
+\r
+  @param [in] pSocket         Address of a DT_SOCKET structure\r
+  \r
+  @retval EFI_SUCCESS - The port is connected\r
+  @retval EFI_NOT_STARTED - The port is not connected\r
+\r
+ **/\r
+ EFI_STATUS\r
+ EslTcpSocketIsConfigured4 (\r
+  IN DT_SOCKET * pSocket\r
+  )\r
+{\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Determine the socket configuration status\r
+  //\r
+  Status = pSocket->bConfigured ? EFI_SUCCESS : EFI_NOT_STARTED;\r
+\r
+  //\r
+  //  Return the port connected state.\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Buffer data for transmission over a network connection.\r
+\r
+  This routine is called by the socket layer API to buffer\r
+  data for transmission.  When necessary, this routine will\r
+  start the transmit engine that performs the data transmission\r
+  on the network connection.\r
+\r
+  The transmit engine uses two queues, one for urgent (out-of-band)\r
+  data and the other for normal data.  The urgent data is provided\r
+  to TCP as soon as it is available, allowing the TCP layer to\r
+  schedule transmission of the urgent data between packets of normal\r
+  data.\r
+\r
+  Transmission errors are returned during the next transmission or\r
+  during the close operation.  Only buffering errors are returned\r
+  during the current transmission attempt.\r
+\r
+  @param [in] pSocket         Address of a DT_SOCKET structure\r
+  \r
+  @param [in] Flags           Message control flags\r
+  \r
+  @param [in] BufferLength    Length of the the buffer\r
+  \r
+  @param [in] pBuffer         Address of a buffer to receive the data.\r
+  \r
+  @param [in] pDataLength     Number of received data bytes in the buffer.\r
+\r
+  @retval EFI_SUCCESS - Socket data successfully buffered\r
+\r
+ **/\r
+EFI_STATUS\r
+EslTcpTxBuffer4 (\r
+  IN DT_SOCKET * pSocket,\r
+  IN int Flags,\r
+  IN size_t BufferLength,\r
+  IN CONST UINT8 * pBuffer,\r
+  OUT size_t * pDataLength\r
+  )\r
+{\r
+  BOOLEAN bUrgent;\r
+  DT_PACKET * pPacket;\r
+  DT_PACKET * pPreviousPacket;\r
+  DT_PACKET ** ppPacket;\r
+  DT_PACKET ** ppQueueHead;\r
+  DT_PACKET ** ppQueueTail;\r
+  DT_PORT * pPort;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_TCP4_IO_TOKEN * pToken;\r
+  size_t * pTxBytes;\r
+  EFI_TCP4_TRANSMIT_DATA * pTxData;\r
+  EFI_STATUS Status;\r
+  EFI_TPL TplPrevious;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Assume failure\r
+  //\r
+  Status = EFI_UNSUPPORTED;\r
+  pSocket->errno = ENOTCONN;\r
+  * pDataLength = 0;\r
+\r
+  //\r
+  //  Verify that the socket is connected\r
+  //\r
+  if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
+    //\r
+    //  Locate the port\r
+    //\r
+    pPort = pSocket->pPortList;\r
+    if ( NULL != pPort ) {\r
+      //\r
+      //  Determine the queue head\r
+      //\r
+      pTcp4 = &pPort->Context.Tcp4;\r
+      bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
+      if ( bUrgent ) {\r
+        ppQueueHead = &pSocket->pTxOobPacketListHead;\r
+        ppQueueTail = &pSocket->pTxOobPacketListTail;\r
+        ppPacket = &pTcp4->pTxOobPacket;\r
+        pToken = &pTcp4->TxOobToken;\r
+        pTxBytes = &pSocket->TxOobBytes;\r
+      }\r
+      else {\r
+        ppQueueHead = &pSocket->pTxPacketListHead;\r
+        ppQueueTail = &pSocket->pTxPacketListTail;\r
+        ppPacket = &pTcp4->pTxPacket;\r
+        pToken = &pTcp4->TxToken;\r
+        pTxBytes = &pSocket->TxBytes;\r
+      }\r
+\r
+      //\r
+      //  Verify that there is enough room to buffer another\r
+      //  transmit operation\r
+      //\r
+      if ( pSocket->MaxTxBuf > *pTxBytes ) {\r
+        //\r
+        //  Attempt to allocate the packet\r
+        //\r
+        Status = EslSocketPacketAllocate ( &pPacket,\r
+                                           sizeof ( pPacket->Op.Tcp4Tx )\r
+                                           - sizeof ( pPacket->Op.Tcp4Tx.Buffer )\r
+                                           + BufferLength,\r
+                                           DEBUG_TX );\r
+        if ( !EFI_ERROR ( Status )) {\r
+          //\r
+          //  Initialize the transmit operation\r
+          //\r
+          pTxData = &pPacket->Op.Tcp4Tx.TxData;\r
+          pTxData->Push = TRUE;\r
+          pTxData->Urgent = bUrgent;\r
+          pTxData->DataLength = (UINT32) BufferLength;\r
+          pTxData->FragmentCount = 1;\r
+          pTxData->FragmentTable[0].FragmentLength = (UINT32) BufferLength;\r
+          pTxData->FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Tx.Buffer[0];\r
+\r
+          //\r
+          //  Copy the data into the buffer\r
+          //\r
+          CopyMem ( &pPacket->Op.Tcp4Tx.Buffer[0],\r
+                    pBuffer,\r
+                    BufferLength );\r
+\r
+          //\r
+          //  Synchronize with the socket layer\r
+          //\r
+          RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+          //\r
+          //  Stop transmission after an error\r
+          //\r
+          if ( !EFI_ERROR ( pSocket->TxError )) {\r
+            //\r
+            //  Display the request\r
+            //\r
+            DEBUG (( DEBUG_TX,\r
+                      "Send %d %s bytes from 0x%08x\r\n",\r
+                      BufferLength,\r
+                      bUrgent ? L"urgent" : L"normal",\r
+                      pBuffer ));\r
+\r
+            //\r
+            //  Queue the data for transmission\r
+            //\r
+            pPacket->pNext = NULL;\r
+            pPreviousPacket = *ppQueueTail;\r
+            if ( NULL == pPreviousPacket ) {\r
+              *ppQueueHead = pPacket;\r
+            }\r
+            else {\r
+              pPreviousPacket->pNext = pPacket;\r
+            }\r
+            *ppQueueTail = pPacket;\r
+            DEBUG (( DEBUG_TX,\r
+                      "0x%08x: Packet on %s transmit list\r\n",\r
+                      pPacket,\r
+                      bUrgent ? L"urgent" : L"normal" ));\r
+\r
+            //\r
+            //  Account for the buffered data\r
+            //\r
+            *pTxBytes += BufferLength;\r
+            *pDataLength = BufferLength;\r
+\r
+            //\r
+            //  Start the transmit engine if it is idle\r
+            //\r
+            if ( NULL == *ppPacket ) {\r
+              EslTcpTxStart4 ( pSocket->pPortList,\r
+                               pToken,\r
+                               ppQueueHead,\r
+                               ppQueueTail,\r
+                               ppPacket );\r
+            }\r
+          }\r
+          else {\r
+            //\r
+            //  Previous transmit error\r
+            //  Stop transmission\r
+            //\r
+            Status = pSocket->TxError;\r
+            pSocket->errno = EIO;\r
+\r
+            //\r
+            //  Free the packet\r
+            //\r
+            EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+          }\r
+\r
+          //\r
+          //  Release the socket layer synchronization\r
+          //\r
+          RESTORE_TPL ( TplPrevious );\r
+        }\r
+        else {\r
+          //\r
+          //  Packet allocation failed\r
+          //\r
+          pSocket->errno = ENOMEM;\r
+        }\r
+      }\r
+      else {\r
+        //\r
+        //  Not enough buffer space available\r
+        //\r
+        pSocket->errno = EAGAIN;\r
+        Status = EFI_NOT_READY;\r
+      }\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Return the operation status\r
+  //\r
+  DBG_EXIT_STATUS ( Status );\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Process the normal data transmit completion\r
+\r
+  @param  Event         The normal transmit completion event\r
+\r
+  @param  pPort         The DT_PORT structure address\r
+\r
+**/\r
+VOID\r
+EslTcpTxComplete4 (\r
+  IN EFI_EVENT Event,\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  UINT32 LengthInBytes;\r
+  DT_PACKET * pCurrentPacket;\r
+  DT_PACKET * pNextPacket;\r
+  DT_PACKET * pPacket;\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+  \r
+  DBG_ENTER ( );\r
+  \r
+  //\r
+  //  Locate the active transmit packet\r
+  //\r
+  pSocket = pPort->pSocket;\r
+  pTcp4 = &pPort->Context.Tcp4;\r
+  pPacket = pTcp4->pTxPacket;\r
+  \r
+  //\r
+  //  Mark this packet as complete\r
+  //\r
+  pTcp4->pTxPacket = NULL;\r
+  LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
+  pSocket->TxBytes -= LengthInBytes;\r
+  \r
+  //\r
+  //  Save any transmit error\r
+  //\r
+  Status = pTcp4->TxToken.CompletionToken.Status;\r
+  if ( EFI_ERROR ( Status )) {\r
+    if ( !EFI_ERROR ( pSocket->TxError )) {\r
+      pSocket->TxError = Status;\r
+    }\r
+    DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+              "ERROR - Transmit failure for packet 0x%08x, Status: %r\r\n",\r
+              pPacket,\r
+              Status ));\r
+\r
+    //\r
+    //  Empty the normal transmit list\r
+    //\r
+    pCurrentPacket = pPacket;\r
+    pNextPacket = pSocket->pTxPacketListHead;\r
+    while ( NULL != pNextPacket ) {\r
+      pPacket = pNextPacket;\r
+      pNextPacket = pPacket->pNext;\r
+      EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+    }\r
+    pSocket->pTxPacketListHead = NULL;\r
+    pSocket->pTxPacketListTail = NULL;\r
+    pPacket = pCurrentPacket;\r
+  }\r
+  else\r
+  {\r
+    DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+              "0x%08x: Packet transmitted %d bytes successfully\r\n",\r
+              pPacket,\r
+              LengthInBytes ));\r
+\r
+    //\r
+    //  Verify the transmit engine is still running\r
+    //\r
+    if ( !pPort->bCloseNow ) {\r
+      //\r
+      //  Start the next packet transmission\r
+      //\r
+      EslTcpTxStart4 ( pPort,\r
+                       &pTcp4->TxToken,\r
+                       &pSocket->pTxPacketListHead,\r
+                       &pSocket->pTxPacketListTail,\r
+                       &pTcp4->pTxPacket );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Release this packet\r
+  //\r
+  EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+\r
+  //\r
+  //  Finish the close operation if necessary\r
+  //\r
+  if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
+    //\r
+    //  Indicate that the transmit is complete\r
+    //\r
+    EslTcpPortCloseTxDone4 ( pPort );\r
+  }\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Process the urgent data transmit completion\r
+\r
+  @param  Event         The urgent transmit completion event\r
+\r
+  @param  pPort         The DT_PORT structure address\r
+\r
+**/\r
+VOID\r
+EslTcpTxOobComplete4 (\r
+  IN EFI_EVENT Event,\r
+  IN DT_PORT * pPort\r
+  )\r
+{\r
+  UINT32 LengthInBytes;\r
+  DT_PACKET * pCurrentPacket;\r
+  DT_PACKET * pNextPacket;\r
+  DT_PACKET * pPacket;\r
+  DT_SOCKET * pSocket;\r
+  DT_TCP4_CONTEXT * pTcp4;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Locate the active transmit packet\r
+  //\r
+  pSocket = pPort->pSocket;\r
+  pTcp4 = &pPort->Context.Tcp4;\r
+  pPacket = pTcp4->pTxOobPacket;\r
+\r
+  //\r
+  //  Mark this packet as complete\r
+  //\r
+  pTcp4->pTxOobPacket = NULL;\r
+  LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
+  pSocket->TxOobBytes -= LengthInBytes;\r
+\r
+  //\r
+  //  Save any transmit error\r
+  //\r
+  Status = pTcp4->TxOobToken.CompletionToken.Status;\r
+  if ( EFI_ERROR ( Status )) {\r
+    if ( !EFI_ERROR ( Status )) {\r
+      pSocket->TxError = Status;\r
+    }\r
+    DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+              "ERROR - Transmit failure for urgent packet 0x%08x, Status: %r\r\n",\r
+              pPacket,\r
+              Status ));\r
+\r
+\r
+    //\r
+    //  Empty the OOB transmit list\r
+    //\r
+    pCurrentPacket = pPacket;\r
+    pNextPacket = pSocket->pTxOobPacketListHead;\r
+    while ( NULL != pNextPacket ) {\r
+      pPacket = pNextPacket;\r
+      pNextPacket = pPacket->pNext;\r
+      EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+    }\r
+    pSocket->pTxOobPacketListHead = NULL;\r
+    pSocket->pTxOobPacketListTail = NULL;\r
+    pPacket = pCurrentPacket;\r
+  }\r
+  else\r
+  {\r
+    DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+              "0x%08x: Urgent packet transmitted %d bytes successfully\r\n",\r
+              pPacket,\r
+              LengthInBytes ));\r
+\r
+    //\r
+    //  Verify the transmit engine is still running\r
+    //\r
+    if ( !pPort->bCloseNow ) {\r
+      //\r
+      //  Start the next packet transmission\r
+      //\r
+      EslTcpTxStart4 ( pPort,\r
+                       &pTcp4->TxOobToken,\r
+                       &pSocket->pTxOobPacketListHead,\r
+                       &pSocket->pTxOobPacketListTail,\r
+                       &pTcp4->pTxOobPacket );\r
+    }\r
+  }\r
+\r
+  //\r
+  //  Release this packet\r
+  //\r
+  EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+\r
+  //\r
+  //  Finish the close operation if necessary\r
+  //\r
+  if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
+    //\r
+    //  Indicate that the transmit is complete\r
+    //\r
+    EslTcpPortCloseTxDone4 ( pPort );\r
+  }\r
+  DBG_EXIT ( );\r
+}\r
+\r
+\r
+/**\r
+  Transmit data using a network connection.\r
+\r
+\r
+  @param [in] pPort           Address of a DT_PORT structure\r
+  @param [in] pToken          Address of either the OOB or normal transmit token\r
+  @param [in] ppQueueHead     Transmit queue head address\r
+  @param [in] ppQueueTail     Transmit queue tail address\r
+  @param [in] ppPacket        Active transmit packet address\r
+\r
+ **/\r
+VOID\r
+EslTcpTxStart4 (\r
+  IN DT_PORT * pPort,\r
+  IN EFI_TCP4_IO_TOKEN * pToken,\r
+  IN DT_PACKET ** ppQueueHead,\r
+  IN DT_PACKET ** ppQueueTail,\r
+  IN DT_PACKET ** ppPacket\r
+  )\r
+{\r
+  DT_PACKET * pNextPacket;\r
+  DT_PACKET * pPacket;\r
+  DT_SOCKET * pSocket;\r
+  EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
+  EFI_STATUS Status;\r
+\r
+  DBG_ENTER ( );\r
+\r
+  //\r
+  //  Assume success\r
+  //\r
+  Status = EFI_SUCCESS;\r
+\r
+  //\r
+  //  Get the packet from the queue head\r
+  //\r
+  pPacket = *ppQueueHead;\r
+  if ( NULL != pPacket ) {\r
+    //\r
+    //  Remove the packet from the queue\r
+    //\r
+    pNextPacket = pPacket->pNext;\r
+    *ppQueueHead = pNextPacket;\r
+    if ( NULL == pNextPacket ) {\r
+      *ppQueueTail = NULL;\r
+    }\r
+\r
+    //\r
+    //  Set the packet as active\r
+    //\r
+    *ppPacket = pPacket;\r
+\r
+    //\r
+    //  Start the transmit operation\r
+    //\r
+    pTcp4Protocol = pPort->Context.Tcp4.pProtocol;\r
+    pToken->Packet.TxData = &pPacket->Op.Tcp4Tx.TxData;\r
+    Status = pTcp4Protocol->Transmit ( pTcp4Protocol, pToken );\r
+    if ( EFI_ERROR ( Status )) {\r
+      pSocket = pPort->pSocket;\r
+      if ( EFI_SUCCESS == pSocket->TxError ) {\r
+        pSocket->TxError = Status;\r
+      }\r
+    }\r
+  }\r
+\r
+  DBG_EXIT ( );\r
+}\r