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