+++ /dev/null
-/** @file\r
- Implement the TCP4 driver support for the socket layer.\r
-\r
- Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-\r
- \section ConnectionManagement Connection Management\r
-\r
- The ::EslTcp4Listen routine initially places the SOCK_STREAM or\r
- SOCK_SEQPACKET socket into a listen state. When a remote machine\r
- makes a connection to the socket, the TCPv4 network layer calls\r
- ::EslTcp4ListenComplete to complete the connection processing.\r
- EslTcp4ListenComplete manages the connections by placing them in\r
- FIFO order in a queue to be serviced by the application. When the\r
- number of connections exceeds the backlog (ESL_SOCKET::MaxFifoDepth),\r
- the new connection is closed. Eventually, the application indirectly\r
- calls ::EslTcp4Accept to remove the next connection from the queue\r
- and get the associated socket.\r
-\r
-**/\r
-\r
-#include "Socket.h"\r
-\r
-\r
-/**\r
- Attempt to connect to a remote TCP port\r
-\r
- This routine starts the connection processing for a SOCK_STREAM\r
- or SOCK_SEQPAKCET socket using the TCPv4 network layer. It\r
- configures the local TCPv4 connection point and then attempts to\r
- connect to a remote system. Upon completion, the\r
- ::EslTcp4ConnectComplete routine gets called with the connection\r
- status.\r
-\r
- This routine is called by ::EslSocketConnect to initiate the TCPv4\r
- network specific connect operations. The connection processing is\r
- initiated by this routine and finished by ::EslTcp4ConnectComplete.\r
- This pair of routines walks through the list of local TCPv4\r
- connection points until a connection to the remote system is\r
- made.\r
-\r
- @param [in] pSocket Address of an ::ESL_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
-EslTcp4ConnectStart (\r
- IN ESL_SOCKET * pSocket\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
- The TCPv4 layer calls this routine when a connection is made to\r
- the socket in the listen state. See the\r
- \ref ConnectionManagement section.\r
-\r
- @param [in] Event The listen completion event\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
-**/\r
-VOID\r
-EslTcp4ListenComplete (\r
- IN EFI_EVENT Event,\r
- IN ESL_PORT * pPort\r
- );\r
-\r
-\r
-/**\r
- Accept a network connection.\r
-\r
- This routine waits for a network connection to the socket and\r
- returns the remote network address to the caller if requested.\r
-\r
- This routine is called by ::EslSocketAccept to handle the TCPv4 protocol\r
- specific accept operations for SOCK_STREAM and SOCK_SEQPACKET sockets.\r
- See the \ref ConnectionManagement section.\r
-\r
- @param [in] pSocket Address of an ::ESL_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
-EslTcp4Accept (\r
- IN ESL_SOCKET * pSocket,\r
- IN struct sockaddr * pSockAddr,\r
- IN OUT socklen_t * pSockAddrLength\r
- )\r
-{\r
- ESL_PORT * pPort;\r
- struct sockaddr_in * pRemoteAddress;\r
- ESL_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
- Process the remote connection completion event.\r
-\r
- This routine handles the completion of a connection attempt. It\r
- releases the port (TCPv4 adapter connection) in the case of an\r
- error and start a connection attempt on the next port. If the\r
- connection attempt was successful then this routine releases all\r
- of the other ports.\r
-\r
- This routine is called by the TCPv4 layer when a connect request\r
- completes. It sets the ESL_SOCKET::bConnected flag to notify the\r
- ::EslTcp4ConnectComplete routine that the connection is available.\r
- The flag is set when the connection is established or no more ports\r
- exist in the list. The connection status is passed via\r
- ESL_SOCKET::ConnectStatus.\r
-\r
- @param [in] Event The connect completion event\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
-**/\r
-VOID\r
-EslTcp4ConnectComplete (\r
- IN EFI_EVENT Event,\r
- IN ESL_PORT * pPort\r
- )\r
-{\r
- BOOLEAN bRemoveFirstPort;\r
- BOOLEAN bRemovePorts;\r
- ESL_PORT * pNextPort;\r
- ESL_SOCKET * pSocket;\r
- ESL_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
- // Start the receive operations\r
- //\r
- pSocket->bConfigured = TRUE;\r
- pSocket->State = SOCKET_STATE_CONNECTED;\r
- EslSocketRxStart ( pPort );\r
-\r
- //\r
- // Remove the rest of the ports\r
- //\r
- bRemovePorts = TRUE;\r
- }\r
- else {\r
- //\r
- // The connection failed\r
- //\r
- if ( pPort->bConfigured ) {\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
- //\r
- // Close the current port\r
- //\r
- Status = EslSocketPortClose ( 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 = EslTcp4ConnectStart ( pSocket );\r
- if ( EFI_NOT_READY != 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
- EslSocketPortClose ( 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
- This routine polls the ESL_SOCKET::bConnected flag to determine\r
- when the connection attempt is complete.\r
-\r
- This routine is called from ::EslSocketConnect to determine when\r
- the connection is complete. The ESL_SOCKET::bConnected flag is\r
- set by ::EslTcp4ConnectComplete when the TCPv4 layer establishes\r
- a connection or runs out of local network adapters. This routine\r
- gets the connection status from ESL_SOCKET::ConnectStatus.\r
-\r
- @param [in] pSocket Address of an ::ESL_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
-EslTcp4ConnectPoll (\r
- IN ESL_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 = ECONNABORTED;\r
- break;\r
-\r
- case EFI_ACCESS_DENIED:\r
- pSocket->errno = EACCES;\r
- break;\r
-\r
- case EFI_CONNECTION_RESET:\r
- pSocket->errno = ECONNRESET;\r
- break;\r
-\r
- case EFI_INVALID_PARAMETER:\r
- pSocket->errno = EADDRNOTAVAIL;\r
- break;\r
-\r
- case EFI_HOST_UNREACHABLE:\r
- case EFI_NO_RESPONSE:\r
- pSocket->errno = EHOSTUNREACH;\r
- break;\r
-\r
- case EFI_NO_MAPPING:\r
- pSocket->errno = EAFNOSUPPORT;\r
- break;\r
-\r
- case EFI_NO_MEDIA:\r
- case EFI_NETWORK_UNREACHABLE:\r
- pSocket->errno = ENETDOWN;\r
- break;\r
-\r
- case EFI_OUT_OF_RESOURCES:\r
- pSocket->errno = ENOBUFS;\r
- break;\r
-\r
- case EFI_PORT_UNREACHABLE:\r
- case EFI_PROTOCOL_UNREACHABLE:\r
- case EFI_CONNECTION_REFUSED:\r
- pSocket->errno = ECONNREFUSED;\r
- break;\r
-\r
- case EFI_SUCCESS:\r
- pSocket->errno = 0;\r
- break;\r
-\r
- case EFI_TIMEOUT:\r
- pSocket->errno = ETIMEDOUT;\r
- break;\r
-\r
- case EFI_UNSUPPORTED:\r
- pSocket->errno = EOPNOTSUPP;\r
- break;\r
- }\r
-\r
- //\r
- // Display the translation\r
- //\r
- DEBUG (( DEBUG_CONNECT,\r
- "ERROR - errno: %d, Status: %r\r\n",\r
- pSocket->errno,\r
- Status ));\r
- }\r
-\r
- //\r
- // Return the initialization 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
- This routine starts the connection processing for a SOCK_STREAM\r
- or SOCK_SEQPAKCET socket using the TCPv4 network layer. It\r
- configures the local TCPv4 connection point and then attempts to\r
- connect to a remote system. Upon completion, the\r
- ::EslTcp4ConnectComplete routine gets called with the connection\r
- status.\r
-\r
- This routine is called by ::EslSocketConnect to initiate the TCPv4\r
- network specific connect operations. The connection processing is\r
- initiated by this routine and finished by ::EslTcp4ConnectComplete.\r
- This pair of routines walks through the list of local TCPv4\r
- connection points until a connection to the remote system is\r
- made.\r
-\r
- @param [in] pSocket Address of an ::ESL_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
-EslTcp4ConnectStart (\r
- IN ESL_SOCKET * pSocket\r
- )\r
-{\r
- ESL_PORT * pPort;\r
- ESL_TCP4_CONTEXT * pTcp4;\r
- EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
- EFI_SIMPLE_NETWORK_MODE SnpModeData;\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 = pPort->pProtocol.TCPv4;\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
- }\r
- else {\r
- DEBUG (( DEBUG_CONNECT,\r
- "0x%08x: Port configured\r\n",\r
- pPort ));\r
- pPort->bConfigured = TRUE;\r
-\r
- //\r
- // Verify the port connection\r
- //\r
- Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,\r
- NULL,\r
- NULL,\r
- NULL,\r
- NULL,\r
- &SnpModeData );\r
- if ( !EFI_ERROR ( Status )) {\r
- if ( SnpModeData.MediaPresentSupported\r
- && ( !SnpModeData.MediaPresent )) {\r
- //\r
- // Port is not connected to the network\r
- //\r
- Status = EFI_NO_MEDIA;\r
- }\r
- else {\r
- //\r
- // Attempt the connection to the remote system\r
- //\r
- Status = pTcp4Protocol->Connect ( pTcp4Protocol,\r
- &pTcp4->ConnectToken );\r
- }\r
- }\r
- if ( EFI_ERROR ( Status )) {\r
- //\r
- // Connection error\r
- //\r
- DEBUG (( DEBUG_CONNECT,\r
- "ERROR - Port 0x%08x not connected, Status: %r\r\n",\r
- pPort,\r
- Status ));\r
- }\r
- }\r
- if ( !EFI_ERROR ( Status )) {\r
- //\r
- // Connection in progress\r
- //\r
- pSocket->errno = EINPROGRESS;\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
- // Error return path is through EslTcp4ConnectComplete to\r
- // enable retry on other ports\r
- //\r
- // Status to errno translation gets done in EslTcp4ConnectPoll\r
- //\r
- pTcp4->ConnectToken.CompletionToken.Status = Status;\r
-\r
- //\r
- // Continue with the next port\r
- //\r
- gBS->CheckEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
- gBS->SignalEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
- }\r
- Status = EFI_NOT_READY;\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
- Establish the known port to listen for network connections.\r
-\r
- This routine places the port into a state that enables connection\r
- attempts.\r
-\r
- This routine is called by ::EslSocketListen to handle the network\r
- specifics of the listen operation for SOCK_STREAM and SOCK_SEQPACKET\r
- sockets. See the \ref ConnectionManagement section.\r
-\r
- @param [in] pSocket Address of an ::ESL_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
-EslTcp4Listen (\r
- IN ESL_SOCKET * pSocket\r
- )\r
-{\r
- ESL_PORT * pNextPort;\r
- ESL_PORT * pPort;\r
- ESL_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)EslTcp4ListenComplete,\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 = pPort->pProtocol.TCPv4;\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
- pPort->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
- EslSocketPortCloseStart ( 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
- Status = EFI_SUCCESS;\r
- pSocket->errno = 0;\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
- The TCPv4 layer calls this routine when a connection is made to\r
- the socket in the listen state. See the\r
- \ref ConnectionManagement section.\r
-\r
- @param [in] Event The listen completion event\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
-**/\r
-VOID\r
-EslTcp4ListenComplete (\r
- IN EFI_EVENT Event,\r
- IN ESL_PORT * pPort\r
- )\r
-{\r
- EFI_HANDLE ChildHandle;\r
- struct sockaddr_in LocalAddress;\r
- EFI_TCP4_CONFIG_DATA * pConfigData;\r
- ESL_PORT * pNewPort;\r
- ESL_SOCKET * pNewSocket;\r
- ESL_SOCKET * pSocket;\r
- ESL_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
- VERIFY_AT_TPL ( TPL_SOCKETS );\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
- Status = EslSocketAllocate ( &ChildHandle,\r
- DEBUG_CONNECTION,\r
- &pNewSocket );\r
- if ( !EFI_ERROR ( Status )) {\r
- //\r
- // Clone the socket parameters\r
- //\r
- pNewSocket->pApi = pSocket->pApi;\r
- pNewSocket->Domain = pSocket->Domain;\r
- pNewSocket->Protocol = pSocket->Protocol;\r
- pNewSocket->Type = pSocket->Type;\r
-\r
- //\r
- // Build the local address\r
- //\r
- pTcp4 = &pPort->Context.Tcp4;\r
- LocalAddress.sin_len = (uint8_t)pNewSocket->pApi->MinimumAddressLength;\r
- LocalAddress.sin_family = AF_INET;\r
- LocalAddress.sin_port = 0;\r
- LocalAddress.sin_addr.s_addr = *(UINT32 *)&pTcp4->ConfigData.AccessPoint.StationAddress.Addr[0];\r
-\r
- //\r
- // Allocate a port for this connection\r
- // Note in this instance Configure may not be called with NULL!\r
- //\r
- Status = EslSocketPortAllocate ( pNewSocket,\r
- pPort->pService,\r
- TcpPortHandle,\r
- (struct sockaddr *)&LocalAddress,\r
- FALSE,\r
- DEBUG_CONNECTION,\r
- &pNewPort );\r
- if ( !EFI_ERROR ( Status )) {\r
- //\r
- // Restart the listen operation on the port\r
- //\r
- pTcp4Protocol = pPort->pProtocol.TCPv4;\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
-\r
- //\r
- // Check for an accept call error\r
- //\r
- if ( !EFI_ERROR ( Status )) {\r
- //\r
- // Get the port configuration\r
- //\r
- pNewPort->bConfigured = TRUE;\r
- pConfigData = &pTcp4->ConfigData;\r
- pConfigData->ControlOption = &pTcp4->Option;\r
- pTcp4Protocol = pNewPort->pProtocol.TCPv4;\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
- EslSocketRxStart ( 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
- EslSocketPortCloseStart ( 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
- Get the local socket address.\r
-\r
- This routine returns the IPv4 address and TCP port number associated\r
- with the local socket.\r
-\r
- This routine is called by ::EslSocketGetLocalAddress to determine the\r
- network address for the SOCK_STREAM or SOCK_SEQPACKET socket.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
- @param [out] pSockAddr Network address to receive the local system address\r
-\r
-**/\r
-VOID\r
-EslTcp4LocalAddressGet (\r
- IN ESL_PORT * pPort,\r
- OUT struct sockaddr * pSockAddr\r
- )\r
-{\r
- struct sockaddr_in * pLocalAddress;\r
- ESL_TCP4_CONTEXT * pTcp4;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Return the local address\r
- //\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pLocalAddress = (struct sockaddr_in *)pSockAddr;\r
- pLocalAddress->sin_family = AF_INET;\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
-\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Set the local port address.\r
-\r
- This routine sets the local port address.\r
-\r
- This support routine is called by ::EslSocketPortAllocate.\r
-\r
- @param [in] pPort Address of an ESL_PORT structure\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] bBindTest TRUE = run bind testing\r
-\r
- @retval EFI_SUCCESS The operation was successful\r
-\r
- **/\r
-EFI_STATUS\r
-EslTcp4LocalAddressSet (\r
- IN ESL_PORT * pPort,\r
- IN CONST struct sockaddr * pSockAddr,\r
- IN BOOLEAN bBindTest\r
- )\r
-{\r
- EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
- CONST struct sockaddr_in * pIpAddress;\r
- CONST UINT8 * pIpv4Address;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Validate the address\r
- //\r
- pIpAddress = (struct sockaddr_in *)pSockAddr;\r
- if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {\r
- //\r
- // The local address must not be the broadcast address\r
- //\r
- Status = EFI_INVALID_PARAMETER;\r
- pPort->pSocket->errno = EADDRNOTAVAIL;\r
- }\r
- else {\r
- //\r
- // Set the local address\r
- //\r
- pIpv4Address = (UINT8 *)&pIpAddress->sin_addr.s_addr;\r
- pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
- pAccessPoint->StationAddress.Addr[0] = pIpv4Address[0];\r
- pAccessPoint->StationAddress.Addr[1] = pIpv4Address[1];\r
- pAccessPoint->StationAddress.Addr[2] = pIpv4Address[2];\r
- pAccessPoint->StationAddress.Addr[3] = pIpv4Address[3];\r
-\r
- //\r
- // Determine if the default address is used\r
- //\r
- pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );\r
-\r
- //\r
- // Set the subnet mask\r
- //\r
- if ( pAccessPoint->UseDefaultAddress ) {\r
- pAccessPoint->SubnetMask.Addr[0] = 0;\r
- pAccessPoint->SubnetMask.Addr[1] = 0;\r
- pAccessPoint->SubnetMask.Addr[2] = 0;\r
- pAccessPoint->SubnetMask.Addr[3] = 0;\r
- }\r
- else {\r
- pAccessPoint->SubnetMask.Addr[0] = 0xff;\r
- pAccessPoint->SubnetMask.Addr[1] = ( 128 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;\r
- pAccessPoint->SubnetMask.Addr[2] = ( 192 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;\r
- pAccessPoint->SubnetMask.Addr[3] = ( 224 <= pAccessPoint->StationAddress.Addr[0]) ? 0xff : 0;\r
- }\r
-\r
- //\r
- // Validate the IP address\r
- //\r
- pAccessPoint->StationPort = 0;\r
- Status = bBindTest ? EslSocketBindTest ( pPort, EADDRNOTAVAIL )\r
- : EFI_SUCCESS;\r
- if ( !EFI_ERROR ( Status )) {\r
- //\r
- // Set the port number\r
- //\r
- pAccessPoint->StationPort = SwapBytes16 ( pIpAddress->sin_port );\r
- pPort->pSocket->bAddressSet = TRUE;\r
-\r
- //\r
- // Display the local address\r
- //\r
- DEBUG (( DEBUG_BIND,\r
- "0x%08x: Port, Local TCP4 Address: %d.%d.%d.%d:%d\r\n",\r
- pPort,\r
- pAccessPoint->StationAddress.Addr[0],\r
- pAccessPoint->StationAddress.Addr[1],\r
- pAccessPoint->StationAddress.Addr[2],\r
- pAccessPoint->StationAddress.Addr[3],\r
- pAccessPoint->StationPort ));\r
- }\r
- }\r
-\r
- //\r
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Free a receive packet\r
-\r
- This routine performs the network specific operations necessary\r
- to free a receive packet.\r
-\r
- This routine is called by ::EslSocketPortCloseTxDone to free a\r
- receive packet.\r
-\r
- @param [in] pPacket Address of an ::ESL_PACKET structure.\r
- @param [in, out] pRxBytes Address of the count of RX bytes\r
-\r
-**/\r
-VOID\r
-EslTcp4PacketFree (\r
- IN ESL_PACKET * pPacket,\r
- IN OUT size_t * pRxBytes\r
- )\r
-{\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Account for the receive bytes\r
- //\r
- *pRxBytes -= pPacket->Op.Tcp4Rx.RxData.DataLength;\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Initialize the network specific portions of an ::ESL_PORT structure.\r
-\r
- This routine initializes the network specific portions of an\r
- ::ESL_PORT structure for use by the socket.\r
-\r
- This support routine is called by ::EslSocketPortAllocate\r
- to connect the socket with the underlying network adapter\r
- running the TCPv4 protocol.\r
-\r
- @param [in] pPort Address of an ESL_PORT structure\r
- @param [in] DebugFlags Flags for debug messages\r
-\r
- @retval EFI_SUCCESS - Socket successfully created\r
-\r
- **/\r
-EFI_STATUS\r
-EslTcp4PortAllocate (\r
- IN ESL_PORT * pPort,\r
- IN UINTN DebugFlags\r
- )\r
-{\r
- EFI_TCP4_ACCESS_POINT * pAccessPoint;\r
- ESL_SOCKET * pSocket;\r
- ESL_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 the close event\r
- //\r
- pSocket = pPort->pSocket;\r
- pTcp4 = &pPort->Context.Tcp4;\r
- Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
- TPL_SOCKETS,\r
- (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,\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)EslTcp4ConnectComplete,\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
- // Initialize the port\r
- //\r
- pSocket->TxPacketOffset = OFFSET_OF ( ESL_PACKET, Op.Tcp4Tx.TxData );\r
- pSocket->TxTokenEventOffset = OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Tx.CompletionToken.Event );\r
- pSocket->TxTokenOffset = OFFSET_OF ( EFI_TCP4_IO_TOKEN, Packet.TxData );\r
-\r
- //\r
- // Save the cancel, receive and transmit addresses\r
- // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED\r
- //\r
- pPort->pfnConfigure = (PFN_NET_CONFIGURE)pPort->pProtocol.TCPv4->Configure;\r
- pPort->pfnRxPoll = (PFN_NET_POLL)pPort->pProtocol.TCPv4->Poll;\r
- pPort->pfnRxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Receive;\r
- pPort->pfnTxStart = (PFN_NET_IO_START)pPort->pProtocol.TCPv4->Transmit;\r
-\r
- //\r
- // Set the configuration flags\r
- //\r
- pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
- pAccessPoint->ActiveFlag = FALSE;\r
- pTcp4->ConfigData.TimeToLive = 255;\r
- break;\r
- }\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 network specific resources allocated by\r
- ::EslTcp4PortAllocate.\r
-\r
- This routine is called by ::EslSocketPortClose.\r
- See the \ref PortCloseStateMachine section.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
- @retval EFI_SUCCESS The port is closed\r
- @retval other Port close error\r
-\r
-**/\r
-EFI_STATUS\r
-EslTcp4PortClose (\r
- IN ESL_PORT * pPort\r
- )\r
-{\r
- UINTN DebugFlags;\r
- ESL_TCP4_CONTEXT * pTcp4;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Locate the port in the socket list\r
- //\r
- Status = EFI_SUCCESS;\r
- DebugFlags = pPort->DebugFlags;\r
- pTcp4 = &pPort->Context.Tcp4;\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
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Perform the network specific close operation on the port.\r
-\r
- This routine performs a cancel operations on the TCPv4 port to\r
- shutdown the receive operations on the port.\r
-\r
- This routine is called by the ::EslSocketPortCloseTxDone\r
- routine after the port completes all of the transmission.\r
-\r
- @param [in] pPort Address of an ::ESL_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
-EslTcp4PortCloseOp (\r
- IN ESL_PORT * pPort\r
- )\r
-{\r
- ESL_TCP4_CONTEXT * pTcp4;\r
- EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Close the configured port\r
- //\r
- Status = EFI_SUCCESS;\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pTcp4Protocol = pPort->pProtocol.TCPv4;\r
- pTcp4->CloseToken.AbortOnClose = pPort->bCloseNow;\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
- 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
- }\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
- This routine attempts to return buffered data to the caller. The\r
- data is removed from the urgent queue if the message flag MSG_OOB\r
- is specified, otherwise data is removed from the normal queue.\r
- See the \ref ReceiveEngine section.\r
-\r
- This routine is called by ::EslSocketReceive to handle the network\r
- specific receive operation to support SOCK_STREAM and SOCK_SEQPACKET\r
- sockets.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
- @param [in] pPacket Address of an ::ESL_PACKET structure.\r
-\r
- @param [in] pbConsumePacket Address of a BOOLEAN indicating if the packet is to be consumed\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 [out] pSkipBytes Address to receive the number of bytes skipped\r
-\r
- @return Returns the address of the next free byte in the buffer.\r
-\r
- **/\r
-UINT8 *\r
-EslTcp4Receive (\r
- IN ESL_PORT * pPort,\r
- IN ESL_PACKET * pPacket,\r
- IN BOOLEAN * pbConsumePacket,\r
- IN size_t BufferLength,\r
- IN UINT8 * pBuffer,\r
- OUT size_t * pDataLength,\r
- OUT struct sockaddr * pAddress,\r
- OUT size_t * pSkipBytes\r
- )\r
-{\r
- size_t DataLength;\r
- struct sockaddr_in * pRemoteAddress;\r
- ESL_TCP4_CONTEXT * pTcp4;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Return the remote system address if requested\r
- //\r
- if ( NULL != pAddress ) {\r
- //\r
- // Build the remote address\r
- //\r
- pTcp4 = &pPort->Context.Tcp4;\r
- DEBUG (( DEBUG_RX,\r
- "Getting packet remote address: %d.%d.%d.%d:%d\r\n",\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
- pRemoteAddress = (struct sockaddr_in *)pAddress;\r
- CopyMem ( &pRemoteAddress->sin_addr,\r
- &pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0],\r
- sizeof ( pRemoteAddress->sin_addr ));\r
- pRemoteAddress->sin_port = SwapBytes16 ( pTcp4->ConfigData.AccessPoint.RemotePort );\r
- }\r
-\r
- //\r
- // Determine the amount of received data\r
- //\r
- DataLength = pPacket->ValidBytes;\r
- if ( BufferLength < DataLength ) {\r
- DataLength = BufferLength;\r
- }\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
- DataLength ));\r
- CopyMem ( pBuffer, pPacket->pBuffer, DataLength );\r
-\r
- //\r
- // Set the next buffer address\r
- //\r
- pBuffer += DataLength;\r
-\r
- //\r
- // Determine if the data is being read\r
- //\r
- if ( *pbConsumePacket ) {\r
- //\r
- // Account for the bytes consumed\r
- //\r
- pPacket->pBuffer += DataLength;\r
- pPacket->ValidBytes -= DataLength;\r
- DEBUG (( DEBUG_RX,\r
- "0x%08x: Port account for 0x%08x bytes\r\n",\r
- pPort,\r
- DataLength ));\r
-\r
- //\r
- // Determine if the entire packet was consumed\r
- //\r
- if (( 0 == pPacket->ValidBytes )\r
- || ( SOCK_STREAM != pPort->pSocket->Type )) {\r
- //\r
- // All done with this packet\r
- // Account for any discarded data\r
- //\r
- *pSkipBytes = pPacket->ValidBytes;\r
- }\r
- else\r
- {\r
- //\r
- // More data to consume later\r
- //\r
- *pbConsumePacket = FALSE;\r
- }\r
- }\r
-\r
- //\r
- // Return the data length and the buffer address\r
- //\r
- *pDataLength = DataLength;\r
- DBG_EXIT_HEX ( pBuffer );\r
- return pBuffer;\r
-}\r
-\r
-\r
-/**\r
- Get the remote socket address.\r
-\r
- This routine returns the address of the remote connection point\r
- associated with the SOCK_STREAM or SOCK_SEQPACKET socket.\r
-\r
- This routine is called by ::EslSocketGetPeerAddress to detemine\r
- the TCPv4 address and por number associated with the network adapter.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
-\r
- @param [out] pAddress Network address to receive the remote system address\r
-\r
-**/\r
-VOID\r
-EslTcp4RemoteAddressGet (\r
- IN ESL_PORT * pPort,\r
- OUT struct sockaddr * pAddress\r
- )\r
-{\r
- struct sockaddr_in * pRemoteAddress;\r
- ESL_TCP4_CONTEXT * pTcp4;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Return the remote address\r
- //\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pRemoteAddress = (struct sockaddr_in *)pAddress;\r
- pRemoteAddress->sin_family = AF_INET;\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
-\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Set the remote address\r
-\r
- This routine sets the remote address in the port.\r
-\r
- This routine is called by ::EslSocketConnect to specify the\r
- remote network address.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT 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 operation was successful\r
-\r
- **/\r
-EFI_STATUS\r
-EslTcp4RemoteAddressSet (\r
- IN ESL_PORT * pPort,\r
- IN CONST struct sockaddr * pSockAddr,\r
- IN socklen_t SockAddrLength\r
- )\r
-{\r
- CONST struct sockaddr_in * pRemoteAddress;\r
- ESL_TCP4_CONTEXT * pTcp4;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Set the remote address\r
- //\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pRemoteAddress = (struct sockaddr_in *)pSockAddr;\r
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[0] = (UINT8)( pRemoteAddress->sin_addr.s_addr );\r
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[1] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 8 );\r
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[2] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 16 );\r
- pTcp4->ConfigData.AccessPoint.RemoteAddress.Addr[3] = (UINT8)( pRemoteAddress->sin_addr.s_addr >> 24 );\r
- pTcp4->ConfigData.AccessPoint.RemotePort = SwapBytes16 ( pRemoteAddress->sin_port );\r
- Status = EFI_SUCCESS;\r
- if ( INADDR_BROADCAST == pRemoteAddress->sin_addr.s_addr ) {\r
- DEBUG (( DEBUG_CONNECT,\r
- "ERROR - Invalid remote address\r\n" ));\r
- Status = EFI_INVALID_PARAMETER;\r
- pPort->pSocket->errno = EAFNOSUPPORT;\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
- This routine queues the data in FIFO order in either the urgent\r
- or normal data queues depending upon the type of data received.\r
- See the \ref ReceiveEngine section.\r
-\r
- This routine is called by the TCPv4 driver when some data is\r
- received.\r
-\r
- Buffer the data that was just received.\r
-\r
- @param [in] Event The receive completion event\r
-\r
- @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
-\r
-**/\r
-VOID\r
-EslTcp4RxComplete (\r
- IN EFI_EVENT Event,\r
- IN ESL_IO_MGMT * pIo\r
- )\r
-{\r
- BOOLEAN bUrgent;\r
- size_t LengthInBytes;\r
- ESL_PACKET * pPacket;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Get the operation status.\r
- //\r
- Status = pIo->Token.Tcp4Rx.CompletionToken.Status;\r
-\r
- //\r
- // +--------------------+ +---------------------------+\r
- // | ESL_IO_MGMT | | ESL_PACKET |\r
- // | | | |\r
- // | +---------------+ +-----------------------+ |\r
- // | | Token | | EFI_TCP4_RECEIVE_DATA | |\r
- // | | RxData --> | | |\r
- // | | | +-----------------------+---+\r
- // | | Event | | Data Buffer |\r
- // +----+---------------+ | |\r
- // | |\r
- // +---------------------------+\r
- //\r
- //\r
- // Duplicate the buffer address and length for use by the\r
- // buffer handling code in EslTcp4Receive. These fields are\r
- // used when a partial read is done of the data from the\r
- // packet.\r
- //\r
- pPacket = pIo->pPacket;\r
- pPacket->pBuffer = pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer;\r
- LengthInBytes = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
- pPacket->ValidBytes = LengthInBytes;\r
-\r
- //\r
- // Get the data type so that it may be linked to the\r
- // correct receive buffer list on the ESL_SOCKET structure\r
- //\r
- bUrgent = pPacket->Op.Tcp4Rx.RxData.UrgentFlag;\r
-\r
- //\r
- // Complete this request\r
- //\r
- EslSocketRxComplete ( pIo, Status, LengthInBytes, bUrgent );\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Start a receive operation\r
-\r
- This routine posts a receive buffer to the TCPv4 driver.\r
- See the \ref ReceiveEngine section.\r
-\r
- This support routine is called by EslSocketRxStart.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
- @param [in] pIo Address of an ::ESL_IO_MGMT structure.\r
-\r
- **/\r
-VOID\r
-EslTcp4RxStart (\r
- IN ESL_PORT * pPort,\r
- IN ESL_IO_MGMT * pIo\r
- )\r
-{\r
- ESL_PACKET * pPacket;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Initialize the buffer for receive\r
- //\r
- pPacket = pIo->pPacket;\r
- pIo->Token.Tcp4Rx.Packet.RxData = &pPacket->Op.Tcp4Rx.RxData;\r
- pPacket->Op.Tcp4Rx.RxData.DataLength = sizeof ( pPacket->Op.Tcp4Rx.Buffer );\r
- pPacket->Op.Tcp4Rx.RxData.FragmentCount = 1;\r
- pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentLength = pPacket->Op.Tcp4Rx.RxData.DataLength;\r
- pPacket->Op.Tcp4Rx.RxData.FragmentTable[0].FragmentBuffer = &pPacket->Op.Tcp4Rx.Buffer[0];\r
-\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Determine if the socket is configured.\r
-\r
- This routine uses the flag ESL_SOCKET::bConfigured to determine\r
- if the network layer's configuration routine has been called.\r
-\r
- This routine is called by EslSocketIsConfigured to verify\r
- that the socket has been configured.\r
-\r
- @param [in] pSocket Address of an ::ESL_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
- EslTcp4SocketIsConfigured (\r
- IN ESL_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 buffers data for the transmit engine in one of two\r
- queues, one for urgent (out-of-band) data and the other for normal\r
- data. The urgent data is provided to TCP as soon as it is available,\r
- allowing the TCP layer to schedule transmission of the urgent data\r
- between packets of normal data.\r
-\r
- This routine is called by ::EslSocketTransmit to buffer\r
- data for transmission. When the \ref TransmitEngine has resources,\r
- this routine will start the transmission of the next buffer on\r
- the network connection.\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 an ::ESL_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 [in] pAddress Network address of the remote system address\r
-\r
- @param [in] AddressLength Length of the remote network address structure\r
-\r
- @retval EFI_SUCCESS - Socket data successfully buffered\r
-\r
- **/\r
-EFI_STATUS\r
-EslTcp4TxBuffer (\r
- IN ESL_SOCKET * pSocket,\r
- IN int Flags,\r
- IN size_t BufferLength,\r
- IN CONST UINT8 * pBuffer,\r
- OUT size_t * pDataLength,\r
- IN const struct sockaddr * pAddress,\r
- IN socklen_t AddressLength\r
- )\r
-{\r
- BOOLEAN bUrgent;\r
- BOOLEAN bUrgentQueue;\r
- ESL_PACKET * pPacket;\r
- ESL_IO_MGMT ** ppActive;\r
- ESL_IO_MGMT ** ppFree;\r
- ESL_PORT * pPort;\r
- ESL_PACKET ** ppQueueHead;\r
- ESL_PACKET ** ppQueueTail;\r
- ESL_PACKET * pPreviousPacket;\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
- bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
- bUrgentQueue = bUrgent\r
- && ( !pSocket->bOobInLine )\r
- && pSocket->pApi->bOobSupported;\r
- if ( bUrgentQueue ) {\r
- ppQueueHead = &pSocket->pTxOobPacketListHead;\r
- ppQueueTail = &pSocket->pTxOobPacketListTail;\r
- ppActive = &pPort->pTxOobActive;\r
- ppFree = &pPort->pTxOobFree;\r
- pTxBytes = &pSocket->TxOobBytes;\r
- }\r
- else {\r
- ppQueueHead = &pSocket->pTxPacketListHead;\r
- ppQueueTail = &pSocket->pTxPacketListTail;\r
- ppActive = &pPort->pTxActive;\r
- ppFree = &pPort->pTxFree;\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
- if ( pPort->bTxFlowControl ) {\r
- DEBUG (( DEBUG_TX,\r
- "TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n0x%08x: pPort, TX flow control released, Max bytes: %d > %d bufferred bytes\r\n",\r
- pPort,\r
- pSocket->MaxTxBuf,\r
- *pTxBytes ));\r
- pPort->bTxFlowControl = FALSE;\r
- }\r
-\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
- 0,\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 || bUrgent;\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
- bUrgentQueue ? 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 != *ppFree ) {\r
- EslSocketTxStart ( pPort,\r
- ppQueueHead,\r
- ppQueueTail,\r
- ppActive,\r
- ppFree );\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
- if ( !pPort->bTxFlowControl ) {\r
- DEBUG (( DEBUG_TX,\r
- "0x%08x: pPort, TX flow control applied, Max bytes %d <= %d bufferred bytes\r\nTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT\r\n",\r
- pPort,\r
- pSocket->MaxTxBuf,\r
- *pTxBytes ));\r
- pPort->bTxFlowControl = TRUE;\r
- }\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
- This routine use ::EslSocketTxComplete to perform the transmit\r
- completion processing for normal data.\r
-\r
- This routine is called by the TCPv4 network layer when a\r
- normal data transmit request completes.\r
-\r
- @param [in] Event The normal transmit completion event\r
-\r
- @param [in] pIo The ESL_IO_MGMT structure address\r
-\r
-**/\r
-VOID\r
-EslTcp4TxComplete (\r
- IN EFI_EVENT Event,\r
- IN ESL_IO_MGMT * pIo\r
- )\r
-{\r
- UINT32 LengthInBytes;\r
- ESL_PACKET * pPacket;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Locate the active transmit packet\r
- //\r
- pPacket = pIo->pPacket;\r
- pPort = pIo->pPort;\r
- pSocket = pPort->pSocket;\r
-\r
- //\r
- // Get the transmit length and status\r
- //\r
- LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
- pSocket->TxBytes -= LengthInBytes;\r
- Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
-\r
- //\r
- // Complete the transmit operation\r
- //\r
- EslSocketTxComplete ( pIo,\r
- LengthInBytes,\r
- Status,\r
- "Normal ",\r
- &pSocket->pTxPacketListHead,\r
- &pSocket->pTxPacketListTail,\r
- &pPort->pTxActive,\r
- &pPort->pTxFree );\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Process the urgent data transmit completion\r
-\r
- This routine use ::EslSocketTxComplete to perform the transmit\r
- completion processing for urgent data.\r
-\r
- This routine is called by the TCPv4 network layer when a\r
- urgent data transmit request completes.\r
-\r
- @param [in] Event The urgent transmit completion event\r
-\r
- @param [in] pIo The ESL_IO_MGMT structure address\r
-\r
-**/\r
-VOID\r
-EslTcp4TxOobComplete (\r
- IN EFI_EVENT Event,\r
- IN ESL_IO_MGMT * pIo\r
- )\r
-{\r
- UINT32 LengthInBytes;\r
- ESL_PACKET * pPacket;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Locate the active transmit packet\r
- //\r
- pPacket = pIo->pPacket;\r
- pPort = pIo->pPort;\r
- pSocket = pPort->pSocket;\r
-\r
- //\r
- // Get the transmit length and status\r
- //\r
- LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
- pSocket->TxOobBytes -= LengthInBytes;\r
- Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
-\r
- //\r
- // Complete the transmit operation\r
- //\r
- EslSocketTxComplete ( pIo,\r
- LengthInBytes,\r
- Status,\r
- "Urgent ",\r
- &pSocket->pTxOobPacketListHead,\r
- &pSocket->pTxOobPacketListTail,\r
- &pPort->pTxOobActive,\r
- &pPort->pTxOobFree );\r
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/**\r
- Verify the adapter's IP address\r
-\r
- This support routine is called by EslSocketBindTest.\r
-\r
- @param [in] pPort Address of an ::ESL_PORT structure.\r
- @param [in] pConfigData Address of the configuration data\r
-\r
- @retval EFI_SUCCESS - The IP address is valid\r
- @retval EFI_NOT_STARTED - The IP address is invalid\r
-\r
- **/\r
-EFI_STATUS\r
-EslTcp4VerifyLocalIpAddress (\r
- IN ESL_PORT * pPort,\r
- IN EFI_TCP4_CONFIG_DATA * pConfigData\r
- )\r
-{\r
- UINTN DataSize;\r
- EFI_TCP4_ACCESS_POINT * pAccess;\r
- EFI_IP4_CONFIG2_INTERFACE_INFO * pIfInfo;\r
- EFI_IP4_CONFIG2_PROTOCOL * pIpConfig2Protocol;\r
- ESL_SERVICE * pService;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Use break instead of goto\r
- //\r
- pIfInfo = NULL;\r
- for ( ; ; ) {\r
- //\r
- // Determine if the IP address is specified\r
- //\r
- pAccess = &pConfigData->AccessPoint;\r
- DEBUG (( DEBUG_BIND,\r
- "UseDefaultAddress: %s\r\n",\r
- pAccess->UseDefaultAddress ? L"TRUE" : L"FALSE" ));\r
- DEBUG (( DEBUG_BIND,\r
- "Requested IP address: %d.%d.%d.%d\r\n",\r
- pAccess->StationAddress.Addr [ 0 ],\r
- pAccess->StationAddress.Addr [ 1 ],\r
- pAccess->StationAddress.Addr [ 2 ],\r
- pAccess->StationAddress.Addr [ 3 ]));\r
- if ( pAccess->UseDefaultAddress\r
- || (( 0 == pAccess->StationAddress.Addr [ 0 ])\r
- && ( 0 == pAccess->StationAddress.Addr [ 1 ])\r
- && ( 0 == pAccess->StationAddress.Addr [ 2 ])\r
- && ( 0 == pAccess->StationAddress.Addr [ 3 ])))\r
- {\r
- Status = EFI_SUCCESS;\r
- break;\r
- }\r
-\r
- //\r
- // Open the configuration protocol\r
- //\r
- pService = pPort->pService;\r
- Status = gBS->OpenProtocol ( \r
- pService->Controller,\r
- &gEfiIp4Config2ProtocolGuid,\r
- (VOID **)&pIpConfig2Protocol,\r
- NULL,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL \r
- );\r
- if ( EFI_ERROR ( Status )) {\r
- DEBUG (( DEBUG_ERROR,\r
- "ERROR - IP Configuration Protocol not available, Status: %r\r\n",\r
- Status ));\r
- break;\r
- }\r
-\r
- //\r
- // Get the interface information size.\r
- //\r
- DataSize = 0;\r
- Status = pIpConfig2Protocol->GetData ( \r
- pIpConfig2Protocol,\r
- Ip4Config2DataTypeInterfaceInfo,\r
- &DataSize,\r
- NULL\r
- );\r
- if ( EFI_BUFFER_TOO_SMALL != Status ) {\r
- DEBUG (( DEBUG_ERROR,\r
- "ERROR - Failed to get the interface information size, Status: %r\r\n",\r
- Status ));\r
- break;\r
- }\r
-\r
- //\r
- // Allocate the interface information buffer\r
- //\r
- pIfInfo = AllocatePool ( DataSize );\r
- if ( NULL == pIfInfo ) {\r
- DEBUG (( DEBUG_ERROR,\r
- "ERROR - Not enough memory to allocate the interface information buffer!\r\n" ));\r
- Status = EFI_OUT_OF_RESOURCES;\r
- break;\r
- }\r
-\r
- //\r
- // Get the interface info.\r
- //\r
- Status = pIpConfig2Protocol->GetData ( \r
- pIpConfig2Protocol,\r
- Ip4Config2DataTypeInterfaceInfo,\r
- &DataSize,\r
- pIfInfo\r
- );\r
- if ( EFI_ERROR ( Status )) {\r
- DEBUG (( DEBUG_ERROR,\r
- "ERROR - Failed to return the interface info, Status: %r\r\n",\r
- Status ));\r
- break;\r
- }\r
-\r
- //\r
- // Display the current configuration\r
- //\r
- DEBUG (( DEBUG_BIND,\r
- "Actual adapter IP address: %d.%d.%d.%d\r\n",\r
- pIfInfo->StationAddress.Addr [ 0 ],\r
- pIfInfo->StationAddress.Addr [ 1 ],\r
- pIfInfo->StationAddress.Addr [ 2 ],\r
- pIfInfo->StationAddress.Addr [ 3 ]));\r
-\r
- //\r
- // Assume the port is not configured\r
- //\r
- Status = EFI_SUCCESS;\r
- if (( pAccess->StationAddress.Addr [ 0 ] == pIfInfo->StationAddress.Addr [ 0 ])\r
- && ( pAccess->StationAddress.Addr [ 1 ] == pIfInfo->StationAddress.Addr [ 1 ])\r
- && ( pAccess->StationAddress.Addr [ 2 ] == pIfInfo->StationAddress.Addr [ 2 ])\r
- && ( pAccess->StationAddress.Addr [ 3 ] == pIfInfo->StationAddress.Addr [ 3 ])) {\r
- break;\r
- }\r
-\r
- //\r
- // The IP address did not match\r
- //\r
- Status = EFI_NOT_STARTED;\r
- break;\r
- }\r
-\r
- //\r
- // Free the buffer if necessary\r
- //\r
- if ( NULL != pIfInfo ) {\r
- FreePool ( pIfInfo );\r
- }\r
-\r
- //\r
- // Return the IP address status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/**\r
- Interface between the socket layer and the network specific\r
- code that supports SOCK_STREAM and SOCK_SEQPACKET sockets\r
- over TCPv4.\r
-**/\r
-CONST ESL_PROTOCOL_API cEslTcp4Api = {\r
- "TCPv4",\r
- IPPROTO_TCP,\r
- OFFSET_OF ( ESL_PORT, Context.Tcp4.ConfigData ),\r
- OFFSET_OF ( ESL_LAYER, pTcp4List ),\r
- OFFSET_OF ( struct sockaddr_in, sin_zero ),\r
- sizeof ( struct sockaddr_in ),\r
- AF_INET,\r
- sizeof (((ESL_PACKET *)0 )->Op.Tcp4Rx ),\r
- OFFSET_OF ( ESL_PACKET, Op.Tcp4Rx.Buffer ) - OFFSET_OF ( ESL_PACKET, Op ),\r
- OFFSET_OF ( ESL_IO_MGMT, Token.Tcp4Rx.Packet.RxData ),\r
- TRUE,\r
- EADDRINUSE,\r
- EslTcp4Accept,\r
- EslTcp4ConnectPoll,\r
- EslTcp4ConnectStart,\r
- EslTcp4SocketIsConfigured,\r
- EslTcp4LocalAddressGet,\r
- EslTcp4LocalAddressSet,\r
- EslTcp4Listen,\r
- NULL, // OptionGet\r
- NULL, // OptionSet\r
- EslTcp4PacketFree,\r
- EslTcp4PortAllocate,\r
- EslTcp4PortClose,\r
- EslTcp4PortCloseOp,\r
- FALSE,\r
- EslTcp4Receive,\r
- EslTcp4RemoteAddressGet,\r
- EslTcp4RemoteAddressSet,\r
- EslTcp4RxComplete,\r
- EslTcp4RxStart,\r
- EslTcp4TxBuffer,\r
- EslTcp4TxComplete,\r
- EslTcp4TxOobComplete,\r
- (PFN_API_VERIFY_LOCAL_IP_ADDRESS)EslTcp4VerifyLocalIpAddress\r
-};\r