+++ /dev/null
-/** @file\r
- Implement the socket support for the socket layer.\r
-\r
- Socket States:\r
- * Bound - pSocket->PortList is not NULL\r
- * Listen - AcceptWait event is not NULL\r
-\r
- Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
- SPDX-License-Identifier: BSD-2-Clause-Patent\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
-/** Socket driver connection points\r
-\r
- List the network stack connection points for the socket driver.\r
-**/\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
- 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
- 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
-/// 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
-EFI_STATUS\r
-EslSocket (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN int domain,\r
- IN int type,\r
- IN int protocol,\r
- IN int * pErrno\r
- )\r
-{\r
- 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
- // Locate the socket\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- // Set the default domain if necessary\r
- if ( AF_UNSPEC == domain ) {\r
- domain = AF_INET;\r
- }\r
-\r
- // Assume success\r
- errno = 0;\r
- Status = EFI_SUCCESS;\r
-\r
- // Use break instead of goto\r
- for ( ; ; ) {\r
- // Validate the domain value\r
- if (( AF_INET != domain )\r
- && ( AF_INET6 != domain )\r
- && ( AF_LOCAL != domain )) {\r
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
- "ERROR - Invalid domain value\r\n" ));\r
- Status = EFI_INVALID_PARAMETER;\r
- errno = EAFNOSUPPORT;\r
- break;\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
- if ( 0 == type ) {\r
- type = SOCK_STREAM;\r
- }\r
-\r
- // Validate the type value\r
- if (( type >= ApiArraySize )\r
- || ( NULL == ppApiArray )\r
- || ( NULL == ppApiArray[ type ])) {\r
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET,\r
- "ERROR - Invalid type value\r\n" ));\r
- // The socket type is not supported\r
- Status = EFI_INVALID_PARAMETER;\r
- errno = EPROTOTYPE;\r
- break;\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
- if (( pApi->DefaultProtocol != protocol )\r
- && ( SOCK_RAW != type )) {\r
- Status = EFI_INVALID_PARAMETER;\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
- // Save the socket attributes\r
- pSocket->pApi = pApi;\r
- pSocket->Domain = domain;\r
- pSocket->Type = type;\r
- pSocket->Protocol = protocol;\r
-\r
- // Done\r
- break;\r
- }\r
- // Return the operation status\r
- if ( NULL != pErrno ) {\r
- *pErrno = errno;\r
- }\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Accept a network connection.\r
-\r
- This routine calls the network specific layer to remove the next\r
- connection from the FIFO.\r
-\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] 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
- @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
-EFI_STATUS\r
-EslSocketAccept (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN struct sockaddr * pSockAddr,\r
- IN OUT socklen_t * pSockAddrLength,\r
- IN EFI_SOCKET_PROTOCOL ** ppSocketProtocol,\r
- IN int * pErrno\r
- )\r
-{\r
- ESL_SOCKET * pNewSocket;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- pNewSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Verify the API\r
- //\r
- if ( NULL == pSocket->pApi->pfnAccept ) {\r
- Status = EFI_UNSUPPORTED;\r
- pSocket->errno = ENOTSUP;\r
- }\r
- else {\r
- //\r
- // Validate the sockaddr\r
- //\r
- if (( NULL != pSockAddr )\r
- && ( NULL == pSockAddrLength )) {\r
- DEBUG (( DEBUG_ACCEPT,\r
- "ERROR - pSockAddr is NULL!\r\n" ));\r
- Status = EFI_INVALID_PARAMETER;\r
- pSocket->errno = EFAULT;\r
- }\r
- else {\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Verify that the socket is in the listen state\r
- //\r
- if ( SOCKET_STATE_LISTENING != pSocket->State ) {\r
- DEBUG (( DEBUG_ACCEPT,\r
- "ERROR - Socket is not listening!\r\n" ));\r
- if ( NULL == pSocket->pApi->pfnAccept ) {\r
- //\r
- // Socket does not support listen\r
- //\r
- pSocket->errno = EOPNOTSUPP;\r
- Status = EFI_UNSUPPORTED;\r
- }\r
- else {\r
- //\r
- // Socket supports listen, but not in listen state\r
- //\r
- pSocket->errno = EINVAL;\r
- Status = EFI_NOT_STARTED;\r
- }\r
- }\r
- else {\r
- //\r
- // Determine if a socket is available\r
- //\r
- if ( 0 == pSocket->FifoDepth ) {\r
- //\r
- // No connections available\r
- // Determine if any ports are available\r
- //\r
- if ( NULL == pSocket->pPortList ) {\r
- //\r
- // No ports available\r
- //\r
- Status = EFI_DEVICE_ERROR;\r
- pSocket->errno = EINVAL;\r
-\r
- //\r
- // Update the socket state\r
- //\r
- pSocket->State = SOCKET_STATE_NO_PORTS;\r
- }\r
- else {\r
- //\r
- // Ports are available\r
- // No connection requests at this time\r
- //\r
- Status = EFI_NOT_READY;\r
- pSocket->errno = EAGAIN;\r
- }\r
- }\r
- else {\r
-\r
- //\r
- // Attempt to accept the connection and\r
- // get the remote network address\r
- //\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
- // Account for this socket\r
- //\r
- pSocket->FifoDepth -= 1;\r
-\r
- //\r
- // Update the new socket's state\r
- //\r
- pNewSocket->State = SOCKET_STATE_CONNECTED;\r
- pNewSocket->bConfigured = TRUE;\r
- DEBUG (( DEBUG_ACCEPT,\r
- "0x%08x: Socket connected\r\n",\r
- pNewSocket ));\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- }\r
- }\r
-\r
- //\r
- // Return the new socket\r
- //\r
- if (( NULL != ppSocketProtocol )\r
- && ( NULL != pNewSocket )) {\r
- *ppSocketProtocol = &pNewSocket->SocketProtocol;\r
- }\r
-\r
- //\r
- // Return the operation status\r
- //\r
- if ( NULL != pErrno ) {\r
- if ( NULL != pSocket ) {\r
- *pErrno = pSocket->errno;\r
- }\r
- else {\r
- Status = EFI_INVALID_PARAMETER;\r
- *pErrno = ENOTSOCK;\r
- }\r
- }\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\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
- If it is NULL, then a new handle is created.\r
- If it is a pointer to an existing UEFI handle,\r
- then the protocol is added to the existing UEFI\r
- handle.\r
- @param[in] DebugFlags Flags for debug messages\r
- @param[in,out] ppSocket The buffer to receive 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 available to create\r
- the child\r
- @retval other The child handle was not created\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-EslSocketAllocate (\r
- IN OUT EFI_HANDLE * pChildHandle,\r
- IN UINTN DebugFlags,\r
- IN OUT ESL_SOCKET ** ppSocket\r
- )\r
-{\r
- UINTN LengthInBytes;\r
- ESL_LAYER * pLayer;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Create a socket structure\r
- //\r
- LengthInBytes = sizeof ( *pSocket );\r
- 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
- LengthInBytes ));\r
-\r
- //\r
- // Initialize the socket protocol\r
- //\r
- pSocket->Signature = SOCKET_SIGNATURE;\r
- pSocket->SocketProtocol.pfnAccept = EslSocketAccept;\r
- pSocket->SocketProtocol.pfnBind = EslSocketBind;\r
- pSocket->SocketProtocol.pfnClosePoll = EslSocketClosePoll;\r
- pSocket->SocketProtocol.pfnCloseStart = EslSocketCloseStart;\r
- pSocket->SocketProtocol.pfnConnect = EslSocketConnect;\r
- pSocket->SocketProtocol.pfnGetLocal = EslSocketGetLocalAddress;\r
- pSocket->SocketProtocol.pfnGetPeer = EslSocketGetPeerAddress;\r
- pSocket->SocketProtocol.pfnListen = EslSocketListen;\r
- pSocket->SocketProtocol.pfnOptionGet = EslSocketOptionGet;\r
- pSocket->SocketProtocol.pfnOptionSet = EslSocketOptionSet;\r
- pSocket->SocketProtocol.pfnPoll = EslSocketPoll;\r
- pSocket->SocketProtocol.pfnReceive = EslSocketReceive;\r
- pSocket->SocketProtocol.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
- // Install the socket protocol on the specified handle\r
- //\r
- Status = gBS->InstallMultipleProtocolInterfaces (\r
- pChildHandle,\r
- &gEfiSocketProtocolGuid,\r
- &pSocket->SocketProtocol,\r
- NULL\r
- );\r
- if ( !EFI_ERROR ( Status )) {\r
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT | DEBUG_INFO,\r
- "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",\r
- *pChildHandle ));\r
- pSocket->SocketProtocol.SocketHandle = *pChildHandle;\r
-\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Add this socket to the list\r
- //\r
- pLayer = &mEslLayer;\r
- pSocket->pNext = pLayer->pSocketList;\r
- pLayer->pSocketList = pSocket;\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
-\r
- //\r
- // Return the socket structure address\r
- //\r
- *ppSocket = pSocket;\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR | DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
- "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",\r
- *pChildHandle,\r
- Status ));\r
- }\r
-\r
- //\r
- // Release the socket if necessary\r
- //\r
- if ( EFI_ERROR ( Status )) {\r
- gBS->FreePool ( pSocket );\r
- DEBUG (( DebugFlags | DEBUG_POOL | DEBUG_INIT,\r
- "0x%08x: Free pSocket, %d bytes\r\n",\r
- pSocket,\r
- sizeof ( *pSocket )));\r
- pSocket = NULL;\r
- }\r
- }\r
- else {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- //\r
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Bind a name to a socket.\r
-\r
- This routine calls the network specific layer to save the network\r
- address of the local connection point.\r
-\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] 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
-EFI_STATUS\r
-EslSocketBind (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN CONST struct sockaddr * pSockAddr,\r
- IN socklen_t SockAddrLength,\r
- OUT int * pErrno\r
- )\r
-{\r
- 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
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Validate the structure pointer\r
- //\r
- 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
-\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
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\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
- // Create the port\r
- //\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
- //\r
- // Open the port\r
- //\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
- // Set the next service\r
- //\r
- pService = pService->pNext;\r
- }\r
-\r
- //\r
- // Verify that at least one network connection was found\r
- //\r
- if ( NULL != pSocket->pPortList ) {\r
- 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
- // 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
- //\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
-/** Test the bind configuration.\r
-\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
-EslSocketBindTest (\r
- IN ESL_PORT * pPort,\r
- IN int ErrnoValue\r
- )\r
-{\r
- UINT8 * pBuffer;\r
- VOID * pConfigData;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Locate the configuration data\r
- //\r
- pBuffer = (UINT8 *)pPort;\r
- pBuffer = &pBuffer [ pPort->pSocket->pApi->ConfigDataOffset ];\r
- pConfigData = (VOID *)pBuffer;\r
-\r
- //\r
- // Validate that the port is connected\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
- pLayer = &mEslLayer;\r
- pNextSocket = pLayer->pSocketList;\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
- while ( NULL != pNextSocket ) {\r
- if ( pNextSocket == pSocket ) {\r
- //\r
- // Determine if the socket is in the closing state\r
- //\r
- if ( SOCKET_STATE_CLOSED == pSocket->State ) {\r
- //\r
- // Walk the list of ports\r
- //\r
- if ( NULL == pSocket->pPortList ) {\r
- //\r
- // All the ports are closed\r
- // Close the WaitAccept event if necessary\r
- //\r
- if ( NULL != pSocket->WaitAccept ) {\r
- Status = gBS->CloseEvent ( pSocket->WaitAccept );\r
- if ( !EFI_ERROR ( Status )) {\r
- DEBUG (( DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
- "0x%08x: Closed WaitAccept event\r\n",\r
- pSocket->WaitAccept ));\r
- //\r
- // Return the transmit status\r
- //\r
- Status = pSocket->TxError;\r
- if ( EFI_ERROR ( Status )) {\r
- pSocket->errno = EIO;\r
- }\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR | DEBUG_SOCKET | DEBUG_CLOSE | DEBUG_POOL,\r
- "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",\r
- Status ));\r
- ASSERT ( EFI_SUCCESS == Status );\r
- }\r
- }\r
- }\r
- else {\r
- //\r
- // At least one port is still open\r
- //\r
- Status = EFI_NOT_READY;\r
- errno = EAGAIN;\r
- }\r
- }\r
- else {\r
- //\r
- // SocketCloseStart was not called\r
- //\r
- Status = EFI_NOT_STARTED;\r
- errno = EPERM;\r
- }\r
- break;\r
- }\r
-\r
- //\r
- // Set the next socket\r
- //\r
- pNextSocket = pNextSocket->pNext;\r
- }\r
-\r
- //\r
- // Handle the error case where the socket was already closed\r
- //\r
- if ( NULL == pSocket ) {\r
- //\r
- // Socket not found\r
- //\r
- Status = EFI_NOT_FOUND;\r
- errno = ENOTSOCK;\r
- }\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
-\r
- //\r
- // Return the operation status\r
- //\r
- if ( NULL != pErrno ) {\r
- *pErrno = errno;\r
- }\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Start the close operation on the socket.\r
-\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
- 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
-EFI_STATUS\r
-EslSocketCloseStart (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN BOOLEAN bCloseNow,\r
- IN int * pErrno\r
- )\r
-{\r
- int errno;\r
- ESL_PORT * pNextPort;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
- errno = 0;\r
-\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Determine if the socket is already closed\r
- //\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
- if ( SOCKET_STATE_CLOSED > pSocket->State ) {\r
- //\r
- // Update the socket state\r
- //\r
- pSocket->State = SOCKET_STATE_CLOSED;\r
-\r
- //\r
- // Walk the list of ports\r
- //\r
- pPort = pSocket->pPortList;\r
- while ( NULL != pPort ) {\r
- //\r
- // Start closing the ports\r
- //\r
- pNextPort = pPort->pLinkSocket;\r
- Status = 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
- break;\r
- }\r
-\r
- //\r
- // Set the next port\r
- //\r
- pPort = pNextPort;\r
- }\r
-\r
- //\r
- // Attempt to finish closing the socket\r
- //\r
- if ( NULL == pPort ) {\r
- Status = EslSocketClosePoll ( pSocketProtocol, &errno );\r
- }\r
- }\r
- else {\r
- Status = EFI_NOT_READY;\r
- errno = EAGAIN;\r
- }\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
-\r
- //\r
- // Return the operation status\r
- //\r
- if ( NULL != pErrno ) {\r
- *pErrno = errno;\r
- }\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Connect to a remote system via the network.\r
-\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
- 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 EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN const struct sockaddr * pSockAddr,\r
- IN socklen_t SockAddrLength,\r
- IN int * pErrno\r
- )\r
-{\r
- struct sockaddr_in6 LocalAddress;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DEBUG (( DEBUG_CONNECT, "Entering SocketConnect\r\n" ));\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Validate the name length\r
- //\r
- if ( SockAddrLength < ( sizeof ( struct sockaddr ) - sizeof ( pSockAddr->sa_data ))) {\r
- DEBUG (( DEBUG_CONNECT,\r
- "ERROR - Invalid bind name length: %d\r\n",\r
- SockAddrLength ));\r
- Status = EFI_INVALID_PARAMETER;\r
- pSocket->errno = EINVAL;\r
- }\r
- else {\r
- //\r
- // Assume success\r
- //\r
- pSocket->errno = 0;\r
-\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Validate the socket state\r
- //\r
- switch ( pSocket->State ) {\r
- default:\r
- //\r
- // Wrong socket state\r
- //\r
- pSocket->errno = EIO;\r
- Status = EFI_DEVICE_ERROR;\r
- break;\r
-\r
- case SOCKET_STATE_NOT_CONFIGURED:\r
- case SOCKET_STATE_BOUND:\r
- //\r
- // Validate the address length\r
- //\r
- if ( SockAddrLength >= pSocket->pApi->MinimumAddressLength ) {\r
- //\r
- // Verify the API\r
- //\r
- if ( NULL == pSocket->pApi->pfnRemoteAddrSet ) {\r
- //\r
- // Already connected\r
- //\r
- pSocket->errno = ENOTSUP;\r
- Status = EFI_UNSUPPORTED;\r
- }\r
- else {\r
- //\r
- // Determine if BIND was already called\r
- //\r
- if ( NULL == pSocket->pPortList ) {\r
- //\r
- // Allow any local port\r
- //\r
- ZeroMem ( &LocalAddress, sizeof ( LocalAddress ));\r
- LocalAddress.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
- 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
- //\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
- }\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
- // Poll the network adapter\r
- //\r
- EslSocketRxPoll ( pSocket );\r
-\r
- //\r
- // Poll for connection completion\r
- //\r
- if ( NULL == pSocket->pApi->pfnConnectPoll ) {\r
- //\r
- // Already connected\r
- //\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_BOUND;\r
- }\r
- }\r
- }\r
- break;\r
-\r
- case SOCKET_STATE_CONNECTED:\r
- //\r
- // Connected\r
- //\r
- Status = EFI_SUCCESS;\r
- break;\r
- }\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- }\r
-\r
- //\r
- // Return the operation status\r
- //\r
- if ( NULL != pErrno ) {\r
- if ( NULL != pSocket ) {\r
- *pErrno = pSocket->errno;\r
- }\r
- else {\r
- //\r
- // Bad socket protocol\r
- //\r
- DEBUG (( DEBUG_ERROR | DEBUG_CONNECT,\r
- "ERROR - pSocketProtocol invalid!\r\n" ));\r
- Status = EFI_INVALID_PARAMETER;\r
- *pErrno = ENOTSOCK;\r
- }\r
- }\r
-\r
- //\r
- // Return the operation status\r
- //\r
- DEBUG (( DEBUG_CONNECT, "Exiting SocketConnect, Status: %r\r\n", Status ));\r
- return Status;\r
-}\r
-\r
-\r
-/** Copy a fragmented buffer into a destination buffer.\r
-\r
- This support routine copies a fragmented buffer to the caller specified buffer.\r
-\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
-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
- size_t BytesToCopy;\r
- UINT32 Fragment;\r
- UINT8 * pBufferEnd;\r
- UINT8 * pData;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Validate the IP and UDP structures are identical\r
- //\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
- // Copy the received data\r
- //\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
-/** Free the socket.\r
-\r
- This routine frees the socket structure and handle resources.\r
-\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
- @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
-EslSocketFree (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN int * pErrno\r
- )\r
-{\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
- // 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
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Walk the socket list\r
- //\r
- pSocketPrevious = pLayer->pSocketList;\r
- if ( NULL != pSocketPrevious ) {\r
- if ( pSocket == pSocketPrevious ) {\r
- //\r
- // Remove the socket from the head of the list\r
- //\r
- pLayer->pSocketList = pSocket->pNext;\r
- }\r
- else {\r
- //\r
- // Find the socket in the middle of the list\r
- //\r
- while (( NULL != pSocketPrevious )\r
- && ( pSocket != pSocketPrevious->pNext )) {\r
- //\r
- // Set the next socket\r
- //\r
- pSocketPrevious = pSocketPrevious->pNext;\r
- }\r
- if ( NULL != pSocketPrevious ) {\r
- //\r
- // Remove the socket from the middle of the list\r
- //\r
- pSocketPrevious = pSocket->pNext;\r
- }\r
- }\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
- "ERROR - Socket list is empty!\r\n" ));\r
- }\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
-\r
- //\r
- // Determine if the socket was found\r
- //\r
- if ( NULL != pSocketPrevious ) {\r
- pSocket->pNext = NULL;\r
-\r
- //\r
- // Remove the socket protocol\r
- //\r
- ChildHandle = pSocket->SocketProtocol.SocketHandle;\r
- Status = gBS->UninstallMultipleProtocolInterfaces (\r
- ChildHandle,\r
- &gEfiSocketProtocolGuid,\r
- &pSocket->SocketProtocol,\r
- NULL );\r
- if ( !EFI_ERROR ( Status )) {\r
- DEBUG (( DEBUG_POOL | DEBUG_INFO,\r
- "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",\r
- ChildHandle ));\r
-\r
- //\r
- // Free the socket structure\r
- //\r
- Status = gBS->FreePool ( pSocket );\r
- if ( !EFI_ERROR ( Status )) {\r
- DEBUG (( DEBUG_POOL,\r
- "0x%08x: Free pSocket, %d bytes\r\n",\r
- pSocket,\r
- sizeof ( *pSocket )));\r
- errno = 0;\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR | DEBUG_POOL,\r
- "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",\r
- pSocket,\r
- Status ));\r
- }\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR | DEBUG_POOL | DEBUG_INFO,\r
- "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",\r
- ChildHandle,\r
- Status ));\r
- }\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR | DEBUG_INFO,\r
- "ERROR - The socket was not in the socket list!\r\n" ));\r
- Status = EFI_NOT_FOUND;\r
- }\r
- }\r
- else {\r
- DEBUG (( DEBUG_ERROR,\r
- "ERROR - 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
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Get the local address.\r
-\r
- This routine calls the network specific layer to get the network\r
- address of the local host connection point.\r
-\r
- The ::getsockname routine calls this routine to obtain the network\r
- address associated with the local host connection point.\r
-\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
-EFI_STATUS\r
-EslSocketGetLocalAddress (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- OUT struct sockaddr * pAddress,\r
- IN OUT socklen_t * pAddressLength,\r
- IN int * pErrno\r
- )\r
-{\r
- socklen_t LengthInBytes;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Verify the socket state\r
- //\r
- EslSocketIsConfigured ( pSocket );\r
- if ( pSocket->bAddressSet ) {\r
- //\r
- // Verify the address buffer and length address\r
- //\r
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
- //\r
- // Verify the API\r
- //\r
- if ( NULL == pSocket->pApi->pfnLocalAddrGet ) {\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 there is just a single connection\r
- //\r
- pPort = pSocket->pPortList;\r
- if ( NULL != pPort ) {\r
- //\r
- // Verify the address length\r
- //\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
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- }\r
- else {\r
- pSocket->errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
- }\r
- }\r
- else {\r
- //\r
- // Address not set\r
- //\r
- Status = EFI_NOT_STARTED;\r
- pSocket->errno = EADDRNOTAVAIL;\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 peer address.\r
-\r
- This routine calls the network specific layer to get the remote\r
- system connection point.\r
-\r
- The ::getpeername routine calls this routine to obtain the network\r
- address of the remote connection point.\r
-\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
-EFI_STATUS\r
-EslSocketGetPeerAddress (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- OUT struct sockaddr * pAddress,\r
- IN OUT socklen_t * pAddressLength,\r
- IN int * pErrno\r
- )\r
-{\r
- socklen_t LengthInBytes;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Verify the socket state\r
- //\r
- Status = EslSocketIsConfigured ( pSocket );\r
- if ( !EFI_ERROR ( Status )) {\r
- //\r
- // Verify the API\r
- //\r
- if ( NULL == pSocket->pApi->pfnRemoteAddrGet ) {\r
- Status = EFI_UNSUPPORTED;\r
- pSocket->errno = ENOTSUP;\r
- }\r
- else {\r
- //\r
- // Verify the address buffer and length address\r
- //\r
- if (( NULL != pAddress ) && ( NULL != pAddressLength )) {\r
- //\r
- // Verify the socket state\r
- //\r
- if ( SOCKET_STATE_CONNECTED == pSocket->State ) {\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Verify that there is just a single connection\r
- //\r
- pPort = pSocket->pPortList;\r
- if (( NULL != pPort ) && ( NULL == pPort->pLinkSocket )) {\r
- //\r
- // Verify the address length\r
- //\r
- LengthInBytes = 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
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- else {\r
- pSocket->errno = ENOTCONN;\r
- Status = EFI_NOT_STARTED;\r
- }\r
- }\r
- else {\r
- pSocket->errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
- }\r
- }\r
- }\r
- }\r
-\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
-/** Free the ESL_IO_MGMT event and structure.\r
-\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
- See the \ref TransmitEngine section.\r
-\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
-EslSocketIoFree (\r
- IN ESL_PORT * pPort,\r
- IN ESL_IO_MGMT ** ppFreeQueue,\r
- IN UINTN DebugFlags,\r
- IN CHAR8 * pEventName\r
- )\r
-{\r
- UINT8 * pBuffer;\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 success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Walk the list of IO structures\r
- //\r
- pSocket = pPort->pSocket;\r
- while ( *ppFreeQueue ) {\r
- //\r
- // Free the event for this structure\r
- //\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
- // Remove this structure from the queue\r
- //\r
- *ppFreeQueue = pIo->pNext;\r
- }\r
-\r
- //\r
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Initialize the ESL_IO_MGMT structures.\r
-\r
- This support routine initializes the ESL_IO_MGMT structure and\r
- places them on to a free list.\r
-\r
- This routine is called by ::EslSocketPortAllocate routines to prepare\r
- the transmit engines. See the \ref TransmitEngine section.\r
-\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
- @retval EFI_SUCCESS - The structures were properly initialized\r
-**/\r
-EFI_STATUS\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
- 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 success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Walk the list of IO structures\r
- //\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
- //\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
- // Add this structure to the queue\r
- //\r
- pIo->pNext = *ppFreeQueue;\r
- *ppFreeQueue = pIo;\r
-\r
- //\r
- // Set the next structure\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
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Determine if the socket is configured.\r
-\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
- @param[in] pSocket Address of an ::ESL_SOCKET structure\r
-\r
- @retval EFI_SUCCESS - The socket is configured\r
-**/\r
-EFI_STATUS\r
-EslSocketIsConfigured (\r
- IN ESL_SOCKET * pSocket\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Verify the socket state\r
- //\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
- // Update the port state\r
- //\r
- pPort->State = PORT_STATE_CLOSE_TX_DONE;\r
- DEBUG (( DEBUG_CLOSE | DEBUG_INFO,\r
- "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",\r
- pPort ));\r
-\r
- //\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
- // The receive operation is complete\r
- // Update the port state\r
- //\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
- //\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
- // Display the pending normal transmit packets\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
- 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
- // Return the operation status\r
- //\r
- DBG_EXIT_STATUS ( Status );\r
- return Status;\r
-}\r
-\r
-\r
-/** Receive data from a network connection.\r
-\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
- 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
- @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
-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
- 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
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Validate the 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
-/** Cancel the receive operations.\r
-\r
- This routine cancels a pending receive operation.\r
- See the \ref ReceiveEngine section.\r
-\r
- This routine is called by ::EslSocketShutdown when the socket\r
- layer is being shutdown.\r
-\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
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Cancel the outstanding receive\r
- //\r
- Status = pPort->pfnRxCancel ( pPort->pProtocol.v,\r
- &pIo->Token );\r
- if ( !EFI_ERROR ( Status )) {\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 (( 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
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/** Process the receive completion.\r
-\r
- This routine queues the data in FIFO order in either the urgent\r
- or normal data queues depending upon the type of data received.\r
- See the \ref ReceiveEngine section.\r
-\r
- This routine is called 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] 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
- DBG_ENTER ( );\r
- VERIFY_AT_TPL ( TPL_SOCKETS );\r
-\r
- //\r
- // Locate the active receive packet\r
- //\r
- pPacket = pIo->pPacket;\r
- pPort = pIo->pPort;\r
- pSocket = pPort->pSocket;\r
-\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
- //\r
- // Free the IO structure\r
- //\r
- pIo->pNext = pPort->pRxFree;\r
- pPort->pRxFree = pIo;\r
-\r
- //\r
- // pRxOobPacketListHead pRxOobPacketListTail\r
- // | |\r
- // V V\r
- // +------------+ +------------+ +------------+\r
- // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL\r
- // +------------+ +------------+ +------------+\r
- //\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
- // Determine if this receive was successful\r
- //\r
- if (( !EFI_ERROR ( Status ))\r
- && ( PORT_STATE_CLOSE_STARTED > pPort->State )\r
- && ( !pSocket->bRxDisable )) {\r
- //\r
- // Account for the received data\r
- //\r
- *pRxBytes += LengthInBytes;\r
-\r
- //\r
- // Log the received data\r
- //\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
- //\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
- //\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
- //\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
- // Receive error, free the packet save the error\r
- //\r
- EslSocketPacketFree ( pPacket, DEBUG_RX );\r
- if ( !EFI_ERROR ( pSocket->RxError )) {\r
- pSocket->RxError = Status;\r
- }\r
-\r
- //\r
- // Update the port state\r
- //\r
- if ( PORT_STATE_CLOSE_STARTED <= pPort->State ) {\r
- if ( PORT_STATE_CLOSE_DONE == pPort->State ) {\r
- EslSocketPortCloseRxDone ( pPort );\r
- }\r
- }\r
- else {\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
- DBG_EXIT ( );\r
-}\r
-\r
-\r
-/** Poll a socket for pending receive activity.\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
- The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit\r
- routines call this routine when there is nothing to do.\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
- DEBUG (( DEBUG_POLL, "Entering EslSocketRxPoll\r\n" ));\r
-\r
- //\r
- // Increase the network performance by extending the\r
- // polling (idle) loop down into the LAN driver\r
- //\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
- DEBUG (( DEBUG_POLL, "Exiting EslSocketRxPoll\r\n" ));\r
-}\r
-\r
-\r
-/** Start a receive operation.\r
-\r
- This routine posts a receive buffer to the network adapter.\r
- See the \ref ReceiveEngine section.\r
-\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
- @param[in] pPort Address of an ::ESL_PORT structure.\r
-**/\r
-VOID\r
-EslSocketRxStart (\r
- IN ESL_PORT * pPort\r
- )\r
-{\r
- UINT8 * pBuffer;\r
- ESL_IO_MGMT * pIo;\r
- ESL_PACKET * pPacket;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Determine if a receive is already pending\r
- //\r
- Status = EFI_SUCCESS;\r
- pPacket = NULL;\r
- pSocket = pPort->pSocket;\r
- if ( !EFI_ERROR ( pPort->pSocket->RxError )) {\r
- if (( NULL != pPort->pRxFree )\r
- && ( !pSocket->bRxDisable )\r
- && ( PORT_STATE_CLOSE_STARTED > pPort->State )) {\r
- //\r
- // Start all of the pending receive operations\r
- //\r
- while ( NULL != pPort->pRxFree ) {\r
- //\r
- // Determine if there are any free packets\r
- //\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
- "0x%08x: Port removed packet 0x%08x from free list\r\n",\r
- pPort,\r
- pPacket ));\r
- }\r
- else {\r
- //\r
- // Allocate a packet structure\r
- //\r
- Status = EslSocketPacketAllocate ( &pPacket,\r
- 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
- }\r
-\r
- //\r
- // Connect the IO and packet structures\r
- //\r
- pIo = pPort->pRxFree;\r
- pIo->pPacket = pPacket;\r
-\r
- //\r
- // Eliminate the need for IP4 and UDP4 specific routines by\r
- // clearing the RX data pointer here.\r
- //\r
- // No driver buffer for this packet\r
- //\r
- // +--------------------+\r
- // | ESL_IO_MGMT |\r
- // | |\r
- // | +---------------+\r
- // | | Token |\r
- // | | RxData --> NULL\r
- // +----+---------------+\r
- //\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
-\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
- // Allocate the receive control structure\r
- //\r
- pPort->pRxFree = pIo->pNext;\r
-\r
- //\r
- // Mark this receive as pending\r
- //\r
- pIo->pNext = pPort->pRxActive;\r
- pPort->pRxActive = pIo;\r
-\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
- // Save the error status\r
- //\r
- pSocket->RxError = Status;\r
- }\r
-\r
- //\r
- // Free the packet\r
- //\r
- pIo->pPacket = NULL;\r
- pPacket->pNext = pSocket->pRxFree;\r
- pSocket->pRxFree = pPacket;\r
- break;\r
- }\r
- }\r
- }\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
- 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
-/** Shutdown the socket receive and transmit operations.\r
-\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
- The ::shutdown routine calls this routine to stop receive and transmit\r
- operations on the socket.\r
-\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
- @retval EFI_SUCCESS - Socket operations successfully shutdown\r
-**/\r
-EFI_STATUS\r
-EslSocketShutdown (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN int How,\r
- IN int * pErrno\r
- )\r
-{\r
- ESL_IO_MGMT * pIo;\r
- ESL_PORT * pPort;\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // Verify that the socket is connected\r
- //\r
- if ( pSocket->bConnected ) {\r
- //\r
- // Validate the How value\r
- //\r
- if (( SHUT_RD <= How ) && ( SHUT_RDWR >= How )) {\r
- //\r
- // Synchronize with the socket layer\r
- //\r
- RAISE_TPL ( TplPrevious, TPL_SOCKETS );\r
-\r
- //\r
- // Disable the receiver if requested\r
- //\r
- if (( SHUT_RD == How ) || ( SHUT_RDWR == How )) {\r
- pSocket->bRxDisable = TRUE;\r
- }\r
-\r
- //\r
- // Disable the transmitter if requested\r
- //\r
- if (( SHUT_WR == How ) || ( SHUT_RDWR == How )) {\r
- pSocket->bTxDisable = TRUE;\r
- }\r
-\r
- //\r
- // Cancel the pending receive operations\r
- //\r
- if ( pSocket->bRxDisable ) {\r
- //\r
- // Walk the list of ports\r
- //\r
- pPort = pSocket->pPortList;\r
- while ( NULL != pPort ) {\r
- //\r
- // Walk the list of active receive operations\r
- //\r
- pIo = pPort->pRxActive;\r
- while ( NULL != pIo ) {\r
- EslSocketRxCancel ( pPort, pIo );\r
- }\r
-\r
- //\r
- // Set the next port\r
- //\r
- pPort = pPort->pLinkSocket;\r
- }\r
- }\r
-\r
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- else {\r
- //\r
- // Invalid How value\r
- //\r
- pSocket->errno = EINVAL;\r
- Status = EFI_INVALID_PARAMETER;\r
- }\r
- }\r
- else {\r
- //\r
- // The socket is not connected\r
- //\r
- pSocket->errno = ENOTCONN;\r
- Status = EFI_NOT_STARTED;\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
-/** Send data using a network connection.\r
-\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
- 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] 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
-EFI_STATUS\r
-EslSocketTransmit (\r
- IN EFI_SOCKET_PROTOCOL * pSocketProtocol,\r
- IN int Flags,\r
- IN size_t BufferLength,\r
- IN CONST UINT8 * pBuffer,\r
- OUT size_t * pDataLength,\r
- IN const struct sockaddr * pAddress,\r
- IN socklen_t AddressLength,\r
- IN int * pErrno\r
- )\r
-{\r
- ESL_SOCKET * pSocket;\r
- EFI_STATUS Status;\r
- EFI_TPL TplPrevious;\r
-\r
- DBG_ENTER ( );\r
-\r
- //\r
- // Assume success\r
- //\r
- Status = EFI_SUCCESS;\r
-\r
- //\r
- // Validate the socket\r
- //\r
- pSocket = NULL;\r
- if ( NULL != pSocketProtocol ) {\r
- pSocket = SOCKET_FROM_PROTOCOL ( pSocketProtocol );\r
-\r
- //\r
- // 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
- // Verify that transmit is still allowed\r
- //\r
- if ( !pSocket->bTxDisable ) {\r
- //\r
- // Validate the buffer length\r
- //\r
- if (( NULL == pDataLength )\r
- && ( 0 > pDataLength )\r
- && ( NULL == pBuffer )) {\r
- if ( NULL == pDataLength ) {\r
- DEBUG (( DEBUG_RX,\r
- "ERROR - pDataLength is NULL!\r\n" ));\r
- }\r
- else if ( NULL == pBuffer ) {\r
- DEBUG (( DEBUG_RX,\r
- "ERROR - pBuffer is NULL!\r\n" ));\r
- }\r
- else {\r
- DEBUG (( DEBUG_RX,\r
- "ERROR - Data length < 0!\r\n" ));\r
- }\r
- Status = EFI_INVALID_PARAMETER;\r
- pSocket->errno = EFAULT;\r
- }\r
- else {\r
- //\r
- // Validate the remote network address\r
- //\r
- if (( NULL != pAddress )\r
- && ( AddressLength < pAddress->sa_len )) {\r
- DEBUG (( DEBUG_TX,\r
- "ERROR - Invalid sin_len field in address\r\n" ));\r
- Status = EFI_INVALID_PARAMETER;\r
- pSocket->errno = EFAULT;\r
- }\r
- else {\r
- //\r
- // Verify the API\r
- //\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
- //\r
- // Poll the network to increase performance\r
- //\r
- EslSocketRxPoll ( pSocket );\r
-\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
- //\r
- // Release the socket layer synchronization\r
- //\r
- RESTORE_TPL ( TplPrevious );\r
- }\r
- }\r
- }\r
- }\r
- else {\r
- //\r
- // The transmitter was shutdown\r
- //\r
- pSocket->errno = EPIPE;\r
- Status = EFI_NOT_STARTED;\r
- }\r
- }\r
- }\r
- }\r
-\r
- //\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
-/** 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
-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