* 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
+ Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials are licensed and made available under\r
+ the terms and conditions of the BSD License that accompanies this distribution.\r
+ 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
+ \section DataStructures Data Structures\r
+\r
+ <code><pre>\r
+\r
+ +---------------+ +-------------+ +-------------+\r
+ Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)\r
+ +---------------+ +-------------+ +-------------+\r
+ ^ | (pPortList) |\r
+ pUdp4List ^ | pTcp4List | |\r
+ | | | |\r
+ ^ | | | |\r
+ pIp4List | | | | |\r
+ +---------------+ | |\r
+ | ::ESL_LAYER | ::mEslLayer | |\r
+ +---------------+ | |\r
+ | (pSocketList) | |\r
+ Socket List V V V\r
+ +---------------+ +-------------+ +-------------+\r
+ | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)\r
+ +---------------+ +-------------+ +-------------+\r
+ | | |\r
+ | | V\r
+ V V NULL\r
+ +-------------+ +-------------+\r
+ | ESL_SOCKET |-->| ESL_PORT |--> NULL\r
+ +-------------+ +-------------+\r
+ | | | | | |\r
+ V | | | | V\r
+ NULL | | | | NULL\r
+ (pNext) | | | | (pLinkService)\r
+ | | | | pRxPacketListHead\r
+ | | | `-----------------------------------------------.\r
+ | | | pRxOobPacketListHead |\r
+ | | `--------------------------------. |\r
+ | | pTxPacketListHead | |\r
+ | `---------------. | |\r
+ pTxOobPacketListHead | | | |\r
+ V V V V\r
+ +--------------+ +------------+ +------------+ +------------+\r
+ | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |\r
+ +--------------+ +------------+ +------------+ +------------+\r
+ | | | |\r
+ V V V V\r
+ +------------+ +------------+ +------------+ +------------+\r
+ | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |\r
+ +------------+ +------------+ +------------+ +------------+\r
+ | | | |\r
+ V V V V\r
+ NULL NULL NULL NULL\r
+ (pNext)\r
+\r
+ </pre></code>\r
+\r
+ ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or\r
+ indirectly to the other data structures. The ESL_LAYER structure has a unique\r
+ service list for each of the network protocol interfaces.\r
+\r
+ ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)\r
+\r
+ ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains\r
+ the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object\r
+ reference and the API into the EFI socket library.\r
+\r
+ ::ESL_PORT manages the connection with a single instance of the lower layer network.\r
+ This structure is the socket equivalent of an IP connection or a TCP or UDP port.\r
+\r
+ ::ESL_PACKET buffers data for transmit and receive. There are four queues connected\r
+ to the ::ESL_SOCKET that manage the data:\r
+ <ul>\r
+ <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>\r
+ <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>\r
+ <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>\r
+ <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>\r
+ </ul>\r
+ The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit\r
+ request as well as the socket option SO_OOBINLINE. The receive queue is selected by\r
+ the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.\r
+\r
+ Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying\r
+ critical elements within the data structures must be done at this TPL. TPL is then\r
+ restored to the previous level. Note that the code verifies that all callbacks are\r
+ entering at TPL_SOCKETS for proper data structure synchronization.\r
+\r
+ \section PortCloseStateMachine Port Close State Machine\r
+\r
+ The port close state machine walks the port through the necessary\r
+ states to stop activity on the port and get it into a state where\r
+ the resources may be released. The state machine consists of the\r
+ following arcs and states:\r
+\r
+ <code><pre>\r
+\r
+ +--------------------------+\r
+ | Open |\r
+ +--------------------------+\r
+ |\r
+ | ::EslSocketPortCloseStart\r
+ V\r
+ +--------------------------+\r
+ | PORT_STATE_CLOSE_STARTED |\r
+ +--------------------------+\r
+ |\r
+ | ::EslSocketPortCloseTxDone\r
+ V\r
+ +--------------------------+\r
+ | PORT_STATE_CLOSE_TX_DONE |\r
+ +--------------------------+\r
+ |\r
+ | ::EslSocketPortCloseComplete\r
+ V\r
+ +--------------------------+\r
+ | PORT_STATE_CLOSE_DONE |\r
+ +--------------------------+\r
+ |\r
+ | ::EslSocketPortCloseRxDone\r
+ V\r
+ +--------------------------+\r
+ | PORT_STATE_CLOSE_RX_DONE |\r
+ +--------------------------+\r
+ |\r
+ | ::EslSocketPortClose\r
+ V\r
+ +--------------------------+\r
+ | Closed |\r
+ +--------------------------+\r
+\r
+ </pre></code>\r
+\r
+ <ul>\r
+ <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and\r
+ initiates the port close operation</li>\r
+ <li>State: PORT_STATE_CLOSE_STARTED</li>\r
+ <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit\r
+ operations to complete. After all of the transmits are complete,\r
+ this routine initiates the network specific close operation by calling\r
+ through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is\r
+ ::EslTcp4PortCloseOp.\r
+ </li>\r
+ <li>State: PORT_STATE_CLOSE_TX_DONE</li>\r
+ <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is\r
+ complete. After the transition to PORT_STATE_CLOSE_DONE,\r
+ this routine calls ::EslSocketRxCancel to abort the pending receive operations.\r
+ </li>\r
+ <li>State: PORT_STATE_CLOSE_DONE</li>\r
+ <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive\r
+ operation have been cancelled. After the transition to\r
+ PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.\r
+ </li>\r
+ <li>State: PORT_STATE_CLOSE_RX_DONE</li>\r
+ <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers\r
+ using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.\r
+ This routine then releases the port resources allocated by ::EslSocketPortAllocate\r
+ and calls the network specific port close routine (e.g. ::EslTcp4PortClose)\r
+ via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.\r
+ </li>\r
+ </ul>\r
+\r
+\r
+ \section ReceiveEngine Receive Engine\r
+\r
+ The receive path accepts data from the network and queues (buffers) it for the\r
+ application. Flow control is applied once a maximum amount of buffering is reached\r
+ and is released when the buffer usage drops below that limit. Eventually the\r
+ application requests data from the socket which removes entries from the queue and\r
+ returns the data.\r
+\r
+ The receive engine is the state machine which reads data from the network and\r
+ fills the queue with received packets. The receive engine uses two data structures\r
+ to manage the network receive opeations and the buffers.\r
+\r
+ At a high level, the ::ESL_IO_MGMT structures are managing the tokens and\r
+ events for the interface to the UEFI network stack. The ::ESL_PACKET\r
+ structures are managing the receive data buffers. The receive engine\r
+ connects these two structures in the network specific receive completion\r
+ routines.\r
+\r
+<code><pre>\r
+\r
+ +------------------+\r
+ | ::ESL_PORT |\r
+ | |\r
+ +------------------+\r
+ | ::ESL_IO_MGMT |\r
+ +------------------+\r
+ | ESL_IO_MGMT |\r
+ +------------------+\r
+ . .\r
+ . ESL_IO_MGMT .\r
+ . .\r
+ +------------------+\r
+\r
+</pre></code>\r
+\r
+ The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in\r
+ ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on\r
+ the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains\r
+ the network layer specific receive completion token and event. The receive engine\r
+ is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these\r
+ structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.\r
+\r
+<code><pre>\r
+\r
+ pPort->pRxActive\r
+ |\r
+ V\r
+ +-------------+ +-------------+ +-------------+\r
+ Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ +-------------+ +-------------+ +-------------+\r
+\r
+ +-------------+ +-------------+ +-------------+\r
+ Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ +-------------+ +-------------+ +-------------+\r
+ ^\r
+ |\r
+ pPort->pRxFree\r
+</pre></code>\r
+\r
+ The receive engine is started by calling ::EslSocketRxStart. Flow control pauses\r
+ the receive engine by stopping the calls to EslSocketRxStart when the amount of\r
+ receive data waiting for the application meets or exceeds MAX_RX_DATA. After\r
+ the application reads enough data that the amount of buffering drops below this\r
+ limit, the calls to EslSockeRxStart continue which releases the flow control.\r
+\r
+ Receive flow control is applied when the port is created, since no receive\r
+ operation are pending to the low layer network driver. The flow control gets\r
+ released when the low layer network port is configured or the first receive\r
+ operation is posted. Flow control remains in the released state until the\r
+ maximum buffer space is consumed. During this time, ::EslSocketRxComplete\r
+ calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete\r
+ by skipping the call to EslSocketRxStart. Flow control is eventually\r
+ released in ::EslSocketReceive when the buffer space drops below the\r
+ maximum amount causing EslSocketReceive to call EslSocketRxStart.\r
+\r
+<code><pre>\r
+\r
+ +------------+ +------------+\r
+ High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)\r
+ Priority | +------------+ +------------+\r
+ |\r
+ | pRxOobPacketListHead\r
+ +------------+\r
+ | ::ESL_SOCKET |\r
+ +------------+\r
+ | pRxPacketListHead\r
+ Low |\r
+ Priority | +------------+ +------------+ +------------+\r
+ `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
+ +------------+ +------------+ +------------+\r
+\r
+</pre></code>\r
+\r
+ ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure\r
+ and then calls the network layer to start the receive operation. Upon\r
+ receive completion, ::EslSocketRxComplete breaks the connection between these\r
+ structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to\r
+ make token and event available for another receive operation. EslSocketRxComplete\r
+ then queues the ESL_PACKET structure (data packet) to either the\r
+ ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on\r
+ whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts\r
+ to start another receive operation.\r
+\r
+<code><pre>\r
+\r
+ Setup for IP4 and UDP4\r
+\r
+ +--------------------+\r
+ | ESL_IO_MGMT |\r
+ | |\r
+ | +---------------+\r
+ | | Token |\r
+ | | RxData --> NULL\r
+ +----+---------------+\r
+ |\r
+ V\r
+ +--------------------+\r
+ | ESL_PACKET |\r
+ | |\r
+ | +---------------+\r
+ | | pRxData --> NULL\r
+ +----+---------------+\r
+\r
+ Completion for IP4 and UDP4\r
+\r
+ +--------------------+ +----------------------+\r
+ | ESL_IO_MGMT | | Data Buffer |\r
+ | | | (Driver owned) |\r
+ | +---------------+ +----------------------+\r
+ | | Token | ^\r
+ | | Rx Event | |\r
+ | | | +----------------------+\r
+ | | RxData --> | EFI_IP4_RECEIVE_DATA |\r
+ +----+---------------+ | (Driver owned) |\r
+ | +----------------------+\r
+ V ^\r
+ +--------------------+ .\r
+ | ESL_PACKET | .\r
+ | | .\r
+ | +---------------+ .\r
+ | | pRxData --> NULL .......\r
+ +----+---------------+\r
+\r
+\r
+ Setup and completion for TCP4\r
+\r
+ +--------------------+ +--------------------------+\r
+ | ESL_IO_MGMT |-->| ESL_PACKET |\r
+ | | | |\r
+ | +---------------+ +----------------------+ |\r
+ | | Token | | EFI_IP4_RECEIVE_DATA | |\r
+ | | RxData --> | | |\r
+ | | | +----------------------+---+\r
+ | | Event | | Data Buffer |\r
+ +----+---------------+ | |\r
+ | |\r
+ +--------------------------+\r
+\r
+</pre></code>\r
+\r
+ To minimize the number of buffer copies, the data is not copied until the\r
+ application makes a receive call. At this point socket performs a single copy\r
+ in the receive path to move the data from the buffer filled by the network layer\r
+ into the application's buffer.\r
+\r
+ The IP4 and UDP4 drivers go one step further to reduce buffer copies. They\r
+ allow the socket layer to hold on to the actual receive buffer until the\r
+ application has performed a receive operation or closes the socket. Both\r
+ of theses operations return the buffer to the lower layer network driver\r
+ by calling ESL_PROTOCOL_API::pfnPacketFree.\r
+\r
+ When a socket application wants to receive data it indirectly calls\r
+ ::EslSocketReceive to remove data from one of the receive data queues. This routine\r
+ removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or\r
+ ESL_SOCKET::pRxPacketListHead and copies the data from the packet\r
+ into the application's buffer. For SOCK_STREAM sockets, if the packet\r
+ contains more data then the ESL_PACKET structures remains at the head of the\r
+ receive queue for the next application receive\r
+ operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET\r
+ structure is removed from the head of the receive queue and any remaining data is\r
+ discarded as the packet is placed on the free queue.\r
+\r
+ During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to\r
+ cancel any pending receive operations. EslSocketRxCancel calls the network specific\r
+ cancel routine using ESL_PORT::pfnRxCancel.\r
+\r
+\r
+ \section TransmitEngine Transmit Engine\r
+\r
+ Application calls to ::EslSocketTransmit cause data to be copied into a buffer.\r
+ The buffer exists as an extension to an ESL_PACKET structure and the structure\r
+ is placed at the end of the transmit queue.\r
+\r
+<code><pre>\r
+\r
+ *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead\r
+ |\r
+ V\r
+ +------------+ +------------+ +------------+\r
+ Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
+ +------------+ +------------+ +------------+\r
+ ^\r
+ |\r
+ *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail\r
+\r
+</pre></code>\r
+\r
+ There are actually two transmit queues the normal or low priority queue which is\r
+ the default and the urgent or high priority queue which is addressed by specifying\r
+ the MSG_OOB flag during the transmit request. Associated with each queue is a\r
+ transmit engine which is responsible for sending the data in that queue.\r
+\r
+ The transmit engine is the state machine which removes entries from the head\r
+ of the transmit queue and causes the data to be sent over the network.\r
+\r
+<code><pre>\r
+\r
+ +--------------------+ +--------------------+\r
+ | ESL_IO_MGMT | | ESL_PACKET |\r
+ | | | |\r
+ | +---------------+ +----------------+ |\r
+ | | Token | | Buffer Length | |\r
+ | | TxData --> | Buffer Address | |\r
+ | | | +----------------+---+\r
+ | | Event | | Data Buffer |\r
+ +----+---------------+ | |\r
+ +--------------------+\r
+</pre></code>\r
+\r
+ At a high level, the transmit engine uses a couple of data structures\r
+ to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and\r
+ events for the interface to the UEFI network stack. The ::ESL_PACKET\r
+ structures manage the data buffers that get sent. The transmit\r
+ engine connects these two structures prior to transmission and disconnects\r
+ them upon completion.\r
+\r
+<code><pre>\r
+\r
+ pPort->pTxActive or pTxOobActive\r
+ |\r
+ V\r
+ +-------------+ +-------------+ +-------------+\r
+ Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ +-------------+ +-------------+ +-------------+\r
+\r
+ +-------------+ +-------------+ +-------------+\r
+ Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ +-------------+ +-------------+ +-------------+\r
+ ^\r
+ |\r
+ pPort->pTxFree or pTxOobFree\r
+\r
+</pre></code>\r
+\r
+ The transmit engine manages multiple transmit operations using the\r
+ active and free lists shown above. ::EslSocketPortAllocate allocates the\r
+ ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.\r
+ This routine places the ESL_IO_MGMT structures on the free list by calling\r
+ ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures\r
+ will move from the free list to the active list and back again. The\r
+ active list contains the packets that are actively being processed by\r
+ the UEFI network stack. Eventually the ESL_IO_MGMT structures will be\r
+ removed from the free list and be deallocated by the EslSocketPortClose\r
+ routine.\r
+\r
+ The network specific code calls the ::EslSocketTxStart routine\r
+ to hand a packet to the network stack. EslSocketTxStart connects\r
+ the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure\r
+ and then queues the result to one of the active lists:\r
+ ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then\r
+ hands the packet to the network stack.\r
+\r
+ Upon completion, the network specific TxComplete routine calls\r
+ ::EslSocketTxComplete to disconnect the transmit packet from the\r
+ ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling\r
+ ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure\r
+ into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.\r
+ EslSocketTxComplete then starts the next transmit operation while\r
+ the socket is active or calls the ::EslSocketPortCloseTxDone routine\r
+ when the socket is shutting down.\r
+\r
**/\r
\r
#include "Socket.h"\r
\r
\r
-/**\r
- Socket driver connection points\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
+CONST ESL_SOCKET_BINDING cEslSocketBinding[] = {\r
+ { L"Ip4",\r
+ &gEfiIp4ServiceBindingProtocolGuid,\r
+ &gEfiIp4ProtocolGuid,\r
+ &mEslIp4ServiceGuid,\r
+ OFFSET_OF ( ESL_LAYER, pIp4List ),\r
+ 4, // RX buffers\r
+ 4, // TX buffers\r
+ 0 }, // TX Oob buffers\r
{ L"Tcp4",\r
&gEfiTcp4ServiceBindingProtocolGuid,\r
+ &gEfiTcp4ProtocolGuid,\r
&mEslTcp4ServiceGuid,\r
- EslTcpInitialize4,\r
- EslTcpShutdown4 },\r
+ OFFSET_OF ( ESL_LAYER, pTcp4List ),\r
+ 4, // RX buffers\r
+ 4, // TX buffers\r
+ 4 }, // TX Oob buffers\r
+ { L"Tcp6",\r
+ &gEfiTcp6ServiceBindingProtocolGuid,\r
+ &gEfiTcp6ProtocolGuid,\r
+ &mEslTcp6ServiceGuid,\r
+ OFFSET_OF ( ESL_LAYER, pTcp6List ),\r
+ 4, // RX buffers\r
+ 4, // TX buffers\r
+ 4 }, // TX Oob buffers\r
{ L"Udp4",\r
&gEfiUdp4ServiceBindingProtocolGuid,\r
+ &gEfiUdp4ProtocolGuid,\r
&mEslUdp4ServiceGuid,\r
- EslUdpInitialize4,\r
- EslUdpShutdown4 }\r
+ OFFSET_OF ( ESL_LAYER, pUdp4List ),\r
+ 4, // RX buffers\r
+ 4, // TX buffers\r
+ 0 }, // TX Oob buffers\r
+ { L"Udp6",\r
+ &gEfiUdp6ServiceBindingProtocolGuid,\r
+ &gEfiUdp6ProtocolGuid,\r
+ &mEslUdp6ServiceGuid,\r
+ OFFSET_OF ( ESL_LAYER, pUdp6List ),\r
+ 4, // RX buffers\r
+ 4, // TX buffers\r
+ 0 } // TX Oob buffers\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
+/// APIs to support the various socket types for the v4 network stack.\r
+CONST ESL_PROTOCOL_API * cEslAfInetApi[] = {\r
+ NULL, // 0\r
+ &cEslTcp4Api, // SOCK_STREAM\r
+ &cEslUdp4Api, // SOCK_DGRAM\r
+ &cEslIp4Api, // SOCK_RAW\r
+ NULL, // SOCK_RDM\r
+ &cEslTcp4Api // SOCK_SEQPACKET\r
+};\r
+\r
+/// Number of entries in the v4 API array ::cEslAfInetApi.\r
+CONST int cEslAfInetApiSize = DIM ( cEslAfInetApi );\r
+\r
+\r
+/// APIs to support the various socket types for the v6 network stack.\r
+CONST ESL_PROTOCOL_API * cEslAfInet6Api[] = {\r
+ NULL, // 0\r
+ &cEslTcp6Api, // SOCK_STREAM\r
+ &cEslUdp6Api, // SOCK_DGRAM\r
+ NULL, // SOCK_RAW\r
+ NULL, // SOCK_RDM\r
+ &cEslTcp6Api // SOCK_SEQPACKET\r
+};\r
+\r
+/// Number of entries in the v6 API array ::cEslAfInet6Api.\r
+CONST int cEslAfInet6ApiSize = DIM ( cEslAfInet6Api );\r
+\r
+\r
+/// Global management structure for the socket layer.\r
+ESL_LAYER mEslLayer;\r
+\r
+\r
+/** Initialize an endpoint for network communication.\r
+\r
+ This routine initializes the communication endpoint.\r
+\r
+ The ::socket routine calls this routine indirectly to create\r
+ the communication endpoint.\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. See the ::socket documentation for values.\r
+ @param[in] type Specifies how to make the network connection.\r
+ See the ::socket documentation for values.\r
+ @param[in] protocol Specifies the lower layer protocol to use.\r
+ See the ::socket documentation for values.\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 int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ CONST ESL_PROTOCOL_API * pApi;\r
+ CONST ESL_PROTOCOL_API ** ppApiArray;\r
+ CONST ESL_PROTOCOL_API ** ppApiArrayEnd;\r
+ int ApiArraySize;\r
+ ESL_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
+ && ( AF_INET6 != domain )\r
+ && ( AF_LOCAL != domain )) {\r
DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
- "ERROR - Invalid domain value" ));\r
+ "ERROR - Invalid domain value\r\n" ));\r
Status = EFI_INVALID_PARAMETER;\r
errno = EAFNOSUPPORT;\r
break;\r
}\r
\r
- //\r
+ // Determine the protocol APIs\r
+ ppApiArray = NULL;\r
+ ApiArraySize = 0;\r
+ if (( AF_INET == domain )\r
+ || ( AF_LOCAL == domain )) {\r
+ ppApiArray = &cEslAfInetApi[0];\r
+ ApiArraySize = cEslAfInetApiSize;\r
+ }\r
+ else {\r
+ ppApiArray = &cEslAfInet6Api[0];\r
+ ApiArraySize = cEslAfInet6ApiSize;\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
+ if (( type >= ApiArraySize )\r
+ || ( NULL == ppApiArray )\r
+ || ( NULL == ppApiArray[ type ])) {\r
DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
- "ERROR - Invalid type value" ));\r
+ "ERROR - Invalid type value\r\n" ));\r
+ // The socket type is not supported\r
Status = EFI_INVALID_PARAMETER;\r
- errno = EINVAL;\r
+ errno = EPROTOTYPE;\r
break;\r
}\r
\r
- //\r
+ // Set the default protocol if necessary\r
+ pApi = ppApiArray[ type ];\r
+ if ( 0 == protocol ) {\r
+ protocol = pApi->DefaultProtocol;\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
+ if (( pApi->DefaultProtocol != protocol )\r
+ && ( SOCK_RAW != type )) {\r
Status = EFI_INVALID_PARAMETER;\r
- errno = EINVAL;\r
+\r
+ // Assume that the driver supports this protocol\r
+ ppApiArray = &cEslAfInetApi[0];\r
+ ppApiArrayEnd = &ppApiArray [ cEslAfInetApiSize ];\r
+ while ( ppApiArrayEnd > ppApiArray ) {\r
+ pApi = *ppApiArray;\r
+ if ( protocol == pApi->DefaultProtocol ) {\r
+ break;\r
+ }\r
+ ppApiArray += 1;\r
+ }\r
+ if ( ppApiArrayEnd <= ppApiArray ) {\r
+ // Verify against the IPv6 table\r
+ ppApiArray = &cEslAfInet6Api[0];\r
+ ppApiArrayEnd = &ppApiArray [ cEslAfInet6ApiSize ];\r
+ while ( ppApiArrayEnd > ppApiArray ) {\r
+ pApi = *ppApiArray;\r
+ if ( protocol == pApi->DefaultProtocol ) {\r
+ break;\r
+ }\r
+ ppApiArray += 1;\r
+ }\r
+ }\r
+ if ( ppApiArrayEnd <= ppApiArray ) {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
+ "ERROR - The protocol is not supported!\r\n" ));\r
+ errno = EPROTONOSUPPORT;\r
+ break;\r
+ }\r
+\r
+ // The driver does not support this protocol\r
+ DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
+ "ERROR - The protocol does not support this socket type!\r\n" ));\r
+ errno = EPROTONOSUPPORT;\r
+ errno = EPROTOTYPE;\r
break;\r
}\r
-\r
- //\r
// Save the socket attributes\r
- //\r
+ pSocket->pApi = pApi;\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
}\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
+/** Accept a network connection.\r
\r
- @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ This routine calls the network specific layer to remove the next\r
+ connection from the FIFO.\r
\r
- @param [in] pSockAddr Address of a buffer to receive the remote\r
- network address.\r
+ The ::accept calls this routine to poll for a network\r
+ connection to the socket. When a connection is available\r
+ this routine returns the ::EFI_SOCKET_PROTOCOL structure address\r
+ associated with the new socket and the remote network address\r
+ if requested.\r
\r
- @param [in, out] pSockAddrLength Length in bytes of the address buffer.\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[in] pSockAddr Address of a buffer to receive the remote\r
+ network address.\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
+ @param[out] ppSocketProtocol Address of a buffer to receive the\r
+ ::EFI_SOCKET_PROTOCOL instance\r
+ associated with the new socket.\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 int * pErrno\r
)\r
{\r
- DT_SOCKET * pNewSocket;\r
- DT_SOCKET * pSocket;\r
+ ESL_SOCKET * pNewSocket;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
\r
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
\r
//\r
- // Validate the sockaddr\r
+ // Verify the API\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
+ if ( NULL == pSocket->pApi->pfnAccept ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\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
+ // Validate the sockaddr\r
//\r
- if ( SOCKET_STATE_LISTENING != pSocket->State ) {\r
+ if (( NULL != pSockAddr )\r
+ && ( NULL == pSockAddrLength )) {\r
DEBUG (( DEBUG_ACCEPT,\r
- "ERROR - Socket is not listening!\r\n" ));\r
- Status = EFI_NOT_STARTED;\r
- pSocket->errno = EOPNOTSUPP;\r
+ "ERROR - pSockAddr is NULL!\r\n" ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
}\r
else {\r
//\r
- // Determine if a socket is available\r
+ // Synchronize with the socket layer\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
+ 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
+ if ( NULL == pSocket->pApi->pfnAccept ) {\r
//\r
- // Update the socket state\r
+ // Socket does not support listen\r
//\r
- pSocket->State = SOCKET_STATE_NO_PORTS;\r
+ pSocket->errno = EOPNOTSUPP;\r
+ Status = EFI_UNSUPPORTED;\r
}\r
else {\r
//\r
- // Ports are available\r
- // No connection requests at this time\r
+ // Socket supports listen, but not in listen state\r
//\r
- Status = EFI_NOT_READY;\r
- pSocket->errno = EAGAIN;\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_NOT_STARTED;\r
}\r
}\r
else {\r
- \r
//\r
- // Get the remote network address\r
+ // Determine if a socket is available\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
+ if ( 0 == pSocket->FifoDepth ) {\r
//\r
- // Determine the connection point within the network stack\r
+ // No connections available\r
+ // Determine if any ports are available\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
+ 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
- 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
+ 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
- // Account for this socket\r
+ // Attempt to accept the connection and\r
+ // get the remote network address\r
//\r
- pSocket->FifoDepth -= 1;\r
+ pNewSocket = pSocket->pFifoHead;\r
+ ASSERT ( NULL != pNewSocket );\r
+ Status = pSocket->pApi->pfnAccept ( pNewSocket,\r
+ pSockAddr,\r
+ pSockAddrLength );\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
- // 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
+ // 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
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
}\r
}\r
\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\r
Status = EFI_INVALID_PARAMETER;\r
- *pErrno = EBADF;\r
+ *pErrno = ENOTSOCK;\r
}\r
}\r
DBG_EXIT_STATUS ( Status );\r
}\r
\r
\r
-/**\r
- Allocate and initialize a DT_SOCKET structure.\r
- \r
- The ::SocketAllocate() function allocates a DT_SOCKET structure\r
+/** Allocate and initialize a ESL_SOCKET structure.\r
+\r
+ This support function allocates an ::ESL_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
+ @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
+ 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
+ @param[in] DebugFlags Flags for debug messages\r
+ @param[in,out] ppSocket The buffer to receive an ::ESL_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
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available 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
+ IN OUT ESL_SOCKET ** ppSocket\r
)\r
{\r
UINTN LengthInBytes;\r
- DT_LAYER * pLayer;\r
- DT_SOCKET * pSocket;\r
+ ESL_LAYER * pLayer;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\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
+ pSocket = (ESL_SOCKET *) AllocateZeroPool ( LengthInBytes );\r
+ if ( NULL != pSocket ) {\r
DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
"0x%08x: Allocate pSocket, %d bytes\r\n",\r
pSocket,\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.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
+ pSocket->SocketProtocol.pfnTransmit = EslSocketTransmit;\r
\r
pSocket->MaxRxBuf = MAX_RX_DATA;\r
pSocket->MaxTxBuf = MAX_TX_DATA;\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
+ Status = EFI_OUT_OF_RESOURCES;\r
}\r
\r
//\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
+/** Bind a name to a socket.\r
\r
- @param [in] pSocketProtocol Address of the socket protocol structure.\r
+ This routine calls the network specific layer to save the network\r
+ address of the local connection point.\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
+ The ::bind routine calls this routine to connect a name\r
+ (network address and port) to a socket on the local machine.\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
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL 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
+ @param[in] SockAddrLength Specifies the length in bytes of the sockaddr structure.\r
+ @param[out] pErrno Address to receive the errno value upon completion.\r
\r
@retval EFI_SUCCESS - Socket successfully created\r
-\r
- **/\r
+**/\r
EFI_STATUS\r
EslSocketBind (\r
IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN const struct sockaddr * pSockAddr,\r
+ IN CONST struct sockaddr * pSockAddr,\r
IN socklen_t SockAddrLength,\r
OUT int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ EFI_HANDLE ChildHandle;\r
+ UINT8 * pBuffer;\r
+ ESL_PORT * pPort;\r
+ ESL_SERVICE ** ppServiceListHead;\r
+ ESL_SOCKET * pSocket;\r
+ ESL_SERVICE * pService;\r
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
\r
//\r
// Validate the structure pointer\r
//\r
+ pSocket->errno = 0;\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
+ //\r
+ // Validate the local address length\r
+ //\r
+ else if ( SockAddrLength < pSocket->pApi->MinimumAddressLength ) {\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Invalid bind name length: %d\r\n",\r
+ SockAddrLength ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EINVAL;\r
+ }\r
+\r
+ //\r
+ // Validate the shutdown state\r
+ //\r
+ else if ( pSocket->bRxDisable || pSocket->bTxDisable ) {\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - Shutdown has been called on socket 0x%08x\r\n",\r
+ pSocket ));\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ else if ( SOCKET_STATE_NOT_CONFIGURED != pSocket->State ) {\r
+ DEBUG (( DEBUG_BIND,\r
+ "ERROR - The socket 0x%08x is already configured!\r\n",\r
+ pSocket ));\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_ALREADY_STARTED;\r
+ }\r
+ else {\r
//\r
- // Validate the name length\r
+ // Synchronize with the socket layer\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
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+ //\r
+ // Assume no ports are available\r
+ //\r
+ pSocket->errno = EADDRNOTAVAIL;\r
+ Status = EFI_INVALID_PARAMETER;\r
\r
+ //\r
+ // Walk the list of services\r
+ //\r
+ pBuffer = (UINT8 *)&mEslLayer;\r
+ pBuffer = &pBuffer[ pSocket->pApi->ServiceListOffset ];\r
+ ppServiceListHead = (ESL_SERVICE **)pBuffer;\r
+ pService = *ppServiceListHead;\r
+ while ( NULL != pService ) {\r
//\r
- // Validate the local address\r
+ // Create the port\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
+ pServiceBinding = pService->pServiceBinding;\r
+ ChildHandle = NULL;\r
+ Status = pServiceBinding->CreateChild ( pServiceBinding,\r
+ &ChildHandle );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
+ "0x%08x: %s port handle created\r\n",\r
+ ChildHandle,\r
+ pService->pSocketBinding->pName ));\r
\r
- case AF_INET:\r
//\r
- // Determine the connection point within the network stack\r
+ // Open the port\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
+ Status = EslSocketPortAllocate ( pSocket,\r
+ pService,\r
+ ChildHandle,\r
+ pSockAddr,\r
+ TRUE,\r
+ DEBUG_BIND,\r
+ &pPort );\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
+ "ERROR - Failed to open %s port handle, Status: %r\r\n",\r
+ pService->pSocketBinding->pName,\r
+ Status ));\r
}\r
\r
//\r
- // Mark this socket as bound if successful\r
+ // Set the next service\r
//\r
- if ( !EFI_ERROR ( Status )) {\r
- pSocket->State = SOCKET_STATE_BOUND;\r
+ pService = pService->pNext;\r
+ }\r
+\r
+ //\r
+ // Verify that at least one network connection was found\r
+ //\r
+ if ( NULL != pSocket->pPortList ) {\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ else {\r
+ if ( EADDRNOTAVAIL == pSocket->errno ) {\r
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
+ "ERROR - Socket address is not available!\r\n" ));\r
+ }\r
+ if ( EADDRINUSE == pSocket->errno ) {\r
+ DEBUG (( DEBUG_BIND | DEBUG_POOL | DEBUG_INIT,\r
+ "ERROR - Socket address is in use!\r\n" ));\r
}\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
+ //\r
+ // Mark this socket as bound if successful\r
+ //\r
+ if ( !EFI_ERROR ( Status )) {\r
+ pSocket->State = SOCKET_STATE_BOUND;\r
+ pSocket->errno = 0;\r
}\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
}\r
}\r
\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\r
Status = EFI_INVALID_PARAMETER;\r
- *pErrno = EBADF;\r
+ *pErrno = ENOTSOCK;\r
}\r
}\r
DBG_EXIT_STATUS ( Status );\r
}\r
\r
\r
-/**\r
- Determine if the socket is closed\r
-\r
- Reverses the operations of the ::SocketAllocate() routine.\r
+/** Test the bind configuration.\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
+ @param[in] pPort Address of the ::ESL_PORT structure.\r
+ @param[in] ErrnoValue errno value if test fails\r
\r
+ @retval EFI_SUCCESS The connection was successfully established.\r
+ @retval Others The connection attempt failed.\r
**/\r
EFI_STATUS\r
-EslSocketClosePoll (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN int * pErrno\r
+EslSocketBindTest (\r
+ IN ESL_PORT * pPort,\r
+ IN int ErrnoValue\r
)\r
{\r
- int errno;\r
- DT_LAYER * pLayer;\r
- DT_SOCKET * pNextSocket;\r
- DT_SOCKET * pSocket;\r
+ UINT8 * pBuffer;\r
+ VOID * pConfigData;\r
EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Assume success\r
+ // Locate the configuration data\r
//\r
- errno = 0;\r
- Status = EFI_SUCCESS;\r
+ pBuffer = (UINT8 *)pPort;\r
+ pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];\r
+ pConfigData = (VOID *)pBuffer;\r
\r
//\r
- // Synchronize with the socket layer\r
+ // Validate that the port is connected\r
//\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
+ Status = pPort->pSocket->pApi->pfnVerifyLocalIpAddress ( pPort, pBuffer );\r
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_WARN | DEBUG_BIND,\r
+ "WARNING - Port 0x%08x invalid IP address: %r\r\n",\r
+ pPort,\r
+ Status ));\r
+ pPort->pSocket->errno = ErrnoValue;\r
+ }\r
+ else {\r
+ //\r
+ // Attempt to use this configuration\r
+ //\r
+ Status = pPort->pfnConfigure ( pPort->pProtocol.v, pConfigData );\r
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_WARN | DEBUG_BIND,\r
+ "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",\r
+ pPort,\r
+ Status ));\r
+ pPort->pSocket->errno = ErrnoValue;\r
+ }\r
+ else {\r
+ //\r
+ // Reset the port\r
+ //\r
+ Status = pPort->pfnConfigure ( pPort->pProtocol.v, NULL );\r
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND,\r
+ "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",\r
+ pPort,\r
+ Status ));\r
+ ASSERT ( EFI_SUCCESS == Status );\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/** Determine if the socket is closed.\r
+\r
+ This routine checks the state of the socket to determine if\r
+ the network specific layer has completed the close operation.\r
+\r
+ The ::close routine polls this routine to determine when the\r
+ close operation is complete. The close operation needs to\r
+ reverse the operations of the ::EslSocketAllocate routine.\r
+\r
+ @param[in] pSocketProtocol Address of an ::EFI_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
+EFI_STATUS\r
+EslSocketClosePoll (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int * pErrno\r
+ )\r
+{\r
+ int errno;\r
+ ESL_LAYER * pLayer;\r
+ ESL_SOCKET * pNextSocket;\r
+ ESL_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
}\r
\r
\r
-/**\r
- Start the close operation on the socket\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
+ This routine calls the network specific layer to initiate the\r
+ close state machine. This routine then calls the network\r
+ specific layer to determine if the close state machine has gone\r
+ to completion. The result from this poll is returned to the\r
+ caller.\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
+ The ::close routine calls this routine to start the close\r
+ operation which reverses the operations of the\r
+ ::EslSocketAllocate routine. The close routine then polls\r
+ the ::EslSocketClosePoll routine to determine when the\r
+ socket is closed.\r
+\r
+ @param[in] pSocketProtocol Address of an ::EFI_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
)\r
{\r
int errno;\r
- DT_PORT * pNextPort;\r
- DT_PORT * pPort;\r
- DT_SOCKET * pSocket;\r
+ ESL_PORT * pNextPort;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\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
+ Status = EslSocketPortCloseStart ( pPort,\r
+ bCloseNow,\r
+ DEBUG_CLOSE | DEBUG_LISTEN | DEBUG_CONNECTION );\r
if (( EFI_SUCCESS != Status )\r
&& ( EFI_NOT_READY != Status )) {\r
errno = EIO;\r
}\r
}\r
else {\r
- Status = EFI_ALREADY_STARTED;\r
- errno = EALREADY;\r
+ Status = EFI_NOT_READY;\r
+ errno = EAGAIN;\r
}\r
\r
//\r
}\r
\r
\r
-/**\r
- Connect to a remote system via the network.\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
+ This routine calls the network specific layer to establish\r
+ the remote system address and establish the connection to\r
+ the remote system.\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
+ The ::connect routine calls this routine to establish a\r
+ connection with the specified remote system. This routine\r
+ is designed to be polled by the connect routine for completion\r
+ of the network connection.\r
\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[in] pSockAddr Network address of the remote system.\r
+ @param[in] SockAddrLength Length in bytes of the network address.\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
EFI_STATUS\r
EslSocketConnect (\r
IN int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ struct sockaddr_in6 LocalAddress;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
- \r
+\r
DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));\r
\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
+ if ( SockAddrLength < ( 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
+ "ERROR - Invalid bind name length: %d\r\n",\r
+ SockAddrLength ));\r
Status = EFI_INVALID_PARAMETER;\r
pSocket->errno = EINVAL;\r
}\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
case SOCKET_STATE_NOT_CONFIGURED:\r
case SOCKET_STATE_BOUND:\r
//\r
- // Validate the local address\r
+ // Validate the address length\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
+ if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {\r
//\r
- // Determine the connection point within the network stack\r
+ // Verify the API\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
+ if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {\r
//\r
- // Start the connection processing\r
+ // Already connected\r
//\r
- Status = EslTcpConnectStart4 ( pSocket,\r
- pSockAddr,\r
- SockAddrLength );\r
-\r
+ pSocket->errno = ENOTSUP;\r
+ Status = EFI_UNSUPPORTED;\r
+ }\r
+ else {\r
//\r
- // Set the next state if connecting\r
+ // Determine if BIND was already called\r
//\r
- if ( EFI_NOT_READY == Status ) {\r
- pSocket->State = SOCKET_STATE_CONNECTING;\r
+ if ( NULL == pSocket->pPortList ) {\r
+ //\r
+ // Allow any local port\r
+ //\r
+ ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
+ LocalAddress.sin6_len = (uint8_t)pSocket->pApi->MinimumAddressLength;\r
+ LocalAddress.sin6_family = pSocket->pApi->AddressFamily;\r
+ Status = EslSocketBind ( &pSocket->SocketProtocol,\r
+ (struct sockaddr *)&LocalAddress,\r
+ LocalAddress.sin6_len,\r
+ &pSocket->errno );\r
}\r
- break;\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
+ Status = pSocket->pApi->pfnRemoteAddrSet ( pPort,\r
+ pSockAddr,\r
+ SockAddrLength );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
\r
- case SOCK_DGRAM:\r
- Status = EslUdpConnect4 ( pSocket,\r
- pSockAddr,\r
- SockAddrLength );\r
- break;\r
+ //\r
+ // Set the next port\r
+ //\r
+ pPort = pPort->pLinkSocket;\r
+ }\r
+\r
+ //\r
+ // Verify the API\r
+ //\r
+ if (( !EFI_ERROR ( Status ))\r
+ && ( NULL != pSocket->pApi->pfnConnectStart )) {\r
+ //\r
+ // Initiate the connection with the remote system\r
+ //\r
+ Status = pSocket->pApi->pfnConnectStart ( pSocket );\r
+\r
+ //\r
+ // Set the next state if connecting\r
+ //\r
+ if ( EFI_NOT_READY == Status ) {\r
+ pSocket->State = SOCKET_STATE_CONNECTING;\r
+ }\r
+ }\r
+ }\r
}\r
- break;\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_CONNECT,\r
+ "ERROR - Invalid address length: %d\r\n",\r
+ SockAddrLength ));\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EINVAL;\r
}\r
break;\r
\r
case SOCKET_STATE_CONNECTING:\r
//\r
- // Validate the local address\r
+ // Poll the network adapter\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
+ EslSocketRxPoll ( pSocket );\r
\r
- case AF_INET:\r
+ //\r
+ // Poll for connection completion\r
+ //\r
+ if ( NULL == pSocket->pApi->pfnConnectPoll ) {\r
//\r
- // Determine the connection point within the network stack\r
+ // Already connected\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
+ pSocket->errno = EISCONN;\r
+ Status = EFI_ALREADY_STARTED;\r
+ }\r
+ else {\r
+ Status = pSocket->pApi->pfnConnectPoll ( 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
+ // Set the next state if connected\r
+ //\r
+ if ( EFI_NOT_READY != Status ) {\r
+ if ( EFI_ERROR ( Status )) {\r
+ pSocket->State = SOCKET_STATE_BOUND;\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
+ // Connected\r
//\r
- pSocket->errno = EISCONN;\r
- Status = EFI_ALREADY_STARTED;\r
+ Status = EFI_SUCCESS;\r
break;\r
}\r
\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\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
+ *pErrno = ENOTSOCK;\r
}\r
}\r
\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
+/** Copy a fragmented buffer into a destination buffer.\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
+ This support routine copies a fragmented buffer to the caller specified buffer.\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
+ This routine is called by ::EslIp4Receive and ::EslUdp4Receive.\r
+\r
+ @param[in] FragmentCount Number of fragments in the table\r
+ @param[in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure\r
+ @param[in] BufferLength Length of the the buffer\r
+ @param[in] pBuffer Address of a buffer to receive the data.\r
+ @param[in] pDataLength Number of received data bytes in the buffer.\r
\r
+ @return Returns the address of the next free byte in the buffer.\r
**/\r
-EFI_STATUS\r
-EFIAPI\r
-EslSocketCreateChild (\r
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,\r
- IN OUT EFI_HANDLE * pChildHandle\r
+UINT8 *\r
+EslSocketCopyFragmentedBuffer (\r
+ IN UINT32 FragmentCount,\r
+ IN EFI_IP4_FRAGMENT_DATA * pFragmentTable,\r
+ IN size_t BufferLength,\r
+ IN UINT8 * pBuffer,\r
+ OUT size_t * pDataLength\r
)\r
{\r
- DT_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
+ size_t BytesToCopy;\r
+ UINT32 Fragment;\r
+ UINT8 * pBufferEnd;\r
+ UINT8 * pData;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Create a socket structure\r
+ // Validate the IP and UDP structures are identical\r
//\r
- Status = EslSocketAllocate ( pChildHandle,\r
- DEBUG_SOCKET,\r
- &pSocket );\r
+ ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentLength )\r
+ == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentLength ));\r
+ ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA, FragmentBuffer )\r
+ == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA, FragmentBuffer ));\r
\r
//\r
- // Return the operation status\r
+ // Copy the received data\r
//\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
+ Fragment = 0;\r
+ pBufferEnd = &pBuffer [ BufferLength ];\r
+ while (( pBufferEnd > pBuffer ) && ( FragmentCount > Fragment )) {\r
+ //\r
+ // Determine the amount of received data\r
+ //\r
+ pData = pFragmentTable[Fragment].FragmentBuffer;\r
+ BytesToCopy = pFragmentTable[Fragment].FragmentLength;\r
+ if (((size_t)( pBufferEnd - pBuffer )) < BytesToCopy ) {\r
+ BytesToCopy = pBufferEnd - pBuffer;\r
+ }\r
+\r
+ //\r
+ // Move the data into the buffer\r
+ //\r
+ DEBUG (( DEBUG_RX,\r
+ "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",\r
+ pData,\r
+ pBuffer,\r
+ BytesToCopy ));\r
+ CopyMem ( pBuffer, pData, BytesToCopy );\r
+ pBuffer += BytesToCopy;\r
+ Fragment += 1;\r
+ }\r
+\r
+ //\r
+ // Return the data length and the buffer address\r
+ //\r
+ *pDataLength = BufferLength - ( pBufferEnd - pBuffer );\r
+ DBG_EXIT_HEX ( pBuffer );\r
+ return pBuffer;\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
+/** Free the socket.\r
+\r
+ This routine frees the socket structure and handle resources.\r
\r
- @param [in] pThis Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance.\r
- @param [in] ChildHandle Handle of the child to destroy\r
+ The ::close routine calls EslServiceFreeProtocol which then calls\r
+ this routine to free the socket context structure and close the\r
+ handle.\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
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[out] pErrno Address to receive the errno value upon completion.\r
\r
+ @retval EFI_SUCCESS The socket resources were returned successfully.\r
**/\r
EFI_STATUS\r
-EFIAPI\r
-EslSocketDestroyChild (\r
- IN EFI_SERVICE_BINDING_PROTOCOL * pThis,\r
- IN EFI_HANDLE ChildHandle\r
+EslSocketFree (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN int * pErrno\r
)\r
{\r
- DT_LAYER * pLayer;\r
- DT_SOCKET * pSocket;\r
- DT_SOCKET * pSocketPrevious;\r
- EFI_SOCKET_PROTOCOL * pSocketProtocol;\r
+ EFI_HANDLE ChildHandle;\r
+ int errno;\r
+ ESL_LAYER * pLayer;\r
+ ESL_SOCKET * pSocket;\r
+ ESL_SOCKET * pSocketPrevious;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Locate the socket control structure\r
+ // Assume failure\r
+ //\r
+ errno = EIO;\r
+ pSocket = NULL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+\r
+ //\r
+ // Validate the socket\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
+ if ( NULL != pSocketProtocol ) {\r
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
\r
//\r
//\r
// Remove the socket protocol\r
//\r
+ ChildHandle = pSocket->SocketProtocol.SocketHandle;\r
Status = gBS->UninstallMultipleProtocolInterfaces (\r
ChildHandle,\r
&gEfiSocketProtocolGuid,\r
"0x%08x: Free pSocket, %d bytes\r\n",\r
pSocket,\r
sizeof ( *pSocket )));\r
+ errno = 0;\r
}\r
else {\r
DEBUG (( DEBUG_ERROR | DEBUG_POOL,\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
+ "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));\r
+ }\r
+\r
+ //\r
+ // Return the errno value if possible\r
+ //\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = errno;\r
}\r
\r
//\r
}\r
\r
\r
-/**\r
- Get the local address.\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
+ This routine calls the network specific layer to get the network\r
+ address of the local host connection point.\r
\r
- @param [in,out] pAddressLength Length of the local network address structure\r
+ The ::getsockname routine calls this routine to obtain the network\r
+ address associated with the local host connection point.\r
\r
- @param [out] pErrno Address to receive the errno value upon completion.\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[out] pAddress Network address to receive the local system address\r
+ @param[in,out] pAddressLength Length of the local network address structure\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 int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ socklen_t LengthInBytes;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
- \r
+\r
DBG_ENTER ( );\r
- \r
+\r
//\r
// Assume success\r
//\r
Status = EFI_SUCCESS;\r
- \r
+\r
//\r
// Validate the socket\r
//\r
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
\r
//\r
- // Verify the address buffer and length address\r
+ // Verify the socket state\r
//\r
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
+ EslSocketIsConfigured ( pSocket );\r
+ if ( pSocket->bAddressSet ) {\r
//\r
- // Verify the socket state\r
+ // Verify the address buffer and length address\r
//\r
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
//\r
- // Validate the local address\r
+ // Verify the API\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
+ if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\r
+ }\r
+ else {\r
//\r
- // Determine the connection point within the network stack\r
+ // Synchronize with the socket layer\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
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
\r
- case SOCK_DGRAM:\r
+ //\r
+ // Verify that there is just a single connection\r
+ //\r
+ pPort = pSocket->pPortList;\r
+ if ( NULL != pPort ) {\r
//\r
- // Get the local address\r
+ // Verify the address length\r
//\r
- Status = EslUdpGetLocalAddress4 ( pSocket,\r
- pAddress,\r
- pAddressLength );\r
- break;\r
+ LengthInBytes = pSocket->pApi->AddressLength;\r
+ if (( LengthInBytes <= *pAddressLength )\r
+ && ( 255 >= LengthInBytes )) {\r
+ //\r
+ // Return the local address and address length\r
+ //\r
+ ZeroMem ( pAddress, LengthInBytes );\r
+ pAddress->sa_len = (uint8_t)LengthInBytes;\r
+ *pAddressLength = pAddress->sa_len;\r
+ pSocket->pApi->pfnLocalAddrGet ( pPort, pAddress );\r
+ pSocket->errno = 0;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ else {\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ else {\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\r
}\r
- break;\r
- }\r
\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
}\r
else {\r
- pSocket->errno = ENOTCONN;\r
- Status = EFI_NOT_STARTED;\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
}\r
}\r
else {\r
- pSocket->errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
+ //\r
+ // Address not set\r
+ //\r
+ Status = EFI_NOT_STARTED;\r
+ pSocket->errno = EADDRNOTAVAIL;\r
}\r
}\r
- \r
+\r
//\r
// Return the operation status\r
//\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\r
Status = EFI_INVALID_PARAMETER;\r
- *pErrno = EBADF;\r
+ *pErrno = ENOTSOCK;\r
}\r
}\r
DBG_EXIT_STATUS ( Status );\r
}\r
\r
\r
-/**\r
- Get the peer address.\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
+ This routine calls the network specific layer to get the remote\r
+ system connection point.\r
\r
- @param [in,out] pAddressLength Length of the remote network address structure\r
+ The ::getpeername routine calls this routine to obtain the network\r
+ address of the remote connection point.\r
\r
- @param [out] pErrno Address to receive the errno value upon completion.\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[out] pAddress Network address to receive the remote system address\r
+ @param[in,out] pAddressLength Length of the remote network address structure\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 int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ socklen_t LengthInBytes;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
- \r
+\r
DBG_ENTER ( );\r
- \r
+\r
//\r
// Assume success\r
//\r
Status = EFI_SUCCESS;\r
- \r
+\r
//\r
// Validate the socket\r
//\r
pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
\r
//\r
- // Verify the address buffer and length address\r
+ // Verify the socket state\r
//\r
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
+ Status = EslSocketIsConfigured ( pSocket );\r
+ if ( !EFI_ERROR ( Status )) {\r
//\r
- // Verify the socket state\r
+ // Verify the API\r
//\r
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
+ if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\r
+ }\r
+ else {\r
//\r
- // Synchronize with the socket layer\r
+ // Verify the address buffer and length address\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
+ if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
//\r
- // Determine the connection point within the network stack\r
+ // Verify the socket state\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
+ if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
\r
- case SOCK_STREAM:\r
- case SOCK_SEQPACKET:\r
//\r
- // Verify the port state\r
+ // Verify that there is just a single connection\r
//\r
- Status = EslTcpGetRemoteAddress4 ( pSocket,\r
- pAddress,\r
- pAddressLength );\r
- break;\r
+ pPort = pSocket->pPortList;\r
+ if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
+ //\r
+ // Verify the address length\r
+ //\r
+ LengthInBytes = pSocket->pApi->AddressLength;\r
+ if ( LengthInBytes <= *pAddressLength ) {\r
+ //\r
+ // Return the local address\r
+ //\r
+ ZeroMem ( pAddress, LengthInBytes );\r
+ pAddress->sa_len = (uint8_t)LengthInBytes;\r
+ *pAddressLength = pAddress->sa_len;\r
+ pSocket->pApi->pfnRemoteAddrGet ( pPort, pAddress );\r
+ pSocket->errno = 0;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ else {\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ else {\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\r
+ }\r
\r
- case SOCK_DGRAM:\r
//\r
- // Verify the port state\r
+ // Release the socket layer synchronization\r
//\r
- Status = EslUdpGetRemoteAddress4 ( pSocket,\r
- pAddress,\r
- pAddressLength );\r
- break;\r
+ RESTORE_TPL ( TplPrevious );\r
+ }\r
+ else {\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\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
+ else {\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ }\r
}\r
}\r
- else {\r
- pSocket->errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
- }\r
}\r
- \r
+\r
//\r
// Return the operation status\r
//\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\r
Status = EFI_INVALID_PARAMETER;\r
- *pErrno = EBADF;\r
+ *pErrno = ENOTSOCK;\r
}\r
}\r
DBG_EXIT_STATUS ( Status );\r
}\r
\r
\r
-/**\r
- Establish the known port to listen for network connections.\r
+/** Free the ESL_IO_MGMT event and structure.\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
+ This support routine walks the free list to close the event in\r
+ the ESL_IO_MGMT structure and remove the structure from the free\r
+ list.\r
\r
- @param [out] pErrno Address to receive the errno value upon completion.\r
+ See the \ref TransmitEngine section.\r
\r
- @retval EFI_SUCCESS - Socket successfully created\r
- @retval Other - Failed to enable the socket for listen\r
+ @param[in] pPort Address of an ::ESL_PORT structure\r
+ @param[in] ppFreeQueue Address of the free queue head\r
+ @param[in] DebugFlags Flags for debug messages\r
+ @param[in] pEventName Zero terminated string containing the event name\r
\r
+ @retval EFI_SUCCESS - The structures were properly initialized\r
**/\r
EFI_STATUS\r
-EslSocketListen (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN INT32 Backlog,\r
- OUT int * pErrno\r
+EslSocketIoFree (\r
+ IN ESL_PORT * pPort,\r
+ IN ESL_IO_MGMT ** ppFreeQueue,\r
+ IN UINTN DebugFlags,\r
+ IN CHAR8 * pEventName\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ UINT8 * pBuffer;\r
+ EFI_EVENT * pEvent;\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
- EFI_STATUS TempStatus;\r
- EFI_TPL TplPrevious;\r
\r
DBG_ENTER ( );\r
\r
Status = EFI_SUCCESS;\r
\r
//\r
- // Validate the socket\r
+ // Walk the list of IO structures\r
//\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
+ pSocket = pPort->pSocket;\r
+ while ( *ppFreeQueue ) {\r
//\r
- // Assume success\r
+ // Free the event for this structure\r
//\r
- pSocket->Status = EFI_SUCCESS;\r
- pSocket->errno = 0;\r
+ pIo = *ppFreeQueue;\r
+ pBuffer = (UINT8 *)pIo;\r
+ pBuffer = &pBuffer[ pSocket->TxTokenEventOffset ];\r
+ pEvent = (EFI_EVENT *)pBuffer;\r
+ Status = gBS->CloseEvent ( *pEvent );\r
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_ERROR | DebugFlags,\r
+ "ERROR - Failed to close the %a event, Status: %r\r\n",\r
+ pEventName,\r
+ Status ));\r
+ pSocket->errno = ENOMEM;\r
+ break;\r
+ }\r
+ DEBUG (( DebugFlags,\r
+ "0x%08x: Closed %a event 0x%08x\r\n",\r
+ pIo,\r
+ pEventName,\r
+ *pEvent ));\r
\r
//\r
- // Verify that the bind operation was successful\r
+ // Remove this structure from the queue\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
+ *ppFreeQueue = pIo->pNext;\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
+/** Initialize the ESL_IO_MGMT structures.\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
+ This support routine initializes the ESL_IO_MGMT structure and\r
+ places them on to a free list.\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
+ This routine is called by ::EslSocketPortAllocate routines to prepare\r
+ the transmit engines. See the \ref TransmitEngine section.\r
\r
- @retval EFI_SUCCESS - Socket data successfully received\r
+ @param[in] pPort Address of an ::ESL_PORT structure\r
+ @param[in, out] ppIo Address containing the first structure address. Upon\r
+ return this buffer contains the next structure address.\r
+ @param[in] TokenCount Number of structures to initialize\r
+ @param[in] ppFreeQueue Address of the free queue head\r
+ @param[in] DebugFlags Flags for debug messages\r
+ @param[in] pEventName Zero terminated string containing the event name\r
+ @param[in] pfnCompletion Completion routine address\r
\r
- **/\r
+ @retval EFI_SUCCESS - The structures were properly initialized\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
+EslSocketIoInit (\r
+ IN ESL_PORT * pPort,\r
+ IN ESL_IO_MGMT ** ppIo,\r
+ IN UINTN TokenCount,\r
+ IN ESL_IO_MGMT ** ppFreeQueue,\r
+ IN UINTN DebugFlags,\r
+ IN CHAR8 * pEventName,\r
+ IN PFN_API_IO_COMPLETE pfnCompletion\r
)\r
{\r
- int errno;\r
- socklen_t LengthInBytes;\r
- socklen_t MaxBytes;\r
- UINT8 * pOptionData;\r
- DT_SOCKET * pSocket;\r
+ ESL_IO_MGMT * pEnd;\r
+ EFI_EVENT * pEvent;\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Assume failure\r
+ // Assume success\r
//\r
- errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
+ Status = EFI_SUCCESS;\r
\r
//\r
- // Validate the socket\r
+ // Walk the list of IO structures\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
+ pSocket = pPort->pSocket;\r
+ pIo = *ppIo;\r
+ pEnd = &pIo [ TokenCount ];\r
+ while ( pEnd > pIo ) {\r
+ //\r
+ // Initialize the IO structure\r
+ //\r
+ pIo->pPort = pPort;\r
+ pIo->pPacket = NULL;\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
+ //\r
+ // Allocate the event for this structure\r
+ //\r
+ pEvent = (EFI_EVENT *)&(((UINT8 *)pIo)[ pSocket->TxTokenEventOffset ]);\r
+ Status = gBS->CreateEvent ( EVT_NOTIFY_SIGNAL,\r
+ TPL_SOCKETS,\r
+ (EFI_EVENT_NOTIFY)pfnCompletion,\r
+ pIo,\r
+ pEvent );\r
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_ERROR | DebugFlags,\r
+ "ERROR - Failed to create the %a event, Status: %r\r\n",\r
+ pEventName,\r
+ Status ));\r
+ pSocket->errno = ENOMEM;\r
break;\r
}\r
+ DEBUG (( DebugFlags,\r
+ "0x%08x: Created %a event 0x%08x\r\n",\r
+ pIo,\r
+ pEventName,\r
+ *pEvent ));\r
\r
//\r
- // Return the option length\r
+ // Add this structure to the queue\r
//\r
- *pOptionLength = LengthInBytes;\r
+ pIo->pNext = *ppFreeQueue;\r
+ *ppFreeQueue = pIo;\r
\r
//\r
- // Return the option value\r
+ // Set the next structure\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
+ pIo += 1;\r
}\r
\r
+ //\r
+ // Save the next structure\r
+ //\r
+ *ppIo = pIo;\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
+/** Determine if the socket is configured.\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
+ This support routine is called to determine if the socket if the\r
+ configuration call was made to the network layer. The following\r
+ routines call this routine to verify that they may be successful\r
+ in their operations:\r
+ <ul>\r
+ <li>::EslSocketGetLocalAddress</li>\r
+ <li>::EslSocketGetPeerAddress</li>\r
+ <li>::EslSocketPoll</li>\r
+ <li>::EslSocketReceive</li>\r
+ <li>::EslSocketTransmit</li>\r
+ </ul>\r
\r
- @retval EFI_SUCCESS - Socket data successfully received\r
+ @param[in] pSocket Address of an ::ESL_SOCKET structure\r
\r
- **/\r
+ @retval EFI_SUCCESS - The socket is configured\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
+EslSocketIsConfigured (\r
+ IN ESL_SOCKET * pSocket\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
+ EFI_TPL TplPrevious;\r
+\r
//\r
- // Assume failure\r
+ // Assume success\r
//\r
- errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
- \r
+ Status = EFI_SUCCESS;\r
+\r
//\r
- // Validate the socket\r
+ // Verify the socket state\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
+ if ( !pSocket->bConfigured ) {\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Verify the API\r
+ //\r
+ if ( NULL == pSocket->pApi->pfnIsConfigured ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\r
+ }\r
+ else {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Determine if the socket is configured\r
+ //\r
+ Status = pSocket->pApi->pfnIsConfigured ( pSocket );\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
+\r
+ DBG_EXIT_STATUS ( Status );\r
+ }\r
+\r
+ //\r
+ // Return the configuration status\r
+ //\r
+ return Status;\r
+}\r
+\r
+\r
+/** Establish the known port to listen for network connections.\r
+\r
+ This routine calls into the network protocol layer to establish\r
+ a handler that is called upon connection completion. The handler\r
+ is responsible for inserting the connection into the FIFO.\r
+\r
+ The ::listen routine indirectly calls this routine to place the\r
+ socket into a state that enables connection attempts. Connections\r
+ are placed in a FIFO that is serviced by the application. The\r
+ application calls the ::accept (::EslSocketAccept) routine to\r
+ remove the next connection from the FIFO and get the associated\r
+ socket and address.\r
+\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\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
+ @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
+EFI_STATUS\r
+EslSocketListen (\r
+ IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
+ IN INT32 Backlog,\r
+ OUT int * pErrno\r
+ )\r
+{\r
+ ESL_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
+ // Verify the API\r
+ //\r
+ if ( NULL == pSocket->pApi->pfnListen ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\r
+ }\r
+ else {\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
+ TPL_SOCKETS,\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
+ // Initiate the connection attempt listen\r
+ //\r
+ Status = pSocket->pApi->pfnListen ( pSocket );\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
+ pSocket->bListenCalled = TRUE;\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 = ( SOCKET_STATE_NOT_CONFIGURED == pSocket->State ) ? EDESTADDRREQ\r
+ : EINVAL;\r
+ Status = EFI_NO_MAPPING;\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
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = ENOTSOCK;\r
+ }\r
+ }\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/** Get the socket options.\r
+\r
+ This routine handles the socket level options and passes the\r
+ others to the network specific layer.\r
+\r
+ The ::getsockopt routine calls this routine to retrieve the\r
+ socket options one at a time by name.\r
+\r
+ @param[in] pSocketProtocol Address of an ::EFI_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
+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
+ CONST UINT8 * pOptionData;\r
+ ESL_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
+ DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));\r
+ }\r
+ else if ( NULL == pOptionValue ) {\r
+ DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));\r
+ }\r
+ else if ( NULL == pOptionLength ) {\r
+ DEBUG (( DEBUG_OPTION, "ERROR - Option length not specified!\r\n" ));\r
+ }\r
+ else {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ LengthInBytes = 0;\r
+ MaxBytes = *pOptionLength;\r
+ pOptionData = NULL;\r
+ switch ( level ) {\r
+ default:\r
+ //\r
+ // See if the protocol will handle the option\r
+ //\r
+ if ( NULL != pSocket->pApi->pfnOptionGet ) {\r
+ if ( pSocket->pApi->DefaultProtocol == level ) {\r
+ Status = pSocket->pApi->pfnOptionGet ( pSocket,\r
+ OptionName,\r
+ (CONST void ** __restrict)&pOptionData,\r
+ &LengthInBytes );\r
+ errno = pSocket->errno;\r
+ break;\r
+ }\r
+ else {\r
+ //\r
+ // Protocol not supported\r
+ //\r
+ DEBUG (( DEBUG_OPTION,\r
+ "ERROR - The socket does not support this protocol!\r\n" ));\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // Protocol level not supported\r
+ //\r
+ DEBUG (( DEBUG_OPTION,\r
+ "ERROR - %a does not support any options!\r\n",\r
+ pSocket->pApi->pName ));\r
+ }\r
+ errno = ENOPROTOOPT;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SOL_SOCKET:\r
+ switch ( OptionName ) {\r
+ default:\r
+ //\r
+ // Socket option not supported\r
+ //\r
+ DEBUG (( DEBUG_INFO | DEBUG_OPTION, "ERROR - Invalid socket option!\r\n" ));\r
+ errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SO_ACCEPTCONN:\r
+ //\r
+ // Return the listen flag\r
+ //\r
+ pOptionData = (CONST UINT8 *)&pSocket->bListenCalled;\r
+ LengthInBytes = sizeof ( pSocket->bListenCalled );\r
+ break;\r
+\r
+ case SO_DEBUG:\r
+ //\r
+ // Return the debug flags\r
+ //\r
+ pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;\r
+ LengthInBytes = sizeof ( pSocket->bOobInLine );\r
+ break;\r
+\r
+ case SO_OOBINLINE:\r
+ //\r
+ // Return the out-of-band inline flag\r
+ //\r
+ pOptionData = (CONST UINT8 *)&pSocket->bOobInLine;\r
+ LengthInBytes = sizeof ( pSocket->bOobInLine );\r
+ break;\r
+\r
+ case SO_RCVTIMEO:\r
+ //\r
+ // Return the receive timeout\r
+ //\r
+ pOptionData = (CONST UINT8 *)&pSocket->RxTimeout;\r
+ LengthInBytes = sizeof ( pSocket->RxTimeout );\r
+ break;\r
+\r
+ case SO_RCVBUF:\r
+ //\r
+ // Return the maximum receive buffer size\r
+ //\r
+ pOptionData = (CONST UINT8 *)&pSocket->MaxRxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
+ break;\r
+\r
+ case SO_REUSEADDR:\r
+ //\r
+ // Return the address reuse flag\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->bReUseAddr;\r
+ LengthInBytes = sizeof ( pSocket->bReUseAddr );\r
+ break;\r
+\r
+ case SO_SNDBUF:\r
+ //\r
+ // Return the maximum transmit buffer size\r
+ //\r
+ pOptionData = (CONST UINT8 *)&pSocket->MaxTxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
+ break;\r
+\r
+ case SO_TYPE:\r
+ //\r
+ // Return the socket type\r
+ //\r
+ pOptionData = (CONST 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
+ // Determine if the option is present\r
+ //\r
+ if ( 0 != LengthInBytes ) {\r
+ //\r
+ // Silently truncate the value length\r
+ //\r
+ if ( LengthInBytes > MaxBytes ) {\r
+ DEBUG (( DEBUG_OPTION,\r
+ "INFO - Truncating option from %d to %d bytes\r\n",\r
+ LengthInBytes,\r
+ MaxBytes ));\r
+ LengthInBytes = MaxBytes;\r
+ }\r
+\r
+ //\r
+ // Return the value\r
+ //\r
+ CopyMem ( pOptionValue, pOptionData, LengthInBytes );\r
+\r
+ //\r
+ // Zero fill any remaining space\r
+ //\r
+ if ( LengthInBytes < MaxBytes ) {\r
+ ZeroMem ( &((UINT8 *)pOptionValue)[LengthInBytes], MaxBytes - LengthInBytes );\r
+ }\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
+/** Set the socket options.\r
+\r
+ This routine handles the socket level options and passes the\r
+ others to the network specific layer.\r
+\r
+ The ::setsockopt routine calls this routine to adjust the socket\r
+ options one at a time by name.\r
+\r
+ @param[in] pSocketProtocol Address of an ::EFI_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 - Option successfully set\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
+ BOOLEAN bTrueFalse;\r
+ int errno;\r
+ socklen_t LengthInBytes;\r
+ UINT8 * pOptionData;\r
+ ESL_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
+ DEBUG (( DEBUG_OPTION, "ERROR - pSocketProtocol is NULL!\r\n" ));\r
+ }\r
+ else if ( NULL == pOptionValue ) {\r
+ DEBUG (( DEBUG_OPTION, "ERROR - No option buffer specified\r\n" ));\r
+ }\r
+ else\r
+ {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+ if ( pSocket->bRxDisable || pSocket->bTxDisable ) {\r
+ DEBUG (( DEBUG_OPTION, "ERROR - Socket has been shutdown!\r\n" ));\r
+ }\r
+ else {\r
+ LengthInBytes = 0;\r
+ pOptionData = NULL;\r
+ switch ( level ) {\r
+ default:\r
+ //\r
+ // See if the protocol will handle the option\r
+ //\r
+ if ( NULL != pSocket->pApi->pfnOptionSet ) {\r
+ if ( pSocket->pApi->DefaultProtocol == level ) {\r
+ Status = pSocket->pApi->pfnOptionSet ( pSocket,\r
+ OptionName,\r
+ pOptionValue,\r
+ OptionLength );\r
+ errno = pSocket->errno;\r
+ break;\r
+ }\r
+ else {\r
+ //\r
+ // Protocol not supported\r
+ //\r
+ DEBUG (( DEBUG_OPTION,\r
+ "ERROR - The socket does not support this protocol!\r\n" ));\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // Protocol level not supported\r
+ //\r
+ DEBUG (( DEBUG_OPTION,\r
+ "ERROR - %a does not support any options!\r\n",\r
+ pSocket->pApi->pName ));\r
+ }\r
+ errno = ENOPROTOOPT;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SOL_SOCKET:\r
+ switch ( OptionName ) {\r
+ default:\r
+ //\r
+ // Option not supported\r
+ //\r
+ DEBUG (( DEBUG_OPTION,\r
+ "ERROR - Sockets does not support this option!\r\n" ));\r
+ errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
+ break;\r
+\r
+ case SO_DEBUG:\r
+ //\r
+ // Set the debug flags\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;\r
+ LengthInBytes = sizeof ( pSocket->bOobInLine );\r
+ break;\r
+\r
+ case SO_OOBINLINE:\r
+ pOptionData = (UINT8 *)&pSocket->bOobInLine;\r
+ LengthInBytes = sizeof ( pSocket->bOobInLine );\r
+\r
+ //\r
+ // Validate the option length\r
+ //\r
+ if ( sizeof ( UINT32 ) == OptionLength ) {\r
+ //\r
+ // Restrict the input to TRUE or FALSE\r
+ //\r
+ bTrueFalse = TRUE;\r
+ if ( 0 == *(UINT32 *)pOptionValue ) {\r
+ bTrueFalse = FALSE;\r
+ }\r
+ pOptionValue = &bTrueFalse;\r
+ }\r
+ else {\r
+ //\r
+ // Force an invalid option length error\r
+ //\r
+ OptionLength = LengthInBytes - 1;\r
+ }\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 receive buffer size\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
+ LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
+ break;\r
+\r
+ case SO_REUSEADDR:\r
+ //\r
+ // Return the address reuse flag\r
+ //\r
+ pOptionData = (UINT8 *)&pSocket->bReUseAddr;\r
+ LengthInBytes = sizeof ( pSocket->bReUseAddr );\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
+ // Determine if an option was found\r
+ //\r
+ if ( 0 != LengthInBytes ) {\r
+ //\r
+ // Validate the option length\r
+ //\r
+ if ( LengthInBytes <= OptionLength ) {\r
+ //\r
+ // Set the option value\r
+ //\r
+ CopyMem ( pOptionData, pOptionValue, LengthInBytes );\r
+ errno = 0;\r
+ Status = EFI_SUCCESS;\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_OPTION,\r
+ "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",\r
+ OptionLength,\r
+ LengthInBytes ));\r
+ }\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
+/** Allocate a packet for a receive or transmit operation.\r
+\r
+ This support routine is called by ::EslSocketRxStart and the\r
+ network specific TxBuffer routines to get buffer space for the\r
+ next operation.\r
+\r
+ @param[in] ppPacket Address to receive the ::ESL_PACKET structure\r
+ @param[in] LengthInBytes Length of the packet structure\r
+ @param[in] ZeroBytes Length of packet to zero\r
+ @param[in] DebugFlags Flags for debug messages\r
+\r
+ @retval EFI_SUCCESS - The packet was allocated successfully\r
+**/\r
+EFI_STATUS\r
+EslSocketPacketAllocate (\r
+ IN ESL_PACKET ** ppPacket,\r
+ IN size_t LengthInBytes,\r
+ IN size_t ZeroBytes,\r
+ IN UINTN DebugFlags\r
+ )\r
+{\r
+ ESL_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,\r
+ "0x%08x: Allocate pPacket, %d bytes\r\n",\r
+ pPacket,\r
+ LengthInBytes ));\r
+ if ( 0 != ZeroBytes ) {\r
+ ZeroMem ( &pPacket->Op, ZeroBytes );\r
+ }\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
+/** Free a packet used for receive or transmit operation.\r
+\r
+ This support routine is called by the network specific Close\r
+ and TxComplete routines and during error cases in RxComplete\r
+ and TxBuffer. Note that the network layers typically place\r
+ receive packets on the ESL_SOCKET::pRxFree list for reuse.\r
+\r
+ @param[in] pPacket Address of an ::ESL_PACKET structure\r
+ @param[in] DebugFlags Flags for debug messages\r
+\r
+ @retval EFI_SUCCESS - The packet was allocated successfully\r
+**/\r
+EFI_STATUS\r
+EslSocketPacketFree (\r
+ IN ESL_PACKET * pPacket,\r
+ IN UINTN DebugFlags\r
+ )\r
+{\r
+ UINTN LengthInBytes;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Free 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
+/** Poll a socket for pending activity.\r
+\r
+ This routine builds a detected event mask which is returned to\r
+ the caller in the buffer provided.\r
+\r
+ The ::poll routine calls this routine to determine if the socket\r
+ needs to be serviced as a result of connection, error, receive or\r
+ transmit activity.\r
+\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[in] Events Events of interest for this socket\r
+ @param[in] pEvents Address to receive the detected events\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
+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
+ ESL_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
+ short ValidEvents;\r
+ int _errno = EINVAL;\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
+ Status = EslSocketIsConfigured ( pSocket );\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
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+\r
+ //\r
+ // Increase the network performance by extending the\r
+ // polling (idle) loop down into the LAN driver\r
+ //\r
+ EslSocketRxPoll ( pSocket );\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\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
+ _errno = pSocket->errno;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the detected events\r
+ //\r
+ *pEvents = DetectedEvents & ( Events\r
+ | POLLERR\r
+ | POLLHUP\r
+ | POLLNVAL );\r
+ if ( NULL != pErrno ) {\r
+ *pErrno = _errno;\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
+/** Allocate and initialize a ESL_PORT structure.\r
+\r
+ This routine initializes an ::ESL_PORT structure for use by\r
+ the socket. This routine calls a routine via\r
+ ESL_PROTOCOL_API::pfnPortAllocate to initialize the network\r
+ specific resources. The resources are released later by the\r
+ \ref PortCloseStateMachine.\r
+\r
+ This support routine is called by:\r
+ <ul>\r
+ <li>::EslSocketBind</li>\r
+ <li>::EslTcp4ListenComplete</li>\r
+ </ul>\r
+ to connect the socket with the underlying network adapter\r
+ to the socket.\r
+\r
+ @param[in] pSocket Address of an ::ESL_SOCKET structure.\r
+ @param[in] pService Address of an ::ESL_SERVICE structure.\r
+ @param[in] ChildHandle Network protocol child handle\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
+ @param[in] bBindTest TRUE if EslSocketBindTest should be called\r
+ @param[in] DebugFlags Flags for debug messages\r
+ @param[out] ppPort Buffer to receive new ::ESL_PORT structure address\r
+\r
+ @retval EFI_SUCCESS - Socket successfully created\r
+**/\r
+EFI_STATUS\r
+EslSocketPortAllocate (\r
+ IN ESL_SOCKET * pSocket,\r
+ IN ESL_SERVICE * pService,\r
+ IN EFI_HANDLE ChildHandle,\r
+ IN CONST struct sockaddr * pSockAddr,\r
+ IN BOOLEAN bBindTest,\r
+ IN UINTN DebugFlags,\r
+ OUT ESL_PORT ** ppPort\r
+ )\r
+{\r
+ UINTN LengthInBytes;\r
+ UINT8 * pBuffer;\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_LAYER * pLayer;\r
+ ESL_PORT * pPort;\r
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
+ CONST ESL_SOCKET_BINDING * pSocketBinding;\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
+ // Use for/break instead of goto\r
+ pSocketBinding = pService->pSocketBinding;\r
+ for ( ; ; ) {\r
+ //\r
+ // Allocate a port structure\r
+ //\r
+ pLayer = &mEslLayer;\r
+ LengthInBytes = sizeof ( *pPort )\r
+ + ESL_STRUCTURE_ALIGNMENT_BYTES\r
+ + (( pSocketBinding->RxIo\r
+ + pSocketBinding->TxIoNormal\r
+ + pSocketBinding->TxIoUrgent )\r
+ * sizeof ( ESL_IO_MGMT ));\r
+ pPort = (ESL_PORT *) AllocateZeroPool ( LengthInBytes );\r
+ if ( NULL == pPort ) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ pSocket->errno = ENOMEM;\r
+ break;\r
+ }\r
+ DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
+ "0x%08x: Allocate pPort, %d bytes\r\n",\r
+ pPort,\r
+ LengthInBytes ));\r
+\r
+ //\r
+ // Initialize the port\r
+ //\r
+ pPort->DebugFlags = DebugFlags;\r
+ pPort->Handle = ChildHandle;\r
+ pPort->pService = pService;\r
+ pPort->pServiceBinding = pService->pServiceBinding;\r
+ pPort->pSocket = pSocket;\r
+ pPort->pSocketBinding = pService->pSocketBinding;\r
+ pPort->Signature = PORT_SIGNATURE;\r
+\r
+ //\r
+ // Open the port protocol\r
+ //\r
+ Status = gBS->OpenProtocol ( pPort->Handle,\r
+ pSocketBinding->pNetworkProtocolGuid,\r
+ &pPort->pProtocol.v,\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 network protocol GUID on controller 0x%08x\r\n",\r
+ pPort->Handle ));\r
+ pSocket->errno = EEXIST;\r
+ break;\r
+ }\r
+ DEBUG (( DebugFlags,\r
+ "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",\r
+ pPort->pProtocol.v,\r
+ pPort->Handle ));\r
+\r
+ //\r
+ // Initialize the port specific resources\r
+ //\r
+ Status = pSocket->pApi->pfnPortAllocate ( pPort,\r
+ DebugFlags );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Set the local address\r
+ //\r
+ Status = pSocket->pApi->pfnLocalAddrSet ( pPort, pSockAddr, bBindTest );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Test the address/port configuration\r
+ //\r
+ if ( bBindTest ) {\r
+ Status = EslSocketBindTest ( pPort, pSocket->pApi->BindTestErrno );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Initialize the receive structures\r
+ //\r
+ pBuffer = (UINT8 *)&pPort[ 1 ];\r
+ pBuffer = &pBuffer[ ESL_STRUCTURE_ALIGNMENT_BYTES ];\r
+ pBuffer = (UINT8 *)( ESL_STRUCTURE_ALIGNMENT_MASK & (UINTN)pBuffer );\r
+ pIo = (ESL_IO_MGMT *)pBuffer;\r
+ if (( 0 != pSocketBinding->RxIo )\r
+ && ( NULL != pSocket->pApi->pfnRxComplete )) {\r
+ Status = EslSocketIoInit ( pPort,\r
+ &pIo,\r
+ pSocketBinding->RxIo,\r
+ &pPort->pRxFree,\r
+ DebugFlags | DEBUG_POOL,\r
+ "receive",\r
+ pSocket->pApi->pfnRxComplete );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Initialize the urgent transmit structures\r
+ //\r
+ if (( 0 != pSocketBinding->TxIoUrgent )\r
+ && ( NULL != pSocket->pApi->pfnTxOobComplete )) {\r
+ Status = EslSocketIoInit ( pPort,\r
+ &pIo,\r
+ pSocketBinding->TxIoUrgent,\r
+ &pPort->pTxOobFree,\r
+ DebugFlags | DEBUG_POOL,\r
+ "urgent transmit",\r
+ pSocket->pApi->pfnTxOobComplete );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Initialize the normal transmit structures\r
+ //\r
+ if (( 0 != pSocketBinding->TxIoNormal )\r
+ && ( NULL != pSocket->pApi->pfnTxComplete )) {\r
+ Status = EslSocketIoInit ( pPort,\r
+ &pIo,\r
+ pSocketBinding->TxIoNormal,\r
+ &pPort->pTxFree,\r
+ DebugFlags | DEBUG_POOL,\r
+ "normal transmit",\r
+ pSocket->pApi->pfnTxComplete );\r
+ if ( EFI_ERROR ( Status )) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Add this port to the socket\r
+ //\r
+ pPort->pLinkSocket = pSocket->pPortList;\r
+ pSocket->pPortList = pPort;\r
+ DEBUG (( DebugFlags,\r
+ "0x%08x: Socket adding port: 0x%08x\r\n",\r
+ pSocket,\r
+ pPort ));\r
+\r
+ //\r
+ // Add this port to the service\r
+ //\r
+ pPort->pLinkService = pService->pPortList;\r
+ pService->pPortList = pPort;\r
+\r
+ //\r
+ // Return the port\r
+ //\r
+ *ppPort = pPort;\r
+ break;\r
+ }\r
+\r
+ //\r
+ // Clean up after the error if necessary\r
+ //\r
+ if ( EFI_ERROR ( Status )) {\r
+ if ( NULL != pPort ) {\r
+ //\r
+ // Close the port\r
+ //\r
+ EslSocketPortClose ( pPort );\r
+ }\r
+ else {\r
+ //\r
+ // Close the port if necessary\r
+ //\r
+ pServiceBinding = pService->pServiceBinding;\r
+ TempStatus = pServiceBinding->DestroyChild ( pServiceBinding,\r
+ ChildHandle );\r
+ if ( !EFI_ERROR ( TempStatus )) {\r
+ DEBUG (( DEBUG_BIND | DEBUG_POOL,\r
+ "0x%08x: %s port handle destroyed\r\n",\r
+ ChildHandle,\r
+ pSocketBinding->pName ));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_BIND | DEBUG_POOL,\r
+ "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",\r
+ pSocketBinding->pName,\r
+ ChildHandle,\r
+ TempStatus ));\r
+ ASSERT ( EFI_SUCCESS == TempStatus );\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/** Close a port.\r
+\r
+ This routine releases the resources allocated by ::EslSocketPortAllocate.\r
+ This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network\r
+ specific resources.\r
+\r
+ This routine is called by:\r
+ <ul>\r
+ <li>::EslSocketPortAllocate - Port initialization failure</li>\r
+ <li>::EslSocketPortCloseRxDone - Last step of close processing</li>\r
+ <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>\r
+ </ul>\r
+ See the \ref PortCloseStateMachine section.\r
+\r
+ @param[in] pPort Address of an ::ESL_PORT structure.\r
+\r
+ @retval EFI_SUCCESS The port is closed\r
+ @retval other Port close error\r
+**/\r
+EFI_STATUS\r
+EslSocketPortClose (\r
+ IN ESL_PORT * pPort\r
+ )\r
+{\r
+ UINTN DebugFlags;\r
+ ESL_LAYER * pLayer;\r
+ ESL_PACKET * pPacket;\r
+ ESL_PORT * pPreviousPort;\r
+ ESL_SERVICE * pService;\r
+ EFI_SERVICE_BINDING_PROTOCOL * pServiceBinding;\r
+ CONST ESL_SOCKET_BINDING * pSocketBinding;\r
+ ESL_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Verify the socket layer synchronization\r
+ //\r
+ VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+ //\r
+ // 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
+ // Note that the port may not be in the service list\r
+ // if the service has been shutdown.\r
+ //\r
+ pService = pPort->pService;\r
+ if ( NULL != 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
+ //\r
+ // Empty the urgent receive queue\r
+ //\r
+ while ( NULL != pSocket->pRxOobPacketListHead ) {\r
+ pPacket = pSocket->pRxOobPacketListHead;\r
+ pSocket->pRxOobPacketListHead = pPacket->pNext;\r
+ pSocket->pApi->pfnPacketFree ( pPacket, &pSocket->RxOobBytes );\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->pApi->pfnPacketFree ( pPacket, &pSocket->RxBytes );\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
+ // Release the network specific resources\r
+ //\r
+ if ( NULL != pSocket->pApi->pfnPortClose ) {\r
+ Status = pSocket->pApi->pfnPortClose ( pPort );\r
+ }\r
+\r
+ //\r
+ // Done with the normal transmit events\r
+ //\r
+ Status = EslSocketIoFree ( pPort,\r
+ &pPort->pTxFree,\r
+ DebugFlags | DEBUG_POOL,\r
+ "normal transmit" );\r
+\r
+ //\r
+ // Done with the urgent transmit events\r
+ //\r
+ Status = EslSocketIoFree ( pPort,\r
+ &pPort->pTxOobFree,\r
+ DebugFlags | DEBUG_POOL,\r
+ "urgent transmit" );\r
+\r
+ //\r
+ // Done with the receive events\r
+ //\r
+ Status = EslSocketIoFree ( pPort,\r
+ &pPort->pRxFree,\r
+ DebugFlags | DEBUG_POOL,\r
+ "receive" );\r
+\r
+ //\r
+ // Done with the lower layer network protocol\r
+ //\r
+ pSocketBinding = pPort->pSocketBinding;\r
+ if ( NULL != pPort->pProtocol.v ) {\r
+ Status = gBS->CloseProtocol ( pPort->Handle,\r
+ pSocketBinding->pNetworkProtocolGuid,\r
+ pLayer->ImageHandle,\r
+ NULL );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DebugFlags,\r
+ "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",\r
+ pPort->pProtocol.v,\r
+ pPort->Handle ));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DebugFlags,\r
+ "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",\r
+ pPort->Handle,\r
+ Status ));\r
+ ASSERT ( EFI_SUCCESS == Status );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Done with the network port\r
+ //\r
+ pServiceBinding = pPort->pServiceBinding;\r
+ if ( NULL != pPort->Handle ) {\r
+ Status = pServiceBinding->DestroyChild ( pServiceBinding,\r
+ pPort->Handle );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ DEBUG (( DebugFlags | DEBUG_POOL,\r
+ "0x%08x: %s port handle destroyed\r\n",\r
+ pPort->Handle,\r
+ pSocketBinding->pName ));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL,\r
+ "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",\r
+ pSocketBinding->pName,\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
+ // Mark the socket as closed if necessary\r
+ //\r
+ if ( NULL == pSocket->pPortList ) {\r
+ pSocket->State = SOCKET_STATE_CLOSED;\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",\r
+ pSocket ));\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/** Port close state 3.\r
+\r
+ This routine attempts to complete the port close operation.\r
+\r
+ This routine is called by the TCP layer upon completion of\r
+ the close operation and by ::EslSocketPortCloseTxDone.\r
+ See the \ref PortCloseStateMachine section.\r
+\r
+ @param[in] Event The close completion event\r
+ @param[in] pPort Address of an ::ESL_PORT structure.\r
+**/\r
+VOID\r
+EslSocketPortCloseComplete (\r
+ IN EFI_EVENT Event,\r
+ IN ESL_PORT * pPort\r
+ )\r
+{\r
+ ESL_IO_MGMT * pIo;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+ VERIFY_AT_TPL ( TPL_SOCKETS );\r
+\r
+ // Update the port state\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
+\r
+ // Shutdown the receive operation on the port\r
+ if ( NULL != pPort->pfnRxCancel ) {\r
+ pIo = pPort->pRxActive;\r
+ while ( NULL != pIo ) {\r
+ EslSocketRxCancel ( pPort, pIo );\r
+ pIo = pIo->pNext;\r
+ }\r
+ }\r
+\r
+ // Determine if the receive operation is pending\r
+ Status = EslSocketPortCloseRxDone ( pPort );\r
+ DBG_EXIT_STATUS ( Status );\r
+ --Status;\r
+}\r
+\r
+\r
+/** Port close state 4.\r
+\r
+ This routine determines the state of the receive operations and\r
+ continues the close operation after the pending receive operations\r
+ are cancelled.\r
+\r
+ This routine is called by\r
+ <ul>\r
+ <li>::EslSocketPortCloseComplete</li>\r
+ <li>::EslSocketPortCloseTxDone</li>\r
+ <li>::EslSocketRxComplete</li>\r
+ </ul>\r
+ to determine the state of the receive operations.\r
+ See the \ref PortCloseStateMachine section.\r
+\r
+ @param[in] pPort Address of an ::ESL_PORT structure.\r
+\r
+ @retval EFI_SUCCESS The port is closed\r
+ @retval 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
+EFI_STATUS\r
+EslSocketPortCloseRxDone (\r
+ IN ESL_PORT * pPort\r
+ )\r
+{\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
+ if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
+ //\r
+ // Determine if the receive operation is pending\r
+ //\r
+ Status = EFI_NOT_READY;\r
+ if ( NULL == pPort->pRxActive ) {\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
+ // Complete the port close operation\r
+ //\r
+ Status = EslSocketPortClose ( pPort );\r
+ }\r
+ else {\r
+ DEBUG_CODE_BEGIN ();\r
+ {\r
+ ESL_IO_MGMT * pIo;\r
+ //\r
+ // Display the outstanding receive operations\r
+ //\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Port Close: Receive still pending!\r\n",\r
+ pPort ));\r
+ pIo = pPort->pRxActive;\r
+ while ( NULL != pIo ) {\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet pending on network adapter\r\n",\r
+ pIo->pPacket ));\r
+ pIo = pIo->pNext;\r
+ }\r
+ }\r
+ DEBUG_CODE_END ( );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/** Start the close operation on a port, state 1.\r
+\r
+ This routine marks the port as closed and initiates the \ref\r
+ PortCloseStateMachine. The first step is to allow the \ref\r
+ TransmitEngine to run down.\r
+\r
+ This routine is called by ::EslSocketCloseStart to initiate the socket\r
+ network specific close operation on the socket.\r
+\r
+ @param[in] pPort Address of an ::ESL_PORT structure.\r
+ @param[in] bCloseNow Set TRUE to abort active transfers\r
+ @param[in] DebugFlags Flags for debug messages\r
+\r
+ @retval EFI_SUCCESS The port is closed, not normally returned\r
+ @retval EFI_NOT_READY The port has started the closing process\r
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
+ most likely the routine was called already.\r
+**/\r
+EFI_STATUS\r
+EslSocketPortCloseStart (\r
+ IN ESL_PORT * pPort,\r
+ IN BOOLEAN bCloseNow,\r
+ IN UINTN DebugFlags\r
+ )\r
+{\r
+ ESL_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Verify the socket layer synchronization\r
+ //\r
+ VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+ //\r
+ // Mark the port as closing\r
+ //\r
+ Status = EFI_ALREADY_STARTED;\r
+ pSocket = pPort->pSocket;\r
+ pSocket->errno = EALREADY;\r
+ if ( PORT_STATE_CLOSE_STARTED > pPort->State ) {\r
+\r
+ //\r
+ // Update the port state\r
+ //\r
+ pPort->State = PORT_STATE_CLOSE_STARTED;\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",\r
+ pPort ));\r
+ pPort->bCloseNow = bCloseNow;\r
+ pPort->DebugFlags = DebugFlags;\r
+\r
+ //\r
+ // Determine if transmits are complete\r
+ //\r
+ Status = EslSocketPortCloseTxDone ( pPort );\r
+ }\r
+\r
+ //\r
+ // Return the operation status\r
+ //\r
+ DBG_EXIT_STATUS ( Status );\r
+ return Status;\r
+}\r
+\r
+\r
+/** Port close state 2.\r
+\r
+ This routine determines the state of the transmit engine and\r
+ continue the close operation after the transmission is complete.\r
+ The next step is to stop the \ref ReceiveEngine.\r
+ See the \ref PortCloseStateMachine section.\r
+\r
+ This routine is called by ::EslSocketPortCloseStart to determine\r
+ if the transmission is complete.\r
+\r
+ @param[in] pPort Address of an ::ESL_PORT structure.\r
+\r
+ @retval EFI_SUCCESS The port is closed, not normally returned\r
+ @retval EFI_NOT_READY The port is still closing\r
+ @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,\r
+ most likely the routine was called already.\r
+\r
+**/\r
+EFI_STATUS\r
+EslSocketPortCloseTxDone (\r
+ IN ESL_PORT * pPort\r
+ )\r
+{\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_SOCKET * pSocket;\r
+ EFI_STATUS Status;\r
+\r
+ DBG_ENTER ( );\r
+\r
+ //\r
+ // Verify the socket layer synchronization\r
+ //\r
+ VERIFY_TPL ( TPL_SOCKETS );\r
+\r
+ //\r
+ // 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
+ || (( NULL == pPort->pTxActive )\r
+ && ( NULL == pPort->pTxOobActive ))) {\r
//\r
- // Protocol level not supported\r
+ // Update the port state\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
+ 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
- case SO_RCVBUF:\r
+ //\r
+ // Close the port\r
+ // Skip the close operation if the port is not configured\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ pSocket = pPort->pSocket;\r
+ if (( pPort->bConfigured )\r
+ && ( NULL != pSocket->pApi->pfnPortCloseOp )) {\r
+ //\r
+ // Start the close operation\r
+ //\r
+ Status = pSocket->pApi->pfnPortCloseOp ( pPort );\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Port Close: Close operation still pending!\r\n",\r
+ pPort ));\r
+ ASSERT ( EFI_SUCCESS == Status );\r
+ }\r
+ else {\r
//\r
- // Return the maximum transmit buffer size\r
+ // The receive operation is complete\r
+ // Update the port state\r
//\r
- pOptionData = (UINT8 *)&pSocket->MaxRxBuf;\r
- LengthInBytes = sizeof ( pSocket->MaxRxBuf );\r
- break;\r
+ EslSocketPortCloseComplete ( NULL, pPort );\r
+ }\r
+ }\r
+ else {\r
+ //\r
+ // Transmissions are still active, exit\r
+ //\r
+ Status = EFI_NOT_READY;\r
+ pSocket->errno = EAGAIN;\r
+ DEBUG_CODE_BEGIN ( );\r
+ {\r
+ ESL_PACKET * pPacket;\r
+\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Port Close: Transmits are still pending!\r\n",\r
+ pPort ));\r
\r
- case SO_SNDBUF:\r
//\r
- // Send buffer size\r
+ // Display the pending urgent transmit packets\r
//\r
+ pPacket = pSocket->pTxOobPacketListHead;\r
+ while ( NULL != pPacket ) {\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",\r
+ pPacket,\r
+ pPacket->PacketSize ));\r
+ pPacket = pPacket->pNext;\r
+ }\r
+\r
+ pIo = pPort->pTxOobActive;\r
+ while ( NULL != pIo ) {\r
+ pPacket = pIo->pPacket;\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",\r
+ pPacket,\r
+ pPacket->PacketSize,\r
+ pIo ));\r
+ pIo = pIo->pNext;\r
+ }\r
+\r
//\r
- // Return the maximum transmit buffer size\r
+ // Display the pending normal transmit packets\r
//\r
- pOptionData = (UINT8 *)&pSocket->MaxTxBuf;\r
- LengthInBytes = sizeof ( pSocket->MaxTxBuf );\r
- break;\r
- }\r
- break;\r
- }\r
+ pPacket = pSocket->pTxPacketListHead;\r
+ while ( NULL != pPacket ) {\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet pending on normal TX list, %d bytes\r\n",\r
+ pPacket,\r
+ pPacket->PacketSize ));\r
+ pPacket = pPacket->pNext;\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
+ pIo = pPort->pTxActive;\r
+ while ( NULL != pIo ) {\r
+ pPacket = pIo->pPacket;\r
+ DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",\r
+ pPacket,\r
+ pPacket->PacketSize,\r
+ pIo ));\r
+ pIo = pIo->pNext;\r
+ }\r
}\r
+ DEBUG_CODE_END ();\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
+/** Receive data from a network connection.\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
+ This routine calls the network specific routine to remove the\r
+ next portion of data from the receive queue and return it to the\r
+ caller.\r
\r
- @retval EFI_SUCCESS - The packet was allocated successfully\r
+ The ::recvfrom routine calls this routine to determine if any data\r
+ is received from the remote system. Note that the other routines\r
+ ::recv and ::read are layered on top of ::recvfrom.\r
\r
- **/\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[in] Flags Message control flags\r
+ @param[in] BufferLength Length of the the buffer\r
+ @param[in] pBuffer Address of a buffer to receive the data.\r
+ @param[in] pDataLength Number of received data bytes in the buffer.\r
+ @param[out] pAddress Network address to receive the remote system address\r
+ @param[in,out] pAddressLength Length of the remote network address structure\r
+ @param[out] pErrno Address to receive the errno value upon completion.\r
+\r
+ @retval EFI_SUCCESS - Socket data successfully received\r
+**/\r
EFI_STATUS\r
-EslSocketPacketAllocate (\r
- IN DT_PACKET ** ppPacket,\r
- IN size_t LengthInBytes,\r
- IN UINTN DebugFlags\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_PACKET * pPacket;\r
+ union {\r
+ struct sockaddr_in v4;\r
+ struct sockaddr_in6 v6;\r
+ } Addr;\r
+ socklen_t AddressLength;\r
+ BOOLEAN bConsumePacket;\r
+ BOOLEAN bUrgentQueue;\r
+ size_t DataLength;\r
+ ESL_PACKET * pNextPacket;\r
+ ESL_PACKET * pPacket;\r
+ ESL_PORT * pPort;\r
+ ESL_PACKET ** ppQueueHead;\r
+ ESL_PACKET ** ppQueueTail;\r
+ struct sockaddr * pRemoteAddress;\r
+ size_t * pRxDataBytes;\r
+ ESL_SOCKET * pSocket;\r
+ size_t SkipBytes;\r
EFI_STATUS Status;\r
+ EFI_TPL TplPrevious;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Allocate a packet structure\r
+ // Assume success\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
+ Status = EFI_SUCCESS;\r
\r
//\r
- // Return the packet\r
+ // Validate the socket\r
//\r
- *ppPacket = pPacket;\r
+ pSocket = NULL;\r
+ if ( NULL != pSocketProtocol ) {\r
+ pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
+\r
+ //\r
+ // Validate the return address parameters\r
+ //\r
+ if (( NULL == pAddress ) || ( NULL != pAddressLength )) {\r
+ //\r
+ // Return the transmit error if necessary\r
+ //\r
+ if ( EFI_SUCCESS != pSocket->TxError ) {\r
+ pSocket->errno = EIO;\r
+ Status = pSocket->TxError;\r
+ pSocket->TxError = EFI_SUCCESS;\r
+ }\r
+ else {\r
+ //\r
+ // Verify the socket state\r
+ //\r
+ Status = EslSocketIsConfigured ( pSocket );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Validate the buffer length\r
+ //\r
+ if (( NULL == pDataLength )\r
+ || ( NULL == pBuffer )) {\r
+ if ( NULL == pDataLength ) {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - pDataLength is NULL!\r\n" ));\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_RX,\r
+ "ERROR - pBuffer is NULL!\r\n" ));\r
+ }\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EFAULT;\r
+ }\r
+ else {\r
+ //\r
+ // Verify the API\r
+ //\r
+ if ( NULL == pSocket->pApi->pfnReceive ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\r
+ }\r
+ else {\r
+ //\r
+ // Zero the receive address if being returned\r
+ //\r
+ pRemoteAddress = NULL;\r
+ if ( NULL != pAddress ) {\r
+ pRemoteAddress = (struct sockaddr *)&Addr;\r
+ ZeroMem ( pRemoteAddress, sizeof ( Addr ));\r
+ pRemoteAddress->sa_family = pSocket->pApi->AddressFamily;\r
+ pRemoteAddress->sa_len = (UINT8)pSocket->pApi->AddressLength;\r
+ }\r
+\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\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
+ //\r
+ // Poll the network to increase performance\r
+ //\r
+ EslSocketRxPoll ( pSocket );\r
+\r
+ //\r
+ // Locate the port\r
+ //\r
+ pPort = pSocket->pPortList;\r
+ if ( NULL != pPort ) {\r
+ //\r
+ // Determine the queue head\r
+ //\r
+ bUrgentQueue = (BOOLEAN)( 0 != ( Flags & MSG_OOB ));\r
+ if ( bUrgentQueue ) {\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
+ *pDataLength = 0;\r
+ pPacket = *ppQueueHead;\r
+ if ( NULL != pPacket ) {\r
+ //\r
+ // Copy the received data\r
+ //\r
+ do {\r
+ //\r
+ // Attempt to receive a packet\r
+ //\r
+ SkipBytes = 0;\r
+ bConsumePacket = (BOOLEAN)( 0 == ( Flags & MSG_PEEK ));\r
+ pBuffer = pSocket->pApi->pfnReceive ( pPort,\r
+ pPacket,\r
+ &bConsumePacket,\r
+ BufferLength,\r
+ pBuffer,\r
+ &DataLength,\r
+ (struct sockaddr *)&Addr,\r
+ &SkipBytes );\r
+ *pDataLength += DataLength;\r
+ BufferLength -= DataLength;\r
+\r
+ //\r
+ // Determine if the data is being read\r
+ //\r
+ pNextPacket = pPacket->pNext;\r
+ if ( bConsumePacket ) {\r
+ //\r
+ // All done with this packet\r
+ // Account for any discarded data\r
+ //\r
+ pSocket->pApi->pfnPacketFree ( pPacket, pRxDataBytes );\r
+ if ( 0 != SkipBytes ) {\r
+ DEBUG (( DEBUG_RX,\r
+ "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",\r
+ pPort,\r
+ SkipBytes ));\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 the receive operation if necessary\r
+ //\r
+ if (( NULL != pPort->pRxFree )\r
+ && ( MAX_RX_DATA > pSocket->RxBytes )) {\r
+ EslSocketRxStart ( pPort );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Get the next packet\r
+ //\r
+ pPacket = pNextPacket;\r
+ } while (( SOCK_STREAM == pSocket->Type )\r
+ && ( NULL != pPacket )\r
+ && ( 0 < BufferLength ));\r
+\r
+ //\r
+ // Successful operation\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ pSocket->errno = 0;\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
+ pSocket->RxError = EFI_SUCCESS;\r
+ switch ( Status ) {\r
+ default:\r
+ pSocket->errno = EIO;\r
+ break;\r
+\r
+ case EFI_CONNECTION_FIN:\r
+ //\r
+ // Continue to return zero bytes received when the\r
+ // peer has successfully closed the connection\r
+ //\r
+ pSocket->RxError = EFI_CONNECTION_FIN;\r
+ *pDataLength = 0;\r
+ pSocket->errno = 0;\r
+ Status = EFI_SUCCESS;\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
+ }\r
+ else {\r
+ Status = EFI_NOT_READY;\r
+ pSocket->errno = EAGAIN;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
+\r
+ if (( !EFI_ERROR ( Status )) && ( NULL != pAddress )) {\r
+ //\r
+ // Return the remote address if requested, truncate if necessary\r
+ //\r
+ AddressLength = pRemoteAddress->sa_len;\r
+ if ( AddressLength > *pAddressLength ) {\r
+ AddressLength = *pAddressLength;\r
+ }\r
+ DEBUG (( DEBUG_RX,\r
+ "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength, pAddress ));\r
+ ZeroMem ( pAddress, *pAddressLength );\r
+ CopyMem ( pAddress, &Addr, AddressLength );\r
+\r
+ //\r
+ // Update the address length\r
+ //\r
+ *pAddressLength = pRemoteAddress->sa_len;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+\r
+ }\r
+ else {\r
+ //\r
+ // Bad return address pointer and length\r
+ //\r
+ Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = EINVAL;\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
+ Status = EFI_INVALID_PARAMETER;\r
+ *pErrno = ENOTSOCK;\r
+ }\r
+ }\r
DBG_EXIT_STATUS ( Status );\r
return Status;\r
}\r
\r
\r
-/**\r
- Free a packet used for receive or transmit operation\r
+/** Cancel the receive operations.\r
\r
- @param [in] pPacket Address of the DT_PACKET structure\r
- @param [in] DebugFlags Flags for debug messages\r
+ This routine cancels a pending receive operation.\r
+ See the \ref ReceiveEngine section.\r
\r
- @retval EFI_SUCCESS - The packet was allocated successfully\r
+ This routine is called by ::EslSocketShutdown when the socket\r
+ layer is being shutdown.\r
\r
- **/\r
-EFI_STATUS\r
-EslSocketPacketFree (\r
- IN DT_PACKET * pPacket,\r
- IN UINTN DebugFlags\r
+ @param[in] pPort Address of an ::ESL_PORT structure\r
+ @param[in] pIo Address of an ::ESL_IO_MGMT structure\r
+**/\r
+VOID\r
+EslSocketRxCancel (\r
+ IN ESL_PORT * pPort,\r
+ IN ESL_IO_MGMT * pIo\r
)\r
{\r
- UINTN LengthInBytes;\r
EFI_STATUS Status;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Allocate a packet structure\r
+ // Cancel the outstanding receive\r
//\r
- LengthInBytes = pPacket->PacketSize;\r
- Status = gBS->FreePool ( pPacket );\r
+ Status = pPort->pfnRxCancel ( pPort->pProtocol.v,\r
+ &pIo->Token );\r
if ( !EFI_ERROR ( Status )) {\r
- DEBUG (( DebugFlags | DEBUG_POOL,\r
- "0x%08x: Free pPacket, %d bytes\r\n",\r
- pPacket,\r
- LengthInBytes ));\r
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet receive aborted on port: 0x%08x\r\n",\r
+ pIo->pPacket,\r
+ pPort ));\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
+ DEBUG (( pPort->DebugFlags | DEBUG_CLOSE | DEBUG_INFO,\r
+ "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",\r
+ pIo->pPacket,\r
+ pPort,\r
Status ));\r
}\r
-\r
- //\r
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
+ DBG_EXIT ( );\r
}\r
\r
\r
-/**\r
- Poll a socket for pending activity.\r
+/** Process the receive completion.\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
+ 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
- @param [in] pSocketProtocol Address of the socket protocol structure.\r
-\r
- @param [in] Events Events of interest for this socket\r
+ This routine is called when some data is received by:\r
+ <ul>\r
+ <li>::EslIp4RxComplete</li>\r
+ <li>::EslTcp4RxComplete</li>\r
+ <li>::EslUdp4RxComplete</li>\r
+ </ul>\r
\r
- @param [in] pEvents Address to receive the detected events\r
+ @param[in] pIo Address of an ::ESL_IO_MGMT structure\r
+ @param[in] Status Receive status\r
+ @param[in] LengthInBytes Length of the receive data\r
+ @param[in] bUrgent TRUE if urgent data is received and FALSE\r
+ for normal data.\r
+**/\r
+VOID\r
+EslSocketRxComplete (\r
+ IN ESL_IO_MGMT * pIo,\r
+ IN EFI_STATUS Status,\r
+ IN UINTN LengthInBytes,\r
+ IN BOOLEAN bUrgent\r
+ )\r
+{\r
+ BOOLEAN bUrgentQueue;\r
+ ESL_IO_MGMT * pIoNext;\r
+ ESL_PACKET * pPacket;\r
+ ESL_PORT * pPort;\r
+ ESL_PACKET * pPrevious;\r
+ ESL_PACKET ** ppQueueHead;\r
+ ESL_PACKET ** ppQueueTail;\r
+ size_t * pRxBytes;\r
+ ESL_SOCKET * pSocket;\r
\r
- @param [out] pErrno Address to receive the errno value upon completion.\r
+ DBG_ENTER ( );\r
+ VERIFY_AT_TPL ( TPL_SOCKETS );\r
\r
- @retval EFI_SUCCESS - Socket successfully polled\r
- @retval EFI_INVALID_PARAMETER - When pEvents is NULL\r
+ //\r
+ // Locate the active receive packet\r
+ //\r
+ pPacket = pIo->pPacket;\r
+ pPort = pIo->pPort;\r
+ pSocket = pPort->pSocket;\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
+ // pPort->pRxActive\r
+ // |\r
+ // V\r
+ // +-------------+ +-------------+ +-------------+\r
+ // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ // +-------------+ +-------------+ +-------------+\r
+ //\r
+ // +-------------+ +-------------+ +-------------+\r
+ // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ // +-------------+ +-------------+ +-------------+\r
+ // ^\r
+ // |\r
+ // pPort->pRxFree\r
+ //\r
+ //\r
+ // Remove the IO structure from the active list\r
+ // The following code searches for the entry in the list and does not\r
+ // assume that the receive operations complete in the order they were\r
+ // issued to the UEFI network layer.\r
+ //\r
+ pIoNext = pPort->pRxActive;\r
+ while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))\r
+ {\r
+ pIoNext = pIoNext->pNext;\r
+ }\r
+ ASSERT ( NULL != pIoNext );\r
+ if ( pIoNext == pIo ) {\r
+ pPort->pRxActive = pIo->pNext; // Beginning of list\r
+ }\r
+ else {\r
+ pIoNext->pNext = pIo->pNext; // Middle of list\r
+ }\r
\r
- DEBUG (( DEBUG_POLL, "Entering SocketPoll\r\n" ));\r
+ //\r
+ // Free the IO structure\r
+ //\r
+ pIo->pNext = pPort->pRxFree;\r
+ pPort->pRxFree = pIo;\r
\r
//\r
- // Assume success\r
+ // pRxOobPacketListHead pRxOobPacketListTail\r
+ // | |\r
+ // V V\r
+ // +------------+ +------------+ +------------+\r
+ // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
+ // +------------+ +------------+ +------------+\r
//\r
- Status = EFI_SUCCESS;\r
- DetectedEvents = 0;\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
- pSocket->errno = 0;\r
+ // +------------+ +------------+ +------------+\r
+ // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
+ // +------------+ +------------+ +------------+\r
+ // ^ ^\r
+ // | |\r
+ // pRxPacketListHead pRxPacketListTail\r
+ //\r
+ //\r
+ // Determine the queue to use\r
+ //\r
+ bUrgentQueue = (BOOLEAN)( bUrgent\r
+ && pSocket->pApi->bOobSupported\r
+ && ( !pSocket->bOobInLine ));\r
+ if ( bUrgentQueue ) {\r
+ ppQueueHead = &pSocket->pRxOobPacketListHead;\r
+ ppQueueTail = &pSocket->pRxOobPacketListTail;\r
+ pRxBytes = &pSocket->RxOobBytes;\r
+ }\r
+ else {\r
+ ppQueueHead = &pSocket->pRxPacketListHead;\r
+ ppQueueTail = &pSocket->pRxPacketListTail;\r
+ pRxBytes = &pSocket->RxBytes;\r
+ }\r
\r
//\r
- // Verify the socket state\r
+ // Determine if this receive was successful\r
//\r
- if ( !pSocket->bConfigured ) {\r
+ if (( !EFI_ERROR ( Status ))\r
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )\r
+ && ( !pSocket->bRxDisable )) {\r
//\r
- // Synchronize with the socket layer\r
+ // Account for the received data\r
//\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+ *pRxBytes += LengthInBytes;\r
\r
//\r
- // Validate the local address\r
+ // Log the received data\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
+ DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+ "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",\r
+ pPacket,\r
+ bUrgentQueue ? L"urgent" : L"normal",\r
+ pPort,\r
+ LengthInBytes,\r
+ bUrgent ? L"urgent" : L"normal" ));\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
+ // Add the packet to the list tail.\r
+ //\r
+ pPacket->pNext = NULL;\r
+ pPrevious = *ppQueueTail;\r
+ if ( NULL == pPrevious ) {\r
+ *ppQueueHead = pPacket;\r
+ }\r
+ else {\r
+ pPrevious->pNext = pPacket;\r
+ }\r
+ *ppQueueTail = pPacket;\r
\r
- case SOCK_STREAM:\r
- case SOCK_SEQPACKET:\r
- //\r
- // Verify the port state\r
- //\r
- Status = EslTcpSocketIsConfigured4 ( pSocket );\r
- break;\r
+ //\r
+ // Attempt to restart this receive operation\r
+ //\r
+ if ( pSocket->MaxRxBuf > pSocket->RxBytes ) {\r
+ EslSocketRxStart ( pPort );\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_RX,\r
+ "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",\r
+ pPort,\r
+ pSocket->RxBytes ));\r
+ }\r
+ }\r
+ else {\r
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+ "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",\r
+ pPort,\r
+ pPacket,\r
+ Status ));\r
+ }\r
\r
- case SOCK_DGRAM:\r
- //\r
- // Verify the port state\r
- //\r
- Status = EslUdpSocketIsConfigured4 ( pSocket );\r
- break;\r
- }\r
- break;\r
+ //\r
+ // Account for the receive bytes and release the driver's buffer\r
+ //\r
+ if ( !EFI_ERROR ( Status )) {\r
+ *pRxBytes += LengthInBytes;\r
+ pSocket->pApi->pfnPacketFree ( pPacket, pRxBytes );\r
}\r
\r
//\r
- // Release the socket layer synchronization\r
+ // Receive error, free the packet save the error\r
//\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- if ( !EFI_ERROR ( Status )) {\r
+ EslSocketPacketFree ( pPacket, DEBUG_RX );\r
+ if ( !EFI_ERROR ( pSocket->RxError )) {\r
+ pSocket->RxError = Status;\r
+ }\r
+\r
//\r
- // Check for invalid events\r
+ // Update the port state\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
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
+ if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
+ EslSocketPortCloseRxDone ( pPort );\r
+ }\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
+ if ( EFI_ERROR ( Status )) {\r
+ DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+ "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",\r
+ pPort,\r
+ Status ));\r
+ pPort->State = PORT_STATE_RX_ERROR;\r
}\r
+ }\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
+ DBG_EXIT ( );\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
+/** Poll a socket for pending receive activity.\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
+ This routine is called at elivated TPL and extends the idle\r
+ loop which polls a socket down into the LAN driver layer to\r
+ determine if there is any receive activity.\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
+ The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit\r
+ routines call this routine when there is nothing to do.\r
\r
- //\r
- // Handle the transmit error\r
- //\r
- if ( EFI_ERROR ( pSocket->TxError )) {\r
- DetectedEvents |= POLLERR;\r
- }\r
- }\r
- }\r
+ @param[in] pSocket Address of an ::EFI_SOCKET structure.\r
+ **/\r
+VOID\r
+EslSocketRxPoll (\r
+ IN ESL_SOCKET * pSocket\r
+ )\r
+{\r
+ ESL_PORT * pPort;\r
\r
- //\r
- // Return the detected events\r
- //\r
- *pEvents = DetectedEvents & ( Events\r
- | POLLERR\r
- | POLLHUP\r
- | POLLNVAL );\r
+ DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));\r
\r
//\r
- // Return the operation status\r
+ // Increase the network performance by extending the\r
+ // polling (idle) loop down into the LAN driver\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
+ pPort = pSocket->pPortList;\r
+ while ( NULL != pPort ) {\r
+ //\r
+ // Poll the LAN adapter\r
+ //\r
+ pPort->pfnRxPoll ( pPort->pProtocol.v );\r
\r
+ //\r
+ // Locate the next LAN adapter\r
+ //\r
+ pPort = pPort->pLinkSocket;\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
+ DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));\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
+/** Start a receive operation.\r
\r
- @param [out] pErrno Address to receive the errno value upon completion.\r
+ This routine posts a receive buffer to the network adapter.\r
+ See the \ref ReceiveEngine section.\r
\r
- @retval EFI_SUCCESS - Socket data successfully received\r
+ This support routine is called by:\r
+ <ul>\r
+ <li>::EslIp4Receive to restart the receive engine to release flow control.</li>\r
+ <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
+ <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>\r
+ <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>\r
+ <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>\r
+ <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
+ <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>\r
+ <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>\r
+ <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>\r
+ </ul>\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
+ @param[in] pPort Address of an ::ESL_PORT structure.\r
+**/\r
+VOID\r
+EslSocketRxStart (\r
+ IN ESL_PORT * pPort\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ UINT8 * pBuffer;\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_PACKET * pPacket;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
\r
DBG_ENTER ( );\r
\r
//\r
- // Assume success\r
+ // Determine if a receive is already pending\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
- // Return the transmit error if necessary\r
- //\r
- if ( EFI_SUCCESS != pSocket->TxError ) {\r
- pSocket->errno = EIO;\r
- Status = pSocket->TxError;\r
- pSocket->TxError = EFI_SUCCESS;\r
- }\r
- else {\r
+ pPacket = NULL;\r
+ pSocket = pPort->pSocket;\r
+ if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
+ if (( NULL != pPort->pRxFree )\r
+ && ( !pSocket->bRxDisable )\r
+ && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
//\r
- // Verify the socket state\r
+ // Start all of the pending receive operations\r
//\r
- if ( !pSocket->bConfigured ) {\r
+ while ( NULL != pPort->pRxFree ) {\r
//\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
+ // Determine if there are any free packets\r
//\r
- // Validate the local address\r
- //\r
- switch ( pSocket->Domain ) {\r
- default:\r
+ pPacket = pSocket->pRxFree;\r
+ if ( NULL != pPacket ) {\r
+ //\r
+ // Remove this packet from the free list\r
+ //\r
+ pSocket->pRxFree = pPacket->pNext;\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
+ "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
+ pPort,\r
+ pPacket ));\r
+ }\r
+ else {\r
//\r
- // Determine the connection point within the network stack\r
+ // Allocate a packet structure\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
+ Status = EslSocketPacketAllocate ( &pPacket,\r
+ pSocket->pApi->RxPacketBytes,\r
+ pSocket->pApi->RxZeroBytes,\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
break;\r
}\r
- break;\r
}\r
\r
//\r
- // Release the socket layer synchronization\r
+ // Connect the IO and packet structures\r
//\r
- RESTORE_TPL ( TplPrevious );\r
+ pIo = pPort->pRxFree;\r
+ pIo->pPacket = pPacket;\r
\r
//\r
- // Set errno if a failure occurs\r
+ // Eliminate the need for IP4 and UDP4 specific routines by\r
+ // clearing the RX data pointer here.\r
//\r
- if ( EFI_ERROR ( Status )) {\r
- pSocket->errno = EADDRNOTAVAIL;\r
- }\r
- }\r
- if ( !EFI_ERROR ( Status )) {\r
+ // No driver buffer for this packet\r
//\r
- // Validate the buffer length\r
+ // +--------------------+\r
+ // | ESL_IO_MGMT |\r
+ // | |\r
+ // | +---------------+\r
+ // | | Token |\r
+ // | | RxData --> NULL\r
+ // +----+---------------+\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
+ pBuffer = (UINT8 *)pIo;\r
+ pBuffer = &pBuffer[ pSocket->pApi->RxBufferOffset ];\r
+ *(VOID **)pBuffer = NULL;\r
+\r
+ //\r
+ // Network specific receive packet initialization\r
+ //\r
+ if ( NULL != pSocket->pApi->pfnRxStart ) {\r
+ pSocket->pApi->pfnRxStart ( pPort, pIo );\r
}\r
- else{\r
+\r
+ //\r
+ // Start the receive on the packet\r
+ //\r
+ Status = pPort->pfnRxStart ( pPort->pProtocol.v, &pIo->Token );\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
- // Synchronize with the socket layer\r
+ // Allocate the receive control structure\r
//\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
+ pPort->pRxFree = pIo->pNext;\r
\r
//\r
- // Validate the local address\r
+ // Mark this receive as pending\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
+ pIo->pNext = pPort->pRxActive;\r
+ pPort->pRxActive = pIo;\r
\r
- case AF_INET:\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
+ if ( !EFI_ERROR ( pSocket->RxError )) {\r
//\r
- // Determine the connection point within the network stack\r
+ // Save the error status\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
+ pSocket->RxError = Status;\r
}\r
\r
//\r
- // Release the socket layer synchronization\r
+ // Free the packet\r
//\r
- RESTORE_TPL ( TplPrevious );\r
+ pIo->pPacket = NULL;\r
+ pPacket->pNext = pSocket->pRxFree;\r
+ pSocket->pRxFree = pPacket;\r
+ break;\r
}\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
+ else {\r
+ if ( NULL == pPort->pRxFree ) {\r
+ DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+ "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",\r
+ pPort));\r
+ }\r
+ if ( pSocket->bRxDisable ) {\r
+ DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+ "0x%08x: Port, receive disabled!\r\n",\r
+ pPort ));\r
+ }\r
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
+ DEBUG (( DEBUG_RX | DEBUG_INFO,\r
+ "0x%08x: Port, is closing!\r\n",\r
+ pPort ));\r
+ }\r
}\r
}\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
+ else {\r
+ DEBUG (( DEBUG_ERROR | DEBUG_RX,\r
+ "ERROR - Previous receive error, Status: %r\r\n",\r
+ pPort->pSocket->RxError ));\r
+ }\r
+\r
+ DBG_EXIT ( );\r
}\r
\r
\r
-/**\r
- Shutdown the socket receive and transmit operations\r
+/** Shutdown the socket receive and transmit operations.\r
\r
- The SocketShutdown routine stops the socket receive and transmit\r
- operations.\r
+ This routine sets a flag to stop future transmissions and calls\r
+ the network specific layer to cancel the pending receive operation.\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
+ The ::shutdown routine calls this routine to stop receive and transmit\r
+ operations on the socket.\r
\r
- @retval EFI_SUCCESS - Socket operations successfully shutdown\r
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[in] How Which operations to stop\r
+ @param[out] pErrno Address to receive the errno value upon completion.\r
\r
- **/\r
+ @retval EFI_SUCCESS - Socket operations successfully shutdown\r
+**/\r
EFI_STATUS\r
EslSocketShutdown (\r
IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
IN int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\r
- \r
+\r
DBG_ENTER ( );\r
- \r
+\r
//\r
// Assume success\r
//\r
}\r
\r
//\r
- // Validate the local address\r
+ // Cancel the pending receive operations\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
+ if ( pSocket->bRxDisable ) {\r
//\r
- // Determine the connection point within the network stack\r
+ // Walk the list of ports\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
+ pPort = pSocket->pPortList;\r
+ while ( NULL != pPort ) {\r
//\r
- // Cancel the pending receive operation\r
+ // Walk the list of active receive operations\r
//\r
- Status = EslTcpRxCancel4 ( pSocket );\r
- break;\r
- \r
- case SOCK_DGRAM:\r
+ pIo = pPort->pRxActive;\r
+ while ( NULL != pIo ) {\r
+ EslSocketRxCancel ( pPort, pIo );\r
+ }\r
+\r
//\r
- // Cancel the pending receive operation\r
+ // Set the next port\r
//\r
- Status = EslUdpRxCancel4 ( pSocket );\r
- break;\r
+ pPort = pPort->pLinkSocket;\r
}\r
- break;\r
}\r
- \r
+\r
//\r
// Release the socket layer synchronization\r
//\r
}\r
else {\r
//\r
- // The socket is not connected\r
+ // Invalid How value\r
//\r
- pSocket->errno = ENOTCONN;\r
- Status = EFI_NOT_STARTED;\r
+ pSocket->errno = EINVAL;\r
+ Status = EFI_INVALID_PARAMETER;\r
}\r
}\r
else {\r
//\r
- // Invalid How value\r
+ // The socket is not connected\r
//\r
- pSocket->errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
+ pSocket->errno = ENOTCONN;\r
+ Status = EFI_NOT_STARTED;\r
}\r
}\r
\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\r
Status = EFI_INVALID_PARAMETER;\r
- *pErrno = EBADF;\r
+ *pErrno = ENOTSOCK;\r
}\r
}\r
DBG_EXIT_STATUS ( 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
+/** Send data using a 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
+ This routine calls the network specific layer to queue the data\r
+ for transmission. Eventually the buffer will reach the head of\r
+ the queue and will get transmitted over the network by the\r
+ \ref TransmitEngine. For datagram\r
+ sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that\r
+ the data reaches the application running on the remote system.\r
\r
- @param [in] pAddress Network address of the remote system address\r
+ The ::sendto routine calls this routine to send data to the remote\r
+ system. Note that ::send and ::write are layered on top of ::sendto.\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
+ @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.\r
+ @param[in] Flags Message control flags\r
+ @param[in] BufferLength Length of the the buffer\r
+ @param[in] pBuffer Address of a buffer containing the data to send\r
+ @param[in] pDataLength Address to receive the number of data bytes sent\r
+ @param[in] pAddress Network address of the remote system address\r
+ @param[in] AddressLength Length of the remote network address structure\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
+**/\r
EFI_STATUS\r
EslSocketTransmit (\r
IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
IN int * pErrno\r
)\r
{\r
- DT_SOCKET * pSocket;\r
+ ESL_SOCKET * pSocket;\r
EFI_STATUS Status;\r
EFI_TPL TplPrevious;\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
+ Status = EslSocketIsConfigured ( pSocket );\r
if ( !EFI_ERROR ( Status )) {\r
//\r
// Verify that transmit is still allowed\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
+ // Verify the API\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
+ if ( NULL == pSocket->pApi->pfnTransmit ) {\r
+ Status = EFI_UNSUPPORTED;\r
+ pSocket->errno = ENOTSUP;\r
+ }\r
+ else {\r
+ //\r
+ // Synchronize with the socket layer\r
+ //\r
+ RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
\r
- case AF_INET:\r
//\r
- // Determine the connection point within the network stack\r
+ // Poll the network to increase performance\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
+ EslSocketRxPoll ( pSocket );\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
+ // Attempt to buffer the packet for transmission\r
+ //\r
+ Status = pSocket->pApi->pfnTransmit ( pSocket,\r
+ Flags,\r
+ BufferLength,\r
+ pBuffer,\r
+ pDataLength,\r
+ pAddress,\r
+ AddressLength );\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
+ // Release the socket layer synchronization\r
+ //\r
+ RESTORE_TPL ( TplPrevious );\r
}\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
}\r
}\r
}\r
if ( NULL != pSocket ) {\r
*pErrno = pSocket->errno;\r
}\r
- else\r
- {\r
+ else {\r
Status = EFI_INVALID_PARAMETER;\r
- *pErrno = EBADF;\r
+ *pErrno = ENOTSOCK;\r
}\r
}\r
DBG_EXIT_STATUS ( Status );\r
}\r
\r
\r
-/**\r
- Socket layer's service binding protocol delcaration.\r
+/** Complete the transmit operation.\r
+\r
+ This support routine handles the transmit completion processing for\r
+ the various network layers. It frees the ::ESL_IO_MGMT structure\r
+ and and frees packet resources by calling ::EslSocketPacketFree.\r
+ Transmit errors are logged in ESL_SOCKET::TxError.\r
+ See the \ref TransmitEngine section.\r
+\r
+ This routine is called by:\r
+ <ul>\r
+ <li>::EslIp4TxComplete</li>\r
+ <li>::EslTcp4TxComplete</li>\r
+ <li>::EslTcp4TxOobComplete</li>\r
+ <li>::EslUdp4TxComplete</li>\r
+ </ul>\r
+\r
+ @param[in] pIo Address of an ::ESL_IO_MGMT structure\r
+ @param[in] LengthInBytes Length of the data in bytes\r
+ @param[in] Status Transmit operation status\r
+ @param[in] pQueueType Zero terminated string describing queue type\r
+ @param[in] ppQueueHead Transmit queue head address\r
+ @param[in] ppQueueTail Transmit queue tail address\r
+ @param[in] ppActive Active transmit queue address\r
+ @param[in] ppFree Free transmit queue address\r
+**/\r
+VOID\r
+EslSocketTxComplete (\r
+ IN ESL_IO_MGMT * pIo,\r
+ IN UINT32 LengthInBytes,\r
+ IN EFI_STATUS Status,\r
+ IN CONST CHAR8 * pQueueType,\r
+ IN ESL_PACKET ** ppQueueHead,\r
+ IN ESL_PACKET ** ppQueueTail,\r
+ IN ESL_IO_MGMT ** ppActive,\r
+ IN ESL_IO_MGMT ** ppFree\r
+ )\r
+{\r
+ ESL_PACKET * pCurrentPacket;\r
+ ESL_IO_MGMT * pIoNext;\r
+ ESL_PACKET * pNextPacket;\r
+ ESL_PACKET * pPacket;\r
+ ESL_PORT * pPort;\r
+ ESL_SOCKET * pSocket;\r
+\r
+ DBG_ENTER ( );\r
+ VERIFY_AT_TPL ( TPL_SOCKETS );\r
+\r
+ //\r
+ // Locate the active transmit packet\r
+ //\r
+ pPacket = pIo->pPacket;\r
+ pPort = pIo->pPort;\r
+ pSocket = pPort->pSocket;\r
+\r
+ //\r
+ // No more packet\r
+ //\r
+ pIo->pPacket = NULL;\r
+\r
+ //\r
+ // Remove the IO structure from the active list\r
+ //\r
+ pIoNext = *ppActive;\r
+ while (( NULL != pIoNext ) && ( pIoNext != pIo ) && ( pIoNext->pNext != pIo ))\r
+ {\r
+ pIoNext = pIoNext->pNext;\r
+ }\r
+ ASSERT ( NULL != pIoNext );\r
+ if ( pIoNext == pIo ) {\r
+ *ppActive = pIo->pNext; // Beginning of list\r
+ }\r
+ else {\r
+ pIoNext->pNext = pIo->pNext; // Middle of list\r
+ }\r
+\r
+ //\r
+ // Free the IO structure\r
+ //\r
+ pIo->pNext = *ppFree;\r
+ *ppFree = pIo;\r
+\r
+ //\r
+ // Display the results\r
+ //\r
+ DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+ "0x%08x: pIo Released\r\n",\r
+ pIo ));\r
+\r
+ //\r
+ // Save any transmit error\r
+ //\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 %apacket 0x%08x, Status: %r\r\n",\r
+ pQueueType,\r
+ pPacket,\r
+ Status ));\r
+\r
+ //\r
+ // Empty the normal transmit list\r
+ //\r
+ pCurrentPacket = pPacket;\r
+ pNextPacket = *ppQueueHead;\r
+ while ( NULL != pNextPacket ) {\r
+ pPacket = pNextPacket;\r
+ pNextPacket = pPacket->pNext;\r
+ EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+ }\r
+ *ppQueueHead = NULL;\r
+ *ppQueueTail = NULL;\r
+ pPacket = pCurrentPacket;\r
+ }\r
+ else {\r
+ DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+ "0x%08x: %apacket transmitted %d bytes successfully\r\n",\r
+ pPacket,\r
+ pQueueType,\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
+ EslSocketTxStart ( pPort,\r
+ ppQueueHead,\r
+ ppQueueTail,\r
+ ppActive,\r
+ ppFree );\r
+ }\r
+ }\r
+\r
+ //\r
+ // Release this packet\r
+ //\r
+ EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+\r
+ //\r
+ // Finish the close operation if necessary\r
+ //\r
+ if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
+ //\r
+ // Indicate that the transmit is complete\r
+ //\r
+ EslSocketPortCloseTxDone ( pPort );\r
+ }\r
+\r
+ DBG_EXIT ( );\r
+}\r
+\r
+\r
+/** Transmit data using a network connection.\r
+\r
+ This support routine starts a transmit operation on the\r
+ underlying network layer.\r
+\r
+ The network specific code calls this routine to start a\r
+ transmit operation. See the \ref TransmitEngine section.\r
+\r
+ @param[in] pPort Address of an ::ESL_PORT structure\r
+ @param[in] ppQueueHead Transmit queue head address\r
+ @param[in] ppQueueTail Transmit queue tail address\r
+ @param[in] ppActive Active transmit queue address\r
+ @param[in] ppFree Free transmit queue address\r
**/\r
-EFI_SERVICE_BINDING_PROTOCOL mEfiServiceBinding = {\r
- EslSocketCreateChild,\r
- EslSocketDestroyChild\r
-};\r
+VOID\r
+EslSocketTxStart (\r
+ IN ESL_PORT * pPort,\r
+ IN ESL_PACKET ** ppQueueHead,\r
+ IN ESL_PACKET ** ppQueueTail,\r
+ IN ESL_IO_MGMT ** ppActive,\r
+ IN ESL_IO_MGMT ** ppFree\r
+ )\r
+{\r
+ UINT8 * pBuffer;\r
+ ESL_IO_MGMT * pIo;\r
+ ESL_PACKET * pNextPacket;\r
+ ESL_PACKET * pPacket;\r
+ VOID ** ppTokenData;\r
+ ESL_SOCKET * pSocket;\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
+ pIo = *ppFree;\r
+ if (( NULL != pPacket ) && ( NULL != pIo )) {\r
+ pSocket = pPort->pSocket;\r
+ //\r
+ // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead\r
+ // |\r
+ // V\r
+ // +------------+ +------------+ +------------+\r
+ // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
+ // +------------+ +------------+ +------------+\r
+ // ^\r
+ // |\r
+ // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail\r
+ //\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
+ pPacket->pNext = NULL;\r
+\r
+ //\r
+ // Eliminate the need for IP4 and UDP4 specific routines by\r
+ // connecting the token with the TX data control structure here.\r
+ //\r
+ // +--------------------+ +--------------------+\r
+ // | ESL_IO_MGMT | | ESL_PACKET |\r
+ // | | | |\r
+ // | +---------------+ +----------------+ |\r
+ // | | Token | | Buffer Length | |\r
+ // | | TxData --> | Buffer Address | |\r
+ // | | | +----------------+---+\r
+ // | | Event | | Data Buffer |\r
+ // +----+---------------+ | |\r
+ // +--------------------+\r
+ //\r
+ // Compute the address of the TxData pointer in the token\r
+ //\r
+ pBuffer = (UINT8 *)&pIo->Token;\r
+ pBuffer = &pBuffer[ pSocket->TxTokenOffset ];\r
+ ppTokenData = (VOID **)pBuffer;\r
+\r
+ //\r
+ // Compute the address of the TX data control structure in the packet\r
+ //\r
+ // * EFI_IP4_TRANSMIT_DATA\r
+ // * EFI_TCP4_TRANSMIT_DATA\r
+ // * EFI_UDP4_TRANSMIT_DATA\r
+ //\r
+ pBuffer = (UINT8 *)pPacket;\r
+ pBuffer = &pBuffer[ pSocket->TxPacketOffset ];\r
+\r
+ //\r
+ // Connect the token to the transmit data control structure\r
+ //\r
+ *ppTokenData = (VOID **)pBuffer;\r
+\r
+ //\r
+ // Display the results\r
+ //\r
+ DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+ "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",\r
+ pIo,\r
+ pPacket ));\r
+\r
+ //\r
+ // Start the transmit operation\r
+ //\r
+ Status = pPort->pfnTxStart ( pPort->pProtocol.v,\r
+ &pIo->Token );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Connect the structures\r
+ //\r
+ pIo->pPacket = pPacket;\r
+\r
+ //\r
+ // +-------------+ +-------------+ +-------------+\r
+ // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ // +-------------+ +-------------+ +-------------+\r
+ // ^\r
+ // |\r
+ // *ppFree: pPort->pTxFree or pTxOobFree\r
+ //\r
+ //\r
+ // Remove the IO structure from the queue\r
+ //\r
+ *ppFree = pIo->pNext;\r
+\r
+ //\r
+ // *ppActive: pPort->pTxActive or pTxOobActive\r
+ // |\r
+ // V\r
+ // +-------------+ +-------------+ +-------------+\r
+ // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL\r
+ // +-------------+ +-------------+ +-------------+\r
+ //\r
+ //\r
+ // Mark this packet as active\r
+ //\r
+ pIo->pPacket = pPacket;\r
+ pIo->pNext = *ppActive;\r
+ *ppActive = pIo;\r
+ }\r
+ else {\r
+ //\r
+ // Display the transmit error\r
+ //\r
+ DEBUG (( DEBUG_TX | DEBUG_INFO,\r
+ "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",\r
+ pIo,\r
+ pPacket,\r
+ Status ));\r
+ if ( EFI_SUCCESS == pSocket->TxError ) {\r
+ pSocket->TxError = Status;\r
+ }\r
+\r
+ //\r
+ // Free the IO structure\r
+ //\r
+ pIo->pNext = *ppFree;\r
+ *ppFree = pIo;\r
+\r
+ //\r
+ // Discard the transmit buffer\r
+ //\r
+ EslSocketPacketFree ( pPacket, DEBUG_TX );\r
+ }\r
+ }\r
+\r
+ DBG_EXIT ( );\r
+}\r