+/** @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