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
+ \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
- 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
+ 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 the socket structure.\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
**/\r
EFI_STATUS\r
-EslTcpAccept4 (\r
- IN DT_SOCKET * pSocket,\r
+EslTcp4Accept (\r
+ IN ESL_SOCKET * pSocket,\r
IN struct sockaddr * pSockAddr,\r
IN OUT socklen_t * pSockAddrLength\r
)\r
{\r
- DT_PORT * pPort;\r
+ ESL_PORT * pPort;\r
struct sockaddr_in * pRemoteAddress;\r
- DT_TCP4_CONTEXT * pTcp4;\r
+ ESL_TCP4_CONTEXT * pTcp4;\r
UINT32 RemoteAddress;\r
EFI_STATUS 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
+ Process the remote connection completion event.\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
+ 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 release all of the other\r
- ports.\r
+ connection attempt was successful then this routine releases all\r
+ of the other ports.\r
\r
- @param Event The connect completion event\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 pPort The DT_PORT structure address\r
+ @param [in] Event The connect completion event\r
+\r
+ @param [in] pPort Address of an ::ESL_PORT structure.\r
\r
**/\r
VOID\r
-EslTcpConnectComplete4 (\r
+EslTcp4ConnectComplete (\r
IN EFI_EVENT Event,\r
- IN DT_PORT * pPort\r
+ IN ESL_PORT * pPort\r
)\r
{\r
BOOLEAN bRemoveFirstPort;\r
BOOLEAN bRemovePorts;\r
- DT_PORT * pNextPort;\r
- DT_SOCKET * pSocket;\r
- DT_TCP4_CONTEXT * pTcp4;\r
+ ESL_PORT * pNextPort;\r
+ ESL_SOCKET * pSocket;\r
+ ESL_TCP4_CONTEXT * pTcp4;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\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.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
//\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
+ 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 = EslTcpPortClose4 ( pPort );\r
+ Status = EslSocketPortClose ( pPort );\r
if ( !EFI_ERROR ( Status )) {\r
DEBUG (( DEBUG_CONNECT,\r
"0x%08x: Port closed\r\n",\r
//\r
// Try to connect using the next port\r
//\r
- Status = EslTcpConnectAttempt4 ( pSocket );\r
+ Status = EslTcp4ConnectStart ( pSocket );\r
if ( EFI_NOT_READY != Status ) {\r
- pSocket->ConnectStatus = Status;\r
bRemoveFirstPort = TRUE;\r
}\r
}\r
//\r
while ( NULL != pPort ) {\r
pNextPort = pPort->pLinkSocket;\r
- EslTcpPortClose4 ( pPort );\r
+ EslSocketPortClose ( pPort );\r
if ( !EFI_ERROR ( Status )) {\r
DEBUG (( DEBUG_CONNECT,\r
"0x%08x: Port closed\r\n",\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
+ This routine polls the ESL_SOCKET::bConnected flag to determine\r
+ when the connection attempt is complete.\r
\r
- @param [in] pSocket Address of the socket structure.\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
\r
**/\r
EFI_STATUS\r
-EslTcpConnectPoll4 (\r
- IN DT_SOCKET * pSocket\r
+EslTcp4ConnectPoll (\r
+ IN ESL_SOCKET * pSocket\r
)\r
{\r
EFI_STATUS Status;\r
break;\r
\r
case EFI_ABORTED:\r
- pSocket->errno = ECONNREFUSED;\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 = EINVAL;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
break;\r
\r
- case EFI_NO_MAPPING:\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 = ENOMEM;\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
break;\r
\r
case EFI_UNSUPPORTED:\r
- pSocket->errno = ENOTSUP;\r
- break;\r
-\r
- case 0x80000069:\r
- pSocket->errno = ECONNRESET;\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
\r
\r
/**\r
- Connect to a remote system via the network.\r
+ Attempt to connect to a remote TCP port\r
\r
- The ::TcpConnectStart4= routine starts the connection processing\r
- for a TCP4 port.\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
- @param [in] pSocket Address of the socket structure.\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
- @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
+EslTcp4ConnectStart (\r
+ IN ESL_SOCKET * pSocket\r
)\r
{\r
- struct sockaddr_in LocalAddress;\r
- DT_PORT * pPort;\r
- DT_TCP4_CONTEXT * pTcp4;\r
- CONST struct sockaddr_in * pIp4Address;\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
//\r
- // Validate the address length\r
+ // Determine if any more local adapters are available\r
//\r
- Status = EFI_SUCCESS;\r
- pIp4Address = (CONST struct sockaddr_in *) pSockAddr;\r
- if ( SockAddrLength >= ( sizeof ( *pIp4Address )\r
- - sizeof ( pIp4Address->sin_zero ))) {\r
+ pPort = pSocket->pPortList;\r
+ if ( NULL != pPort ) {\r
//\r
- // Determine if BIND was already called\r
+ // Configure the port\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
+ 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
- // Attempt a connection using the first adapter\r
+ // Verify the port connection\r
//\r
- Status = EslTcpConnectAttempt4 ( pSocket );\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
- }\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
+ if ( !EFI_ERROR ( Status )) {\r
//\r
- // Return the local address\r
+ // Connection in progress\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
+ 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
- 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
+ // 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
- // 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
+ // Continue with the next port\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
+ gBS->CheckEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
+ gBS->SignalEvent ( pTcp4->ConnectToken.CompletionToken.Event );\r
}\r
+ Status = EFI_NOT_READY;\r
}\r
else {\r
- pSocket->errno = ENOTCONN;\r
- Status = EFI_NOT_STARTED;\r
+ //\r
+ // No more local adapters available\r
+ //\r
+ pSocket->errno = ENETUNREACH;\r
+ Status = EFI_NO_RESPONSE;\r
}\r
- \r
+\r
//\r
// Return the operation status\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
+ 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 the socket structure.\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
-EslTcpListen4 (\r
- IN DT_SOCKET * pSocket\r
+EslTcp4Listen (\r
+ IN ESL_SOCKET * pSocket\r
)\r
{\r
- DT_PORT * pNextPort;\r
- DT_PORT * pPort;\r
- DT_TCP4_CONTEXT * pTcp4;\r
+ ESL_PORT * pNextPort;\r
+ ESL_PORT * pPort;\r
+ ESL_TCP4_CONTEXT * pTcp4;\r
EFI_TCP4_PROTOCOL * pTcp4Protocol;\r
EFI_STATUS Status;\r
\r
pTcp4 = &pPort->Context.Tcp4;\r
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
TPL_SOCKETS,\r
- (EFI_EVENT_NOTIFY)EslTcpListenComplete4,\r
+ (EFI_EVENT_NOTIFY)EslTcp4ListenComplete,\r
pPort,\r
&pTcp4->ListenToken.CompletionToken.Event );\r
if ( EFI_ERROR ( Status )) {\r
//\r
// Configure the port\r
//\r
- pTcp4Protocol = pTcp4->pProtocol;\r
+ pTcp4Protocol = pPort->pProtocol.TCPv4;\r
Status = pTcp4Protocol->Configure ( pTcp4Protocol,\r
&pTcp4->ConfigData );\r
if ( EFI_ERROR ( Status )) {\r
DEBUG (( DEBUG_LISTEN,\r
"0x%08x: Port configured\r\n",\r
pPort ));\r
- pTcp4->bConfigured = TRUE;\r
+ pPort->bConfigured = TRUE;\r
\r
//\r
// Start the listen operation on the port\r
//\r
// Close the port upon error\r
//\r
- if ( EFI_ERROR ( Status ))\r
- {\r
- EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );\r
+ if ( EFI_ERROR ( Status )) {\r
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );\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
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
+ 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 pPort The DT_PORT structure address\r
+ @param [in] Event The listen completion event\r
+\r
+ @param [in] pPort Address of an ::ESL_PORT structure.\r
\r
**/\r
VOID\r
-EslTcpListenComplete4 (\r
+EslTcp4ListenComplete (\r
IN EFI_EVENT Event,\r
- IN DT_PORT * pPort\r
+ IN ESL_PORT * pPort\r
)\r
{\r
EFI_HANDLE ChildHandle;\r
+ struct sockaddr_in LocalAddress;\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
+ ESL_LAYER * pLayer;\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
// 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
- // Allocate a port for this connection\r
+ // Build the local address\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
+ 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 = pTcp4->pProtocol;\r
+ pTcp4Protocol = pPort->pProtocol.TCPv4;\r
Status = pTcp4Protocol->Accept ( pTcp4Protocol,\r
&pTcp4->ListenToken );\r
\r
//\r
TcpPortHandle = NULL;\r
pTcp4 = &pNewPort->Context.Tcp4;\r
- pTcp4->bConfigured = TRUE;\r
\r
//\r
// Check for an accept call error\r
//\r
// Get the port configuration\r
//\r
+ pNewPort->bConfigured = TRUE;\r
pConfigData = &pTcp4->ConfigData;\r
pConfigData->ControlOption = &pTcp4->Option;\r
- pTcp4Protocol = pTcp4->pProtocol;\r
+ pTcp4Protocol = pNewPort->pProtocol.TCPv4;\r
Status = pTcp4Protocol->GetModeData ( pTcp4Protocol,\r
NULL,\r
pConfigData,\r
//\r
// Start the receive operation\r
//\r
- EslTcpRxStart4 ( pNewPort );\r
+ EslSocketRxStart ( pNewPort );\r
}\r
else {\r
DEBUG (( DEBUG_ERROR | DEBUG_CONNECTION | DEBUG_INFO,\r
//\r
// Close the listening port\r
//\r
- EslTcpPortCloseStart4 ( pPort, TRUE, DEBUG_LISTEN );\r
+ EslSocketPortCloseStart ( pPort, TRUE, DEBUG_LISTEN );\r
}\r
}\r
\r
\r
\r
/**\r
- Allocate and initialize a DT_PORT structure.\r
+ Get the local socket address.\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
+ This routine returns the IPv4 address and TCP port number associated\r
+ with the local socket.\r
\r
- @retval EFI_SUCCESS - Socket successfully created\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
-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
+EslTcp4LocalAddressSet (\r
+ IN ESL_PORT * pPort,\r
+ IN CONST struct sockaddr * pSockAddr,\r
+ IN BOOLEAN bBindTest\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
+ CONST struct sockaddr_in * pIpAddress;\r
+ CONST UINT8 * pIpv4Address;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Use for/break instead of goto\r
- for ( ; ; ) {\r
+ // Validate the address\r
+ //\r
+ pIpAddress = (struct sockaddr_in *)pSockAddr;\r
+ if ( INADDR_BROADCAST == pIpAddress->sin_addr.s_addr ) {\r
//\r
- // Allocate a port structure\r
+ // The local address must not be the broadcast address\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
+ Status = EFI_INVALID_PARAMETER;\r
+ pPort->pSocket->errno = EADDRNOTAVAIL;\r
+ }\r
+ else {\r
//\r
- // Initialize the port\r
+ // Set the local address\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
+ 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
- // Allocate the receive event\r
+ // Determine if the default address is used\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
+ pAccessPoint->UseDefaultAddress = (BOOLEAN)( 0 == pIpAddress->sin_addr.s_addr );\r
+ \r
//\r
- // Allocate the urgent transmit event\r
+ // Set the subnet mask\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
+ 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
- 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
+ else {\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
- DEBUG (( DEBUG_CLOSE | DEBUG_POOL,\r
- "0x%08x: Created normal transmit event\r\n",\r
- pTcp4->TxToken.CompletionToken.Event ));\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)EslTcpPortCloseComplete4,\r
+ (EFI_EVENT_NOTIFY)EslSocketPortCloseComplete,\r
pPort,\r
&pTcp4->CloseToken.CompletionToken.Event);\r
if ( EFI_ERROR ( Status )) {\r
//\r
Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
TPL_SOCKETS,\r
- (EFI_EVENT_NOTIFY)EslTcpConnectComplete4,\r
+ (EFI_EVENT_NOTIFY)EslTcp4ConnectComplete,\r
pPort,\r
&pTcp4->ConnectToken.CompletionToken.Event);\r
if ( EFI_ERROR ( Status )) {\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
+ // Initialize the port\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
+ 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
- // Add this port to the service\r
+ // Save the cancel, receive and transmit addresses\r
+ // pPort->pfnRxCancel = NULL; since the UEFI implementation returns EFI_UNSUPPORTED\r
//\r
- pPort->pLinkService = pService->pPortList;\r
- pService->pPortList = pPort;\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
- // Return the port\r
+ // Set the configuration flags\r
//\r
- *ppPort = pPort;\r
+ pAccessPoint = &pPort->Context.Tcp4.ConfigData.AccessPoint;\r
+ pAccessPoint->ActiveFlag = FALSE;\r
+ pTcp4->ConfigData.TimeToLive = 255;\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
/**\r
Close a TCP4 port.\r
\r
- This routine releases the resources allocated by\r
- ::TcpPortAllocate4().\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 the port structure.\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
-EslTcpPortClose4 (\r
- IN DT_PORT * pPort\r
+EslTcp4PortClose (\r
+ IN ESL_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
+ ESL_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
}\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
\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
+ 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
-/**\r
- Start the close operation on a TCP4 port, state 1.\r
+ This routine is called by the ::EslSocketPortCloseTxDone\r
+ routine after the port completes all of the transmission.\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
+ @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 has started the closing process\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
-EslTcpPortCloseStart4 (\r
- IN DT_PORT * pPort,\r
- IN BOOLEAN bCloseNow,\r
- IN UINTN DebugFlags\r
+EslTcp4PortCloseOp (\r
+ IN ESL_PORT * pPort\r
)\r
{\r
- DT_SOCKET * pSocket;\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
- // Mark the port as closing\r
+ // Close the configured port\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
+ 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
- pPort->bCloseNow = bCloseNow;\r
- pPort->DebugFlags = DebugFlags;\r
-\r
- //\r
- // Determine if transmits are complete\r
- //\r
- Status = EslTcpPortCloseTxDone4 ( 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
\r
\r
/**\r
- Port close state 3\r
+ Receive data from a network connection.\r
\r
- Continue the close operation after the receive is complete.\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
- @param [in] pPort Address of the port structure.\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
- @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
+ @param [in] pPort Address of an ::ESL_PORT structure.\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
+ @param [in] pPacket Address of an ::ESL_PACKET structure.\r
\r
- @param [in] Flags Message control flags\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
\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
+ @param [out] pSkipBytes Address to receive the number of bytes skipped\r
\r
- @retval EFI_SUCCESS - Socket data successfully received\r
+ @return Returns the address of the next free byte in the buffer.\r
\r
**/\r
-EFI_STATUS\r
-EslTcpReceive4 (\r
- IN DT_SOCKET * pSocket,\r
- IN INT32 Flags,\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
- IN OUT socklen_t * pAddressLength\r
+ OUT size_t * pSkipBytes\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
+ size_t DataLength;\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
+ ESL_TCP4_CONTEXT * pTcp4;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Assume failure\r
+ // Return the remote system address if requested\r
//\r
- Status = EFI_NOT_FOUND;\r
-\r
- //\r
- // Locate the port\r
- //\r
- pPort = pSocket->pPortList;\r
- if ( NULL != pPort ) {\r
+ if ( NULL != pAddress ) {\r
//\r
- // Determine if a receive is pending\r
+ // Build the remote address\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
+ 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
- // Return the operation status\r
+ // Determine the amount of received data\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
+ DataLength = pPacket->ValidBytes;\r
+ if ( BufferLength < DataLength ) {\r
+ DataLength = BufferLength;\r
+ }\r
\r
//\r
- // Mark this receive complete\r
+ // Move the data into the buffer\r
//\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pPacket = pTcp4->pReceivePending;\r
- pTcp4->pReceivePending = NULL;\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
- // 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
+ // 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
- // Log the received data\r
+ // Account for the bytes consumed\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
+ 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
- LengthInBytes,\r
- bUrgent ? L"urgent" : L"normal" ));\r
+ DataLength ));\r
\r
//\r
- // Attempt to restart this receive operation\r
+ // Determine if the entire packet was consumed\r
//\r
- if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
- EslTcpRxStart4 ( pPort );\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
- DEBUG (( DEBUG_RX,\r
- "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
- pPort,\r
- pSocket->RxBytes ));\r
+ else\r
+ {\r
+ //\r
+ // More data to consume later\r
+ //\r
+ *pbConsumePacket = FALSE;\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
+ // Return the data length and the buffer address\r
+ //\r
+ *pDataLength = DataLength;\r
+ DBG_EXIT_HEX ( pBuffer );\r
+ return pBuffer;\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
+/**\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
- Start a receive operation\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
- @param [in] pPort Address of the DT_PORT structure.\r
+ @retval EFI_SUCCESS The operation was successful\r
\r
**/\r
-VOID\r
-EslTcpRxStart4 (\r
- IN DT_PORT * pPort\r
+EFI_STATUS\r
+EslTcp4RemoteAddressSet (\r
+ IN ESL_PORT * pPort,\r
+ IN CONST struct sockaddr * pSockAddr,\r
+ IN socklen_t SockAddrLength\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
+ CONST struct sockaddr_in * pRemoteAddress;\r
+ ESL_TCP4_CONTEXT * pTcp4;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Determine if a receive is already pending\r
+ // Set the remote address\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
+ 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
- DBG_EXIT ( );\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
}\r
\r
\r
/**\r
- Shutdown the TCP4 service.\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
- This routine undoes the work performed by ::TcpInitialize4.\r
+ Buffer the data that was just received.\r
+\r
+ @param [in] Event The receive completion event\r
\r
- @param [in] pService DT_SERVICE structure address\r
+ @param [in] pIo Address of an ::ESL_IO_MGMT structure\r
\r
**/\r
VOID\r
-EFIAPI\r
-EslTcpShutdown4 (\r
- IN DT_SERVICE * pService\r
+EslTcp4RxComplete (\r
+ IN EFI_EVENT Event,\r
+ IN ESL_IO_MGMT * pIo\r
)\r
{\r
- DT_LAYER * pLayer;\r
- DT_PORT * pPort;\r
- DT_SERVICE * pPreviousService;\r
+ BOOLEAN bUrgent;\r
+ size_t LengthInBytes;\r
+ ESL_PACKET * pPacket;\r
+ EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Verify the socket layer synchronization\r
+ // Get the operation status.\r
//\r
- VERIFY_TPL ( TPL_SOCKETS );\r
+ Status = pIo->Token.Tcp4Rx.CompletionToken.Status;\r
\r
//\r
- // Walk the list of ports\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
- 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
+ // 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
- // Close the port\r
- // TODO: Fix this\r
- //\r
-// pPort->pfnClosePort ( pPort, DEBUG_LISTEN | DEBUG_CONNECTION );\r
- }\r
- } while ( NULL != pPort );\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
- // Remove the service from the service list\r
+ // Complete this request\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
+ 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
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
- @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
+ EslTcp4SocketIsConfigured (\r
+ IN ESL_SOCKET * pSocket\r
)\r
{\r
EFI_STATUS Status;\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
+ 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
- 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
+ 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 a DT_SOCKET structure\r
+ @param [in] pSocket Address of an ::ESL_SOCKET structure\r
\r
@param [in] Flags Message control flags\r
\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
-EslTcpTxBuffer4 (\r
- IN DT_SOCKET * pSocket,\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
+ OUT size_t * pDataLength,\r
+ IN const struct sockaddr * pAddress,\r
+ IN socklen_t AddressLength\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
+ 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
+ ESL_TCP4_CONTEXT * pTcp4;\r
size_t * pTxBytes;\r
EFI_TCP4_TRANSMIT_DATA * pTxData;\r
EFI_STATUS Status;\r
//\r
Status = EFI_UNSUPPORTED;\r
pSocket->errno = ENOTCONN;\r
- * pDataLength = 0;\r
+ *pDataLength = 0;\r
\r
//\r
// Verify that the socket is connected\r
//\r
pTcp4 = &pPort->Context.Tcp4;\r
bUrgent = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
- if ( bUrgent ) {\r
+ bUrgentQueue = bUrgent\r
+ && ( !pSocket->bOobInLine )\r
+ && pSocket->pApi->bOobSupported;\r
+ if ( bUrgentQueue ) {\r
ppQueueHead = &pSocket->pTxOobPacketListHead;\r
ppQueueTail = &pSocket->pTxOobPacketListTail;\r
- ppPacket = &pTcp4->pTxOobPacket;\r
- pToken = &pTcp4->TxOobToken;\r
+ ppActive = &pPort->pTxOobActive;\r
+ ppFree = &pPort->pTxOobFree;\r
pTxBytes = &pSocket->TxOobBytes;\r
}\r
else {\r
ppQueueHead = &pSocket->pTxPacketListHead;\r
ppQueueTail = &pSocket->pTxPacketListTail;\r
- ppPacket = &pTcp4->pTxPacket;\r
- pToken = &pTcp4->TxToken;\r
+ ppActive = &pPort->pTxActive;\r
+ ppFree = &pPort->pTxFree;\r
pTxBytes = &pSocket->TxBytes;\r
}\r
\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
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;\r
+ pTxData->Push = TRUE || bUrgent;\r
pTxData->Urgent = bUrgent;\r
pTxData->DataLength = (UINT32) BufferLength;\r
pTxData->FragmentCount = 1;\r
DEBUG (( DEBUG_TX,\r
"0x%08x: Packet on %s transmit list\r\n",\r
pPacket,\r
- bUrgent ? L"urgent" : L"normal" ));\r
+ bUrgentQueue ? L"urgent" : L"normal" ));\r
\r
//\r
// Account for the buffered data\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
+ if ( NULL != *ppFree ) {\r
+ EslSocketTxStart ( pPort,\r
+ ppQueueHead,\r
+ ppQueueTail,\r
+ ppActive,\r
+ ppFree );\r
}\r
}\r
else {\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
/**\r
Process the normal data transmit completion\r
\r
- @param Event The normal transmit completion event\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 pPort The DT_PORT structure address\r
+ @param [in] pIo The ESL_IO_MGMT structure address\r
\r
**/\r
VOID\r
-EslTcpTxComplete4 (\r
+EslTcp4TxComplete (\r
IN EFI_EVENT Event,\r
- IN DT_PORT * pPort\r
+ IN ESL_IO_MGMT * pIo\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
+ ESL_PACKET * pPacket;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
- \r
+\r
//\r
// Locate the active transmit packet\r
//\r
+ pPacket = pIo->pPacket;\r
+ pPort = pIo->pPort;\r
pSocket = pPort->pSocket;\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pPacket = pTcp4->pTxPacket;\r
- \r
+\r
//\r
- // Mark this packet as complete\r
+ // Get the transmit length and status\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
+ Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\r
\r
//\r
- // Finish the close operation if necessary\r
+ // Complete the transmit operation\r
//\r
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
- //\r
- // Indicate that the transmit is complete\r
- //\r
- EslTcpPortCloseTxDone4 ( pPort );\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
Process the urgent data transmit completion\r
\r
- @param Event The urgent transmit completion event\r
+ This routine use ::EslSocketTxComplete to perform the transmit\r
+ completion processing for urgent data.\r
\r
- @param pPort The DT_PORT structure address\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
-EslTcpTxOobComplete4 (\r
+EslTcp4TxOobComplete (\r
IN EFI_EVENT Event,\r
- IN DT_PORT * pPort\r
+ IN ESL_IO_MGMT * pIo\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
+ ESL_PACKET * pPacket;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
//\r
// Locate the active transmit packet\r
//\r
+ pPacket = pIo->pPacket;\r
+ pPort = pIo->pPort;\r
pSocket = pPort->pSocket;\r
- pTcp4 = &pPort->Context.Tcp4;\r
- pPacket = pTcp4->pTxOobPacket;\r
\r
//\r
- // Mark this packet as complete\r
+ // Get the transmit length and status\r
//\r
- pTcp4->pTxOobPacket = NULL;\r
LengthInBytes = pPacket->Op.Tcp4Tx.TxData.DataLength;\r
pSocket->TxOobBytes -= LengthInBytes;\r
+ Status = pIo->Token.Tcp4Tx.CompletionToken.Status;\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
+ // Complete the transmit operation\r
//\r
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
- //\r
- // Indicate that the transmit is complete\r
- //\r
- EslTcpPortCloseTxDone4 ( pPort );\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
- 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
+ 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
+};\r