2 Implement the socket support for the socket layer.
5 * Bound - pSocket->PortList is not NULL
6 * Listen - AcceptWait event is not NULL
8 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
9 SPDX-License-Identifier: BSD-2-Clause-Patent
12 \section DataStructures Data Structures
16 +---------------+ +-------------+ +-------------+
17 Service Lists | ::ESL_SERVICE |-->| ESL_SERVICE |-->| ESL_SERVICE |--> NULL (pNext)
18 +---------------+ +-------------+ +-------------+
20 pUdp4List ^ | pTcp4List | |
25 | ::ESL_LAYER | ::mEslLayer | |
29 +---------------+ +-------------+ +-------------+
30 | ::ESL_SOCKET |-->| ::ESL_PORT |-->| ESL_PORT |--> NULL (pLinkSocket)
31 +---------------+ +-------------+ +-------------+
35 +-------------+ +-------------+
36 | ESL_SOCKET |-->| ESL_PORT |--> NULL
37 +-------------+ +-------------+
41 (pNext) | | | | (pLinkService)
42 | | | | pRxPacketListHead
43 | | | `-----------------------------------------------.
44 | | | pRxOobPacketListHead |
45 | | `--------------------------------. |
46 | | pTxPacketListHead | |
47 | `---------------. | |
48 pTxOobPacketListHead | | | |
50 +--------------+ +------------+ +------------+ +------------+
51 | ::ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
52 +--------------+ +------------+ +------------+ +------------+
55 +------------+ +------------+ +------------+ +------------+
56 | ESL_PACKET | | ESL_PACKET | | ESL_PACKET | | ESL_PACKET |
57 +------------+ +------------+ +------------+ +------------+
65 ::mEslLayer is the one and only ::ESL_LAYER structure. It connects directly or
66 indirectly to the other data structures. The ESL_LAYER structure has a unique
67 service list for each of the network protocol interfaces.
69 ::ESL_SERVICE manages the network interfaces for a given transport type (IP4, TCP4, UDP4, etc.)
71 ::ESL_SOCKET manages the activity for a single socket instance. As such, it contains
72 the ::EFI_SOCKET_PROTOCOL structure which the BSD socket library uses as the object
73 reference and the API into the EFI socket library.
75 ::ESL_PORT manages the connection with a single instance of the lower layer network.
76 This structure is the socket equivalent of an IP connection or a TCP or UDP port.
78 ::ESL_PACKET buffers data for transmit and receive. There are four queues connected
79 to the ::ESL_SOCKET that manage the data:
81 <li>ESL_SOCKET::pRxPacketListHead - Normal (low) priority receive data</li>
82 <li>ESL_SOCKET::pRxOobPacketListHead - High (out-of-band or urgent) priority receive data</li>
83 <li>ESL_SOCKET::pTxPacketListHead - Normal (low) priority transmit data</li>
84 <li>ESL_SOCKET::pTxOobPacketListHead - High (out-of-band or urgent) priority transmit data</li>
86 The selection of the transmit queue is controlled by the MSG_OOB flag on the transmit
87 request as well as the socket option SO_OOBINLINE. The receive queue is selected by
88 the URGENT data flag for TCP and the setting of the socket option SO_OOBINLINE.
90 Data structure synchronization is done by raising TPL to TPL_SOCKET. Modifying
91 critical elements within the data structures must be done at this TPL. TPL is then
92 restored to the previous level. Note that the code verifies that all callbacks are
93 entering at TPL_SOCKETS for proper data structure synchronization.
95 \section PortCloseStateMachine Port Close State Machine
97 The port close state machine walks the port through the necessary
98 states to stop activity on the port and get it into a state where
99 the resources may be released. The state machine consists of the
100 following arcs and states:
104 +--------------------------+
106 +--------------------------+
108 | ::EslSocketPortCloseStart
110 +--------------------------+
111 | PORT_STATE_CLOSE_STARTED |
112 +--------------------------+
114 | ::EslSocketPortCloseTxDone
116 +--------------------------+
117 | PORT_STATE_CLOSE_TX_DONE |
118 +--------------------------+
120 | ::EslSocketPortCloseComplete
122 +--------------------------+
123 | PORT_STATE_CLOSE_DONE |
124 +--------------------------+
126 | ::EslSocketPortCloseRxDone
128 +--------------------------+
129 | PORT_STATE_CLOSE_RX_DONE |
130 +--------------------------+
132 | ::EslSocketPortClose
134 +--------------------------+
136 +--------------------------+
141 <li>Arc: ::EslSocketPortCloseStart - Marks the port as closing and
142 initiates the port close operation</li>
143 <li>State: PORT_STATE_CLOSE_STARTED</li>
144 <li>Arc: ::EslSocketPortCloseTxDone - Waits until all of the transmit
145 operations to complete. After all of the transmits are complete,
146 this routine initiates the network specific close operation by calling
147 through ESL_PROTOCOL_API::pfnPortCloseOp. One such routine is
148 ::EslTcp4PortCloseOp.
150 <li>State: PORT_STATE_CLOSE_TX_DONE</li>
151 <li>Arc: ::EslSocketPortCloseComplete - Called when the close operation is
152 complete. After the transition to PORT_STATE_CLOSE_DONE,
153 this routine calls ::EslSocketRxCancel to abort the pending receive operations.
155 <li>State: PORT_STATE_CLOSE_DONE</li>
156 <li>Arc: ::EslSocketPortCloseRxDone - Waits until all of the receive
157 operation have been cancelled. After the transition to
158 PORT_STATE_CLOSE_RX_DONE, this routine calls ::EslSocketPortClose.
160 <li>State: PORT_STATE_CLOSE_RX_DONE</li>
161 <li>Arc: ::EslSocketPortClose - This routine discards any receive buffers
162 using a network specific support routine via ESL_PROTOCOL_API::pfnPacketFree.
163 This routine then releases the port resources allocated by ::EslSocketPortAllocate
164 and calls the network specific port close routine (e.g. ::EslTcp4PortClose)
165 via ESL_PROTOCOL_API::pfnPortClose to release any network specific resources.
170 \section ReceiveEngine Receive Engine
172 The receive path accepts data from the network and queues (buffers) it for the
173 application. Flow control is applied once a maximum amount of buffering is reached
174 and is released when the buffer usage drops below that limit. Eventually the
175 application requests data from the socket which removes entries from the queue and
178 The receive engine is the state machine which reads data from the network and
179 fills the queue with received packets. The receive engine uses two data structures
180 to manage the network receive opeations and the buffers.
182 At a high level, the ::ESL_IO_MGMT structures are managing the tokens and
183 events for the interface to the UEFI network stack. The ::ESL_PACKET
184 structures are managing the receive data buffers. The receive engine
185 connects these two structures in the network specific receive completion
205 The ::ESL_IO_MGMT structures are allocated as part of the ::ESL_PORT structure in
206 ::EslSocketPortAllocate. The ESL_IO_MGMT structures are separated and placed on
207 the free list by calling ::EslSocketIoInit. The ESL_IO_MGMT structure contains
208 the network layer specific receive completion token and event. The receive engine
209 is eventually shutdown by ::EslSocketPortCloseTxDone and the resources in these
210 structures are released in ::EslSocketPortClose by a call to ::EslSocketIoFree.
217 +-------------+ +-------------+ +-------------+
218 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
219 +-------------+ +-------------+ +-------------+
221 +-------------+ +-------------+ +-------------+
222 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
223 +-------------+ +-------------+ +-------------+
229 The receive engine is started by calling ::EslSocketRxStart. Flow control pauses
230 the receive engine by stopping the calls to EslSocketRxStart when the amount of
231 receive data waiting for the application meets or exceeds MAX_RX_DATA. After
232 the application reads enough data that the amount of buffering drops below this
233 limit, the calls to EslSockeRxStart continue which releases the flow control.
235 Receive flow control is applied when the port is created, since no receive
236 operation are pending to the low layer network driver. The flow control gets
237 released when the low layer network port is configured or the first receive
238 operation is posted. Flow control remains in the released state until the
239 maximum buffer space is consumed. During this time, ::EslSocketRxComplete
240 calls ::EslSocketRxStart. Flow control is applied in EslSocketRxComplete
241 by skipping the call to EslSocketRxStart. Flow control is eventually
242 released in ::EslSocketReceive when the buffer space drops below the
243 maximum amount causing EslSocketReceive to call EslSocketRxStart.
247 +------------+ +------------+
248 High .----->| ESL_PACKET |-->| ESL_PACKET |--> NULL (pNext)
249 Priority | +------------+ +------------+
251 | pRxOobPacketListHead
257 Priority | +------------+ +------------+ +------------+
258 `----->| ::ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
259 +------------+ +------------+ +------------+
263 ::EslSocketRxStart connects an ::ESL_PACKET structure to the ::ESL_IO_MGMT structure
264 and then calls the network layer to start the receive operation. Upon
265 receive completion, ::EslSocketRxComplete breaks the connection between these
266 structrues and places the ESL_IO_MGMT structure onto the ESL_PORT::pRxFree list to
267 make token and event available for another receive operation. EslSocketRxComplete
268 then queues the ESL_PACKET structure (data packet) to either the
269 ESL_SOCKET::pRxOobPacketListTail or ESL_SOCKET::pRxPacketListTail depending on
270 whether urgent or normal data was received. Finally ::EslSocketRxComplete attempts
271 to start another receive operation.
275 Setup for IP4 and UDP4
277 +--------------------+
283 +----+---------------+
286 +--------------------+
291 +----+---------------+
293 Completion for IP4 and UDP4
295 +--------------------+ +----------------------+
296 | ESL_IO_MGMT | | Data Buffer |
297 | | | (Driver owned) |
298 | +---------------+ +----------------------+
301 | | | +----------------------+
302 | | RxData --> | EFI_IP4_RECEIVE_DATA |
303 +----+---------------+ | (Driver owned) |
304 | +----------------------+
306 +--------------------+ .
309 | +---------------+ .
310 | | pRxData --> NULL .......
311 +----+---------------+
314 Setup and completion for TCP4
316 +--------------------+ +--------------------------+
317 | ESL_IO_MGMT |-->| ESL_PACKET |
319 | +---------------+ +----------------------+ |
320 | | Token | | EFI_IP4_RECEIVE_DATA | |
322 | | | +----------------------+---+
323 | | Event | | Data Buffer |
324 +----+---------------+ | |
326 +--------------------------+
330 To minimize the number of buffer copies, the data is not copied until the
331 application makes a receive call. At this point socket performs a single copy
332 in the receive path to move the data from the buffer filled by the network layer
333 into the application's buffer.
335 The IP4 and UDP4 drivers go one step further to reduce buffer copies. They
336 allow the socket layer to hold on to the actual receive buffer until the
337 application has performed a receive operation or closes the socket. Both
338 of theses operations return the buffer to the lower layer network driver
339 by calling ESL_PROTOCOL_API::pfnPacketFree.
341 When a socket application wants to receive data it indirectly calls
342 ::EslSocketReceive to remove data from one of the receive data queues. This routine
343 removes the next available packet from ESL_SOCKET::pRxOobPacketListHead or
344 ESL_SOCKET::pRxPacketListHead and copies the data from the packet
345 into the application's buffer. For SOCK_STREAM sockets, if the packet
346 contains more data then the ESL_PACKET structures remains at the head of the
347 receive queue for the next application receive
348 operation. For SOCK_DGRAM, SOCK_RAW and SOCK_SEQ_PACKET sockets, the ::ESL_PACKET
349 structure is removed from the head of the receive queue and any remaining data is
350 discarded as the packet is placed on the free queue.
352 During socket layer shutdown, ::EslSocketShutdown calls ::EslSocketRxCancel to
353 cancel any pending receive operations. EslSocketRxCancel calls the network specific
354 cancel routine using ESL_PORT::pfnRxCancel.
357 \section TransmitEngine Transmit Engine
359 Application calls to ::EslSocketTransmit cause data to be copied into a buffer.
360 The buffer exists as an extension to an ESL_PACKET structure and the structure
361 is placed at the end of the transmit queue.
365 *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
368 +------------+ +------------+ +------------+
369 Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
370 +------------+ +------------+ +------------+
373 *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
377 There are actually two transmit queues the normal or low priority queue which is
378 the default and the urgent or high priority queue which is addressed by specifying
379 the MSG_OOB flag during the transmit request. Associated with each queue is a
380 transmit engine which is responsible for sending the data in that queue.
382 The transmit engine is the state machine which removes entries from the head
383 of the transmit queue and causes the data to be sent over the network.
387 +--------------------+ +--------------------+
388 | ESL_IO_MGMT | | ESL_PACKET |
390 | +---------------+ +----------------+ |
391 | | Token | | Buffer Length | |
392 | | TxData --> | Buffer Address | |
393 | | | +----------------+---+
394 | | Event | | Data Buffer |
395 +----+---------------+ | |
396 +--------------------+
399 At a high level, the transmit engine uses a couple of data structures
400 to manage the data flow. The ::ESL_IO_MGMT structures manage the tokens and
401 events for the interface to the UEFI network stack. The ::ESL_PACKET
402 structures manage the data buffers that get sent. The transmit
403 engine connects these two structures prior to transmission and disconnects
404 them upon completion.
408 pPort->pTxActive or pTxOobActive
411 +-------------+ +-------------+ +-------------+
412 Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
413 +-------------+ +-------------+ +-------------+
415 +-------------+ +-------------+ +-------------+
416 Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
417 +-------------+ +-------------+ +-------------+
420 pPort->pTxFree or pTxOobFree
424 The transmit engine manages multiple transmit operations using the
425 active and free lists shown above. ::EslSocketPortAllocate allocates the
426 ::ESL_IO_MGMT structures as an extension to the ::ESL_PORT structure.
427 This routine places the ESL_IO_MGMT structures on the free list by calling
428 ::EslSocketIoInit. During their lifetime, the ESL_IO_MGMT structures
429 will move from the free list to the active list and back again. The
430 active list contains the packets that are actively being processed by
431 the UEFI network stack. Eventually the ESL_IO_MGMT structures will be
432 removed from the free list and be deallocated by the EslSocketPortClose
435 The network specific code calls the ::EslSocketTxStart routine
436 to hand a packet to the network stack. EslSocketTxStart connects
437 the transmit packet (::ESL_PACKET) to an ::ESL_IO_MGMT structure
438 and then queues the result to one of the active lists:
439 ESL_PORT::pTxActive or ESL_PORT::pTxOobActive. The routine then
440 hands the packet to the network stack.
442 Upon completion, the network specific TxComplete routine calls
443 ::EslSocketTxComplete to disconnect the transmit packet from the
444 ESL_IO_MGMT structure and frees the ::ESL_PACKET structure by calling
445 ::EslSocketPacketFree. The routine places the ::ESL_IO_MGMT structure
446 into the free list either ESL_PORT::pTxFree or ESL_PORT::pTxOobFree.
447 EslSocketTxComplete then starts the next transmit operation while
448 the socket is active or calls the ::EslSocketPortCloseTxDone routine
449 when the socket is shutting down.
456 /** Socket driver connection points
458 List the network stack connection points for the socket driver.
460 CONST ESL_SOCKET_BINDING cEslSocketBinding
[] = {
462 &gEfiIp4ServiceBindingProtocolGuid
,
463 &gEfiIp4ProtocolGuid
,
465 OFFSET_OF ( ESL_LAYER
, pIp4List
),
468 0 }, // TX Oob buffers
470 &gEfiTcp4ServiceBindingProtocolGuid
,
471 &gEfiTcp4ProtocolGuid
,
472 &mEslTcp4ServiceGuid
,
473 OFFSET_OF ( ESL_LAYER
, pTcp4List
),
476 4 }, // TX Oob buffers
478 &gEfiTcp6ServiceBindingProtocolGuid
,
479 &gEfiTcp6ProtocolGuid
,
480 &mEslTcp6ServiceGuid
,
481 OFFSET_OF ( ESL_LAYER
, pTcp6List
),
484 4 }, // TX Oob buffers
486 &gEfiUdp4ServiceBindingProtocolGuid
,
487 &gEfiUdp4ProtocolGuid
,
488 &mEslUdp4ServiceGuid
,
489 OFFSET_OF ( ESL_LAYER
, pUdp4List
),
492 0 }, // TX Oob buffers
494 &gEfiUdp6ServiceBindingProtocolGuid
,
495 &gEfiUdp6ProtocolGuid
,
496 &mEslUdp6ServiceGuid
,
497 OFFSET_OF ( ESL_LAYER
, pUdp6List
),
500 0 } // TX Oob buffers
503 CONST UINTN cEslSocketBindingEntries
= DIM ( cEslSocketBinding
);
505 /// APIs to support the various socket types for the v4 network stack.
506 CONST ESL_PROTOCOL_API
* cEslAfInetApi
[] = {
508 &cEslTcp4Api
, // SOCK_STREAM
509 &cEslUdp4Api
, // SOCK_DGRAM
510 &cEslIp4Api
, // SOCK_RAW
512 &cEslTcp4Api
// SOCK_SEQPACKET
515 /// Number of entries in the v4 API array ::cEslAfInetApi.
516 CONST
int cEslAfInetApiSize
= DIM ( cEslAfInetApi
);
519 /// APIs to support the various socket types for the v6 network stack.
520 CONST ESL_PROTOCOL_API
* cEslAfInet6Api
[] = {
522 &cEslTcp6Api
, // SOCK_STREAM
523 &cEslUdp6Api
, // SOCK_DGRAM
526 &cEslTcp6Api
// SOCK_SEQPACKET
529 /// Number of entries in the v6 API array ::cEslAfInet6Api.
530 CONST
int cEslAfInet6ApiSize
= DIM ( cEslAfInet6Api
);
533 /// Global management structure for the socket layer.
537 /** Initialize an endpoint for network communication.
539 This routine initializes the communication endpoint.
541 The ::socket routine calls this routine indirectly to create
542 the communication endpoint.
544 @param[in] pSocketProtocol Address of the socket protocol structure.
545 @param[in] domain Select the family of protocols for the client or server
546 application. See the ::socket documentation for values.
547 @param[in] type Specifies how to make the network connection.
548 See the ::socket documentation for values.
549 @param[in] protocol Specifies the lower layer protocol to use.
550 See the ::socket documentation for values.
551 @param[out] pErrno Address to receive the errno value upon completion.
553 @retval EFI_SUCCESS - Socket successfully created
554 @retval EFI_INVALID_PARAMETER - Invalid domain value, errno = EAFNOSUPPORT
555 @retval EFI_INVALID_PARAMETER - Invalid type value, errno = EINVAL
556 @retval EFI_INVALID_PARAMETER - Invalid protocol value, errno = EINVAL
560 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
567 CONST ESL_PROTOCOL_API
* pApi
;
568 CONST ESL_PROTOCOL_API
** ppApiArray
;
569 CONST ESL_PROTOCOL_API
** ppApiArrayEnd
;
571 ESL_SOCKET
* pSocket
;
578 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
580 // Set the default domain if necessary
581 if ( AF_UNSPEC
== domain
) {
587 Status
= EFI_SUCCESS
;
589 // Use break instead of goto
591 // Validate the domain value
592 if (( AF_INET
!= domain
)
593 && ( AF_INET6
!= domain
)
594 && ( AF_LOCAL
!= domain
)) {
595 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
596 "ERROR - Invalid domain value\r\n" ));
597 Status
= EFI_INVALID_PARAMETER
;
598 errno
= EAFNOSUPPORT
;
602 // Determine the protocol APIs
605 if (( AF_INET
== domain
)
606 || ( AF_LOCAL
== domain
)) {
607 ppApiArray
= &cEslAfInetApi
[0];
608 ApiArraySize
= cEslAfInetApiSize
;
611 ppApiArray
= &cEslAfInet6Api
[0];
612 ApiArraySize
= cEslAfInet6ApiSize
;
615 // Set the default type if necessary
620 // Validate the type value
621 if (( type
>= ApiArraySize
)
622 || ( NULL
== ppApiArray
)
623 || ( NULL
== ppApiArray
[ type
])) {
624 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
625 "ERROR - Invalid type value\r\n" ));
626 // The socket type is not supported
627 Status
= EFI_INVALID_PARAMETER
;
632 // Set the default protocol if necessary
633 pApi
= ppApiArray
[ type
];
634 if ( 0 == protocol
) {
635 protocol
= pApi
->DefaultProtocol
;
638 // Validate the protocol value
639 if (( pApi
->DefaultProtocol
!= protocol
)
640 && ( SOCK_RAW
!= type
)) {
641 Status
= EFI_INVALID_PARAMETER
;
643 // Assume that the driver supports this protocol
644 ppApiArray
= &cEslAfInetApi
[0];
645 ppApiArrayEnd
= &ppApiArray
[ cEslAfInetApiSize
];
646 while ( ppApiArrayEnd
> ppApiArray
) {
648 if ( protocol
== pApi
->DefaultProtocol
) {
653 if ( ppApiArrayEnd
<= ppApiArray
) {
654 // Verify against the IPv6 table
655 ppApiArray
= &cEslAfInet6Api
[0];
656 ppApiArrayEnd
= &ppApiArray
[ cEslAfInet6ApiSize
];
657 while ( ppApiArrayEnd
> ppApiArray
) {
659 if ( protocol
== pApi
->DefaultProtocol
) {
665 if ( ppApiArrayEnd
<= ppApiArray
) {
666 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
667 "ERROR - The protocol is not supported!\r\n" ));
668 errno
= EPROTONOSUPPORT
;
672 // The driver does not support this protocol
673 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
,
674 "ERROR - The protocol does not support this socket type!\r\n" ));
675 errno
= EPROTONOSUPPORT
;
679 // Save the socket attributes
680 pSocket
->pApi
= pApi
;
681 pSocket
->Domain
= domain
;
682 pSocket
->Type
= type
;
683 pSocket
->Protocol
= protocol
;
688 // Return the operation status
689 if ( NULL
!= pErrno
) {
692 DBG_EXIT_STATUS ( Status
);
697 /** Accept a network connection.
699 This routine calls the network specific layer to remove the next
700 connection from the FIFO.
702 The ::accept calls this routine to poll for a network
703 connection to the socket. When a connection is available
704 this routine returns the ::EFI_SOCKET_PROTOCOL structure address
705 associated with the new socket and the remote network address
708 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
709 @param[in] pSockAddr Address of a buffer to receive the remote
711 @param[in,out] pSockAddrLength Length in bytes of the address buffer.
712 On output specifies the length of the
713 remote network address.
714 @param[out] ppSocketProtocol Address of a buffer to receive the
715 ::EFI_SOCKET_PROTOCOL instance
716 associated with the new socket.
717 @param[out] pErrno Address to receive the errno value upon completion.
719 @retval EFI_SUCCESS New connection successfully created
720 @retval EFI_NOT_READY No connection is available
724 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
725 IN
struct sockaddr
* pSockAddr
,
726 IN OUT socklen_t
* pSockAddrLength
,
727 IN EFI_SOCKET_PROTOCOL
** ppSocketProtocol
,
731 ESL_SOCKET
* pNewSocket
;
732 ESL_SOCKET
* pSocket
;
741 Status
= EFI_SUCCESS
;
744 // Validate the socket
748 if ( NULL
!= pSocketProtocol
) {
749 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
754 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
755 Status
= EFI_UNSUPPORTED
;
756 pSocket
->errno
= ENOTSUP
;
760 // Validate the sockaddr
762 if (( NULL
!= pSockAddr
)
763 && ( NULL
== pSockAddrLength
)) {
764 DEBUG (( DEBUG_ACCEPT
,
765 "ERROR - pSockAddr is NULL!\r\n" ));
766 Status
= EFI_INVALID_PARAMETER
;
767 pSocket
->errno
= EFAULT
;
771 // Synchronize with the socket layer
773 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
776 // Verify that the socket is in the listen state
778 if ( SOCKET_STATE_LISTENING
!= pSocket
->State
) {
779 DEBUG (( DEBUG_ACCEPT
,
780 "ERROR - Socket is not listening!\r\n" ));
781 if ( NULL
== pSocket
->pApi
->pfnAccept
) {
783 // Socket does not support listen
785 pSocket
->errno
= EOPNOTSUPP
;
786 Status
= EFI_UNSUPPORTED
;
790 // Socket supports listen, but not in listen state
792 pSocket
->errno
= EINVAL
;
793 Status
= EFI_NOT_STARTED
;
798 // Determine if a socket is available
800 if ( 0 == pSocket
->FifoDepth
) {
802 // No connections available
803 // Determine if any ports are available
805 if ( NULL
== pSocket
->pPortList
) {
807 // No ports available
809 Status
= EFI_DEVICE_ERROR
;
810 pSocket
->errno
= EINVAL
;
813 // Update the socket state
815 pSocket
->State
= SOCKET_STATE_NO_PORTS
;
819 // Ports are available
820 // No connection requests at this time
822 Status
= EFI_NOT_READY
;
823 pSocket
->errno
= EAGAIN
;
829 // Attempt to accept the connection and
830 // get the remote network address
832 pNewSocket
= pSocket
->pFifoHead
;
833 ASSERT ( NULL
!= pNewSocket
);
834 Status
= pSocket
->pApi
->pfnAccept ( pNewSocket
,
837 if ( !EFI_ERROR ( Status
)) {
839 // Remove the new socket from the list
841 pSocket
->pFifoHead
= pNewSocket
->pNextConnection
;
842 if ( NULL
== pSocket
->pFifoHead
) {
843 pSocket
->pFifoTail
= NULL
;
847 // Account for this socket
849 pSocket
->FifoDepth
-= 1;
852 // Update the new socket's state
854 pNewSocket
->State
= SOCKET_STATE_CONNECTED
;
855 pNewSocket
->bConfigured
= TRUE
;
856 DEBUG (( DEBUG_ACCEPT
,
857 "0x%08x: Socket connected\r\n",
864 // Release the socket layer synchronization
866 RESTORE_TPL ( TplPrevious
);
872 // Return the new socket
874 if (( NULL
!= ppSocketProtocol
)
875 && ( NULL
!= pNewSocket
)) {
876 *ppSocketProtocol
= &pNewSocket
->SocketProtocol
;
880 // Return the operation status
882 if ( NULL
!= pErrno
) {
883 if ( NULL
!= pSocket
) {
884 *pErrno
= pSocket
->errno
;
887 Status
= EFI_INVALID_PARAMETER
;
891 DBG_EXIT_STATUS ( Status
);
896 /** Allocate and initialize a ESL_SOCKET structure.
898 This support function allocates an ::ESL_SOCKET structure
899 and installs a protocol on ChildHandle. If pChildHandle is a
900 pointer to NULL, then a new handle is created and returned in
901 pChildHandle. If pChildHandle is not a pointer to NULL, then
902 the protocol installs on the existing pChildHandle.
904 @param[in,out] pChildHandle Pointer to the handle of the child to create.
905 If it is NULL, then a new handle is created.
906 If it is a pointer to an existing UEFI handle,
907 then the protocol is added to the existing UEFI
909 @param[in] DebugFlags Flags for debug messages
910 @param[in,out] ppSocket The buffer to receive an ::ESL_SOCKET structure address.
912 @retval EFI_SUCCESS The protocol was added to ChildHandle.
913 @retval EFI_INVALID_PARAMETER ChildHandle is NULL.
914 @retval EFI_OUT_OF_RESOURCES There are not enough resources available to create
916 @retval other The child handle was not created
921 IN OUT EFI_HANDLE
* pChildHandle
,
923 IN OUT ESL_SOCKET
** ppSocket
928 ESL_SOCKET
* pSocket
;
935 // Create a socket structure
937 LengthInBytes
= sizeof ( *pSocket
);
938 pSocket
= (ESL_SOCKET
*) AllocateZeroPool ( LengthInBytes
);
939 if ( NULL
!= pSocket
) {
940 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
941 "0x%08x: Allocate pSocket, %d bytes\r\n",
946 // Initialize the socket protocol
948 pSocket
->Signature
= SOCKET_SIGNATURE
;
949 pSocket
->SocketProtocol
.pfnAccept
= EslSocketAccept
;
950 pSocket
->SocketProtocol
.pfnBind
= EslSocketBind
;
951 pSocket
->SocketProtocol
.pfnClosePoll
= EslSocketClosePoll
;
952 pSocket
->SocketProtocol
.pfnCloseStart
= EslSocketCloseStart
;
953 pSocket
->SocketProtocol
.pfnConnect
= EslSocketConnect
;
954 pSocket
->SocketProtocol
.pfnGetLocal
= EslSocketGetLocalAddress
;
955 pSocket
->SocketProtocol
.pfnGetPeer
= EslSocketGetPeerAddress
;
956 pSocket
->SocketProtocol
.pfnListen
= EslSocketListen
;
957 pSocket
->SocketProtocol
.pfnOptionGet
= EslSocketOptionGet
;
958 pSocket
->SocketProtocol
.pfnOptionSet
= EslSocketOptionSet
;
959 pSocket
->SocketProtocol
.pfnPoll
= EslSocketPoll
;
960 pSocket
->SocketProtocol
.pfnReceive
= EslSocketReceive
;
961 pSocket
->SocketProtocol
.pfnShutdown
= EslSocketShutdown
;
962 pSocket
->SocketProtocol
.pfnSocket
= EslSocket
;
963 pSocket
->SocketProtocol
.pfnTransmit
= EslSocketTransmit
;
965 pSocket
->MaxRxBuf
= MAX_RX_DATA
;
966 pSocket
->MaxTxBuf
= MAX_TX_DATA
;
969 // Install the socket protocol on the specified handle
971 Status
= gBS
->InstallMultipleProtocolInterfaces (
973 &gEfiSocketProtocolGuid
,
974 &pSocket
->SocketProtocol
,
977 if ( !EFI_ERROR ( Status
)) {
978 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
| DEBUG_INFO
,
979 "Installed: gEfiSocketProtocolGuid on 0x%08x\r\n",
981 pSocket
->SocketProtocol
.SocketHandle
= *pChildHandle
;
984 // Synchronize with the socket layer
986 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
989 // Add this socket to the list
992 pSocket
->pNext
= pLayer
->pSocketList
;
993 pLayer
->pSocketList
= pSocket
;
996 // Release the socket layer synchronization
998 RESTORE_TPL ( TplPrevious
);
1001 // Return the socket structure address
1003 *ppSocket
= pSocket
;
1006 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1007 "ERROR - Failed to install gEfiSocketProtocolGuid on 0x%08x, Status: %r\r\n",
1013 // Release the socket if necessary
1015 if ( EFI_ERROR ( Status
)) {
1016 gBS
->FreePool ( pSocket
);
1017 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
1018 "0x%08x: Free pSocket, %d bytes\r\n",
1020 sizeof ( *pSocket
)));
1025 Status
= EFI_OUT_OF_RESOURCES
;
1029 // Return the operation status
1031 DBG_EXIT_STATUS ( Status
);
1036 /** Bind a name to a socket.
1038 This routine calls the network specific layer to save the network
1039 address of the local connection point.
1041 The ::bind routine calls this routine to connect a name
1042 (network address and port) to a socket on the local machine.
1044 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1045 @param[in] pSockAddr Address of a sockaddr structure that contains the
1046 connection point on the local machine. An IPv4 address
1047 of INADDR_ANY specifies that the connection is made to
1048 all of the network stacks on the platform. Specifying a
1049 specific IPv4 address restricts the connection to the
1050 network stack supporting that address. Specifying zero
1051 for the port causes the network layer to assign a port
1052 number from the dynamic range. Specifying a specific
1053 port number causes the network layer to use that port.
1054 @param[in] SockAddrLength Specifies the length in bytes of the sockaddr structure.
1055 @param[out] pErrno Address to receive the errno value upon completion.
1057 @retval EFI_SUCCESS - Socket successfully created
1061 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1062 IN CONST
struct sockaddr
* pSockAddr
,
1063 IN socklen_t SockAddrLength
,
1067 EFI_HANDLE ChildHandle
;
1070 ESL_SERVICE
** ppServiceListHead
;
1071 ESL_SOCKET
* pSocket
;
1072 ESL_SERVICE
* pService
;
1073 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
1075 EFI_TPL TplPrevious
;
1082 Status
= EFI_SUCCESS
;
1085 // Validate the socket
1088 if ( NULL
!= pSocketProtocol
) {
1089 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1092 // Validate the structure pointer
1095 if ( NULL
== pSockAddr
) {
1096 DEBUG (( DEBUG_BIND
,
1097 "ERROR - pSockAddr is NULL!\r\n" ));
1098 Status
= EFI_INVALID_PARAMETER
;
1099 pSocket
->errno
= EFAULT
;
1103 // Validate the local address length
1105 else if ( SockAddrLength
< pSocket
->pApi
->MinimumAddressLength
) {
1106 DEBUG (( DEBUG_BIND
,
1107 "ERROR - Invalid bind name length: %d\r\n",
1109 Status
= EFI_INVALID_PARAMETER
;
1110 pSocket
->errno
= EINVAL
;
1114 // Validate the shutdown state
1116 else if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
1117 DEBUG (( DEBUG_BIND
,
1118 "ERROR - Shutdown has been called on socket 0x%08x\r\n",
1120 pSocket
->errno
= EINVAL
;
1121 Status
= EFI_INVALID_PARAMETER
;
1125 // Verify the socket state
1127 else if ( SOCKET_STATE_NOT_CONFIGURED
!= pSocket
->State
) {
1128 DEBUG (( DEBUG_BIND
,
1129 "ERROR - The socket 0x%08x is already configured!\r\n",
1131 pSocket
->errno
= EINVAL
;
1132 Status
= EFI_ALREADY_STARTED
;
1136 // Synchronize with the socket layer
1138 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1141 // Assume no ports are available
1143 pSocket
->errno
= EADDRNOTAVAIL
;
1144 Status
= EFI_INVALID_PARAMETER
;
1147 // Walk the list of services
1149 pBuffer
= (UINT8
*)&mEslLayer
;
1150 pBuffer
= &pBuffer
[ pSocket
->pApi
->ServiceListOffset
];
1151 ppServiceListHead
= (ESL_SERVICE
**)pBuffer
;
1152 pService
= *ppServiceListHead
;
1153 while ( NULL
!= pService
) {
1157 pServiceBinding
= pService
->pServiceBinding
;
1159 Status
= pServiceBinding
->CreateChild ( pServiceBinding
,
1161 if ( !EFI_ERROR ( Status
)) {
1162 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1163 "0x%08x: %s port handle created\r\n",
1165 pService
->pSocketBinding
->pName
));
1170 Status
= EslSocketPortAllocate ( pSocket
,
1179 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
1180 "ERROR - Failed to open %s port handle, Status: %r\r\n",
1181 pService
->pSocketBinding
->pName
,
1186 // Set the next service
1188 pService
= pService
->pNext
;
1192 // Verify that at least one network connection was found
1194 if ( NULL
!= pSocket
->pPortList
) {
1195 Status
= EFI_SUCCESS
;
1198 if ( EADDRNOTAVAIL
== pSocket
->errno
) {
1199 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1200 "ERROR - Socket address is not available!\r\n" ));
1202 if ( EADDRINUSE
== pSocket
->errno
) {
1203 DEBUG (( DEBUG_BIND
| DEBUG_POOL
| DEBUG_INIT
,
1204 "ERROR - Socket address is in use!\r\n" ));
1206 Status
= EFI_INVALID_PARAMETER
;
1210 // Mark this socket as bound if successful
1212 if ( !EFI_ERROR ( Status
)) {
1213 pSocket
->State
= SOCKET_STATE_BOUND
;
1218 // Release the socket layer synchronization
1220 RESTORE_TPL ( TplPrevious
);
1225 // Return the operation status
1227 if ( NULL
!= pErrno
) {
1228 if ( NULL
!= pSocket
) {
1229 *pErrno
= pSocket
->errno
;
1232 Status
= EFI_INVALID_PARAMETER
;
1236 DBG_EXIT_STATUS ( Status
);
1241 /** Test the bind configuration.
1243 @param[in] pPort Address of the ::ESL_PORT structure.
1244 @param[in] ErrnoValue errno value if test fails
1246 @retval EFI_SUCCESS The connection was successfully established.
1247 @retval Others The connection attempt failed.
1251 IN ESL_PORT
* pPort
,
1262 // Locate the configuration data
1264 pBuffer
= (UINT8
*)pPort
;
1265 pBuffer
= &pBuffer
[ pPort
->pSocket
->pApi
->ConfigDataOffset
];
1266 pConfigData
= (VOID
*)pBuffer
;
1269 // Validate that the port is connected
1271 Status
= pPort
->pSocket
->pApi
->pfnVerifyLocalIpAddress ( pPort
, pBuffer
);
1272 if ( EFI_ERROR ( Status
)) {
1273 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1274 "WARNING - Port 0x%08x invalid IP address: %r\r\n",
1277 pPort
->pSocket
->errno
= ErrnoValue
;
1281 // Attempt to use this configuration
1283 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, pConfigData
);
1284 if ( EFI_ERROR ( Status
)) {
1285 DEBUG (( DEBUG_WARN
| DEBUG_BIND
,
1286 "WARNING - Port 0x%08x failed configuration, Status: %r\r\n",
1289 pPort
->pSocket
->errno
= ErrnoValue
;
1295 Status
= pPort
->pfnConfigure ( pPort
->pProtocol
.v
, NULL
);
1296 if ( EFI_ERROR ( Status
)) {
1297 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
,
1298 "ERROR - Port 0x%08x failed configuration reset, Status: %r\r\n",
1301 ASSERT ( EFI_SUCCESS
== Status
);
1307 // Return the operation status
1309 DBG_EXIT_STATUS ( Status
);
1314 /** Determine if the socket is closed.
1316 This routine checks the state of the socket to determine if
1317 the network specific layer has completed the close operation.
1319 The ::close routine polls this routine to determine when the
1320 close operation is complete. The close operation needs to
1321 reverse the operations of the ::EslSocketAllocate routine.
1323 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1324 @param[out] pErrno Address to receive the errno value upon completion.
1326 @retval EFI_SUCCESS Socket successfully closed
1327 @retval EFI_NOT_READY Close still in progress
1328 @retval EFI_ALREADY Close operation already in progress
1329 @retval Other Failed to close the socket
1332 EslSocketClosePoll (
1333 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1339 ESL_SOCKET
* pNextSocket
;
1340 ESL_SOCKET
* pSocket
;
1342 EFI_TPL TplPrevious
;
1350 Status
= EFI_SUCCESS
;
1353 // Synchronize with the socket layer
1355 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1358 // Locate the socket
1360 pLayer
= &mEslLayer
;
1361 pNextSocket
= pLayer
->pSocketList
;
1362 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1363 while ( NULL
!= pNextSocket
) {
1364 if ( pNextSocket
== pSocket
) {
1366 // Determine if the socket is in the closing state
1368 if ( SOCKET_STATE_CLOSED
== pSocket
->State
) {
1370 // Walk the list of ports
1372 if ( NULL
== pSocket
->pPortList
) {
1374 // All the ports are closed
1375 // Close the WaitAccept event if necessary
1377 if ( NULL
!= pSocket
->WaitAccept
) {
1378 Status
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
1379 if ( !EFI_ERROR ( Status
)) {
1380 DEBUG (( DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1381 "0x%08x: Closed WaitAccept event\r\n",
1382 pSocket
->WaitAccept
));
1384 // Return the transmit status
1386 Status
= pSocket
->TxError
;
1387 if ( EFI_ERROR ( Status
)) {
1388 pSocket
->errno
= EIO
;
1392 DEBUG (( DEBUG_ERROR
| DEBUG_SOCKET
| DEBUG_CLOSE
| DEBUG_POOL
,
1393 "ERROR - Failed to close the WaitAccept event, Status: %r\r\n",
1395 ASSERT ( EFI_SUCCESS
== Status
);
1401 // At least one port is still open
1403 Status
= EFI_NOT_READY
;
1409 // SocketCloseStart was not called
1411 Status
= EFI_NOT_STARTED
;
1418 // Set the next socket
1420 pNextSocket
= pNextSocket
->pNext
;
1424 // Handle the error case where the socket was already closed
1426 if ( NULL
== pSocket
) {
1430 Status
= EFI_NOT_FOUND
;
1435 // Release the socket layer synchronization
1437 RESTORE_TPL ( TplPrevious
);
1440 // Return the operation status
1442 if ( NULL
!= pErrno
) {
1445 DBG_EXIT_STATUS ( Status
);
1450 /** Start the close operation on the socket.
1452 This routine calls the network specific layer to initiate the
1453 close state machine. This routine then calls the network
1454 specific layer to determine if the close state machine has gone
1455 to completion. The result from this poll is returned to the
1458 The ::close routine calls this routine to start the close
1459 operation which reverses the operations of the
1460 ::EslSocketAllocate routine. The close routine then polls
1461 the ::EslSocketClosePoll routine to determine when the
1464 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1465 @param[in] bCloseNow Boolean to control close behavior
1466 @param[out] pErrno Address to receive the errno value upon completion.
1468 @retval EFI_SUCCESS Socket successfully closed
1469 @retval EFI_NOT_READY Close still in progress
1470 @retval EFI_ALREADY Close operation already in progress
1471 @retval Other Failed to close the socket
1474 EslSocketCloseStart (
1475 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1476 IN BOOLEAN bCloseNow
,
1481 ESL_PORT
* pNextPort
;
1483 ESL_SOCKET
* pSocket
;
1485 EFI_TPL TplPrevious
;
1492 Status
= EFI_SUCCESS
;
1496 // Synchronize with the socket layer
1498 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1501 // Determine if the socket is already closed
1503 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1504 if ( SOCKET_STATE_CLOSED
> pSocket
->State
) {
1506 // Update the socket state
1508 pSocket
->State
= SOCKET_STATE_CLOSED
;
1511 // Walk the list of ports
1513 pPort
= pSocket
->pPortList
;
1514 while ( NULL
!= pPort
) {
1516 // Start closing the ports
1518 pNextPort
= pPort
->pLinkSocket
;
1519 Status
= EslSocketPortCloseStart ( pPort
,
1521 DEBUG_CLOSE
| DEBUG_LISTEN
| DEBUG_CONNECTION
);
1522 if (( EFI_SUCCESS
!= Status
)
1523 && ( EFI_NOT_READY
!= Status
)) {
1529 // Set the next port
1535 // Attempt to finish closing the socket
1537 if ( NULL
== pPort
) {
1538 Status
= EslSocketClosePoll ( pSocketProtocol
, &errno
);
1542 Status
= EFI_NOT_READY
;
1547 // Release the socket layer synchronization
1549 RESTORE_TPL ( TplPrevious
);
1552 // Return the operation status
1554 if ( NULL
!= pErrno
) {
1557 DBG_EXIT_STATUS ( Status
);
1562 /** Connect to a remote system via the network.
1564 This routine calls the network specific layer to establish
1565 the remote system address and establish the connection to
1568 The ::connect routine calls this routine to establish a
1569 connection with the specified remote system. This routine
1570 is designed to be polled by the connect routine for completion
1571 of the network connection.
1573 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1574 @param[in] pSockAddr Network address of the remote system.
1575 @param[in] SockAddrLength Length in bytes of the network address.
1576 @param[out] pErrno Address to receive the errno value upon completion.
1578 @retval EFI_SUCCESS The connection was successfully established.
1579 @retval EFI_NOT_READY The connection is in progress, call this routine again.
1580 @retval Others The connection attempt failed.
1584 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1585 IN
const struct sockaddr
* pSockAddr
,
1586 IN socklen_t SockAddrLength
,
1590 struct sockaddr_in6 LocalAddress
;
1592 ESL_SOCKET
* pSocket
;
1594 EFI_TPL TplPrevious
;
1596 DEBUG (( DEBUG_CONNECT
, "Entering SocketConnect\r\n" ));
1601 Status
= EFI_SUCCESS
;
1604 // Validate the socket
1607 if ( NULL
!= pSocketProtocol
) {
1608 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1611 // Validate the name length
1613 if ( SockAddrLength
< ( sizeof ( struct sockaddr
) - sizeof ( pSockAddr
->sa_data
))) {
1614 DEBUG (( DEBUG_CONNECT
,
1615 "ERROR - Invalid bind name length: %d\r\n",
1617 Status
= EFI_INVALID_PARAMETER
;
1618 pSocket
->errno
= EINVAL
;
1627 // Synchronize with the socket layer
1629 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1632 // Validate the socket state
1634 switch ( pSocket
->State
) {
1637 // Wrong socket state
1639 pSocket
->errno
= EIO
;
1640 Status
= EFI_DEVICE_ERROR
;
1643 case SOCKET_STATE_NOT_CONFIGURED
:
1644 case SOCKET_STATE_BOUND
:
1646 // Validate the address length
1648 if ( SockAddrLength
>= pSocket
->pApi
->MinimumAddressLength
) {
1652 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrSet
) {
1654 // Already connected
1656 pSocket
->errno
= ENOTSUP
;
1657 Status
= EFI_UNSUPPORTED
;
1661 // Determine if BIND was already called
1663 if ( NULL
== pSocket
->pPortList
) {
1665 // Allow any local port
1667 ZeroMem ( &LocalAddress
, sizeof ( LocalAddress
));
1668 LocalAddress
.sin6_len
= (uint8_t)pSocket
->pApi
->MinimumAddressLength
;
1669 LocalAddress
.sin6_family
= pSocket
->pApi
->AddressFamily
;
1670 Status
= EslSocketBind ( &pSocket
->SocketProtocol
,
1671 (struct sockaddr
*)&LocalAddress
,
1672 LocalAddress
.sin6_len
,
1675 if ( NULL
!= pSocket
->pPortList
) {
1677 // Walk the list of ports
1679 pPort
= pSocket
->pPortList
;
1680 while ( NULL
!= pPort
) {
1682 // Set the remote address
1684 Status
= pSocket
->pApi
->pfnRemoteAddrSet ( pPort
,
1687 if ( EFI_ERROR ( Status
)) {
1692 // Set the next port
1694 pPort
= pPort
->pLinkSocket
;
1700 if (( !EFI_ERROR ( Status
))
1701 && ( NULL
!= pSocket
->pApi
->pfnConnectStart
)) {
1703 // Initiate the connection with the remote system
1705 Status
= pSocket
->pApi
->pfnConnectStart ( pSocket
);
1708 // Set the next state if connecting
1710 if ( EFI_NOT_READY
== Status
) {
1711 pSocket
->State
= SOCKET_STATE_CONNECTING
;
1718 DEBUG (( DEBUG_CONNECT
,
1719 "ERROR - Invalid address length: %d\r\n",
1721 Status
= EFI_INVALID_PARAMETER
;
1722 pSocket
->errno
= EINVAL
;
1726 case SOCKET_STATE_CONNECTING
:
1728 // Poll the network adapter
1730 EslSocketRxPoll ( pSocket
);
1733 // Poll for connection completion
1735 if ( NULL
== pSocket
->pApi
->pfnConnectPoll
) {
1737 // Already connected
1739 pSocket
->errno
= EISCONN
;
1740 Status
= EFI_ALREADY_STARTED
;
1743 Status
= pSocket
->pApi
->pfnConnectPoll ( pSocket
);
1746 // Set the next state if connected
1748 if ( EFI_NOT_READY
!= Status
) {
1749 if ( EFI_ERROR ( Status
)) {
1750 pSocket
->State
= SOCKET_STATE_BOUND
;
1756 case SOCKET_STATE_CONNECTED
:
1760 Status
= EFI_SUCCESS
;
1765 // Release the socket layer synchronization
1767 RESTORE_TPL ( TplPrevious
);
1772 // Return the operation status
1774 if ( NULL
!= pErrno
) {
1775 if ( NULL
!= pSocket
) {
1776 *pErrno
= pSocket
->errno
;
1780 // Bad socket protocol
1782 DEBUG (( DEBUG_ERROR
| DEBUG_CONNECT
,
1783 "ERROR - pSocketProtocol invalid!\r\n" ));
1784 Status
= EFI_INVALID_PARAMETER
;
1790 // Return the operation status
1792 DEBUG (( DEBUG_CONNECT
, "Exiting SocketConnect, Status: %r\r\n", Status
));
1797 /** Copy a fragmented buffer into a destination buffer.
1799 This support routine copies a fragmented buffer to the caller specified buffer.
1801 This routine is called by ::EslIp4Receive and ::EslUdp4Receive.
1803 @param[in] FragmentCount Number of fragments in the table
1804 @param[in] pFragmentTable Address of an EFI_IP4_FRAGMENT_DATA structure
1805 @param[in] BufferLength Length of the the buffer
1806 @param[in] pBuffer Address of a buffer to receive the data.
1807 @param[in] pDataLength Number of received data bytes in the buffer.
1809 @return Returns the address of the next free byte in the buffer.
1812 EslSocketCopyFragmentedBuffer (
1813 IN UINT32 FragmentCount
,
1814 IN EFI_IP4_FRAGMENT_DATA
* pFragmentTable
,
1815 IN
size_t BufferLength
,
1817 OUT
size_t * pDataLength
1828 // Validate the IP and UDP structures are identical
1830 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentLength
)
1831 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentLength
));
1832 ASSERT ( OFFSET_OF ( EFI_IP4_FRAGMENT_DATA
, FragmentBuffer
)
1833 == OFFSET_OF ( EFI_UDP4_FRAGMENT_DATA
, FragmentBuffer
));
1836 // Copy the received data
1839 pBufferEnd
= &pBuffer
[ BufferLength
];
1840 while (( pBufferEnd
> pBuffer
) && ( FragmentCount
> Fragment
)) {
1842 // Determine the amount of received data
1844 pData
= pFragmentTable
[Fragment
].FragmentBuffer
;
1845 BytesToCopy
= pFragmentTable
[Fragment
].FragmentLength
;
1846 if (((size_t)( pBufferEnd
- pBuffer
)) < BytesToCopy
) {
1847 BytesToCopy
= pBufferEnd
- pBuffer
;
1851 // Move the data into the buffer
1854 "0x%08x --> 0x%08x: Copy data 0x%08x bytes\r\n",
1858 CopyMem ( pBuffer
, pData
, BytesToCopy
);
1859 pBuffer
+= BytesToCopy
;
1864 // Return the data length and the buffer address
1866 *pDataLength
= BufferLength
- ( pBufferEnd
- pBuffer
);
1867 DBG_EXIT_HEX ( pBuffer
);
1872 /** Free the socket.
1874 This routine frees the socket structure and handle resources.
1876 The ::close routine calls EslServiceFreeProtocol which then calls
1877 this routine to free the socket context structure and close the
1880 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
1881 @param[out] pErrno Address to receive the errno value upon completion.
1883 @retval EFI_SUCCESS The socket resources were returned successfully.
1887 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
1891 EFI_HANDLE ChildHandle
;
1894 ESL_SOCKET
* pSocket
;
1895 ESL_SOCKET
* pSocketPrevious
;
1897 EFI_TPL TplPrevious
;
1906 Status
= EFI_INVALID_PARAMETER
;
1909 // Validate the socket
1911 pLayer
= &mEslLayer
;
1912 if ( NULL
!= pSocketProtocol
) {
1913 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
1916 // Synchronize with the socket layer
1918 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
1921 // Walk the socket list
1923 pSocketPrevious
= pLayer
->pSocketList
;
1924 if ( NULL
!= pSocketPrevious
) {
1925 if ( pSocket
== pSocketPrevious
) {
1927 // Remove the socket from the head of the list
1929 pLayer
->pSocketList
= pSocket
->pNext
;
1933 // Find the socket in the middle of the list
1935 while (( NULL
!= pSocketPrevious
)
1936 && ( pSocket
!= pSocketPrevious
->pNext
)) {
1938 // Set the next socket
1940 pSocketPrevious
= pSocketPrevious
->pNext
;
1942 if ( NULL
!= pSocketPrevious
) {
1944 // Remove the socket from the middle of the list
1946 pSocketPrevious
= pSocket
->pNext
;
1951 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
1952 "ERROR - Socket list is empty!\r\n" ));
1956 // Release the socket layer synchronization
1958 RESTORE_TPL ( TplPrevious
);
1961 // Determine if the socket was found
1963 if ( NULL
!= pSocketPrevious
) {
1964 pSocket
->pNext
= NULL
;
1967 // Remove the socket protocol
1969 ChildHandle
= pSocket
->SocketProtocol
.SocketHandle
;
1970 Status
= gBS
->UninstallMultipleProtocolInterfaces (
1972 &gEfiSocketProtocolGuid
,
1973 &pSocket
->SocketProtocol
,
1975 if ( !EFI_ERROR ( Status
)) {
1976 DEBUG (( DEBUG_POOL
| DEBUG_INFO
,
1977 "Removed: gEfiSocketProtocolGuid from 0x%08x\r\n",
1981 // Free the socket structure
1983 Status
= gBS
->FreePool ( pSocket
);
1984 if ( !EFI_ERROR ( Status
)) {
1985 DEBUG (( DEBUG_POOL
,
1986 "0x%08x: Free pSocket, %d bytes\r\n",
1988 sizeof ( *pSocket
)));
1992 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
1993 "ERROR - Failed to free pSocket 0x%08x, Status: %r\r\n",
1999 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
| DEBUG_INFO
,
2000 "ERROR - Failed to remove gEfiSocketProtocolGuid from 0x%08x, Status: %r\r\n",
2006 DEBUG (( DEBUG_ERROR
| DEBUG_INFO
,
2007 "ERROR - The socket was not in the socket list!\r\n" ));
2008 Status
= EFI_NOT_FOUND
;
2012 DEBUG (( DEBUG_ERROR
,
2013 "ERROR - Invalid parameter pSocketProtocol is NULL\r\n" ));
2017 // Return the errno value if possible
2019 if ( NULL
!= pErrno
) {
2024 // Return the operation status
2026 DBG_EXIT_STATUS ( Status
);
2031 /** Get the local address.
2033 This routine calls the network specific layer to get the network
2034 address of the local host connection point.
2036 The ::getsockname routine calls this routine to obtain the network
2037 address associated with the local host connection point.
2039 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2040 @param[out] pAddress Network address to receive the local system address
2041 @param[in,out] pAddressLength Length of the local network address structure
2042 @param[out] pErrno Address to receive the errno value upon completion.
2044 @retval EFI_SUCCESS - Local address successfully returned
2047 EslSocketGetLocalAddress (
2048 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2049 OUT
struct sockaddr
* pAddress
,
2050 IN OUT socklen_t
* pAddressLength
,
2054 socklen_t LengthInBytes
;
2056 ESL_SOCKET
* pSocket
;
2058 EFI_TPL TplPrevious
;
2065 Status
= EFI_SUCCESS
;
2068 // Validate the socket
2071 if ( NULL
!= pSocketProtocol
) {
2072 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2075 // Verify the socket state
2077 EslSocketIsConfigured ( pSocket
);
2078 if ( pSocket
->bAddressSet
) {
2080 // Verify the address buffer and length address
2082 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2086 if ( NULL
== pSocket
->pApi
->pfnLocalAddrGet
) {
2087 Status
= EFI_UNSUPPORTED
;
2088 pSocket
->errno
= ENOTSUP
;
2092 // Synchronize with the socket layer
2094 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2097 // Verify that there is just a single connection
2099 pPort
= pSocket
->pPortList
;
2100 if ( NULL
!= pPort
) {
2102 // Verify the address length
2104 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2105 if (( LengthInBytes
<= *pAddressLength
)
2106 && ( 255 >= LengthInBytes
)) {
2108 // Return the local address and address length
2110 ZeroMem ( pAddress
, LengthInBytes
);
2111 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2112 *pAddressLength
= pAddress
->sa_len
;
2113 pSocket
->pApi
->pfnLocalAddrGet ( pPort
, pAddress
);
2115 Status
= EFI_SUCCESS
;
2118 pSocket
->errno
= EINVAL
;
2119 Status
= EFI_INVALID_PARAMETER
;
2123 pSocket
->errno
= ENOTCONN
;
2124 Status
= EFI_NOT_STARTED
;
2128 // Release the socket layer synchronization
2130 RESTORE_TPL ( TplPrevious
);
2134 pSocket
->errno
= EINVAL
;
2135 Status
= EFI_INVALID_PARAMETER
;
2142 Status
= EFI_NOT_STARTED
;
2143 pSocket
->errno
= EADDRNOTAVAIL
;
2148 // Return the operation status
2150 if ( NULL
!= pErrno
) {
2151 if ( NULL
!= pSocket
) {
2152 *pErrno
= pSocket
->errno
;
2155 Status
= EFI_INVALID_PARAMETER
;
2159 DBG_EXIT_STATUS ( Status
);
2164 /** Get the peer address.
2166 This routine calls the network specific layer to get the remote
2167 system connection point.
2169 The ::getpeername routine calls this routine to obtain the network
2170 address of the remote connection point.
2172 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2173 @param[out] pAddress Network address to receive the remote system address
2174 @param[in,out] pAddressLength Length of the remote network address structure
2175 @param[out] pErrno Address to receive the errno value upon completion.
2177 @retval EFI_SUCCESS - Remote address successfully returned
2180 EslSocketGetPeerAddress (
2181 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2182 OUT
struct sockaddr
* pAddress
,
2183 IN OUT socklen_t
* pAddressLength
,
2187 socklen_t LengthInBytes
;
2189 ESL_SOCKET
* pSocket
;
2191 EFI_TPL TplPrevious
;
2198 Status
= EFI_SUCCESS
;
2201 // Validate the socket
2204 if ( NULL
!= pSocketProtocol
) {
2205 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2208 // Verify the socket state
2210 Status
= EslSocketIsConfigured ( pSocket
);
2211 if ( !EFI_ERROR ( Status
)) {
2215 if ( NULL
== pSocket
->pApi
->pfnRemoteAddrGet
) {
2216 Status
= EFI_UNSUPPORTED
;
2217 pSocket
->errno
= ENOTSUP
;
2221 // Verify the address buffer and length address
2223 if (( NULL
!= pAddress
) && ( NULL
!= pAddressLength
)) {
2225 // Verify the socket state
2227 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
2229 // Synchronize with the socket layer
2231 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2234 // Verify that there is just a single connection
2236 pPort
= pSocket
->pPortList
;
2237 if (( NULL
!= pPort
) && ( NULL
== pPort
->pLinkSocket
)) {
2239 // Verify the address length
2241 LengthInBytes
= pSocket
->pApi
->AddressLength
;
2242 if ( LengthInBytes
<= *pAddressLength
) {
2244 // Return the local address
2246 ZeroMem ( pAddress
, LengthInBytes
);
2247 pAddress
->sa_len
= (uint8_t)LengthInBytes
;
2248 *pAddressLength
= pAddress
->sa_len
;
2249 pSocket
->pApi
->pfnRemoteAddrGet ( pPort
, pAddress
);
2251 Status
= EFI_SUCCESS
;
2254 pSocket
->errno
= EINVAL
;
2255 Status
= EFI_INVALID_PARAMETER
;
2259 pSocket
->errno
= ENOTCONN
;
2260 Status
= EFI_NOT_STARTED
;
2264 // Release the socket layer synchronization
2266 RESTORE_TPL ( TplPrevious
);
2269 pSocket
->errno
= ENOTCONN
;
2270 Status
= EFI_NOT_STARTED
;
2274 pSocket
->errno
= EINVAL
;
2275 Status
= EFI_INVALID_PARAMETER
;
2282 // Return the operation status
2284 if ( NULL
!= pErrno
) {
2285 if ( NULL
!= pSocket
) {
2286 *pErrno
= pSocket
->errno
;
2289 Status
= EFI_INVALID_PARAMETER
;
2293 DBG_EXIT_STATUS ( Status
);
2298 /** Free the ESL_IO_MGMT event and structure.
2300 This support routine walks the free list to close the event in
2301 the ESL_IO_MGMT structure and remove the structure from the free
2304 See the \ref TransmitEngine section.
2306 @param[in] pPort Address of an ::ESL_PORT structure
2307 @param[in] ppFreeQueue Address of the free queue head
2308 @param[in] DebugFlags Flags for debug messages
2309 @param[in] pEventName Zero terminated string containing the event name
2311 @retval EFI_SUCCESS - The structures were properly initialized
2315 IN ESL_PORT
* pPort
,
2316 IN ESL_IO_MGMT
** ppFreeQueue
,
2317 IN UINTN DebugFlags
,
2318 IN CHAR8
* pEventName
2324 ESL_SOCKET
* pSocket
;
2332 Status
= EFI_SUCCESS
;
2335 // Walk the list of IO structures
2337 pSocket
= pPort
->pSocket
;
2338 while ( *ppFreeQueue
) {
2340 // Free the event for this structure
2343 pBuffer
= (UINT8
*)pIo
;
2344 pBuffer
= &pBuffer
[ pSocket
->TxTokenEventOffset
];
2345 pEvent
= (EFI_EVENT
*)pBuffer
;
2346 Status
= gBS
->CloseEvent ( *pEvent
);
2347 if ( EFI_ERROR ( Status
)) {
2348 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2349 "ERROR - Failed to close the %a event, Status: %r\r\n",
2352 pSocket
->errno
= ENOMEM
;
2355 DEBUG (( DebugFlags
,
2356 "0x%08x: Closed %a event 0x%08x\r\n",
2362 // Remove this structure from the queue
2364 *ppFreeQueue
= pIo
->pNext
;
2368 // Return the operation status
2370 DBG_EXIT_STATUS ( Status
);
2375 /** Initialize the ESL_IO_MGMT structures.
2377 This support routine initializes the ESL_IO_MGMT structure and
2378 places them on to a free list.
2380 This routine is called by ::EslSocketPortAllocate routines to prepare
2381 the transmit engines. See the \ref TransmitEngine section.
2383 @param[in] pPort Address of an ::ESL_PORT structure
2384 @param[in, out] ppIo Address containing the first structure address. Upon
2385 return this buffer contains the next structure address.
2386 @param[in] TokenCount Number of structures to initialize
2387 @param[in] ppFreeQueue Address of the free queue head
2388 @param[in] DebugFlags Flags for debug messages
2389 @param[in] pEventName Zero terminated string containing the event name
2390 @param[in] pfnCompletion Completion routine address
2392 @retval EFI_SUCCESS - The structures were properly initialized
2396 IN ESL_PORT
* pPort
,
2397 IN ESL_IO_MGMT
** ppIo
,
2398 IN UINTN TokenCount
,
2399 IN ESL_IO_MGMT
** ppFreeQueue
,
2400 IN UINTN DebugFlags
,
2401 IN CHAR8
* pEventName
,
2402 IN PFN_API_IO_COMPLETE pfnCompletion
2408 ESL_SOCKET
* pSocket
;
2416 Status
= EFI_SUCCESS
;
2419 // Walk the list of IO structures
2421 pSocket
= pPort
->pSocket
;
2423 pEnd
= &pIo
[ TokenCount
];
2424 while ( pEnd
> pIo
) {
2426 // Initialize the IO structure
2429 pIo
->pPacket
= NULL
;
2432 // Allocate the event for this structure
2434 pEvent
= (EFI_EVENT
*)&(((UINT8
*)pIo
)[ pSocket
->TxTokenEventOffset
]);
2435 Status
= gBS
->CreateEvent ( EVT_NOTIFY_SIGNAL
,
2437 (EFI_EVENT_NOTIFY
)pfnCompletion
,
2440 if ( EFI_ERROR ( Status
)) {
2441 DEBUG (( DEBUG_ERROR
| DebugFlags
,
2442 "ERROR - Failed to create the %a event, Status: %r\r\n",
2445 pSocket
->errno
= ENOMEM
;
2448 DEBUG (( DebugFlags
,
2449 "0x%08x: Created %a event 0x%08x\r\n",
2455 // Add this structure to the queue
2457 pIo
->pNext
= *ppFreeQueue
;
2461 // Set the next structure
2467 // Save the next structure
2472 // Return the operation status
2474 DBG_EXIT_STATUS ( Status
);
2479 /** Determine if the socket is configured.
2481 This support routine is called to determine if the socket if the
2482 configuration call was made to the network layer. The following
2483 routines call this routine to verify that they may be successful
2484 in their operations:
2486 <li>::EslSocketGetLocalAddress</li>
2487 <li>::EslSocketGetPeerAddress</li>
2488 <li>::EslSocketPoll</li>
2489 <li>::EslSocketReceive</li>
2490 <li>::EslSocketTransmit</li>
2493 @param[in] pSocket Address of an ::ESL_SOCKET structure
2495 @retval EFI_SUCCESS - The socket is configured
2498 EslSocketIsConfigured (
2499 IN ESL_SOCKET
* pSocket
2503 EFI_TPL TplPrevious
;
2508 Status
= EFI_SUCCESS
;
2511 // Verify the socket state
2513 if ( !pSocket
->bConfigured
) {
2519 if ( NULL
== pSocket
->pApi
->pfnIsConfigured
) {
2520 Status
= EFI_UNSUPPORTED
;
2521 pSocket
->errno
= ENOTSUP
;
2525 // Synchronize with the socket layer
2527 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2530 // Determine if the socket is configured
2532 Status
= pSocket
->pApi
->pfnIsConfigured ( pSocket
);
2535 // Release the socket layer synchronization
2537 RESTORE_TPL ( TplPrevious
);
2540 // Set errno if a failure occurs
2542 if ( EFI_ERROR ( Status
)) {
2543 pSocket
->errno
= EADDRNOTAVAIL
;
2547 DBG_EXIT_STATUS ( Status
);
2551 // Return the configuration status
2557 /** Establish the known port to listen for network connections.
2559 This routine calls into the network protocol layer to establish
2560 a handler that is called upon connection completion. The handler
2561 is responsible for inserting the connection into the FIFO.
2563 The ::listen routine indirectly calls this routine to place the
2564 socket into a state that enables connection attempts. Connections
2565 are placed in a FIFO that is serviced by the application. The
2566 application calls the ::accept (::EslSocketAccept) routine to
2567 remove the next connection from the FIFO and get the associated
2570 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2571 @param[in] Backlog Backlog specifies the maximum FIFO depth for
2572 the connections waiting for the application
2573 to call accept. Connection attempts received
2574 while the queue is full are refused.
2575 @param[out] pErrno Address to receive the errno value upon completion.
2577 @retval EFI_SUCCESS - Socket successfully created
2578 @retval Other - Failed to enable the socket for listen
2582 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2587 ESL_SOCKET
* pSocket
;
2589 EFI_STATUS TempStatus
;
2590 EFI_TPL TplPrevious
;
2597 Status
= EFI_SUCCESS
;
2600 // Validate the socket
2603 if ( NULL
!= pSocketProtocol
) {
2604 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2609 if ( NULL
== pSocket
->pApi
->pfnListen
) {
2610 Status
= EFI_UNSUPPORTED
;
2611 pSocket
->errno
= ENOTSUP
;
2617 pSocket
->Status
= EFI_SUCCESS
;
2621 // Verify that the bind operation was successful
2623 if ( SOCKET_STATE_BOUND
== pSocket
->State
) {
2625 // Synchronize with the socket layer
2627 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
2630 // Create the event for SocketAccept completion
2632 Status
= gBS
->CreateEvent ( 0,
2636 &pSocket
->WaitAccept
);
2637 if ( !EFI_ERROR ( Status
)) {
2638 DEBUG (( DEBUG_POOL
,
2639 "0x%08x: Created WaitAccept event\r\n",
2640 pSocket
->WaitAccept
));
2642 // Set the maximum FIFO depth
2644 if ( 0 >= Backlog
) {
2645 Backlog
= MAX_PENDING_CONNECTIONS
;
2648 if ( SOMAXCONN
< Backlog
) {
2649 Backlog
= SOMAXCONN
;
2652 pSocket
->MaxFifoDepth
= Backlog
;
2657 // Initiate the connection attempt listen
2659 Status
= pSocket
->pApi
->pfnListen ( pSocket
);
2662 // Place the socket in the listen state if successful
2664 if ( !EFI_ERROR ( Status
)) {
2665 pSocket
->State
= SOCKET_STATE_LISTENING
;
2666 pSocket
->bListenCalled
= TRUE
;
2670 // Not waiting for SocketAccept to complete
2672 TempStatus
= gBS
->CloseEvent ( pSocket
->WaitAccept
);
2673 if ( !EFI_ERROR ( TempStatus
)) {
2674 DEBUG (( DEBUG_POOL
,
2675 "0x%08x: Closed WaitAccept event\r\n",
2676 pSocket
->WaitAccept
));
2677 pSocket
->WaitAccept
= NULL
;
2680 DEBUG (( DEBUG_ERROR
| DEBUG_POOL
,
2681 "ERROR - Failed to close WaitAccept event, Status: %r\r\n",
2683 ASSERT ( EFI_SUCCESS
== TempStatus
);
2688 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2689 "ERROR - Failed to create the WaitAccept event, Status: %r\r\n",
2691 pSocket
->errno
= ENOMEM
;
2695 // Release the socket layer synchronization
2697 RESTORE_TPL ( TplPrevious
);
2700 DEBUG (( DEBUG_ERROR
| DEBUG_LISTEN
,
2701 "ERROR - Bind operation must be performed first!\r\n" ));
2702 pSocket
->errno
= ( SOCKET_STATE_NOT_CONFIGURED
== pSocket
->State
) ? EDESTADDRREQ
2704 Status
= EFI_NO_MAPPING
;
2710 // Return the operation status
2712 if ( NULL
!= pErrno
) {
2713 if ( NULL
!= pSocket
) {
2714 *pErrno
= pSocket
->errno
;
2717 Status
= EFI_INVALID_PARAMETER
;
2721 DBG_EXIT_STATUS ( Status
);
2726 /** Get the socket options.
2728 This routine handles the socket level options and passes the
2729 others to the network specific layer.
2731 The ::getsockopt routine calls this routine to retrieve the
2732 socket options one at a time by name.
2734 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2735 @param[in] level Option protocol level
2736 @param[in] OptionName Name of the option
2737 @param[out] pOptionValue Buffer to receive the option value
2738 @param[in,out] pOptionLength Length of the buffer in bytes,
2739 upon return length of the option value in bytes
2740 @param[out] pErrno Address to receive the errno value upon completion.
2742 @retval EFI_SUCCESS - Socket data successfully received
2745 EslSocketOptionGet (
2746 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2749 OUT
void * __restrict pOptionValue
,
2750 IN OUT socklen_t
* __restrict pOptionLength
,
2755 socklen_t LengthInBytes
;
2757 CONST UINT8
* pOptionData
;
2758 ESL_SOCKET
* pSocket
;
2767 Status
= EFI_INVALID_PARAMETER
;
2770 // Validate the socket
2773 if ( NULL
== pSocketProtocol
) {
2774 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2776 else if ( NULL
== pOptionValue
) {
2777 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
2779 else if ( NULL
== pOptionLength
) {
2780 DEBUG (( DEBUG_OPTION
, "ERROR - Option length not specified!\r\n" ));
2783 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
2785 MaxBytes
= *pOptionLength
;
2790 // See if the protocol will handle the option
2792 if ( NULL
!= pSocket
->pApi
->pfnOptionGet
) {
2793 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
2794 Status
= pSocket
->pApi
->pfnOptionGet ( pSocket
,
2796 (CONST
void ** __restrict
)&pOptionData
,
2798 errno
= pSocket
->errno
;
2803 // Protocol not supported
2805 DEBUG (( DEBUG_OPTION
,
2806 "ERROR - The socket does not support this protocol!\r\n" ));
2811 // Protocol level not supported
2813 DEBUG (( DEBUG_OPTION
,
2814 "ERROR - %a does not support any options!\r\n",
2815 pSocket
->pApi
->pName
));
2817 errno
= ENOPROTOOPT
;
2818 Status
= EFI_INVALID_PARAMETER
;
2822 switch ( OptionName
) {
2825 // Socket option not supported
2827 DEBUG (( DEBUG_INFO
| DEBUG_OPTION
, "ERROR - Invalid socket option!\r\n" ));
2829 Status
= EFI_INVALID_PARAMETER
;
2834 // Return the listen flag
2836 pOptionData
= (CONST UINT8
*)&pSocket
->bListenCalled
;
2837 LengthInBytes
= sizeof ( pSocket
->bListenCalled
);
2842 // Return the debug flags
2844 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2845 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2850 // Return the out-of-band inline flag
2852 pOptionData
= (CONST UINT8
*)&pSocket
->bOobInLine
;
2853 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
2858 // Return the receive timeout
2860 pOptionData
= (CONST UINT8
*)&pSocket
->RxTimeout
;
2861 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
2866 // Return the maximum receive buffer size
2868 pOptionData
= (CONST UINT8
*)&pSocket
->MaxRxBuf
;
2869 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
2874 // Return the address reuse flag
2876 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
2877 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
2882 // Return the maximum transmit buffer size
2884 pOptionData
= (CONST UINT8
*)&pSocket
->MaxTxBuf
;
2885 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
2890 // Return the socket type
2892 pOptionData
= (CONST UINT8
*)&pSocket
->Type
;
2893 LengthInBytes
= sizeof ( pSocket
->Type
);
2900 // Return the option length
2902 *pOptionLength
= LengthInBytes
;
2905 // Determine if the option is present
2907 if ( 0 != LengthInBytes
) {
2909 // Silently truncate the value length
2911 if ( LengthInBytes
> MaxBytes
) {
2912 DEBUG (( DEBUG_OPTION
,
2913 "INFO - Truncating option from %d to %d bytes\r\n",
2916 LengthInBytes
= MaxBytes
;
2922 CopyMem ( pOptionValue
, pOptionData
, LengthInBytes
);
2925 // Zero fill any remaining space
2927 if ( LengthInBytes
< MaxBytes
) {
2928 ZeroMem ( &((UINT8
*)pOptionValue
)[LengthInBytes
], MaxBytes
- LengthInBytes
);
2931 Status
= EFI_SUCCESS
;
2936 // Return the operation status
2938 if ( NULL
!= pErrno
) {
2941 DBG_EXIT_STATUS ( Status
);
2946 /** Set the socket options.
2948 This routine handles the socket level options and passes the
2949 others to the network specific layer.
2951 The ::setsockopt routine calls this routine to adjust the socket
2952 options one at a time by name.
2954 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
2955 @param[in] level Option protocol level
2956 @param[in] OptionName Name of the option
2957 @param[in] pOptionValue Buffer containing the option value
2958 @param[in] OptionLength Length of the buffer in bytes
2959 @param[out] pErrno Address to receive the errno value upon completion.
2961 @retval EFI_SUCCESS - Option successfully set
2964 EslSocketOptionSet (
2965 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
2968 IN CONST
void * pOptionValue
,
2969 IN socklen_t OptionLength
,
2975 socklen_t LengthInBytes
;
2976 UINT8
* pOptionData
;
2977 ESL_SOCKET
* pSocket
;
2986 Status
= EFI_INVALID_PARAMETER
;
2989 // Validate the socket
2992 if ( NULL
== pSocketProtocol
) {
2993 DEBUG (( DEBUG_OPTION
, "ERROR - pSocketProtocol is NULL!\r\n" ));
2995 else if ( NULL
== pOptionValue
) {
2996 DEBUG (( DEBUG_OPTION
, "ERROR - No option buffer specified\r\n" ));
3000 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3001 if ( pSocket
->bRxDisable
|| pSocket
->bTxDisable
) {
3002 DEBUG (( DEBUG_OPTION
, "ERROR - Socket has been shutdown!\r\n" ));
3010 // See if the protocol will handle the option
3012 if ( NULL
!= pSocket
->pApi
->pfnOptionSet
) {
3013 if ( pSocket
->pApi
->DefaultProtocol
== level
) {
3014 Status
= pSocket
->pApi
->pfnOptionSet ( pSocket
,
3018 errno
= pSocket
->errno
;
3023 // Protocol not supported
3025 DEBUG (( DEBUG_OPTION
,
3026 "ERROR - The socket does not support this protocol!\r\n" ));
3031 // Protocol level not supported
3033 DEBUG (( DEBUG_OPTION
,
3034 "ERROR - %a does not support any options!\r\n",
3035 pSocket
->pApi
->pName
));
3037 errno
= ENOPROTOOPT
;
3038 Status
= EFI_INVALID_PARAMETER
;
3042 switch ( OptionName
) {
3045 // Option not supported
3047 DEBUG (( DEBUG_OPTION
,
3048 "ERROR - Sockets does not support this option!\r\n" ));
3050 Status
= EFI_INVALID_PARAMETER
;
3055 // Set the debug flags
3057 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3058 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3062 pOptionData
= (UINT8
*)&pSocket
->bOobInLine
;
3063 LengthInBytes
= sizeof ( pSocket
->bOobInLine
);
3066 // Validate the option length
3068 if ( sizeof ( UINT32
) == OptionLength
) {
3070 // Restrict the input to TRUE or FALSE
3073 if ( 0 == *(UINT32
*)pOptionValue
) {
3076 pOptionValue
= &bTrueFalse
;
3080 // Force an invalid option length error
3082 OptionLength
= LengthInBytes
- 1;
3088 // Return the receive timeout
3090 pOptionData
= (UINT8
*)&pSocket
->RxTimeout
;
3091 LengthInBytes
= sizeof ( pSocket
->RxTimeout
);
3096 // Return the maximum receive buffer size
3098 pOptionData
= (UINT8
*)&pSocket
->MaxRxBuf
;
3099 LengthInBytes
= sizeof ( pSocket
->MaxRxBuf
);
3104 // Return the address reuse flag
3106 pOptionData
= (UINT8
*)&pSocket
->bReUseAddr
;
3107 LengthInBytes
= sizeof ( pSocket
->bReUseAddr
);
3115 // Return the maximum transmit buffer size
3117 pOptionData
= (UINT8
*)&pSocket
->MaxTxBuf
;
3118 LengthInBytes
= sizeof ( pSocket
->MaxTxBuf
);
3125 // Determine if an option was found
3127 if ( 0 != LengthInBytes
) {
3129 // Validate the option length
3131 if ( LengthInBytes
<= OptionLength
) {
3133 // Set the option value
3135 CopyMem ( pOptionData
, pOptionValue
, LengthInBytes
);
3137 Status
= EFI_SUCCESS
;
3140 DEBUG (( DEBUG_OPTION
,
3141 "ERROR - Buffer to small, %d bytes < %d bytes!\r\n",
3150 // Return the operation status
3152 if ( NULL
!= pErrno
) {
3155 DBG_EXIT_STATUS ( Status
);
3160 /** Allocate a packet for a receive or transmit operation.
3162 This support routine is called by ::EslSocketRxStart and the
3163 network specific TxBuffer routines to get buffer space for the
3166 @param[in] ppPacket Address to receive the ::ESL_PACKET structure
3167 @param[in] LengthInBytes Length of the packet structure
3168 @param[in] ZeroBytes Length of packet to zero
3169 @param[in] DebugFlags Flags for debug messages
3171 @retval EFI_SUCCESS - The packet was allocated successfully
3174 EslSocketPacketAllocate (
3175 IN ESL_PACKET
** ppPacket
,
3176 IN
size_t LengthInBytes
,
3177 IN
size_t ZeroBytes
,
3181 ESL_PACKET
* pPacket
;
3187 // Allocate a packet structure
3189 LengthInBytes
+= sizeof ( *pPacket
)
3190 - sizeof ( pPacket
->Op
);
3191 Status
= gBS
->AllocatePool ( EfiRuntimeServicesData
,
3193 (VOID
**)&pPacket
);
3194 if ( !EFI_ERROR ( Status
)) {
3195 DEBUG (( DebugFlags
| DEBUG_POOL
,
3196 "0x%08x: Allocate pPacket, %d bytes\r\n",
3199 if ( 0 != ZeroBytes
) {
3200 ZeroMem ( &pPacket
->Op
, ZeroBytes
);
3202 pPacket
->PacketSize
= LengthInBytes
;
3205 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3206 "ERROR - Packet allocation failed for %d bytes, Status: %r\r\n",
3213 // Return the packet
3215 *ppPacket
= pPacket
;
3218 // Return the operation status
3220 DBG_EXIT_STATUS ( Status
);
3225 /** Free a packet used for receive or transmit operation.
3227 This support routine is called by the network specific Close
3228 and TxComplete routines and during error cases in RxComplete
3229 and TxBuffer. Note that the network layers typically place
3230 receive packets on the ESL_SOCKET::pRxFree list for reuse.
3232 @param[in] pPacket Address of an ::ESL_PACKET structure
3233 @param[in] DebugFlags Flags for debug messages
3235 @retval EFI_SUCCESS - The packet was allocated successfully
3238 EslSocketPacketFree (
3239 IN ESL_PACKET
* pPacket
,
3243 UINTN LengthInBytes
;
3249 // Free a packet structure
3251 LengthInBytes
= pPacket
->PacketSize
;
3252 Status
= gBS
->FreePool ( pPacket
);
3253 if ( !EFI_ERROR ( Status
)) {
3254 DEBUG (( DebugFlags
| DEBUG_POOL
,
3255 "0x%08x: Free pPacket, %d bytes\r\n",
3260 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INFO
,
3261 "ERROR - Failed to free packet 0x%08x, Status: %r\r\n",
3267 // Return the operation status
3269 DBG_EXIT_STATUS ( Status
);
3274 /** Poll a socket for pending activity.
3276 This routine builds a detected event mask which is returned to
3277 the caller in the buffer provided.
3279 The ::poll routine calls this routine to determine if the socket
3280 needs to be serviced as a result of connection, error, receive or
3283 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
3284 @param[in] Events Events of interest for this socket
3285 @param[in] pEvents Address to receive the detected events
3286 @param[out] pErrno Address to receive the errno value upon completion.
3288 @retval EFI_SUCCESS - Socket successfully polled
3289 @retval EFI_INVALID_PARAMETER - When pEvents is NULL
3293 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
3299 short DetectedEvents
;
3300 ESL_SOCKET
* pSocket
;
3302 EFI_TPL TplPrevious
;
3304 int _errno
= EINVAL
;
3306 DEBUG (( DEBUG_POLL
, "Entering SocketPoll\r\n" ));
3311 Status
= EFI_SUCCESS
;
3313 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
3317 // Verify the socket state
3319 Status
= EslSocketIsConfigured ( pSocket
);
3320 if ( !EFI_ERROR ( Status
)) {
3322 // Check for invalid events
3324 ValidEvents
= POLLIN
3326 | POLLOUT
| POLLWRNORM
3333 if ( 0 != ( Events
& ( ~ValidEvents
))) {
3334 DetectedEvents
|= POLLNVAL
;
3335 DEBUG (( DEBUG_INFO
| DEBUG_POLL
,
3336 "ERROR - Invalid event mask, Valid Events: 0x%04x, Invalid Events: 0x%04x\r\n",
3337 Events
& ValidEvents
,
3338 Events
& ( ~ValidEvents
)));
3342 // Synchronize with the socket layer
3344 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
3347 // Increase the network performance by extending the
3348 // polling (idle) loop down into the LAN driver
3350 EslSocketRxPoll ( pSocket
);
3353 // Release the socket layer synchronization
3355 RESTORE_TPL ( TplPrevious
);
3358 // Check for pending connections
3360 if ( 0 != pSocket
->FifoDepth
) {
3362 // A connection is waiting for an accept call
3363 // See posix connect documentation at
3364 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.htm
3366 DetectedEvents
|= POLLIN
| POLLRDNORM
;
3368 if ( pSocket
->bConnected
) {
3370 // A connection is present
3371 // See posix connect documentation at
3372 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.htm
3374 DetectedEvents
|= POLLOUT
| POLLWRNORM
;
3378 // The following bits are set based upon the POSIX poll documentation at
3379 // http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html
3383 // Check for urgent receive data
3385 if ( 0 < pSocket
->RxOobBytes
) {
3386 DetectedEvents
|= POLLRDBAND
| POLLPRI
| POLLIN
;
3390 // Check for normal receive data
3392 if (( 0 < pSocket
->RxBytes
)
3393 || ( EFI_SUCCESS
!= pSocket
->RxError
)) {
3394 DetectedEvents
|= POLLRDNORM
| POLLIN
;
3398 // Handle the receive errors
3400 if (( EFI_SUCCESS
!= pSocket
->RxError
)
3401 && ( 0 == ( DetectedEvents
& POLLIN
))) {
3402 DetectedEvents
|= POLLERR
| POLLIN
| POLLRDNORM
| POLLRDBAND
;
3406 // Check for urgent transmit data buffer space
3408 if (( MAX_TX_DATA
> pSocket
->TxOobBytes
)
3409 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3410 DetectedEvents
|= POLLWRBAND
;
3414 // Check for normal transmit data buffer space
3416 if (( MAX_TX_DATA
> pSocket
->TxBytes
)
3417 || ( EFI_SUCCESS
!= pSocket
->TxError
)) {
3418 DetectedEvents
|= POLLWRNORM
;
3422 // Handle the transmit error
3424 if ( EFI_ERROR ( pSocket
->TxError
)) {
3425 DetectedEvents
|= POLLERR
;
3427 _errno
= pSocket
->errno
;
3432 // Return the detected events
3434 *pEvents
= DetectedEvents
& ( Events
3438 if ( NULL
!= pErrno
) {
3442 // Return the operation status
3444 DEBUG (( DEBUG_POLL
, "Exiting SocketPoll, Status: %r\r\n", Status
));
3449 /** Allocate and initialize a ESL_PORT structure.
3451 This routine initializes an ::ESL_PORT structure for use by
3452 the socket. This routine calls a routine via
3453 ESL_PROTOCOL_API::pfnPortAllocate to initialize the network
3454 specific resources. The resources are released later by the
3455 \ref PortCloseStateMachine.
3457 This support routine is called by:
3459 <li>::EslSocketBind</li>
3460 <li>::EslTcp4ListenComplete</li>
3462 to connect the socket with the underlying network adapter
3465 @param[in] pSocket Address of an ::ESL_SOCKET structure.
3466 @param[in] pService Address of an ::ESL_SERVICE structure.
3467 @param[in] ChildHandle Network protocol child handle
3468 @param[in] pSockAddr Address of a sockaddr structure that contains the
3469 connection point on the local machine. An IPv4 address
3470 of INADDR_ANY specifies that the connection is made to
3471 all of the network stacks on the platform. Specifying a
3472 specific IPv4 address restricts the connection to the
3473 network stack supporting that address. Specifying zero
3474 for the port causes the network layer to assign a port
3475 number from the dynamic range. Specifying a specific
3476 port number causes the network layer to use that port.
3477 @param[in] bBindTest TRUE if EslSocketBindTest should be called
3478 @param[in] DebugFlags Flags for debug messages
3479 @param[out] ppPort Buffer to receive new ::ESL_PORT structure address
3481 @retval EFI_SUCCESS - Socket successfully created
3484 EslSocketPortAllocate (
3485 IN ESL_SOCKET
* pSocket
,
3486 IN ESL_SERVICE
* pService
,
3487 IN EFI_HANDLE ChildHandle
,
3488 IN CONST
struct sockaddr
* pSockAddr
,
3489 IN BOOLEAN bBindTest
,
3490 IN UINTN DebugFlags
,
3491 OUT ESL_PORT
** ppPort
3494 UINTN LengthInBytes
;
3499 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3500 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3502 EFI_STATUS TempStatus
;
3507 // Verify the socket layer synchronization
3509 VERIFY_TPL ( TPL_SOCKETS
);
3512 // Use for/break instead of goto
3513 pSocketBinding
= pService
->pSocketBinding
;
3516 // Allocate a port structure
3518 pLayer
= &mEslLayer
;
3519 LengthInBytes
= sizeof ( *pPort
)
3520 + ESL_STRUCTURE_ALIGNMENT_BYTES
3521 + (( pSocketBinding
->RxIo
3522 + pSocketBinding
->TxIoNormal
3523 + pSocketBinding
->TxIoUrgent
)
3524 * sizeof ( ESL_IO_MGMT
));
3525 pPort
= (ESL_PORT
*) AllocateZeroPool ( LengthInBytes
);
3526 if ( NULL
== pPort
) {
3527 Status
= EFI_OUT_OF_RESOURCES
;
3528 pSocket
->errno
= ENOMEM
;
3531 DEBUG (( DebugFlags
| DEBUG_POOL
| DEBUG_INIT
,
3532 "0x%08x: Allocate pPort, %d bytes\r\n",
3537 // Initialize the port
3539 pPort
->DebugFlags
= DebugFlags
;
3540 pPort
->Handle
= ChildHandle
;
3541 pPort
->pService
= pService
;
3542 pPort
->pServiceBinding
= pService
->pServiceBinding
;
3543 pPort
->pSocket
= pSocket
;
3544 pPort
->pSocketBinding
= pService
->pSocketBinding
;
3545 pPort
->Signature
= PORT_SIGNATURE
;
3548 // Open the port protocol
3550 Status
= gBS
->OpenProtocol ( pPort
->Handle
,
3551 pSocketBinding
->pNetworkProtocolGuid
,
3552 &pPort
->pProtocol
.v
,
3553 pLayer
->ImageHandle
,
3555 EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);
3556 if ( EFI_ERROR ( Status
)) {
3557 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3558 "ERROR - Failed to open network protocol GUID on controller 0x%08x\r\n",
3560 pSocket
->errno
= EEXIST
;
3563 DEBUG (( DebugFlags
,
3564 "0x%08x: Network protocol GUID opened on controller 0x%08x\r\n",
3569 // Initialize the port specific resources
3571 Status
= pSocket
->pApi
->pfnPortAllocate ( pPort
,
3573 if ( EFI_ERROR ( Status
)) {
3578 // Set the local address
3580 Status
= pSocket
->pApi
->pfnLocalAddrSet ( pPort
, pSockAddr
, bBindTest
);
3581 if ( EFI_ERROR ( Status
)) {
3586 // Test the address/port configuration
3589 Status
= EslSocketBindTest ( pPort
, pSocket
->pApi
->BindTestErrno
);
3590 if ( EFI_ERROR ( Status
)) {
3596 // Initialize the receive structures
3598 pBuffer
= (UINT8
*)&pPort
[ 1 ];
3599 pBuffer
= &pBuffer
[ ESL_STRUCTURE_ALIGNMENT_BYTES
];
3600 pBuffer
= (UINT8
*)( ESL_STRUCTURE_ALIGNMENT_MASK
& (UINTN
)pBuffer
);
3601 pIo
= (ESL_IO_MGMT
*)pBuffer
;
3602 if (( 0 != pSocketBinding
->RxIo
)
3603 && ( NULL
!= pSocket
->pApi
->pfnRxComplete
)) {
3604 Status
= EslSocketIoInit ( pPort
,
3606 pSocketBinding
->RxIo
,
3608 DebugFlags
| DEBUG_POOL
,
3610 pSocket
->pApi
->pfnRxComplete
);
3611 if ( EFI_ERROR ( Status
)) {
3617 // Initialize the urgent transmit structures
3619 if (( 0 != pSocketBinding
->TxIoUrgent
)
3620 && ( NULL
!= pSocket
->pApi
->pfnTxOobComplete
)) {
3621 Status
= EslSocketIoInit ( pPort
,
3623 pSocketBinding
->TxIoUrgent
,
3625 DebugFlags
| DEBUG_POOL
,
3627 pSocket
->pApi
->pfnTxOobComplete
);
3628 if ( EFI_ERROR ( Status
)) {
3634 // Initialize the normal transmit structures
3636 if (( 0 != pSocketBinding
->TxIoNormal
)
3637 && ( NULL
!= pSocket
->pApi
->pfnTxComplete
)) {
3638 Status
= EslSocketIoInit ( pPort
,
3640 pSocketBinding
->TxIoNormal
,
3642 DebugFlags
| DEBUG_POOL
,
3644 pSocket
->pApi
->pfnTxComplete
);
3645 if ( EFI_ERROR ( Status
)) {
3651 // Add this port to the socket
3653 pPort
->pLinkSocket
= pSocket
->pPortList
;
3654 pSocket
->pPortList
= pPort
;
3655 DEBUG (( DebugFlags
,
3656 "0x%08x: Socket adding port: 0x%08x\r\n",
3661 // Add this port to the service
3663 pPort
->pLinkService
= pService
->pPortList
;
3664 pService
->pPortList
= pPort
;
3674 // Clean up after the error if necessary
3676 if ( EFI_ERROR ( Status
)) {
3677 if ( NULL
!= pPort
) {
3681 EslSocketPortClose ( pPort
);
3685 // Close the port if necessary
3687 pServiceBinding
= pService
->pServiceBinding
;
3688 TempStatus
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3690 if ( !EFI_ERROR ( TempStatus
)) {
3691 DEBUG (( DEBUG_BIND
| DEBUG_POOL
,
3692 "0x%08x: %s port handle destroyed\r\n",
3694 pSocketBinding
->pName
));
3697 DEBUG (( DEBUG_ERROR
| DEBUG_BIND
| DEBUG_POOL
,
3698 "ERROR - Failed to destroy the %s port handle 0x%08x, Status: %r\r\n",
3699 pSocketBinding
->pName
,
3702 ASSERT ( EFI_SUCCESS
== TempStatus
);
3707 // Return the operation status
3709 DBG_EXIT_STATUS ( Status
);
3716 This routine releases the resources allocated by ::EslSocketPortAllocate.
3717 This routine calls ESL_PROTOCOL_API::pfnPortClose to release the network
3720 This routine is called by:
3722 <li>::EslSocketPortAllocate - Port initialization failure</li>
3723 <li>::EslSocketPortCloseRxDone - Last step of close processing</li>
3724 <li>::EslTcp4ConnectComplete - Connection failure and reducing the port list to a single port</li>
3726 See the \ref PortCloseStateMachine section.
3728 @param[in] pPort Address of an ::ESL_PORT structure.
3730 @retval EFI_SUCCESS The port is closed
3731 @retval other Port close error
3734 EslSocketPortClose (
3740 ESL_PACKET
* pPacket
;
3741 ESL_PORT
* pPreviousPort
;
3742 ESL_SERVICE
* pService
;
3743 EFI_SERVICE_BINDING_PROTOCOL
* pServiceBinding
;
3744 CONST ESL_SOCKET_BINDING
* pSocketBinding
;
3745 ESL_SOCKET
* pSocket
;
3751 // Verify the socket layer synchronization
3753 VERIFY_TPL ( TPL_SOCKETS
);
3756 // Locate the port in the socket list
3758 Status
= EFI_SUCCESS
;
3759 pLayer
= &mEslLayer
;
3760 DebugFlags
= pPort
->DebugFlags
;
3761 pSocket
= pPort
->pSocket
;
3762 pPreviousPort
= pSocket
->pPortList
;
3763 if ( pPreviousPort
== pPort
) {
3765 // Remove this port from the head of the socket list
3767 pSocket
->pPortList
= pPort
->pLinkSocket
;
3771 // Locate the port in the middle of the socket list
3773 while (( NULL
!= pPreviousPort
)
3774 && ( pPreviousPort
->pLinkSocket
!= pPort
)) {
3775 pPreviousPort
= pPreviousPort
->pLinkSocket
;
3777 if ( NULL
!= pPreviousPort
) {
3779 // Remove the port from the middle of the socket list
3781 pPreviousPort
->pLinkSocket
= pPort
->pLinkSocket
;
3786 // Locate the port in the service list
3787 // Note that the port may not be in the service list
3788 // if the service has been shutdown.
3790 pService
= pPort
->pService
;
3791 if ( NULL
!= pService
) {
3792 pPreviousPort
= pService
->pPortList
;
3793 if ( pPreviousPort
== pPort
) {
3795 // Remove this port from the head of the service list
3797 pService
->pPortList
= pPort
->pLinkService
;
3801 // Locate the port in the middle of the service list
3803 while (( NULL
!= pPreviousPort
)
3804 && ( pPreviousPort
->pLinkService
!= pPort
)) {
3805 pPreviousPort
= pPreviousPort
->pLinkService
;
3807 if ( NULL
!= pPreviousPort
) {
3809 // Remove the port from the middle of the service list
3811 pPreviousPort
->pLinkService
= pPort
->pLinkService
;
3817 // Empty the urgent receive queue
3819 while ( NULL
!= pSocket
->pRxOobPacketListHead
) {
3820 pPacket
= pSocket
->pRxOobPacketListHead
;
3821 pSocket
->pRxOobPacketListHead
= pPacket
->pNext
;
3822 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxOobBytes
);
3823 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3825 pSocket
->pRxOobPacketListTail
= NULL
;
3826 ASSERT ( 0 == pSocket
->RxOobBytes
);
3829 // Empty the receive queue
3831 while ( NULL
!= pSocket
->pRxPacketListHead
) {
3832 pPacket
= pSocket
->pRxPacketListHead
;
3833 pSocket
->pRxPacketListHead
= pPacket
->pNext
;
3834 pSocket
->pApi
->pfnPacketFree ( pPacket
, &pSocket
->RxBytes
);
3835 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3837 pSocket
->pRxPacketListTail
= NULL
;
3838 ASSERT ( 0 == pSocket
->RxBytes
);
3841 // Empty the receive free queue
3843 while ( NULL
!= pSocket
->pRxFree
) {
3844 pPacket
= pSocket
->pRxFree
;
3845 pSocket
->pRxFree
= pPacket
->pNext
;
3846 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
3850 // Release the network specific resources
3852 if ( NULL
!= pSocket
->pApi
->pfnPortClose
) {
3853 Status
= pSocket
->pApi
->pfnPortClose ( pPort
);
3857 // Done with the normal transmit events
3859 Status
= EslSocketIoFree ( pPort
,
3861 DebugFlags
| DEBUG_POOL
,
3862 "normal transmit" );
3865 // Done with the urgent transmit events
3867 Status
= EslSocketIoFree ( pPort
,
3869 DebugFlags
| DEBUG_POOL
,
3870 "urgent transmit" );
3873 // Done with the receive events
3875 Status
= EslSocketIoFree ( pPort
,
3877 DebugFlags
| DEBUG_POOL
,
3881 // Done with the lower layer network protocol
3883 pSocketBinding
= pPort
->pSocketBinding
;
3884 if ( NULL
!= pPort
->pProtocol
.v
) {
3885 Status
= gBS
->CloseProtocol ( pPort
->Handle
,
3886 pSocketBinding
->pNetworkProtocolGuid
,
3887 pLayer
->ImageHandle
,
3889 if ( !EFI_ERROR ( Status
)) {
3890 DEBUG (( DebugFlags
,
3891 "0x%08x: Network protocol GUID closed on controller 0x%08x\r\n",
3896 DEBUG (( DEBUG_ERROR
| DebugFlags
,
3897 "ERROR - Failed to close network protocol GUID on controller 0x%08x, Status: %r\r\n",
3900 ASSERT ( EFI_SUCCESS
== Status
);
3905 // Done with the network port
3907 pServiceBinding
= pPort
->pServiceBinding
;
3908 if ( NULL
!= pPort
->Handle
) {
3909 Status
= pServiceBinding
->DestroyChild ( pServiceBinding
,
3911 if ( !EFI_ERROR ( Status
)) {
3912 DEBUG (( DebugFlags
| DEBUG_POOL
,
3913 "0x%08x: %s port handle destroyed\r\n",
3915 pSocketBinding
->pName
));
3918 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
3919 "ERROR - Failed to destroy the %s port handle, Status: %r\r\n",
3920 pSocketBinding
->pName
,
3922 ASSERT ( EFI_SUCCESS
== Status
);
3927 // Release the port structure
3929 Status
= gBS
->FreePool ( pPort
);
3930 if ( !EFI_ERROR ( Status
)) {
3931 DEBUG (( DebugFlags
| DEBUG_POOL
,
3932 "0x%08x: Free pPort, %d bytes\r\n",
3934 sizeof ( *pPort
)));
3937 DEBUG (( DEBUG_ERROR
| DebugFlags
| DEBUG_POOL
,
3938 "ERROR - Failed to free pPort: 0x%08x, Status: %r\r\n",
3941 ASSERT ( EFI_SUCCESS
== Status
);
3945 // Mark the socket as closed if necessary
3947 if ( NULL
== pSocket
->pPortList
) {
3948 pSocket
->State
= SOCKET_STATE_CLOSED
;
3949 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3950 "0x%08x: Socket State: SOCKET_STATE_CLOSED\r\n",
3955 // Return the operation status
3957 DBG_EXIT_STATUS ( Status
);
3962 /** Port close state 3.
3964 This routine attempts to complete the port close operation.
3966 This routine is called by the TCP layer upon completion of
3967 the close operation and by ::EslSocketPortCloseTxDone.
3968 See the \ref PortCloseStateMachine section.
3970 @param[in] Event The close completion event
3971 @param[in] pPort Address of an ::ESL_PORT structure.
3974 EslSocketPortCloseComplete (
3983 VERIFY_AT_TPL ( TPL_SOCKETS
);
3985 // Update the port state
3986 pPort
->State
= PORT_STATE_CLOSE_DONE
;
3987 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
3988 "0x%08x: Port Close State: PORT_STATE_CLOSE_DONE\r\n",
3991 // Shutdown the receive operation on the port
3992 if ( NULL
!= pPort
->pfnRxCancel
) {
3993 pIo
= pPort
->pRxActive
;
3994 while ( NULL
!= pIo
) {
3995 EslSocketRxCancel ( pPort
, pIo
);
4000 // Determine if the receive operation is pending
4001 Status
= EslSocketPortCloseRxDone ( pPort
);
4002 DBG_EXIT_STATUS ( Status
);
4007 /** Port close state 4.
4009 This routine determines the state of the receive operations and
4010 continues the close operation after the pending receive operations
4013 This routine is called by
4015 <li>::EslSocketPortCloseComplete</li>
4016 <li>::EslSocketPortCloseTxDone</li>
4017 <li>::EslSocketRxComplete</li>
4019 to determine the state of the receive operations.
4020 See the \ref PortCloseStateMachine section.
4022 @param[in] pPort Address of an ::ESL_PORT structure.
4024 @retval EFI_SUCCESS The port is closed
4025 @retval EFI_NOT_READY The port is still closing
4026 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4027 most likely the routine was called already.
4030 EslSocketPortCloseRxDone (
4039 // Verify the socket layer synchronization
4041 VERIFY_TPL ( TPL_SOCKETS
);
4044 // Verify that the port is closing
4046 Status
= EFI_ALREADY_STARTED
;
4047 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4049 // Determine if the receive operation is pending
4051 Status
= EFI_NOT_READY
;
4052 if ( NULL
== pPort
->pRxActive
) {
4054 // The receive operation is complete
4055 // Update the port state
4057 pPort
->State
= PORT_STATE_CLOSE_RX_DONE
;
4058 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4059 "0x%08x: Port Close State: PORT_STATE_CLOSE_RX_DONE\r\n",
4063 // Complete the port close operation
4065 Status
= EslSocketPortClose ( pPort
);
4068 DEBUG_CODE_BEGIN ();
4072 // Display the outstanding receive operations
4074 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4075 "0x%08x: Port Close: Receive still pending!\r\n",
4077 pIo
= pPort
->pRxActive
;
4078 while ( NULL
!= pIo
) {
4079 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4080 "0x%08x: Packet pending on network adapter\r\n",
4090 // Return the operation status
4092 DBG_EXIT_STATUS ( Status
);
4097 /** Start the close operation on a port, state 1.
4099 This routine marks the port as closed and initiates the \ref
4100 PortCloseStateMachine. The first step is to allow the \ref
4101 TransmitEngine to run down.
4103 This routine is called by ::EslSocketCloseStart to initiate the socket
4104 network specific close operation on the socket.
4106 @param[in] pPort Address of an ::ESL_PORT structure.
4107 @param[in] bCloseNow Set TRUE to abort active transfers
4108 @param[in] DebugFlags Flags for debug messages
4110 @retval EFI_SUCCESS The port is closed, not normally returned
4111 @retval EFI_NOT_READY The port has started the closing process
4112 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4113 most likely the routine was called already.
4116 EslSocketPortCloseStart (
4117 IN ESL_PORT
* pPort
,
4118 IN BOOLEAN bCloseNow
,
4122 ESL_SOCKET
* pSocket
;
4128 // Verify the socket layer synchronization
4130 VERIFY_TPL ( TPL_SOCKETS
);
4133 // Mark the port as closing
4135 Status
= EFI_ALREADY_STARTED
;
4136 pSocket
= pPort
->pSocket
;
4137 pSocket
->errno
= EALREADY
;
4138 if ( PORT_STATE_CLOSE_STARTED
> pPort
->State
) {
4141 // Update the port state
4143 pPort
->State
= PORT_STATE_CLOSE_STARTED
;
4144 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4145 "0x%08x: Port Close State: PORT_STATE_CLOSE_STARTED\r\n",
4147 pPort
->bCloseNow
= bCloseNow
;
4148 pPort
->DebugFlags
= DebugFlags
;
4151 // Determine if transmits are complete
4153 Status
= EslSocketPortCloseTxDone ( pPort
);
4157 // Return the operation status
4159 DBG_EXIT_STATUS ( Status
);
4164 /** Port close state 2.
4166 This routine determines the state of the transmit engine and
4167 continue the close operation after the transmission is complete.
4168 The next step is to stop the \ref ReceiveEngine.
4169 See the \ref PortCloseStateMachine section.
4171 This routine is called by ::EslSocketPortCloseStart to determine
4172 if the transmission is complete.
4174 @param[in] pPort Address of an ::ESL_PORT structure.
4176 @retval EFI_SUCCESS The port is closed, not normally returned
4177 @retval EFI_NOT_READY The port is still closing
4178 @retval EFI_ALREADY_STARTED Error, the port is in the wrong state,
4179 most likely the routine was called already.
4183 EslSocketPortCloseTxDone (
4188 ESL_SOCKET
* pSocket
;
4194 // Verify the socket layer synchronization
4196 VERIFY_TPL ( TPL_SOCKETS
);
4199 // All transmissions are complete or must be stopped
4200 // Mark the port as TX complete
4202 Status
= EFI_ALREADY_STARTED
;
4203 if ( PORT_STATE_CLOSE_STARTED
== pPort
->State
) {
4205 // Verify that the transmissions are complete
4207 pSocket
= pPort
->pSocket
;
4208 if ( pPort
->bCloseNow
4209 || ( EFI_SUCCESS
!= pSocket
->TxError
)
4210 || (( NULL
== pPort
->pTxActive
)
4211 && ( NULL
== pPort
->pTxOobActive
))) {
4213 // Update the port state
4215 pPort
->State
= PORT_STATE_CLOSE_TX_DONE
;
4216 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4217 "0x%08x: Port Close State: PORT_STATE_CLOSE_TX_DONE\r\n",
4222 // Skip the close operation if the port is not configured
4224 Status
= EFI_SUCCESS
;
4225 pSocket
= pPort
->pSocket
;
4226 if (( pPort
->bConfigured
)
4227 && ( NULL
!= pSocket
->pApi
->pfnPortCloseOp
)) {
4229 // Start the close operation
4231 Status
= pSocket
->pApi
->pfnPortCloseOp ( pPort
);
4232 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4233 "0x%08x: Port Close: Close operation still pending!\r\n",
4235 ASSERT ( EFI_SUCCESS
== Status
);
4239 // The receive operation is complete
4240 // Update the port state
4242 EslSocketPortCloseComplete ( NULL
, pPort
);
4247 // Transmissions are still active, exit
4249 Status
= EFI_NOT_READY
;
4250 pSocket
->errno
= EAGAIN
;
4251 DEBUG_CODE_BEGIN ( );
4253 ESL_PACKET
* pPacket
;
4255 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4256 "0x%08x: Port Close: Transmits are still pending!\r\n",
4260 // Display the pending urgent transmit packets
4262 pPacket
= pSocket
->pTxOobPacketListHead
;
4263 while ( NULL
!= pPacket
) {
4264 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4265 "0x%08x: Packet pending on urgent TX list, %d bytes\r\n",
4267 pPacket
->PacketSize
));
4268 pPacket
= pPacket
->pNext
;
4271 pIo
= pPort
->pTxOobActive
;
4272 while ( NULL
!= pIo
) {
4273 pPacket
= pIo
->pPacket
;
4274 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4275 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4277 pPacket
->PacketSize
,
4283 // Display the pending normal transmit packets
4285 pPacket
= pSocket
->pTxPacketListHead
;
4286 while ( NULL
!= pPacket
) {
4287 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4288 "0x%08x: Packet pending on normal TX list, %d bytes\r\n",
4290 pPacket
->PacketSize
));
4291 pPacket
= pPacket
->pNext
;
4294 pIo
= pPort
->pTxActive
;
4295 while ( NULL
!= pIo
) {
4296 pPacket
= pIo
->pPacket
;
4297 DEBUG (( DEBUG_CLOSE
| DEBUG_INFO
,
4298 "0x%08x: Packet active %d bytes, pIo: 0x%08x\r\n",
4300 pPacket
->PacketSize
,
4310 // Return the operation status
4312 DBG_EXIT_STATUS ( Status
);
4317 /** Receive data from a network connection.
4319 This routine calls the network specific routine to remove the
4320 next portion of data from the receive queue and return it to the
4323 The ::recvfrom routine calls this routine to determine if any data
4324 is received from the remote system. Note that the other routines
4325 ::recv and ::read are layered on top of ::recvfrom.
4327 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
4328 @param[in] Flags Message control flags
4329 @param[in] BufferLength Length of the the buffer
4330 @param[in] pBuffer Address of a buffer to receive the data.
4331 @param[in] pDataLength Number of received data bytes in the buffer.
4332 @param[out] pAddress Network address to receive the remote system address
4333 @param[in,out] pAddressLength Length of the remote network address structure
4334 @param[out] pErrno Address to receive the errno value upon completion.
4336 @retval EFI_SUCCESS - Socket data successfully received
4340 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
4342 IN
size_t BufferLength
,
4344 OUT
size_t * pDataLength
,
4345 OUT
struct sockaddr
* pAddress
,
4346 IN OUT socklen_t
* pAddressLength
,
4351 struct sockaddr_in v4
;
4352 struct sockaddr_in6 v6
;
4354 socklen_t AddressLength
;
4355 BOOLEAN bConsumePacket
;
4356 BOOLEAN bUrgentQueue
;
4358 ESL_PACKET
* pNextPacket
;
4359 ESL_PACKET
* pPacket
;
4361 ESL_PACKET
** ppQueueHead
;
4362 ESL_PACKET
** ppQueueTail
;
4363 struct sockaddr
* pRemoteAddress
;
4364 size_t * pRxDataBytes
;
4365 ESL_SOCKET
* pSocket
;
4368 EFI_TPL TplPrevious
;
4375 Status
= EFI_SUCCESS
;
4378 // Validate the socket
4381 if ( NULL
!= pSocketProtocol
) {
4382 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
4385 // Validate the return address parameters
4387 if (( NULL
== pAddress
) || ( NULL
!= pAddressLength
)) {
4389 // Return the transmit error if necessary
4391 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
4392 pSocket
->errno
= EIO
;
4393 Status
= pSocket
->TxError
;
4394 pSocket
->TxError
= EFI_SUCCESS
;
4398 // Verify the socket state
4400 Status
= EslSocketIsConfigured ( pSocket
);
4401 if ( !EFI_ERROR ( Status
)) {
4403 // Validate the buffer length
4405 if (( NULL
== pDataLength
)
4406 || ( NULL
== pBuffer
)) {
4407 if ( NULL
== pDataLength
) {
4409 "ERROR - pDataLength is NULL!\r\n" ));
4413 "ERROR - pBuffer is NULL!\r\n" ));
4415 Status
= EFI_INVALID_PARAMETER
;
4416 pSocket
->errno
= EFAULT
;
4422 if ( NULL
== pSocket
->pApi
->pfnReceive
) {
4423 Status
= EFI_UNSUPPORTED
;
4424 pSocket
->errno
= ENOTSUP
;
4428 // Zero the receive address if being returned
4430 pRemoteAddress
= NULL
;
4431 if ( NULL
!= pAddress
) {
4432 pRemoteAddress
= (struct sockaddr
*)&Addr
;
4433 ZeroMem ( pRemoteAddress
, sizeof ( Addr
));
4434 pRemoteAddress
->sa_family
= pSocket
->pApi
->AddressFamily
;
4435 pRemoteAddress
->sa_len
= (UINT8
)pSocket
->pApi
->AddressLength
;
4439 // Synchronize with the socket layer
4441 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
4446 Status
= EFI_UNSUPPORTED
;
4447 pSocket
->errno
= ENOTCONN
;
4450 // Verify that the socket is connected
4452 if ( SOCKET_STATE_CONNECTED
== pSocket
->State
) {
4454 // Poll the network to increase performance
4456 EslSocketRxPoll ( pSocket
);
4461 pPort
= pSocket
->pPortList
;
4462 if ( NULL
!= pPort
) {
4464 // Determine the queue head
4466 bUrgentQueue
= (BOOLEAN
)( 0 != ( Flags
& MSG_OOB
));
4467 if ( bUrgentQueue
) {
4468 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4469 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4470 pRxDataBytes
= &pSocket
->RxOobBytes
;
4473 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4474 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4475 pRxDataBytes
= &pSocket
->RxBytes
;
4479 // Determine if there is any data on the queue
4482 pPacket
= *ppQueueHead
;
4483 if ( NULL
!= pPacket
) {
4485 // Copy the received data
4489 // Attempt to receive a packet
4492 bConsumePacket
= (BOOLEAN
)( 0 == ( Flags
& MSG_PEEK
));
4493 pBuffer
= pSocket
->pApi
->pfnReceive ( pPort
,
4499 (struct sockaddr
*)&Addr
,
4501 *pDataLength
+= DataLength
;
4502 BufferLength
-= DataLength
;
4505 // Determine if the data is being read
4507 pNextPacket
= pPacket
->pNext
;
4508 if ( bConsumePacket
) {
4510 // All done with this packet
4511 // Account for any discarded data
4513 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxDataBytes
);
4514 if ( 0 != SkipBytes
) {
4516 "0x%08x: Port, packet read, skipping over 0x%08x bytes\r\n",
4522 // Remove this packet from the queue
4524 *ppQueueHead
= pPacket
->pNext
;
4525 if ( NULL
== *ppQueueHead
) {
4526 *ppQueueTail
= NULL
;
4530 // Move the packet to the free queue
4532 pPacket
->pNext
= pSocket
->pRxFree
;
4533 pSocket
->pRxFree
= pPacket
;
4535 "0x%08x: Port freeing packet 0x%08x\r\n",
4540 // Restart the receive operation if necessary
4542 if (( NULL
!= pPort
->pRxFree
)
4543 && ( MAX_RX_DATA
> pSocket
->RxBytes
)) {
4544 EslSocketRxStart ( pPort
);
4549 // Get the next packet
4551 pPacket
= pNextPacket
;
4552 } while (( SOCK_STREAM
== pSocket
->Type
)
4553 && ( NULL
!= pPacket
)
4554 && ( 0 < BufferLength
));
4557 // Successful operation
4559 Status
= EFI_SUCCESS
;
4564 // The queue is empty
4565 // Determine if it is time to return the receive error
4567 if ( EFI_ERROR ( pSocket
->RxError
)
4568 && ( NULL
== pSocket
->pRxPacketListHead
)
4569 && ( NULL
== pSocket
->pRxOobPacketListHead
)) {
4570 Status
= pSocket
->RxError
;
4571 pSocket
->RxError
= EFI_SUCCESS
;
4574 pSocket
->errno
= EIO
;
4577 case EFI_CONNECTION_FIN
:
4579 // Continue to return zero bytes received when the
4580 // peer has successfully closed the connection
4582 pSocket
->RxError
= EFI_CONNECTION_FIN
;
4585 Status
= EFI_SUCCESS
;
4588 case EFI_CONNECTION_REFUSED
:
4589 pSocket
->errno
= ECONNREFUSED
;
4592 case EFI_CONNECTION_RESET
:
4593 pSocket
->errno
= ECONNRESET
;
4596 case EFI_HOST_UNREACHABLE
:
4597 pSocket
->errno
= EHOSTUNREACH
;
4600 case EFI_NETWORK_UNREACHABLE
:
4601 pSocket
->errno
= ENETUNREACH
;
4604 case EFI_PORT_UNREACHABLE
:
4605 pSocket
->errno
= EPROTONOSUPPORT
;
4608 case EFI_PROTOCOL_UNREACHABLE
:
4609 pSocket
->errno
= ENOPROTOOPT
;
4614 Status
= EFI_NOT_READY
;
4615 pSocket
->errno
= EAGAIN
;
4622 // Release the socket layer synchronization
4624 RESTORE_TPL ( TplPrevious
);
4626 if (( !EFI_ERROR ( Status
)) && ( NULL
!= pAddress
)) {
4628 // Return the remote address if requested, truncate if necessary
4630 AddressLength
= pRemoteAddress
->sa_len
;
4631 if ( AddressLength
> *pAddressLength
) {
4632 AddressLength
= *pAddressLength
;
4635 "Returning the remote address, 0x%016x bytes --> 0x%16x\r\n", *pAddressLength
, pAddress
));
4636 ZeroMem ( pAddress
, *pAddressLength
);
4637 CopyMem ( pAddress
, &Addr
, AddressLength
);
4640 // Update the address length
4642 *pAddressLength
= pRemoteAddress
->sa_len
;
4653 // Bad return address pointer and length
4655 Status
= EFI_INVALID_PARAMETER
;
4656 pSocket
->errno
= EINVAL
;
4661 // Return the operation status
4663 if ( NULL
!= pErrno
) {
4664 if ( NULL
!= pSocket
) {
4665 *pErrno
= pSocket
->errno
;
4668 Status
= EFI_INVALID_PARAMETER
;
4672 DBG_EXIT_STATUS ( Status
);
4677 /** Cancel the receive operations.
4679 This routine cancels a pending receive operation.
4680 See the \ref ReceiveEngine section.
4682 This routine is called by ::EslSocketShutdown when the socket
4683 layer is being shutdown.
4685 @param[in] pPort Address of an ::ESL_PORT structure
4686 @param[in] pIo Address of an ::ESL_IO_MGMT structure
4690 IN ESL_PORT
* pPort
,
4691 IN ESL_IO_MGMT
* pIo
4699 // Cancel the outstanding receive
4701 Status
= pPort
->pfnRxCancel ( pPort
->pProtocol
.v
,
4703 if ( !EFI_ERROR ( Status
)) {
4704 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4705 "0x%08x: Packet receive aborted on port: 0x%08x\r\n",
4710 DEBUG (( pPort
->DebugFlags
| DEBUG_CLOSE
| DEBUG_INFO
,
4711 "0x%08x: Packet receive pending on Port 0x%08x, Status: %r\r\n",
4720 /** Process the receive completion.
4722 This routine queues the data in FIFO order in either the urgent
4723 or normal data queues depending upon the type of data received.
4724 See the \ref ReceiveEngine section.
4726 This routine is called when some data is received by:
4728 <li>::EslIp4RxComplete</li>
4729 <li>::EslTcp4RxComplete</li>
4730 <li>::EslUdp4RxComplete</li>
4733 @param[in] pIo Address of an ::ESL_IO_MGMT structure
4734 @param[in] Status Receive status
4735 @param[in] LengthInBytes Length of the receive data
4736 @param[in] bUrgent TRUE if urgent data is received and FALSE
4740 EslSocketRxComplete (
4741 IN ESL_IO_MGMT
* pIo
,
4742 IN EFI_STATUS Status
,
4743 IN UINTN LengthInBytes
,
4747 BOOLEAN bUrgentQueue
;
4748 ESL_IO_MGMT
* pIoNext
;
4749 ESL_PACKET
* pPacket
;
4751 ESL_PACKET
* pPrevious
;
4752 ESL_PACKET
** ppQueueHead
;
4753 ESL_PACKET
** ppQueueTail
;
4755 ESL_SOCKET
* pSocket
;
4758 VERIFY_AT_TPL ( TPL_SOCKETS
);
4761 // Locate the active receive packet
4763 pPacket
= pIo
->pPacket
;
4765 pSocket
= pPort
->pSocket
;
4771 // +-------------+ +-------------+ +-------------+
4772 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4773 // +-------------+ +-------------+ +-------------+
4775 // +-------------+ +-------------+ +-------------+
4776 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
4777 // +-------------+ +-------------+ +-------------+
4783 // Remove the IO structure from the active list
4784 // The following code searches for the entry in the list and does not
4785 // assume that the receive operations complete in the order they were
4786 // issued to the UEFI network layer.
4788 pIoNext
= pPort
->pRxActive
;
4789 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
4791 pIoNext
= pIoNext
->pNext
;
4793 ASSERT ( NULL
!= pIoNext
);
4794 if ( pIoNext
== pIo
) {
4795 pPort
->pRxActive
= pIo
->pNext
; // Beginning of list
4798 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
4802 // Free the IO structure
4804 pIo
->pNext
= pPort
->pRxFree
;
4805 pPort
->pRxFree
= pIo
;
4808 // pRxOobPacketListHead pRxOobPacketListTail
4811 // +------------+ +------------+ +------------+
4812 // Urgent Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4813 // +------------+ +------------+ +------------+
4815 // +------------+ +------------+ +------------+
4816 // Normal Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
4817 // +------------+ +------------+ +------------+
4820 // pRxPacketListHead pRxPacketListTail
4823 // Determine the queue to use
4825 bUrgentQueue
= (BOOLEAN
)( bUrgent
4826 && pSocket
->pApi
->bOobSupported
4827 && ( !pSocket
->bOobInLine
));
4828 if ( bUrgentQueue
) {
4829 ppQueueHead
= &pSocket
->pRxOobPacketListHead
;
4830 ppQueueTail
= &pSocket
->pRxOobPacketListTail
;
4831 pRxBytes
= &pSocket
->RxOobBytes
;
4834 ppQueueHead
= &pSocket
->pRxPacketListHead
;
4835 ppQueueTail
= &pSocket
->pRxPacketListTail
;
4836 pRxBytes
= &pSocket
->RxBytes
;
4840 // Determine if this receive was successful
4842 if (( !EFI_ERROR ( Status
))
4843 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)
4844 && ( !pSocket
->bRxDisable
)) {
4846 // Account for the received data
4848 *pRxBytes
+= LengthInBytes
;
4851 // Log the received data
4853 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4854 "0x%08x: Packet queued on %s queue of port 0x%08x with 0x%08x bytes of %s data\r\n",
4856 bUrgentQueue
? L
"urgent" : L
"normal",
4859 bUrgent
? L
"urgent" : L
"normal" ));
4862 // Add the packet to the list tail.
4864 pPacket
->pNext
= NULL
;
4865 pPrevious
= *ppQueueTail
;
4866 if ( NULL
== pPrevious
) {
4867 *ppQueueHead
= pPacket
;
4870 pPrevious
->pNext
= pPacket
;
4872 *ppQueueTail
= pPacket
;
4875 // Attempt to restart this receive operation
4877 if ( pSocket
->MaxRxBuf
> pSocket
->RxBytes
) {
4878 EslSocketRxStart ( pPort
);
4882 "0x%08x: Port RX suspended, 0x%08x bytes queued\r\n",
4884 pSocket
->RxBytes
));
4888 if ( EFI_ERROR ( Status
)) {
4889 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4890 "ERROR - Receive error on port 0x%08x, packet 0x%08x, Status:%r\r\n",
4897 // Account for the receive bytes and release the driver's buffer
4899 if ( !EFI_ERROR ( Status
)) {
4900 *pRxBytes
+= LengthInBytes
;
4901 pSocket
->pApi
->pfnPacketFree ( pPacket
, pRxBytes
);
4905 // Receive error, free the packet save the error
4907 EslSocketPacketFree ( pPacket
, DEBUG_RX
);
4908 if ( !EFI_ERROR ( pSocket
->RxError
)) {
4909 pSocket
->RxError
= Status
;
4913 // Update the port state
4915 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
4916 if ( PORT_STATE_CLOSE_DONE
== pPort
->State
) {
4917 EslSocketPortCloseRxDone ( pPort
);
4921 if ( EFI_ERROR ( Status
)) {
4922 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
4923 "0x%08x: Port state: PORT_STATE_RX_ERROR, Status: %r\r\n",
4926 pPort
->State
= PORT_STATE_RX_ERROR
;
4935 /** Poll a socket for pending receive activity.
4937 This routine is called at elivated TPL and extends the idle
4938 loop which polls a socket down into the LAN driver layer to
4939 determine if there is any receive activity.
4941 The ::EslSocketPoll, ::EslSocketReceive and ::EslSocketTransmit
4942 routines call this routine when there is nothing to do.
4944 @param[in] pSocket Address of an ::EFI_SOCKET structure.
4948 IN ESL_SOCKET
* pSocket
4953 DEBUG (( DEBUG_POLL
, "Entering EslSocketRxPoll\r\n" ));
4956 // Increase the network performance by extending the
4957 // polling (idle) loop down into the LAN driver
4959 pPort
= pSocket
->pPortList
;
4960 while ( NULL
!= pPort
) {
4962 // Poll the LAN adapter
4964 pPort
->pfnRxPoll ( pPort
->pProtocol
.v
);
4967 // Locate the next LAN adapter
4969 pPort
= pPort
->pLinkSocket
;
4972 DEBUG (( DEBUG_POLL
, "Exiting EslSocketRxPoll\r\n" ));
4976 /** Start a receive operation.
4978 This routine posts a receive buffer to the network adapter.
4979 See the \ref ReceiveEngine section.
4981 This support routine is called by:
4983 <li>::EslIp4Receive to restart the receive engine to release flow control.</li>
4984 <li>::EslIp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4985 <li>::EslIp4SocketIsConfigured to start the receive engine for the new socket.</li>
4986 <li>::EslTcp4ListenComplete to start the recevie engine for the new socket.</li>
4987 <li>::EslTcp4Receive to restart the receive engine to release flow control.</li>
4988 <li>::EslTcp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4989 <li>::EslUdp4Receive to restart the receive engine to release flow control.</li>
4990 <li>::EslUdp4RxComplete to continue the operation of the receive engine if flow control is not being applied.</li>
4991 <li>::EslUdp4SocketIsConfigured to start the recevie engine for the new socket.</li>
4994 @param[in] pPort Address of an ::ESL_PORT structure.
5003 ESL_PACKET
* pPacket
;
5004 ESL_SOCKET
* pSocket
;
5010 // Determine if a receive is already pending
5012 Status
= EFI_SUCCESS
;
5014 pSocket
= pPort
->pSocket
;
5015 if ( !EFI_ERROR ( pPort
->pSocket
->RxError
)) {
5016 if (( NULL
!= pPort
->pRxFree
)
5017 && ( !pSocket
->bRxDisable
)
5018 && ( PORT_STATE_CLOSE_STARTED
> pPort
->State
)) {
5020 // Start all of the pending receive operations
5022 while ( NULL
!= pPort
->pRxFree
) {
5024 // Determine if there are any free packets
5026 pPacket
= pSocket
->pRxFree
;
5027 if ( NULL
!= pPacket
) {
5029 // Remove this packet from the free list
5031 pSocket
->pRxFree
= pPacket
->pNext
;
5033 "0x%08x: Port removed packet 0x%08x from free list\r\n",
5039 // Allocate a packet structure
5041 Status
= EslSocketPacketAllocate ( &pPacket
,
5042 pSocket
->pApi
->RxPacketBytes
,
5043 pSocket
->pApi
->RxZeroBytes
,
5045 if ( EFI_ERROR ( Status
)) {
5047 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5048 "0x%08x: Port failed to allocate RX packet, Status: %r\r\n",
5056 // Connect the IO and packet structures
5058 pIo
= pPort
->pRxFree
;
5059 pIo
->pPacket
= pPacket
;
5062 // Eliminate the need for IP4 and UDP4 specific routines by
5063 // clearing the RX data pointer here.
5065 // No driver buffer for this packet
5067 // +--------------------+
5070 // | +---------------+
5072 // | | RxData --> NULL
5073 // +----+---------------+
5075 pBuffer
= (UINT8
*)pIo
;
5076 pBuffer
= &pBuffer
[ pSocket
->pApi
->RxBufferOffset
];
5077 *(VOID
**)pBuffer
= NULL
;
5080 // Network specific receive packet initialization
5082 if ( NULL
!= pSocket
->pApi
->pfnRxStart
) {
5083 pSocket
->pApi
->pfnRxStart ( pPort
, pIo
);
5087 // Start the receive on the packet
5089 Status
= pPort
->pfnRxStart ( pPort
->pProtocol
.v
, &pIo
->Token
);
5090 if ( !EFI_ERROR ( Status
)) {
5091 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5092 "0x%08x: Packet receive pending on port 0x%08x\r\n",
5096 // Allocate the receive control structure
5098 pPort
->pRxFree
= pIo
->pNext
;
5101 // Mark this receive as pending
5103 pIo
->pNext
= pPort
->pRxActive
;
5104 pPort
->pRxActive
= pIo
;
5108 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5109 "ERROR - Failed to post a receive on port 0x%08x, Status: %r\r\n",
5112 if ( !EFI_ERROR ( pSocket
->RxError
)) {
5114 // Save the error status
5116 pSocket
->RxError
= Status
;
5122 pIo
->pPacket
= NULL
;
5123 pPacket
->pNext
= pSocket
->pRxFree
;
5124 pSocket
->pRxFree
= pPacket
;
5130 if ( NULL
== pPort
->pRxFree
) {
5131 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5132 "0x%08x: Port, no available ESL_IO_MGMT structures\r\n",
5135 if ( pSocket
->bRxDisable
) {
5136 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5137 "0x%08x: Port, receive disabled!\r\n",
5140 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5141 DEBUG (( DEBUG_RX
| DEBUG_INFO
,
5142 "0x%08x: Port, is closing!\r\n",
5148 DEBUG (( DEBUG_ERROR
| DEBUG_RX
,
5149 "ERROR - Previous receive error, Status: %r\r\n",
5150 pPort
->pSocket
->RxError
));
5157 /** Shutdown the socket receive and transmit operations.
5159 This routine sets a flag to stop future transmissions and calls
5160 the network specific layer to cancel the pending receive operation.
5162 The ::shutdown routine calls this routine to stop receive and transmit
5163 operations on the socket.
5165 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5166 @param[in] How Which operations to stop
5167 @param[out] pErrno Address to receive the errno value upon completion.
5169 @retval EFI_SUCCESS - Socket operations successfully shutdown
5173 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5180 ESL_SOCKET
* pSocket
;
5182 EFI_TPL TplPrevious
;
5189 Status
= EFI_SUCCESS
;
5192 // Validate the socket
5195 if ( NULL
!= pSocketProtocol
) {
5196 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5199 // Verify that the socket is connected
5201 if ( pSocket
->bConnected
) {
5203 // Validate the How value
5205 if (( SHUT_RD
<= How
) && ( SHUT_RDWR
>= How
)) {
5207 // Synchronize with the socket layer
5209 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5212 // Disable the receiver if requested
5214 if (( SHUT_RD
== How
) || ( SHUT_RDWR
== How
)) {
5215 pSocket
->bRxDisable
= TRUE
;
5219 // Disable the transmitter if requested
5221 if (( SHUT_WR
== How
) || ( SHUT_RDWR
== How
)) {
5222 pSocket
->bTxDisable
= TRUE
;
5226 // Cancel the pending receive operations
5228 if ( pSocket
->bRxDisable
) {
5230 // Walk the list of ports
5232 pPort
= pSocket
->pPortList
;
5233 while ( NULL
!= pPort
) {
5235 // Walk the list of active receive operations
5237 pIo
= pPort
->pRxActive
;
5238 while ( NULL
!= pIo
) {
5239 EslSocketRxCancel ( pPort
, pIo
);
5243 // Set the next port
5245 pPort
= pPort
->pLinkSocket
;
5250 // Release the socket layer synchronization
5252 RESTORE_TPL ( TplPrevious
);
5256 // Invalid How value
5258 pSocket
->errno
= EINVAL
;
5259 Status
= EFI_INVALID_PARAMETER
;
5264 // The socket is not connected
5266 pSocket
->errno
= ENOTCONN
;
5267 Status
= EFI_NOT_STARTED
;
5272 // Return the operation status
5274 if ( NULL
!= pErrno
) {
5275 if ( NULL
!= pSocket
) {
5276 *pErrno
= pSocket
->errno
;
5279 Status
= EFI_INVALID_PARAMETER
;
5283 DBG_EXIT_STATUS ( Status
);
5288 /** Send data using a network connection.
5290 This routine calls the network specific layer to queue the data
5291 for transmission. Eventually the buffer will reach the head of
5292 the queue and will get transmitted over the network by the
5293 \ref TransmitEngine. For datagram
5294 sockets (SOCK_DGRAM and SOCK_RAW) there is no guarantee that
5295 the data reaches the application running on the remote system.
5297 The ::sendto routine calls this routine to send data to the remote
5298 system. Note that ::send and ::write are layered on top of ::sendto.
5300 @param[in] pSocketProtocol Address of an ::EFI_SOCKET_PROTOCOL structure.
5301 @param[in] Flags Message control flags
5302 @param[in] BufferLength Length of the the buffer
5303 @param[in] pBuffer Address of a buffer containing the data to send
5304 @param[in] pDataLength Address to receive the number of data bytes sent
5305 @param[in] pAddress Network address of the remote system address
5306 @param[in] AddressLength Length of the remote network address structure
5307 @param[out] pErrno Address to receive the errno value upon completion.
5309 @retval EFI_SUCCESS - Socket data successfully queued for transmit
5313 IN EFI_SOCKET_PROTOCOL
* pSocketProtocol
,
5315 IN
size_t BufferLength
,
5316 IN CONST UINT8
* pBuffer
,
5317 OUT
size_t * pDataLength
,
5318 IN
const struct sockaddr
* pAddress
,
5319 IN socklen_t AddressLength
,
5323 ESL_SOCKET
* pSocket
;
5325 EFI_TPL TplPrevious
;
5332 Status
= EFI_SUCCESS
;
5335 // Validate the socket
5338 if ( NULL
!= pSocketProtocol
) {
5339 pSocket
= SOCKET_FROM_PROTOCOL ( pSocketProtocol
);
5342 // Return the transmit error if necessary
5344 if ( EFI_SUCCESS
!= pSocket
->TxError
) {
5345 pSocket
->errno
= EIO
;
5346 Status
= pSocket
->TxError
;
5347 pSocket
->TxError
= EFI_SUCCESS
;
5351 // Verify the socket state
5353 Status
= EslSocketIsConfigured ( pSocket
);
5354 if ( !EFI_ERROR ( Status
)) {
5356 // Verify that transmit is still allowed
5358 if ( !pSocket
->bTxDisable
) {
5360 // Validate the buffer length
5362 if (( NULL
== pDataLength
)
5363 && ( 0 > pDataLength
)
5364 && ( NULL
== pBuffer
)) {
5365 if ( NULL
== pDataLength
) {
5367 "ERROR - pDataLength is NULL!\r\n" ));
5369 else if ( NULL
== pBuffer
) {
5371 "ERROR - pBuffer is NULL!\r\n" ));
5375 "ERROR - Data length < 0!\r\n" ));
5377 Status
= EFI_INVALID_PARAMETER
;
5378 pSocket
->errno
= EFAULT
;
5382 // Validate the remote network address
5384 if (( NULL
!= pAddress
)
5385 && ( AddressLength
< pAddress
->sa_len
)) {
5387 "ERROR - Invalid sin_len field in address\r\n" ));
5388 Status
= EFI_INVALID_PARAMETER
;
5389 pSocket
->errno
= EFAULT
;
5395 if ( NULL
== pSocket
->pApi
->pfnTransmit
) {
5396 Status
= EFI_UNSUPPORTED
;
5397 pSocket
->errno
= ENOTSUP
;
5401 // Synchronize with the socket layer
5403 RAISE_TPL ( TplPrevious
, TPL_SOCKETS
);
5406 // Poll the network to increase performance
5408 EslSocketRxPoll ( pSocket
);
5411 // Attempt to buffer the packet for transmission
5413 Status
= pSocket
->pApi
->pfnTransmit ( pSocket
,
5422 // Release the socket layer synchronization
5424 RESTORE_TPL ( TplPrevious
);
5431 // The transmitter was shutdown
5433 pSocket
->errno
= EPIPE
;
5434 Status
= EFI_NOT_STARTED
;
5441 // Return the operation status
5443 if ( NULL
!= pErrno
) {
5444 if ( NULL
!= pSocket
) {
5445 *pErrno
= pSocket
->errno
;
5448 Status
= EFI_INVALID_PARAMETER
;
5452 DBG_EXIT_STATUS ( Status
);
5457 /** Complete the transmit operation.
5459 This support routine handles the transmit completion processing for
5460 the various network layers. It frees the ::ESL_IO_MGMT structure
5461 and and frees packet resources by calling ::EslSocketPacketFree.
5462 Transmit errors are logged in ESL_SOCKET::TxError.
5463 See the \ref TransmitEngine section.
5465 This routine is called by:
5467 <li>::EslIp4TxComplete</li>
5468 <li>::EslTcp4TxComplete</li>
5469 <li>::EslTcp4TxOobComplete</li>
5470 <li>::EslUdp4TxComplete</li>
5473 @param[in] pIo Address of an ::ESL_IO_MGMT structure
5474 @param[in] LengthInBytes Length of the data in bytes
5475 @param[in] Status Transmit operation status
5476 @param[in] pQueueType Zero terminated string describing queue type
5477 @param[in] ppQueueHead Transmit queue head address
5478 @param[in] ppQueueTail Transmit queue tail address
5479 @param[in] ppActive Active transmit queue address
5480 @param[in] ppFree Free transmit queue address
5483 EslSocketTxComplete (
5484 IN ESL_IO_MGMT
* pIo
,
5485 IN UINT32 LengthInBytes
,
5486 IN EFI_STATUS Status
,
5487 IN CONST CHAR8
* pQueueType
,
5488 IN ESL_PACKET
** ppQueueHead
,
5489 IN ESL_PACKET
** ppQueueTail
,
5490 IN ESL_IO_MGMT
** ppActive
,
5491 IN ESL_IO_MGMT
** ppFree
5494 ESL_PACKET
* pCurrentPacket
;
5495 ESL_IO_MGMT
* pIoNext
;
5496 ESL_PACKET
* pNextPacket
;
5497 ESL_PACKET
* pPacket
;
5499 ESL_SOCKET
* pSocket
;
5502 VERIFY_AT_TPL ( TPL_SOCKETS
);
5505 // Locate the active transmit packet
5507 pPacket
= pIo
->pPacket
;
5509 pSocket
= pPort
->pSocket
;
5514 pIo
->pPacket
= NULL
;
5517 // Remove the IO structure from the active list
5519 pIoNext
= *ppActive
;
5520 while (( NULL
!= pIoNext
) && ( pIoNext
!= pIo
) && ( pIoNext
->pNext
!= pIo
))
5522 pIoNext
= pIoNext
->pNext
;
5524 ASSERT ( NULL
!= pIoNext
);
5525 if ( pIoNext
== pIo
) {
5526 *ppActive
= pIo
->pNext
; // Beginning of list
5529 pIoNext
->pNext
= pIo
->pNext
; // Middle of list
5533 // Free the IO structure
5535 pIo
->pNext
= *ppFree
;
5539 // Display the results
5541 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5542 "0x%08x: pIo Released\r\n",
5546 // Save any transmit error
5548 if ( EFI_ERROR ( Status
)) {
5549 if ( !EFI_ERROR ( pSocket
->TxError
)) {
5550 pSocket
->TxError
= Status
;
5552 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5553 "ERROR - Transmit failure for %apacket 0x%08x, Status: %r\r\n",
5559 // Empty the normal transmit list
5561 pCurrentPacket
= pPacket
;
5562 pNextPacket
= *ppQueueHead
;
5563 while ( NULL
!= pNextPacket
) {
5564 pPacket
= pNextPacket
;
5565 pNextPacket
= pPacket
->pNext
;
5566 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5568 *ppQueueHead
= NULL
;
5569 *ppQueueTail
= NULL
;
5570 pPacket
= pCurrentPacket
;
5573 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5574 "0x%08x: %apacket transmitted %d bytes successfully\r\n",
5580 // Verify the transmit engine is still running
5582 if ( !pPort
->bCloseNow
) {
5584 // Start the next packet transmission
5586 EslSocketTxStart ( pPort
,
5595 // Release this packet
5597 EslSocketPacketFree ( pPacket
, DEBUG_TX
);
5600 // Finish the close operation if necessary
5602 if ( PORT_STATE_CLOSE_STARTED
<= pPort
->State
) {
5604 // Indicate that the transmit is complete
5606 EslSocketPortCloseTxDone ( pPort
);
5613 /** Transmit data using a network connection.
5615 This support routine starts a transmit operation on the
5616 underlying network layer.
5618 The network specific code calls this routine to start a
5619 transmit operation. See the \ref TransmitEngine section.
5621 @param[in] pPort Address of an ::ESL_PORT structure
5622 @param[in] ppQueueHead Transmit queue head address
5623 @param[in] ppQueueTail Transmit queue tail address
5624 @param[in] ppActive Active transmit queue address
5625 @param[in] ppFree Free transmit queue address
5629 IN ESL_PORT
* pPort
,
5630 IN ESL_PACKET
** ppQueueHead
,
5631 IN ESL_PACKET
** ppQueueTail
,
5632 IN ESL_IO_MGMT
** ppActive
,
5633 IN ESL_IO_MGMT
** ppFree
5638 ESL_PACKET
* pNextPacket
;
5639 ESL_PACKET
* pPacket
;
5640 VOID
** ppTokenData
;
5641 ESL_SOCKET
* pSocket
;
5649 Status
= EFI_SUCCESS
;
5652 // Get the packet from the queue head
5654 pPacket
= *ppQueueHead
;
5656 if (( NULL
!= pPacket
) && ( NULL
!= pIo
)) {
5657 pSocket
= pPort
->pSocket
;
5659 // *ppQueueHead: pSocket->pRxPacketListHead or pSocket->pRxOobPacketListHead
5662 // +------------+ +------------+ +------------+
5663 // Data | ESL_PACKET |-->| ESL_PACKET |-->| ESL_PACKET |--> NULL
5664 // +------------+ +------------+ +------------+
5667 // *ppQueueTail: pSocket->pRxPacketListTail or pSocket->pRxOobPacketListTail
5670 // Remove the packet from the queue
5672 pNextPacket
= pPacket
->pNext
;
5673 *ppQueueHead
= pNextPacket
;
5674 if ( NULL
== pNextPacket
) {
5675 *ppQueueTail
= NULL
;
5677 pPacket
->pNext
= NULL
;
5680 // Eliminate the need for IP4 and UDP4 specific routines by
5681 // connecting the token with the TX data control structure here.
5683 // +--------------------+ +--------------------+
5684 // | ESL_IO_MGMT | | ESL_PACKET |
5686 // | +---------------+ +----------------+ |
5687 // | | Token | | Buffer Length | |
5688 // | | TxData --> | Buffer Address | |
5689 // | | | +----------------+---+
5690 // | | Event | | Data Buffer |
5691 // +----+---------------+ | |
5692 // +--------------------+
5694 // Compute the address of the TxData pointer in the token
5696 pBuffer
= (UINT8
*)&pIo
->Token
;
5697 pBuffer
= &pBuffer
[ pSocket
->TxTokenOffset
];
5698 ppTokenData
= (VOID
**)pBuffer
;
5701 // Compute the address of the TX data control structure in the packet
5703 // * EFI_IP4_TRANSMIT_DATA
5704 // * EFI_TCP4_TRANSMIT_DATA
5705 // * EFI_UDP4_TRANSMIT_DATA
5707 pBuffer
= (UINT8
*)pPacket
;
5708 pBuffer
= &pBuffer
[ pSocket
->TxPacketOffset
];
5711 // Connect the token to the transmit data control structure
5713 *ppTokenData
= (VOID
**)pBuffer
;
5716 // Display the results
5718 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5719 "0x%08x: pIo allocated for pPacket: 0x%08x\r\n",
5724 // Start the transmit operation
5726 Status
= pPort
->pfnTxStart ( pPort
->pProtocol
.v
,
5728 if ( !EFI_ERROR ( Status
)) {
5730 // Connect the structures
5732 pIo
->pPacket
= pPacket
;
5735 // +-------------+ +-------------+ +-------------+
5736 // Free | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5737 // +-------------+ +-------------+ +-------------+
5740 // *ppFree: pPort->pTxFree or pTxOobFree
5743 // Remove the IO structure from the queue
5745 *ppFree
= pIo
->pNext
;
5748 // *ppActive: pPort->pTxActive or pTxOobActive
5751 // +-------------+ +-------------+ +-------------+
5752 // Active | ESL_IO_MGMT |-->| ESL_IO_MGMT |-->| ESL_IO_MGMT |--> NULL
5753 // +-------------+ +-------------+ +-------------+
5756 // Mark this packet as active
5758 pIo
->pPacket
= pPacket
;
5759 pIo
->pNext
= *ppActive
;
5764 // Display the transmit error
5766 DEBUG (( DEBUG_TX
| DEBUG_INFO
,
5767 "0x%08x, 0x%08x: pIo, pPacket transmit failure: %r\r\n",
5771 if ( EFI_SUCCESS
== pSocket
->TxError
) {
5772 pSocket
->TxError
= Status
;
5776 // Free the IO structure
5778 pIo
->pNext
= *ppFree
;
5782 // Discard the transmit buffer
5784 EslSocketPacketFree ( pPacket
, DEBUG_TX
);