--- /dev/null
+/** @file\r
+ Implement the socket support for the socket layer.\r
+\r
+ Socket States:\r
+ * Bound - pSocket->PortList is not NULL\r
+ * Listen - AcceptWait event is not NULL\r
+\r
+ Copyright (c) 2011, Intel Corporation\r
+ All rights reserved. This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Socket.h"\r
+\r
+\r
+/**\r
+ Socket driver connection points\r
+\r
+ List the network stack connection points for the socket driver.\r
+**/\r
+CONST DT_SOCKET_BINDING cEslSocketBinding [] = {\r
+ { L"Tcp4",\r
+ &gEfiTcp4ServiceBindingProtocolGuid,\r
+ &mEslTcp4ServiceGuid,\r
+ EslTcpInitialize4,\r
+ EslTcpShutdown4 },\r
+ { L"Udp4",\r
+ &gEfiUdp4ServiceBindingProtocolGuid,\r
+ &mEslUdp4ServiceGuid,\r
+ EslUdpInitialize4,\r
+ EslUdpShutdown4 }\r
+};\r
+\r
+CONST UINTN cEslSocketBindingEntries = DIM ( cEslSocketBinding );\r
+\r
+DT_LAYER mEslLayer;\r
+\r
+\r
+/**\r
+ Initialize an endpoint for network communication.\r
+\r
+ The ::Socket routine initializes the communication endpoint by providing\r
+ the support for the socket library function ::socket. The\r
+ <a href="http://www.linuxhowtos.org/manpages/2/socket.htm">Linux</a>,\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html">POSIX</a>\r
+ and <a href="http://msdn.microsoft.com/en-us/library/ms740506(v=VS.85).aspx">Windows</a>\r
+ documentation for the socket routine are available online for reference.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ @param [in] domain Select the family of protocols for the client or server\r
+ application.\r
+\r
+ @param [in] type Specifies how to make the network connection. The following values\r
+ are supported:\r
+ <ul>\r
+ <li>\r
+ SOCK_STREAM - Connect to TCP, provides a byte stream\r
+ that is manipluated by read, recv, send and write.\r
+ </li>\r
+ <li>\r
+ SOCK_SEQPACKET - Connect to TCP, provides sequenced packet stream\r
+ that is manipulated by read, recv, send and write.\r
+ </li>\r
+ <li>\r
+ SOCK_DGRAM - Connect to UDP, provides a datagram service that is\r
+ manipulated by recvfrom and sendto.\r
+ </li>\r
+ </ul>\r
+\r
+ @param [in] protocol Specifies the lower layer protocol to use. The following\r
+ values are supported:\r
+ <ul>\r
+ <li>IPPROTO_TCP</li> - This value must be combined with SOCK_STREAM.</li>\r
+ <li>IPPROTO_UDP</li> - This value must be combined with SOCK_DGRAM.</li>\r
+ </ul>\r
+\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket successfully created\r
+ @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT\r
+ @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL\r
+ @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocket (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int domain,\r
+ IN int type,\r
+ IN int protocol,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ int errno;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Locate the socket\r
+ //\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Set the default domain if necessary\r
+ //\r
+ if ( AF_UNSPEC == domain ) {\r
+ domain = AF_INET;\r
+ }\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ errno = 0;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Use break instead of goto\r
+ //\r
+ for ( ; ; ) {\r
+ //\r
+ // Validate the domain value\r
+ //\r
+ if (( AF_INET != domain )\r
+ && ( AF_LOCAL != domain ))\r
+ {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
+ "ERROR - Invalid domain value" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ errno = EAFNOSUPPORT;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Set the default type if necessary\r
+ //\r
+ if ( 0 == type ) {\r
+ type = SOCK_STREAM;\r
+ }\r
+\r
+ //\r
+ // Validate the type value\r
+ //\r
+ if (( SOCK_STREAM == type )\r
+ || ( SOCK_SEQPACKET == type )) {\r
+ //\r
+ // Set the default protocol if necessary\r
+ //\r
+ if ( 0 == protocol ) {\r
+ protocol = IPPROTO_TCP;\r
+ }\r
+ }\r
+ else if ( SOCK_DGRAM == type ) {\r
+ //\r
+ // Set the default protocol if necessary\r
+ //\r
+ if ( 0 == protocol ) {\r
+ protocol = IPPROTO_UDP;\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
+ "ERROR - Invalid type value" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ errno = EINVAL;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Validate the protocol value\r
+ //\r
+ if (( IPPROTO_TCP != protocol )\r
+ && ( IPPROTO_UDP != protocol )) {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
+ "ERROR - Invalid protocol value" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ errno = EINVAL;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Save the socket attributes\r
+ //\r
+ pSocket->Domain = domain;\r
+ pSocket->Type = type;\r
+ pSocket->Protocol = protocol;\r
+\r
+ //\r
+ // Done\r
+ //\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = errno;\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\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
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+\r
+ @param [in] pSockAddr Address of a buffer to receive the remote\r
+ network address.\r
+\r
+ @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
+ On output specifies the length of the\r
+ remote network address.\r
+\r
+ @param [out] ppSocketProtocol Address of a buffer to receive the socket protocol\r
+ instance associated with the new socket.\r
+\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS New connection successfully created\r
+ @retval EFI_NOT_READY No connection is available\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketAccept (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN struct sockaddr * pSockAddr,\r
+ IN OUT socklen_t * pSockAddrLength,\r
+ IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pNewSocket;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ pNewSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Validate the sockaddr\r
+ //\r
+ if (( NULL != pSockAddr )\r
+ && ( NULL == pSockAddrLength )) {\r
+ DEBUG (( DEBUG_ACCEPT,\r
+ "ERROR - pSockAddr is NULL!\r\n" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
+ }\r
+ else {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Verify that the socket is in the listen state\r
+ //\r
+ if ( SOCKET_STATE_LISTENING != pSocket->State ) {\r
+ DEBUG (( DEBUG_ACCEPT,\r
+ "ERROR - Socket is not listening!\r\n" ));\r
+ Status = EFI_NOT_STARTED;\r
+ pSocket->errno = EOPNOTSUPP;\r
+ }\r
+ else {\r
+ //\r
+ // Determine if a socket is available\r
+ //\r
+ if ( 0 == pSocket->FifoDepth ) {\r
+ //\r
+ // No connections available\r
+ // Determine if any ports are available\r
+ //\r
+ if ( NULL == pSocket->pPortList ) {\r
+ //\r
+ // No ports available\r
+ //\r
+ Status = EFI_DEVICE_ERROR;\r
+ pSocket->errno = EINVAL;\r
+\r
+ //\r
+ // Update the socket state\r
+ //\r
+ pSocket->State = SOCKET_STATE_NO_PORTS;\r
+ }\r
+ else {\r
+ //\r
+ // Ports are available\r
+ // No connection requests at this time\r
+ //\r
+ Status = EFI_NOT_READY;\r
+ pSocket->errno = EAGAIN;\r
+ }\r
+ }\r
+ else {\r
+ \r
+ //\r
+ // Get the remote network address\r
+ //\r
+ pNewSocket = pSocket->pFifoHead;\r
+ ASSERT ( NULL != pNewSocket );\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_ACCEPT,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_ACCEPT,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ Status = EslTcpAccept4 ( pNewSocket,\r
+ pSockAddr,\r
+ pSockAddrLength );\r
+ break;\r
+\r
+ /*\r
+ case SOCK_DGRAM:\r
+ Status = UdpAccept4 ( pSocket );\r
+ break;\r
+ */\r
+ }\r
+ break;\r
+ }\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Remove the new socket from the list\r
+ //\r
+ pSocket->pFifoHead = pNewSocket->pNextConnection;\r
+ if ( NULL == pSocket->pFifoHead ) {\r
+ pSocket->pFifoTail = NULL;\r
+ }\r
+\r
+ //\r
+ // Account for this socket\r
+ //\r
+ pSocket->FifoDepth -= 1;\r
+\r
+ //\r
+ // Update the new socket's state\r
+ //\r
+ pNewSocket->State = SOCKET_STATE_CONNECTED;\r
+ pNewSocket->bConfigured = TRUE;\r
+ DEBUG (( DEBUG_ACCEPT,\r
+ "0x%08x: Socket connected\r\n",\r
+ pNewSocket ));\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the new socket\r
+ //\r
+ if (( NULL != ppSocketProtocol )\r
+ && ( NULL != pNewSocket )) {\r
+ *ppSocketProtocol = &pNewSocket->SocketProtocol;\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Allocate and initialize a DT_SOCKET structure.\r
+ \r
+ The ::SocketAllocate() function allocates a DT_SOCKET structure\r
+ and installs a protocol on ChildHandle. If pChildHandle is a\r
+ pointer to NULL, then a new handle is created and returned in\r
+ pChildHandle. If pChildHandle is not a pointer to NULL, then\r
+ the protocol installs on the existing pChildHandle.\r
+\r
+ @param [in, out] pChildHandle Pointer to the handle of the child to create.\r
+ If it is NULL, then a new handle is created.\r
+ If it is a pointer to an existing UEFI handle, \r
+ then the protocol is added to the existing UEFI\r
+ handle.\r
+ @param [in] DebugFlags Flags for debug messages\r
+ @param [in, out] ppSocket The buffer to receive the DT_SOCKET structure address.\r
+\r
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
+ the child\r
+ @retval other The child handle was not created\r
+ \r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EslSocketAllocate (\r
+ IN OUT EFI_HANDLE * pChildHandle,\r
+ IN UINTN DebugFlags,\r
+ IN OUT DT_SOCKET ** ppSocket\r
+ )\r
+{\r
+ UINTN LengthInBytes;\r
+ DT_LAYER * pLayer;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Create a socket structure\r
+ //\r
+ LengthInBytes = sizeof ( *pSocket );\r
+ Status = gBS->AllocatePool (\r
+ EfiRuntimeServicesData,\r
+ LengthInBytes,\r
+ (VOID **) &pSocket\r
+ );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+ "0x%08x: Allocate pSocket, %d bytes\r\n",\r
+ pSocket,\r
+ LengthInBytes ));\r
+\r
+ //\r
+ // Initialize the socket protocol\r
+ //\r
+ ZeroMem ( pSocket, LengthInBytes );\r
+\r
+ pSocket->Signature = SOCKET_SIGNATURE;\r
+ pSocket->SocketProtocol.pfnAccept = EslSocketAccept;\r
+ pSocket->SocketProtocol.pfnBind = EslSocketBind;\r
+ pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;\r
+ pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;\r
+ pSocket->SocketProtocol.pfnConnect = EslSocketConnect;\r
+ pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;\r
+ pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;\r
+ pSocket->SocketProtocol.pfnListen = EslSocketListen;\r
+ pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;\r
+ pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;\r
+ pSocket->SocketProtocol.pfnPoll = EslSocketPoll;\r
+ pSocket->SocketProtocol.pfnReceive = EslSocketReceive;\r
+ pSocket->SocketProtocol.pfnSend = EslSocketTransmit;\r
+ pSocket->SocketProtocol.pfnShutdown = EslSocketShutdown;\r
+ pSocket->SocketProtocol.pfnSocket = EslSocket;\r
+\r
+ pSocket->MaxRxBuf = MAX_RX_DATA;\r
+ pSocket->MaxTxBuf = MAX_TX_DATA;\r
+\r
+ //\r
+ // Install the socket protocol on the specified handle\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ pChildHandle,\r
+ &gEfiSocketProtocolGuid,\r
+ &pSocket->SocketProtocol,\r
+ NULL\r
+ );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
+ "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",\r
+ *pChildHandle ));\r
+ pSocket->SocketProtocol.SocketHandle = *pChildHandle;\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Add this socket to the list\r
+ //\r
+ pLayer = &mEslLayer;\r
+ pSocket->pNext = pLayer->pSocketList;\r
+ pLayer->pSocketList = pSocket;\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\r
+ //\r
+ // Return the socket structure address\r
+ //\r
+ *ppSocket = pSocket;\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+ "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",\r
+ *pChildHandle,\r
+ Status ));\r
+ }\r
+\r
+ //\r
+ // Release the socket if necessary\r
+ //\r
+ if ( EFI_ERROR ( Status )) {\r
+ gBS->FreePool ( pSocket );\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+ "0x%08x: Free pSocket, %d bytes\r\n",\r
+ pSocket,\r
+ sizeof ( *pSocket )));\r
+ pSocket = NULL;\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+ "ERROR - Failed socket allocation, Status: %r\r\n",\r
+ Status ));\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Bind a name to a socket.\r
+\r
+ The ::SocketBind routine connects a name to a socket on the local machine. The\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html">POSIX</a>\r
+ documentation for the bind routine is available online for reference.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol 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
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket successfully created\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketBind (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN const struct sockaddr * pSockAddr,\r
+ IN socklen_t SockAddrLength,\r
+ OUT int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Validate the structure pointer\r
+ //\r
+ if ( NULL == pSockAddr ) {\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - pSockAddr is NULL!\r\n" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
+ }\r
+ else{\r
+ //\r
+ // Validate the name length\r
+ //\r
+ if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))\r
+ || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",\r
+ SockAddrLength,\r
+ pSockAddr->sa_len ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EINVAL;\r
+ }\r
+ else {\r
+ //\r
+ // Set the socket address length\r
+ //\r
+ if ( SockAddrLength > pSockAddr->sa_len ) {\r
+ SockAddrLength = pSockAddr->sa_len;\r
+ }\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSockAddr->sa_family ) {\r
+ default:\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Invalid bind address family: %d\r\n",\r
+ pSockAddr->sa_family ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ Status = EslTcpBind4 ( pSocket,\r
+ pSockAddr,\r
+ SockAddrLength );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ Status = EslUdpBind4 ( pSocket,\r
+ pSockAddr,\r
+ SockAddrLength );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Mark this socket as bound if successful\r
+ //\r
+ if ( !EFI_ERROR ( Status )) {\r
+ pSocket->State = SOCKET_STATE_BOUND;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Determine if the socket is closed\r
+\r
+ Reverses the operations of the ::SocketAllocate() routine.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS Socket successfully closed\r
+ @retval EFI_NOT_READY Close still in progress\r
+ @retval EFI_ALREADY Close operation already in progress\r
+ @retval Other Failed to close the socket\r
+\r
+**/\r
+EFI_STATUS\r
+EslSocketClosePoll (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ int errno;\r
+ DT_LAYER * pLayer;\r
+ DT_SOCKET * pNextSocket;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ errno = 0;\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Locate the socket\r
+ //\r
+ pLayer = &mEslLayer;\r
+ pNextSocket = pLayer->pSocketList;\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ while ( NULL != pNextSocket ) {\r
+ if ( pNextSocket == pSocket ) {\r
+ //\r
+ // Determine if the socket is in the closing state\r
+ //\r
+ if ( SOCKET_STATE_CLOSED == pSocket->State ) {\r
+ //\r
+ // Walk the list of ports\r
+ //\r
+ if ( NULL == pSocket->pPortList ) {\r
+ //\r
+ // All the ports are closed\r
+ // Close the WaitAccept event if necessary\r
+ //\r
+ if ( NULL != pSocket->WaitAccept ) {\r
+ Status = gBS->CloseEvent ( pSocket->WaitAccept );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
+ "0x%08x: Closed WaitAccept event\r\n",\r
+ pSocket->WaitAccept ));\r
+ //\r
+ // Return the transmit status\r
+ //\r
+ Status = pSocket->TxError;\r
+ if ( EFI_ERROR ( Status )) {\r
+ pSocket->errno = EIO;\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
+ "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",\r
+ Status ));\r
+ ASSERT ( EFI_SUCCESS == Status );\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // At least one port is still open\r
+ //\r
+ Status = EFI_NOT_READY;\r
+ errno = EAGAIN;\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // SocketCloseStart was not called\r
+ //\r
+ Status = EFI_NOT_STARTED;\r
+ errno = EPERM;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Set the next socket\r
+ //\r
+ pNextSocket = pNextSocket->pNext;\r
+ }\r
+\r
+ //\r
+ // Handle the error case where the socket was already closed\r
+ //\r
+ if ( NULL == pSocket ) {\r
+ //\r
+ // Socket not found\r
+ //\r
+ Status = EFI_NOT_FOUND;\r
+ errno = ENOTSOCK;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = errno;\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Start the close operation on the socket\r
+\r
+ Start closing the socket by closing all of the ports. Upon\r
+ completion, the ::SocketPoll() routine finishes closing the\r
+ socket.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ @param [in] bCloseNow Boolean to control close behavior\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS Socket successfully closed\r
+ @retval EFI_NOT_READY Close still in progress\r
+ @retval EFI_ALREADY Close operation already in progress\r
+ @retval Other Failed to close the socket\r
+\r
+**/\r
+EFI_STATUS\r
+EslSocketCloseStart (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN BOOLEAN bCloseNow,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ int errno;\r
+ DT_PORT * pNextPort;\r
+ DT_PORT * pPort;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ errno = 0;\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Determine if the socket is already closed\r
+ //\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ if ( SOCKET_STATE_CLOSED > pSocket->State ) {\r
+ //\r
+ // Update the socket state\r
+ //\r
+ pSocket->State = SOCKET_STATE_CLOSED;\r
+\r
+ //\r
+ // Walk the list of ports\r
+ //\r
+ pPort = pSocket->pPortList;\r
+ while ( NULL != pPort ) {\r
+ //\r
+ // Start closing the ports\r
+ //\r
+ pNextPort = pPort->pLinkSocket;\r
+ Status = pPort->pfnCloseStart ( pPort,\r
+ bCloseNow,\r
+ DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );\r
+ if (( EFI_SUCCESS != Status )\r
+ && ( EFI_NOT_READY != Status )) {\r
+ errno = EIO;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Set the next port\r
+ //\r
+ pPort = pNextPort;\r
+ }\r
+\r
+ //\r
+ // Attempt to finish closing the socket\r
+ //\r
+ if ( NULL == pPort ) {\r
+ Status = EslSocketClosePoll ( pSocketProtocol, &errno );\r
+ }\r
+ }\r
+ else {\r
+ Status = EFI_ALREADY_STARTED;\r
+ errno = EALREADY;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = errno;\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Connect to a remote system via the network.\r
+\r
+ The ::SocketConnect routine attempts to establish a connection to a\r
+ socket on the local or remote system using the specified address.\r
+ The POSIX\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html">connect</a>\r
+ documentation is available online.\r
+\r
+ There are three states associated with a connection:\r
+ <ul>\r
+ <li>Not connected</li>\r
+ <li>Connection in progress</li>\r
+ <li>Connected</li>\r
+ </ul>\r
+ In the "Not connected" state, calls to ::connect start the connection\r
+ processing and update the state to "Connection in progress". During\r
+ the "Connection in progress" state, connect polls for connection completion\r
+ and moves the state to "Connected" after the connection is established.\r
+ Note that these states are only visible when the file descriptor is marked\r
+ with O_NONBLOCK. Also, the POLL_WRITE bit is set when the connection\r
+ completes and may be used by poll or select as an indicator to call\r
+ connect again.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol 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 [out] pErrno Address to receive the errno value upon completion.\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
+EslSocketConnect (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN const struct sockaddr * pSockAddr,\r
+ IN socklen_t SockAddrLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+ \r
+ DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Validate the name length\r
+ //\r
+ if (( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))\r
+ || ( pSockAddr->sa_len < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data )))) {\r
+ DEBUG (( DEBUG_CONNECT,\r
+ "ERROR - Invalid bind name length: %d, sa_len: %d\r\n",\r
+ SockAddrLength,\r
+ pSockAddr->sa_len ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EINVAL;\r
+ }\r
+ else {\r
+ //\r
+ // Assume success\r
+ //\r
+ pSocket->errno = 0;\r
+\r
+ //\r
+ // Set the socket address length\r
+ //\r
+ if ( SockAddrLength > pSockAddr->sa_len ) {\r
+ SockAddrLength = pSockAddr->sa_len;\r
+ }\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the socket state\r
+ //\r
+ switch ( pSocket->State ) {\r
+ default:\r
+ //\r
+ // Wrong socket state\r
+ //\r
+ pSocket->errno = EIO;\r
+ Status = EFI_DEVICE_ERROR;\r
+ break;\r
+\r
+ case SOCKET_STATE_NOT_CONFIGURED:\r
+ case SOCKET_STATE_BOUND:\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSockAddr->sa_family ) {\r
+ default:\r
+ DEBUG (( DEBUG_CONNECT,\r
+ "ERROR - Invalid bind address family: %d\r\n",\r
+ pSockAddr->sa_family ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_CONNECT,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Start the connection processing\r
+ //\r
+ Status = EslTcpConnectStart4 ( pSocket,\r
+ pSockAddr,\r
+ SockAddrLength );\r
+\r
+ //\r
+ // Set the next state if connecting\r
+ //\r
+ if ( EFI_NOT_READY == Status ) {\r
+ pSocket->State = SOCKET_STATE_CONNECTING;\r
+ }\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ Status = EslUdpConnect4 ( pSocket,\r
+ pSockAddr,\r
+ SockAddrLength );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case SOCKET_STATE_CONNECTING:\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSockAddr->sa_family ) {\r
+ default:\r
+ DEBUG (( DEBUG_CONNECT,\r
+ "ERROR - Invalid bind address family: %d\r\n",\r
+ pSockAddr->sa_family ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_CONNECT,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Determine if the connection processing is completed\r
+ //\r
+ Status = EslTcpConnectPoll4 ( pSocket );\r
+\r
+ //\r
+ // Set the next state if connected\r
+ //\r
+ if ( EFI_NOT_READY != Status ) {\r
+ if ( !EFI_ERROR ( Status )) {\r
+ pSocket->State = SOCKET_STATE_CONNECTED;\r
+ }\r
+ else {\r
+ pSocket->State = SOCKET_STATE_BOUND;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ //\r
+ // Already connected\r
+ //\r
+ pSocket->errno = EISCONN;\r
+ Status = EFI_ALREADY_STARTED;\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ break;\r
+\r
+ case SOCKET_STATE_CONNECTED:\r
+ //\r
+ // Already connected\r
+ //\r
+ pSocket->errno = EISCONN;\r
+ Status = EFI_ALREADY_STARTED;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ //\r
+ // Bad socket protocol\r
+ //\r
+ DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,\r
+ "ERROR - pSocketProtocol invalid!\r\n" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Creates a child handle and installs a protocol.\r
+ \r
+ The CreateChild() function installs a protocol on ChildHandle. \r
+ If pChildHandle is a pointer to NULL, then a new handle is created and returned in pChildHandle. \r
+ If pChildHandle is not a pointer to NULL, then the protocol installs on the existing pChildHandle.\r
+\r
+ @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
+ @param [in] pChildHandle Pointer to the handle of the child to create. If it is NULL,\r
+ then a new handle is created. If it is a pointer to an existing UEFI handle, \r
+ then the protocol is added to the existing UEFI handle.\r
+\r
+ @retval EFI_SUCCESS The protocol was added to ChildHandle.\r
+ @retval EFI_INVALID_PARAMETER ChildHandle is NULL.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources availabe to create\r
+ the child\r
+ @retval other The child handle was not created\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EslSocketCreateChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,\r
+ IN OUT EFI_HANDLE * pChildHandle\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Create a socket structure\r
+ //\r
+ Status = EslSocketAllocate ( pChildHandle,\r
+ DEBUG_SOCKET,\r
+ &pSocket );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Destroys a child handle with a protocol installed on it.\r
+ \r
+ The DestroyChild() function does the opposite of CreateChild(). It removes a protocol \r
+ that was installed by CreateChild() from ChildHandle. If the removed protocol is the \r
+ last protocol on ChildHandle, then ChildHandle is destroyed.\r
+\r
+ @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
+ @param [in] ChildHandle Handle of the child to destroy\r
+\r
+ @retval EFI_SUCCESS The protocol was removed from ChildHandle.\r
+ @retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed.\r
+ @retval EFI_INVALID_PARAMETER Child handle is not a valid UEFI Handle.\r
+ @retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle\r
+ because its services are being used.\r
+ @retval other The child handle was not destroyed\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EslSocketDestroyChild (\r
+ IN EFI_SERVICE_BINDING_PROTOCOL * pThis,\r
+ IN EFI_HANDLE ChildHandle\r
+ )\r
+{\r
+ DT_LAYER * pLayer;\r
+ DT_SOCKET * pSocket;\r
+ DT_SOCKET * pSocketPrevious;\r
+ EFI_SOCKET_PROTOCOL * pSocketProtocol;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Locate the socket control structure\r
+ //\r
+ pLayer = &mEslLayer;\r
+ Status = gBS->OpenProtocol (\r
+ ChildHandle,\r
+ &gEfiSocketProtocolGuid,\r
+ (VOID **)&pSocketProtocol,\r
+ pLayer->ImageHandle,\r
+ NULL,\r
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+ );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Walk the socket list\r
+ //\r
+ pSocketPrevious = pLayer->pSocketList;\r
+ if ( NULL != pSocketPrevious ) {\r
+ if ( pSocket == pSocketPrevious ) {\r
+ //\r
+ // Remove the socket from the head of the list\r
+ //\r
+ pLayer->pSocketList = pSocket->pNext;\r
+ }\r
+ else {\r
+ //\r
+ // Find the socket in the middle of the list\r
+ //\r
+ while (( NULL != pSocketPrevious )\r
+ && ( pSocket != pSocketPrevious->pNext )) {\r
+ //\r
+ // Set the next socket\r
+ //\r
+ pSocketPrevious = pSocketPrevious->pNext;\r
+ }\r
+ if ( NULL != pSocketPrevious ) {\r
+ //\r
+ // Remove the socket from the middle of the list\r
+ //\r
+ pSocketPrevious = pSocket->pNext;\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
+ "ERROR - Socket list is empty!\r\n" ));\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\r
+ //\r
+ // Determine if the socket was found\r
+ //\r
+ if ( NULL != pSocketPrevious ) {\r
+ pSocket->pNext = NULL;\r
+\r
+ //\r
+ // Remove the socket protocol\r
+ //\r
+ Status = gBS->UninstallMultipleProtocolInterfaces (\r
+ ChildHandle,\r
+ &gEfiSocketProtocolGuid,\r
+ &pSocket->SocketProtocol,\r
+ NULL );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_POOL | DEBUG_INFO,\r
+ "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",\r
+ ChildHandle ));\r
+\r
+ //\r
+ // Free the socket structure\r
+ //\r
+ Status = gBS->FreePool ( pSocket );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_POOL,\r
+ "0x%08x: Free pSocket, %d bytes\r\n",\r
+ pSocket,\r
+ sizeof ( *pSocket )));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
+ "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",\r
+ pSocket,\r
+ Status ));\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,\r
+ "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",\r
+ ChildHandle,\r
+ Status ));\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
+ "ERROR - The socket was not in the socket list!\r\n" ));\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR,\r
+ "ERROR - Failed to open socket protocol on 0x%08x, Status; %r\r\n",\r
+ ChildHandle,\r
+ Status ));\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Get the local address.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol 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
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Local address successfully returned\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketGetLocalAddress (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ OUT struct sockaddr * pAddress,\r
+ IN OUT socklen_t * pAddressLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+ \r
+ DBG_ENTER ( );\r
+ \r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ \r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Verify the address buffer and length address\r
+ //\r
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Get the local address\r
+ //\r
+ Status = EslTcpGetLocalAddress4 ( pSocket,\r
+ pAddress,\r
+ pAddressLength );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ //\r
+ // Get the local address\r
+ //\r
+ Status = EslUdpGetLocalAddress4 ( pSocket,\r
+ pAddress,\r
+ pAddressLength );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ else {\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\r
+ }\r
+ }\r
+ else {\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Get the peer address.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol 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
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Remote address successfully returned\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketGetPeerAddress (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ OUT struct sockaddr * pAddress,\r
+ IN OUT socklen_t * pAddressLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+ \r
+ DBG_ENTER ( );\r
+ \r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ \r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Verify the address buffer and length address\r
+ //\r
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslTcpGetRemoteAddress4 ( pSocket,\r
+ pAddress,\r
+ pAddressLength );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslUdpGetRemoteAddress4 ( pSocket,\r
+ pAddress,\r
+ pAddressLength );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ else {\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\r
+ }\r
+ }\r
+ else {\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Establish the known port to listen for network connections.\r
+\r
+ The ::SocketListen 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 ::SocketAccept routine to remove\r
+ the next connection from the queue and get the associated socket. The\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html">POSIX</a>\r
+ documentation for the listen routine is available online for reference.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+\r
+ @param [in] Backlog Backlog specifies the maximum FIFO depth for\r
+ the connections waiting for the application\r
+ to call accept. Connection attempts received\r
+ while the queue is full are refused.\r
+\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket successfully created\r
+ @retval Other - Failed to enable the socket for listen\r
+\r
+**/\r
+EFI_STATUS\r
+EslSocketListen (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN INT32 Backlog,\r
+ OUT int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_STATUS TempStatus;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ pSocket->Status = EFI_SUCCESS;\r
+ pSocket->errno = 0;\r
+\r
+ //\r
+ // Verify that the bind operation was successful\r
+ //\r
+ if ( SOCKET_STATE_BOUND == pSocket->State ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Create the event for SocketAccept completion\r
+ //\r
+ Status = gBS->CreateEvent ( 0,\r
+ TplPrevious,\r
+ NULL,\r
+ NULL,\r
+ &pSocket->WaitAccept );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_POOL,\r
+ "0x%08x: Created WaitAccept event\r\n",\r
+ pSocket->WaitAccept ));\r
+ //\r
+ // Set the maximum FIFO depth\r
+ //\r
+ if ( 0 >= Backlog ) {\r
+ Backlog = MAX_PENDING_CONNECTIONS;\r
+ }\r
+ else {\r
+ if ( SOMAXCONN < Backlog ) {\r
+ Backlog = SOMAXCONN;\r
+ }\r
+ else {\r
+ pSocket->MaxFifoDepth = Backlog;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ Status = EslTcpListen4 ( pSocket );\r
+ break;\r
+\r
+/*\r
+ case SOCK_DGRAM:\r
+ Status = UdpListen4 ( pSocket );\r
+ break;\r
+*/\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Place the socket in the listen state if successful\r
+ //\r
+ if ( !EFI_ERROR ( Status )) {\r
+ pSocket->State = SOCKET_STATE_LISTENING;\r
+ }\r
+ else {\r
+ //\r
+ // Not waiting for SocketAccept to complete\r
+ //\r
+ TempStatus = gBS->CloseEvent ( pSocket->WaitAccept );\r
+ if ( !EFI_ERROR ( TempStatus )) {\r
+ DEBUG (( DEBUG_POOL,\r
+ "0x%08x: Closed WaitAccept event\r\n",\r
+ pSocket->WaitAccept ));\r
+ pSocket->WaitAccept = NULL;\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
+ "ERROR - Failed to close WaitAccept event, Status: %r\r\n",\r
+ TempStatus ));\r
+ ASSERT ( EFI_SUCCESS == TempStatus );\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
+ "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",\r
+ Status ));\r
+ pSocket->errno = ENOMEM;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_LISTEN,\r
+ "ERROR - Bind operation must be performed first!\r\n" ));\r
+ pSocket->errno = EDESTADDRREQ;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Get the socket options\r
+\r
+ Retrieve the socket options one at a time by name. The\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html">POSIX</a>\r
+ documentation is available online.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ @param [in] level Option protocol level\r
+ @param [in] OptionName Name of the option\r
+ @param [out] pOptionValue Buffer to receive the option value\r
+ @param [in,out] pOptionLength Length of the buffer in bytes,\r
+ upon return length of the option value in bytes\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket data successfully received\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketOptionGet (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int level,\r
+ IN int OptionName,\r
+ OUT void * __restrict pOptionValue,\r
+ IN OUT socklen_t * __restrict pOptionLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ int errno;\r
+ socklen_t LengthInBytes;\r
+ socklen_t MaxBytes;\r
+ UINT8 * pOptionData;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume failure\r
+ //\r
+ errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if (( NULL != pSocketProtocol )\r
+ && ( NULL != pOptionValue )\r
+ && ( NULL != pOptionLength )) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ LengthInBytes = 0;\r
+ MaxBytes = *pOptionLength;\r
+ pOptionData = NULL;\r
+ switch ( level ) {\r
+ default:\r
+ //\r
+ // Protocol level not supported\r
+ //\r
+ errno = ENOTSUP;\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+\r
+ case SOL_SOCKET:\r
+ switch ( OptionName ) {\r
+ default:\r
+ //\r
+ // Option not supported\r
+ //\r
+ errno = ENOTSUP;\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+\r
+ case SO_RCVTIMEO:\r
+ //\r
+ // Return the receive timeout\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->RxTimeout;\r
+ LengthInBytes = sizeof ( pSocket->RxTimeout );\r
+ break;\r
+ \r
+ case SO_RCVBUF:\r
+ //\r
+ // Return the maximum transmit buffer size\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
+ break;\r
+\r
+ case SO_SNDBUF:\r
+ //\r
+ // Return the maximum transmit buffer size\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
+ break;\r
+\r
+ case SO_TYPE:\r
+ //\r
+ // Return the socket type\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->Type;\r
+ LengthInBytes = sizeof ( pSocket->Type );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Return the option length\r
+ //\r
+ *pOptionLength = LengthInBytes;\r
+\r
+ //\r
+ // Return the option value\r
+ //\r
+ if ( NULL != pOptionData ) {\r
+ //\r
+ // Silently truncate the value length\r
+ //\r
+ if ( LengthInBytes > MaxBytes ) {\r
+ LengthInBytes = MaxBytes;\r
+ }\r
+ CopyMem ( pOptionValue, pOptionData, LengthInBytes );\r
+ errno = 0;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = errno;\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Set the socket options\r
+\r
+ Adjust the socket options one at a time by name. The\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html">POSIX</a>\r
+ documentation is available online.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ @param [in] level Option protocol level\r
+ @param [in] OptionName Name of the option\r
+ @param [in] pOptionValue Buffer containing the option value\r
+ @param [in] OptionLength Length of the buffer in bytes\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket data successfully received\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketOptionSet (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int level,\r
+ IN int OptionName,\r
+ IN CONST void * pOptionValue,\r
+ IN socklen_t OptionLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ int errno;\r
+ socklen_t LengthInBytes;\r
+ UINT8 * pOptionData;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ \r
+ DBG_ENTER ( );\r
+ \r
+ //\r
+ // Assume failure\r
+ //\r
+ errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ \r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if (( NULL != pSocketProtocol )\r
+ && ( NULL != pOptionValue )) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ LengthInBytes = 0;\r
+ pOptionData = NULL;\r
+ switch ( level ) {\r
+ default:\r
+ //\r
+ // Protocol level not supported\r
+ //\r
+ errno = ENOTSUP;\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+ \r
+ case SOL_SOCKET:\r
+ switch ( OptionName ) {\r
+ default:\r
+ //\r
+ // Option not supported\r
+ //\r
+ errno = ENOTSUP;\r
+ Status = EFI_UNSUPPORTED;\r
+ break;\r
+ \r
+ case SO_RCVTIMEO:\r
+ //\r
+ // Return the receive timeout\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->RxTimeout;\r
+ LengthInBytes = sizeof ( pSocket->RxTimeout );\r
+ break;\r
+\r
+ case SO_RCVBUF:\r
+ //\r
+ // Return the maximum transmit buffer size\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
+ break;\r
+\r
+ case SO_SNDBUF:\r
+ //\r
+ // Send buffer size\r
+ //\r
+ //\r
+ // Return the maximum transmit buffer size\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Validate the option length\r
+ //\r
+ if ( LengthInBytes <= OptionLength ) {\r
+ //\r
+ // Set the option value\r
+ //\r
+ if ( NULL != pOptionData ) {\r
+ CopyMem ( pOptionData, pOptionValue, LengthInBytes );\r
+ errno = 0;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ }\r
+ }\r
+ \r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = errno;\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Allocate a packet for a receive or transmit operation\r
+\r
+ @param [in] ppPacket Address to receive the DT_PACKET structure\r
+ @param [in] LengthInBytes Length of the packet structure\r
+ @param [in] DebugFlags Flags for debug messages\r
+\r
+ @retval EFI_SUCCESS - The packet was allocated successfully\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketPacketAllocate (\r
+ IN DT_PACKET ** ppPacket,\r
+ IN size_t LengthInBytes,\r
+ IN UINTN DebugFlags\r
+ )\r
+{\r
+ DT_PACKET * pPacket;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Allocate a packet structure\r
+ //\r
+ LengthInBytes += sizeof ( *pPacket )\r
+ - sizeof ( pPacket->Op );\r
+ Status = gBS->AllocatePool ( EfiRuntimeServicesData,\r
+ LengthInBytes,\r
+ (VOID **)&pPacket );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+ "0x%08x: Allocate pPacket, %d bytes\r\n",\r
+ pPacket,\r
+ LengthInBytes ));\r
+ pPacket->PacketSize = LengthInBytes;\r
+ }\r
+ else {\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
+ "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",\r
+ LengthInBytes,\r
+ Status ));\r
+ pPacket = NULL;\r
+ }\r
+\r
+ //\r
+ // Return the packet\r
+ //\r
+ *ppPacket = pPacket;\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Free a packet used for receive or transmit operation\r
+\r
+ @param [in] pPacket Address of the DT_PACKET structure\r
+ @param [in] DebugFlags Flags for debug messages\r
+\r
+ @retval EFI_SUCCESS - The packet was allocated successfully\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketPacketFree (\r
+ IN DT_PACKET * pPacket,\r
+ IN UINTN DebugFlags\r
+ )\r
+{\r
+ UINTN LengthInBytes;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Allocate a packet structure\r
+ //\r
+ LengthInBytes = pPacket->PacketSize;\r
+ Status = gBS->FreePool ( pPacket );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DebugFlags | DEBUG_POOL,\r
+ "0x%08x: Free pPacket, %d bytes\r\n",\r
+ pPacket,\r
+ LengthInBytes ));\r
+ }\r
+ else {\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INFO,\r
+ "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",\r
+ pPacket,\r
+ Status ));\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Poll a socket for pending activity.\r
+\r
+ The SocketPoll routine checks a socket for pending activity associated\r
+ with the event mask. Activity is returned in the detected event buffer.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+\r
+ @param [in] Events Events of interest for this socket\r
+\r
+ @param [in] pEvents Address to receive the detected events\r
+\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket successfully polled\r
+ @retval EFI_INVALID_PARAMETER - When pEvents is NULL\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketPoll (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN short Events,\r
+ IN short * pEvents,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ short DetectedEvents;\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+ short ValidEvents;\r
+\r
+ DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ DetectedEvents = 0;\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ pSocket->errno = 0;\r
+\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ if ( !pSocket->bConfigured ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslTcpSocketIsConfigured4 ( pSocket );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslUdpSocketIsConfigured4 ( pSocket );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Check for invalid events\r
+ //\r
+ ValidEvents = POLLIN\r
+ | POLLPRI\r
+ | POLLOUT | POLLWRNORM\r
+ | POLLERR\r
+ | POLLHUP\r
+ | POLLNVAL\r
+ | POLLRDNORM\r
+ | POLLRDBAND\r
+ | POLLWRBAND ;\r
+ if ( 0 != ( Events & ( ~ValidEvents ))) {\r
+ DetectedEvents |= POLLNVAL;\r
+ DEBUG (( DEBUG_INFO | DEBUG_POLL,\r
+ "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",\r
+ Events & ValidEvents,\r
+ Events & ( ~ValidEvents )));\r
+ }\r
+ else {\r
+ //\r
+ // Check for pending connections\r
+ //\r
+ if ( 0 != pSocket->FifoDepth ) {\r
+ //\r
+ // A connection is waiting for an accept call\r
+ // See posix connect documentation at\r
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm\r
+ //\r
+ DetectedEvents |= POLLIN | POLLRDNORM;\r
+ }\r
+ if ( pSocket->bConnected ) {\r
+ //\r
+ // A connection is present\r
+ // See posix connect documentation at\r
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm\r
+ //\r
+ DetectedEvents |= POLLOUT | POLLWRNORM;\r
+ }\r
+\r
+ //\r
+ // The following bits are set based upon the POSIX poll documentation at\r
+ // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html\r
+ //\r
+\r
+ //\r
+ // Check for urgent receive data\r
+ //\r
+ if ( 0 < pSocket->RxOobBytes ) {\r
+ DetectedEvents |= POLLRDBAND | POLLPRI | POLLIN;\r
+ }\r
+\r
+ //\r
+ // Check for normal receive data\r
+ //\r
+ if (( 0 < pSocket->RxBytes )\r
+ || ( EFI_SUCCESS != pSocket->RxError )) {\r
+ DetectedEvents |= POLLRDNORM | POLLIN;\r
+ }\r
+\r
+ //\r
+ // Handle the receive errors\r
+ //\r
+ if (( EFI_SUCCESS != pSocket->RxError )\r
+ && ( 0 == ( DetectedEvents & POLLIN ))) {\r
+ DetectedEvents |= POLLERR | POLLIN | POLLRDNORM | POLLRDBAND;\r
+ }\r
+\r
+ //\r
+ // Check for urgent transmit data buffer space\r
+ //\r
+ if (( MAX_TX_DATA > pSocket->TxOobBytes )\r
+ || ( EFI_SUCCESS != pSocket->TxError )) {\r
+ DetectedEvents |= POLLWRBAND;\r
+ }\r
+\r
+ //\r
+ // Check for normal transmit data buffer space\r
+ //\r
+ if (( MAX_TX_DATA > pSocket->TxBytes )\r
+ || ( EFI_SUCCESS != pSocket->TxError )) {\r
+ DetectedEvents |= POLLWRNORM;\r
+ }\r
+\r
+ //\r
+ // Handle the transmit error\r
+ //\r
+ if ( EFI_ERROR ( pSocket->TxError )) {\r
+ DetectedEvents |= POLLERR;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the detected events\r
+ //\r
+ *pEvents = DetectedEvents & ( Events\r
+ | POLLERR\r
+ | POLLHUP\r
+ | POLLNVAL );\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DEBUG (( DEBUG_POLL, "Exiting SocketPoll, Status: %r\r\n", Status ));\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Receive data from a network connection.\r
+\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ \r
+ @param [in] Flags Message control flags\r
+ \r
+ @param [in] BufferLength Length of the the buffer\r
+ \r
+ @param [in] pBuffer Address of a buffer to receive the data.\r
+ \r
+ @param [in] pDataLength Number of received data bytes in the buffer.\r
+\r
+ @param [out] pAddress Network address to receive the remote system address\r
+\r
+ @param [in,out] pAddressLength Length of the remote network address structure\r
+\r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket data successfully received\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketReceive (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN INT32 Flags,\r
+ IN size_t BufferLength,\r
+ IN UINT8 * pBuffer,\r
+ OUT size_t * pDataLength,\r
+ OUT struct sockaddr * pAddress,\r
+ IN OUT socklen_t * pAddressLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ if ( !pSocket->bConfigured ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslTcpSocketIsConfigured4 ( pSocket );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslUdpSocketIsConfigured4 ( pSocket );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\r
+ //\r
+ // Set errno if a failure occurs\r
+ //\r
+ if ( EFI_ERROR ( Status )) {\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ }\r
+ }\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Validate the buffer length\r
+ //\r
+ if (( NULL == pDataLength )\r
+ && ( 0 > pDataLength )\r
+ && ( NULL == pBuffer )) {\r
+ if ( NULL == pDataLength ) {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - pDataLength is NULL!\r\n" ));\r
+ }\r
+ else if ( NULL == pBuffer ) {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - pBuffer is NULL!\r\n" ));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Data length < 0!\r\n" ));\r
+ }\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
+ }\r
+ else{\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ Status = EslTcpReceive4 ( pSocket,\r
+ Flags,\r
+ BufferLength,\r
+ pBuffer,\r
+ pDataLength,\r
+ pAddress,\r
+ pAddressLength );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ Status = EslUdpReceive4 ( pSocket,\r
+ Flags,\r
+ BufferLength,\r
+ pBuffer,\r
+ pDataLength,\r
+ pAddress,\r
+ pAddressLength);\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Shutdown the socket receive and transmit operations\r
+\r
+ The SocketShutdown routine stops the socket receive and transmit\r
+ operations.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ \r
+ @param [in] How Which operations to stop\r
+ \r
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket operations successfully shutdown\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketShutdown (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int How,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+ \r
+ DBG_ENTER ( );\r
+ \r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Verify that the socket is connected\r
+ //\r
+ if ( pSocket->bConnected ) {\r
+ //\r
+ // Validate the How value\r
+ //\r
+ if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Disable the receiver if requested\r
+ //\r
+ if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {\r
+ pSocket->bRxDisable = TRUE;\r
+ }\r
+\r
+ //\r
+ // Disable the transmitter if requested\r
+ //\r
+ if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {\r
+ pSocket->bTxDisable = TRUE;\r
+ }\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+ \r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ \r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Cancel the pending receive operation\r
+ //\r
+ Status = EslTcpRxCancel4 ( pSocket );\r
+ break;\r
+ \r
+ case SOCK_DGRAM:\r
+ //\r
+ // Cancel the pending receive operation\r
+ //\r
+ Status = EslUdpRxCancel4 ( pSocket );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ \r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ else {\r
+ //\r
+ // The socket is not connected\r
+ //\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // Invalid How value\r
+ //\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Send data using a network connection.\r
+\r
+ The SocketTransmit routine queues the data for transmission to the\r
+ remote network connection.\r
+\r
+ @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ \r
+ @param [in] Flags Message control flags\r
+ \r
+ @param [in] BufferLength Length of the the buffer\r
+ \r
+ @param [in] pBuffer Address of a buffer containing the data to send\r
+ \r
+ @param [in] pDataLength Address to receive the number of data bytes sent\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
+ @param [out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket data successfully queued for transmit\r
+\r
+ **/\r
+EFI_STATUS\r
+EslSocketTransmit (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int Flags,\r
+ IN size_t BufferLength,\r
+ IN CONST UINT8 * pBuffer,\r
+ OUT size_t * pDataLength,\r
+ IN const struct sockaddr * pAddress,\r
+ IN socklen_t AddressLength,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ DT_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Assume success\r
+ //\r
+ Status = EFI_SUCCESS;\r
+\r
+ //\r
+ // Validate the socket\r
+ //\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ if ( !pSocket->bConfigured ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+ \r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+ \r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+ \r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslTcpSocketIsConfigured4 ( pSocket );\r
+ break;\r
+ \r
+ case SOCK_DGRAM:\r
+ //\r
+ // Verify the port state\r
+ //\r
+ Status = EslUdpSocketIsConfigured4 ( pSocket );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+ \r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ \r
+ //\r
+ // Set errno if a failure occurs\r
+ //\r
+ if ( EFI_ERROR ( Status )) {\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ }\r
+ }\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Verify that transmit is still allowed\r
+ //\r
+ if ( !pSocket->bTxDisable ) {\r
+ //\r
+ // Validate the buffer length\r
+ //\r
+ if (( NULL == pDataLength )\r
+ && ( 0 > pDataLength )\r
+ && ( NULL == pBuffer )) {\r
+ if ( NULL == pDataLength ) {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - pDataLength is NULL!\r\n" ));\r
+ }\r
+ else if ( NULL == pBuffer ) {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - pBuffer is NULL!\r\n" ));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Data length < 0!\r\n" ));\r
+ }\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
+ }\r
+ else {\r
+ //\r
+ // Validate the remote network address\r
+ //\r
+ if (( NULL != pAddress )\r
+ && ( AddressLength < pAddress->sa_len )) {\r
+ DEBUG (( DEBUG_TX,\r
+ "ERROR - Invalid sin_len field in address\r\n" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
+ }\r
+ else {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Validate the local address\r
+ //\r
+ switch ( pSocket->Domain ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket address family: %d\r\n",\r
+ pSocket->Domain ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case AF_INET:\r
+ //\r
+ // Determine the connection point within the network stack\r
+ //\r
+ switch ( pSocket->Type ) {\r
+ default:\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - Invalid socket type: %d\r\n",\r
+ pSocket->Type));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ break;\r
+\r
+ case SOCK_STREAM:\r
+ case SOCK_SEQPACKET:\r
+ Status = EslTcpTxBuffer4 ( pSocket,\r
+ Flags,\r
+ BufferLength,\r
+ pBuffer,\r
+ pDataLength );\r
+ break;\r
+\r
+ case SOCK_DGRAM:\r
+ Status = EslUdpTxBuffer4 ( pSocket,\r
+ Flags,\r
+ BufferLength,\r
+ pBuffer,\r
+ pDataLength,\r
+ pAddress,\r
+ AddressLength );\r
+ break;\r
+ }\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // The transmitter was shutdown\r
+ //\r
+ pSocket->errno = EPIPE;\r
+ Status = EFI_NOT_STARTED;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ if ( NULL != pSocket ) {\r
+ *pErrno = pSocket->errno;\r
+ }\r
+ else\r
+ {\r
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = EBADF;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Socket layer's service binding protocol delcaration.\r
+**/\r
+EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {\r
+ EslSocketCreateChild,\r
+ EslSocketDestroyChild\r
+};\r